0

I am beating my head against a wall trying to figure out how to resize and rearrange the camera app I am building on Raspberry Pi. I want to be able to resize the window by tapping on the video, from a full-screen app to a smaller version that will display in the corner of my touch screen.

https://github.com/eighty2fifty1/multicam

Small Screen

Full Screen

I'm using OpenCV to run the camera itself. While the point of the app is to run 4 cameras and switch between them, that all happens in external hardware, so just think of it as displaying one USB webcam. I'm not completely set on using OpenCV for this, but it's worked so far.

I also seem to get segmentation faults on my RPi 4 when I try to adjust the size, minimize, or maximize the window. Not sure if that's related, but I've tried it using two brand new SD cards hoping to rule out a hardware problem.

What I've tried:

  • Programatically rearranging the window. Won't display video and also gives me a segmentation fault.

  • Subclassing MyWindowClass into BigWindowClass and SmallWindowClass, then sending the separate .ui files to their respective classes, then using the .show() and .hide() methods to determine which one I want displayed. This will show the video in the big window, but not the small one.

I left out a few of my functions for clarity's sake, but the full source code is in the github link above.

class Thread(QThread):
    global file, big, small
    changePixmap = pyqtSignal(QImage)

    def run(self):
        cap = cv2.VideoCapture(0)
        while running:
            ret, frame = cap.read()
            if ret:
                # not sure if the queue was necessary to prevent memory or processor problems
                if q.qsize() < 10:
                    q.put(frame)
                else:
                    print(q.qsize())

                if not q.empty():
                    f = q.get()
                    rgbImage = cv2.cvtColor(f, cv2.COLOR_BGR2RGB)
                    h, w, ch = rgbImage.shape
                    bytesPerLine = ch * w
                    convertToQtFormat = QImage(rgbImage.data, w, h, bytesPerLine, QImage.Format_RGB888)
                    if file == big:
                        p = convertToQtFormat.scaled(640, 480, Qt.KeepAspectRatio)
                    elif file == small:
                        p = convertToQtFormat.scaled(200, 150, Qt.KeepAspectRatio)

                    else:
                        pass
                    self.changePixmap.emit(p)

        if self.isFinished():
            print("thread killed")


class MyWindowClass(QMainWindow, form_class):
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        self.setupUi(self)
        self.sel = Selector()
        self.press = 0
        self.rel = 0

        self.videoLbl = ClickableLabel(self.videoLbl)
        self.setWindowTitle('Camera')

        self.connectSignals()
        self.th = Thread(self)
        self.th.changePixmap.connect(self.setImage)
        self.th.start()
        self.show()

    @pyqtSlot(QImage)
    def setImage(self, image):
        pixmap = QPixmap.fromImage(image)
        self.videoLbl.setPixmap(pixmap)

 # this will eventually be the function to change views
    def _resize(self):
        print("resize clicked")

    # signal connections
    def connectSignals(self):
        self.cam1.clicked.connect(lambda: self.sel.selectCamera(1))
        self.cam2.clicked.connect(lambda: self.sel.selectCamera(2))
        self.cam3.clicked.connect(lambda: self.sel.selectCamera(3))
        self.cam4.clicked.connect(lambda: self.sel.selectCamera(4))

        self.buttonGroup.setId(self.cam1, 1)
        self.buttonGroup.setId(self.cam2, 2)
        self.buttonGroup.setId(self.cam3, 3)
        self.buttonGroup.setId(self.cam4, 4)
        '''
        self.resizeButton.clicked.connect(resizeWindow)
        self.posCheck.clicked.connect(posit)
        '''
        self.pairButton.pressed.connect(self.prPress)
        self.pairButton.released.connect(self.prRel)

        self.sel.camSelected.connect(self.selected)
        self.videoLbl.clicked.connect(self._resize)


app = QtWidgets.QApplication(sys.argv)
window = MyWindowClass(None)
window.show()
running = True

app.exec_()
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
James Ford
  • 123
  • 6

1 Answers1

1

So I found a solution on my own. It's probably not the most elegant or efficient but it is working. I got a big clue from Qt crashes when picture from OpenCV is too large that I need to copy my QImage first.

convertToQtFormat = QImage(rgbImage.data, w, h, bytesPerLine, QImage.Format_RGB888)
i = convertToQtFormat.copy()
self.changePixmap.emit(i)

I revisited the attempt at subclassing my Main Window and using 2 separate .ui files, and after a few more tweaks, the program works as desired.

https://github.com/eighty2fifty1/multicam/blob/master/multicam4.py

James Ford
  • 123
  • 6
  • Thank you!! I encountered exactly the same problem. I got segment fault when executing my python script. And if I ran the script with gdb, gdb reported that the segment fault happened in this function: qt_convert_rgb888_to_rgb32(unsigned int*, unsigned char const*, int) () from /lib/arm-linux-gnueabihf/libQt5Gui.so.5. – FreemanX Nov 19 '21 at 03:12