0

I am trying to have a shape on the video while still having that video as a label instead of having it as a background.

import os
import sys
import numpy as np
import cv2

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *

 # https://stackoverflow.com/questions/67488022/how-do-i-run-a-video-in-a-pyqt-container
class ThreadOpenCV(QThread):
    
    changePixmap = pyqtSignal(QImage)

    def __init__(self, source):
        super().__init__()

        self.source = source

        self.running = True

    def run(self):
        print('start')

        cap = cv2.VideoCapture(self.source)

        self.running = True
        
        while self.running:
            ret, frame = cap.read()
            if ret:
                frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)

                h, w, ch = frame.shape
                bytes_per_line = ch * w   # PEP8: `lower_case_names` for variables
                
                image = QImage(frame.data, w, h, bytes_per_line, QImage.Format_RGB888)
                image = image.scaled(640, 480, Qt.KeepAspectRatio)
                self.changePixmap.emit(image)
            
        cap.release()
        print('stop')
        
    def stop(self):
        self.running = False


class Widget(QtWidgets.QMainWindow):
    
    def __init__(self):
        super().__init__()
        
        PATH_TO_VIDEO = os.path.join(os.getcwd(), 'videoname.mp4')


        self.thread = ThreadOpenCV(PATH_TO_VIDEO)
        self.thread.changePixmap.connect(self.setImage)
        self.image =""
        
        # layout and adding buttons and images
        layout = QVBoxLayout()

        self.label_video = QLabel()
        layout.addWidget(self.label_video)

        self.btn1 = QPushButton("PLAY")
        self.btn1.clicked.connect(self.playVideo)
        layout.addWidget(self.btn1)

        self.btn_stop = QPushButton("STOP")
        self.btn_stop.clicked.connect(self.stopVideo)
        layout.addWidget(self.btn_stop)
        
        self.widget = QWidget()
        self.widget.setLayout(layout)

        self.setCentralWidget(self.widget)
        
    def playVideo(self):
        self.thread.start()

    def stopVideo(self):
        self.thread.running = False


    def setImage(self, image):
        
        self.image = QPixmap.fromImage(image)
        self.update()
        self.label_video.setPixmap(self.image)

# https://stackoverflow.com/questions/42769354/draw-on-top-of-image
    def paintEvent(self, event):
        painter = QPainter(self)
        pixmap = QPixmap(self.image)
        painter.drawPixmap(self.rect(), pixmap)
        pen = QPen(Qt.red, 3)
        painter.setPen(pen)
        painter.drawEllipse(int(self.frameGeometry().width()//2),int(self.frameGeometry().height()//2) ,50,50)
    
 
 



if __name__ == '__main__':

    app = QtWidgets.QApplication([])

    mw = Widget()
    mw.show()

    app.exec()

I was able to get the video to play with a shape on it however it seemed to set the video as a background which isn't what I wanted and the video is also playing but without the drawing Infront. (if self.label_video.setPixmap(self.image) is commented out you can see that the background image does have a drawing on it)

I was curious if this could be done by drawing something and then bringing the drawing to the front if this could be done then how so? (I looked into the raise() method but couldn't figure out how to use it)

Community
  • 1
  • 1
Bosseness
  • 1
  • 3
  • Child widgets are stacked *above* their parents. If you paint something on the parent, it will be partially (or completely) hidden by the children. Imagine the parent as a tablet, and the child as a smartphone put above it which is playing a video: if you display an image on the tablet, the smartphone will prevent you to see it. You must override the `paintEvent()` of the widget *on top of which* you want to draw. – musicamante May 13 '23 at 00:06

1 Answers1

0

I was able to fix it by changing the run function to this

    def run(self):
    # print('start')
    # try:
    #     self.count
    # except:
        
    cap = cv2.VideoCapture(self.source)
    fps = float(cap.get(cv2.CAP_PROP_FPS))

    self.running = True
    
    while self.running:
        time.sleep(1/fps)
        ret, frame = cap.read()

        if ret:
            frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)

            h, w, ch = frame.shape
            bytes_per_line = ch * w   # PEP8: `lower_case_names` for variables
            
            image = QImage(frame.data, w, h, bytes_per_line, QImage.Format_RGB888)
            image = image.scaled(640, 480, Qt.KeepAspectRatio)

            painter = QPainter(image)
            pixmap = QPixmap(image)
            painter.drawPixmap(640,480, pixmap)
            pen = QPen(QColor(0, 0, 0), 1)
            painter.setPen(pen)
            painter.drawEllipse(285,45 ,30,50) 

            self.count +=1
            del painter
            del pen

            self.changePixmap.emit(image)
            
Bosseness
  • 1
  • 3
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jun 02 '23 at 16:50