英文:
Pyside6 Multi threading Opencv Webcam
问题
在以下代码中,我有一个使用Pyside6创建的应用程序,动态创建了一组标签和下拉框,它们是并排排列的。每个下拉框右侧都有一个可用摄像头的列表,而左侧(黑色背景)有一个标签列表,用于显示摄像头。
我使用了currentIndexChanged
,每当选择任何摄像头设备时,线程都会启动,并在最后一个标签上显示。
我遇到的困难是:
- 基于下拉框的索引,我想在标签的相同索引上显示视频流(在这个示例中,我选择了索引0的下拉框,但在索引4的标签上显示)。
- 将所选摄像头的索引(在各个下拉框中)传递给
cv2.VideoCapture(index)
,以便用户可以选择要显示的摄像头。 - 如何进行多线程,以便同时显示多个摄像头。
以下是代码:
import sys
from PySide6 import QtWidgets
from PySide6.QtCore import Qt, QThread, Signal, Slot
from PySide6.QtGui import QImage
from PySide6.QtGui import QIcon, QPixmap, QImage
from PySide6.QtMultimedia import QMediaDevices
import cv2
class MyWidget(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.layout = QtWidgets.QGridLayout(self)
self.lists = ["1", "2", "3"]
self.availableCameras = []
self.th = Thread(self)
self.th.finished.connect(self.close)
self.th.updateFrame.connect(self.setImage)
for i in range(5):
self.label = QtWidgets.QLabel(self)
self.label.id_number = i
self.label.setStyleSheet("background-color: black;")
self.layout.addWidget(self.label, i, 0)
self.combobox = QtWidgets.QComboBox(self)
self.combobox.id_number = i
self.getAvailableCameras()
self.combobox.addItems(self.availableCameras)
self.layout.addWidget(self.combobox, i, 1)
self.combobox.currentIndexChanged.connect(self.runWebCam)
@Slot(QImage)
def runWebCam(self, idx):
combo = self.sender()
print(f"Selected the variable {idx} from combo {combo.id_number}")
self.th.start()
@Slot(QImage)
def setImage(self, image):
self.label.setPixmap(QPixmap.fromImage(image)
def getAvailableCameras(self):
cameras = QMediaDevices.videoInputs()
for cameraDevice in cameras:
self.availableCameras.append(cameraDevice.description())
class Thread(QThread):
updateFrame = Signal(QImage)
def __init__(self, parent=None):
QThread.__init__(self, parent)
self.status = True
self.cap = True
def run(self):
self.cap = cv2.VideoCapture(0)
while self.status:
ret, frame = self.cap.read()
if not ret:
continue
h, w, ch = frame.shape
img = QImage(frame.data, w, h, ch * w, QImage.Format_RGB888)
scaled_img = img.scaled(640, 480, Qt.KeepAspectRatio)
# Emit signal
self.updateFrame.emit(scaled_img)
sys.exit(-1)
if __name__ == "__main__":
app = QtWidgets.QApplication([])
widget = MyWidget()
widget.resize(800, 600)
widget.show()
sys.exit(app.exec_())
<details>
<summary>英文:</summary>
In the below code I have a Pyside6 application that dynamically creates a list of labels and comboboxes paralel to each other.
To the right, each combobox has a list of available cameras and to the left(colored in black) I have a list of labels where in which I want to display the cameras.
- This is what it looks like:
---
[![enter image description here][1]][1]
As I used the `currentIndexChanged`, whenevever you select any camera device, the thread will be launched and will be displayed at the last label.
Like so:
---
[![enter image description here][2]][2]
---
What I am struggling with, is:
1) Based on the index of the combobox I want to display the video stream on the same index of the label(as in this example i selected the combo box at index 0 but it displayed in label at index 4)
2) Pass the index of the selected camera(in the individual combobox) to the `cv2.VideoCapture(index)` so that the user can select what camera they want to display
3) How to be able to multi thread, so as to be able to display multiple cameras at the same time.
Here is the code:
---
import sys
from PySide6 import QtWidgets
from PySide6.QtCore import Qt, QThread, Signal, Slot
from PySide6.QtGui import QImage
from PySide6.QtGui import QIcon, QPixmap, QImage
from PySide6.QtMultimedia import QMediaDevices
import cv2
class MyWidget(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.layout = QtWidgets.QGridLayout(self)
self.lists = ["1", "2", "3"]
self.availableCameras = []
self.th = Thread(self)
self.th.finished.connect(self.close)
self.th.updateFrame.connect(self.setImage)
for i in range(5):
self.label = QtWidgets.QLabel(self)
self.label.id_number = i
self.label.setStyleSheet(u"background-color: black;")
self.layout.addWidget(self.label, i, 0)
self.combobox = QtWidgets.QComboBox(self)
self.combobox.id_number = i
self.getAvailableCameras()
self.combobox.addItems(self.availableCameras)
self.layout.addWidget(self.combobox, i, 1)
self.combobox.currentIndexChanged.connect(self.runWebCam)
@Slot(QImage)
def runWebCam(self, idx):
combo = self.sender()
print(f"Selected the variable {idx} from combo {combo.id_number}")
self.th.start()
@Slot(QImage)
def setImage(self, image):
self.label.setPixmap(QPixmap.fromImage(image))
def getAvailableCameras(self):
cameras = QMediaDevices.videoInputs()
for cameraDevice in cameras:
self.availableCameras.append(cameraDevice.description())
class Thread(QThread):
updateFrame = Signal(QImage)
def __init__(self, parent=None):
QThread.__init__(self, parent)
self.status = True
self.cap = True
def run(self):
self.cap = cv2.VideoCapture(0)
while self.status:
ret, frame = self.cap.read()
if not ret:
continue
h, w, ch = frame.shape
img = QImage(frame.data, w, h, ch * w, QImage.Format_RGB888)
scaled_img = img.scaled(640, 480, Qt.KeepAspectRatio)
# Emit signal
self.updateFrame.emit(scaled_img)
sys.exit(-1)
if __name__ == "__main__":
app = QtWidgets.QApplication([])
widget = MyWidget()
widget.resize(800, 600)
widget.show()
sys.exit(app.exec_())
[1]: https://i.stack.imgur.com/sfNXy.png
[2]: https://i.stack.imgur.com/9nHAX.png
</details>
# 答案1
**得分**: 1
```python
def runWebCam(self, idx):
self.idx = idx
combo = self.sender()
print(f"Selected the variable {idx} from combo {combo.id_number}")
self.th.start()
def setImage(self, image):
self.label_list[self.idx].setPixmap(QPixmap.fromImage(image))
'''here self.label is the widget object of the last label which you have created.
I tried storing the self.label into a list **(self.label_list)** and when you are selecting the item in the combo_box, get the idx value.
Using the above idx value as a list index, select the right label to display.
[See the picture attached][1]'''
英文:
def runWebCam(self, idx):
self.idx = idx
combo = self.sender()
print(f"Selected the variable {idx} from combo {combo.id_number}")
self.th.start()
def setImage(self, image):
self.label_list[self.idx].setPixmap(QPixmap.fromImage(image))
'''here self.label is the widget object of last label which you have created.
I tried storing the self.label into a list (self.label_list) and when you are selecting the item in the combo_box getting the idx value
Using the above idx value as list index, selecting the right label to display.
See the picture attached'''
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论