首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >不是display PyQt的视频帧的坐标

不是display PyQt的视频帧的坐标
EN

Stack Overflow用户
提问于 2020-05-13 16:23:34
回答 1查看 146关注 0票数 1

我正在尝试使用PyQt制作一个视频流应用程序,我希望当我点击视频帧的点的坐标时,而不是显示器的坐标。我的意思是,如果我的相机分辨率是640*480,显示分辨率是1920*1080,那么当我点击显示器的右下角时,我应该会得到(640,480)

摄像头代码:

代码语言:javascript
运行
复制
from PyQt4 import QtCore, QtGui
from threading import Thread
from collections import deque
from datetime import datetime
import time
import sys
import cv2
import imutils


class CameraWidget(QtGui.QWidget):
    """Independent camera feed
    Uses threading to grab IP camera frames in the background

    @param width - Width of the video frame
    @param height - Height of the video frame
    @param stream_link - IP/RTSP/Webcam link
    @param aspect_ratio - Whether to maintain frame aspect ratio or force into fraame
    """

    def __init__(self, width, height, stream_link=0, aspect_ratio=False, parent=None, deque_size=1):
        super(CameraWidget, self).__init__(parent)

        # Initialize deque used to store frames read from the stream
        self.deque = deque(maxlen=deque_size)

        self.screen_width = width
        self.screen_height = height
        self.maintain_aspect_ratio = aspect_ratio

        self.camera_stream_link = stream_link

        # Flag to check if camera is valid/working
        self.online = False
        self.capture = None
        self.video_frame = QtGui.QLabel()

        self.load_network_stream()

        # Start background frame grabbing
        self.get_frame_thread = Thread(target=self.get_frame, args=())
        self.get_frame_thread.daemon = True
        self.get_frame_thread.start()

        # Periodically set video frame to display
        self.timer = QtCore.QTimer()
        self.timer.timeout.connect(self.set_frame)
        self.timer.start(.5)

        print('Started camera: {}'.format(self.camera_stream_link))

    def load_network_stream(self):
        """Verifies stream link and open new stream if valid"""

        def load_network_stream_thread():
            if self.verify_network_stream(self.camera_stream_link):
                self.capture = cv2.VideoCapture(self.camera_stream_link)
                self.online = True
        self.load_stream_thread = Thread(target=load_network_stream_thread, args=())
        self.load_stream_thread.daemon = True
        self.load_stream_thread.start()

    def verify_network_stream(self, link):
        """Attempts to receive a frame from given link"""

        cap = cv2.VideoCapture(link)
        if not cap.isOpened():
            return False
        cap.release()
        return True

    def get_frame(self):
        """Reads frame, resizes, and converts image to pixmap"""

        while True:
            try:
                if self.capture.isOpened() and self.online:
                    # Read next frame from stream and insert into deque
                    status, frame = self.capture.read()
                    if status:
                        self.deque.append(frame)
                    else:
                        self.capture.release()
                        self.online = False
                else:
                    # Attempt to reconnect
                    print('attempting to reconnect', self.camera_stream_link)
                    self.load_network_stream()
                    self.spin(2)
                self.spin(.001)
            except AttributeError:
                pass

    def spin(self, seconds):
        """Pause for set amount of seconds, replaces time.sleep so program doesnt stall"""

        time_end = time.time() + seconds
        while time.time() < time_end:
            QtGui.QApplication.processEvents()

    def set_frame(self):
        """Sets pixmap image to video frame"""

        if not self.online:
            self.spin(1)
            return

        if self.deque and self.online:
            # Grab latest frame
            frame = self.deque[-1]

            # Keep frame aspect ratio
            if self.maintain_aspect_ratio:
                self.frame = imutils.resize(frame, width=self.screen_width)
            # Force resize
            else:
                self.frame = cv2.resize(frame, (self.screen_width, self.screen_height))
                self.frame = cv2.cvtColor(self.frame, cv2.COLOR_BGR2RGB)
                h, w, ch = self.frame.shape
                bytesPerLine = ch * w

            # Convert to pixmap and set to video frame
            self.img = QtGui.QImage(self.frame, w, h, bytesPerLine, QtGui.QImage.Format_RGB888)
            self.pix = QtGui.QPixmap.fromImage(self.img)
            self.video_frame.setPixmap(self.pix)

    def get_video_frame(self):
        return self.video_frame

下面是我的窗口代码:

代码语言:javascript
运行
复制
class Window(QtGui.QWidget):
    def __init__(self, cam=None, parent=None):
        super(Window, self).__init__(parent)

        self.showMaximized()

        self.screen_width = self.width()
        self.screen_height = self.height()

        # Create camera widget
        print('Creating Camera Widget...')
        self.camera = CameraWidget(self.screen_width, self.screen_height, cam)

        self.layout = QtGui.QVBoxLayout()
        self.layout.setContentsMargins(0,0,0,0)
        self.layout.setSpacing(0)
        self.layout.addWidget(self.camera.get_video_frame())
        self.setLayout(self.layout)

        self.camera.get_video_frame().mousePressEvent = self.getPos   

    def getPos(self , event):
        x = event.pos().x()
        y = event.pos().y()
        print('x,y: ', x, y)


camera = 'rtsp://admin:vaaan@123@192.168.1.51/Streaming/Channels/2'

if __name__=='__main__':
    app = QtGui.QApplication([])
    win = Window(camera)
    sys.exit(app.exec_())
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-05-14 05:34:07

不要使用QLabel来显示图像,因为很难映射坐标,请使用QGraphicsPixmapItem:

代码语言:javascript
运行
复制
from collections import deque
from datetime import datetime
import sys
from threading import Thread
import time

import cv2

from PyQt4 import QtCore, QtGui


class CameraWidget(QtGui.QGraphicsView):
    """Independent camera feed
    Uses threading to grab IP camera frames in the background

    @param width - Width of the video frame
    @param height - Height of the video frame
    @param stream_link - IP/RTSP/Webcam link
    @param aspect_ratio - Whether to maintain frame aspect ratio or force into fraame
    """

    def __init__(
        self,
        width,
        height,
        stream_link=0,
        aspect_ratio=False,
        parent=None,
        deque_size=1,
    ):
        super(CameraWidget, self).__init__(parent)

        # Initialize deque used to store frames read from the stream
        self.deque = deque(maxlen=deque_size)

        self.screen_width = width
        self.screen_height = height
        self.maintain_aspect_ratio = aspect_ratio

        self.camera_stream_link = stream_link

        # Flag to check if camera is valid/working
        self.online = False
        self.capture = None

        self.setScene(QtGui.QGraphicsScene(self))

        self._pixmap_item = self.scene().addPixmap(QtGui.QPixmap())

        self.load_network_stream()

        # Start background frame grabbing
        self.get_frame_thread = Thread(target=self.get_frame, args=())
        self.get_frame_thread.daemon = True
        self.get_frame_thread.start()

        # Periodically set video frame to display
        self.timer = QtCore.QTimer()
        self.timer.timeout.connect(self.set_frame)
        self.timer.start(0.5)

        print("Started camera: {}".format(self.camera_stream_link))

    def load_network_stream(self):
        """Verifies stream link and open new stream if valid"""

        def load_network_stream_thread():
            if self.verify_network_stream(self.camera_stream_link):
                self.capture = cv2.VideoCapture(self.camera_stream_link)
                self.online = True

        self.load_stream_thread = Thread(target=load_network_stream_thread, args=())
        self.load_stream_thread.daemon = True
        self.load_stream_thread.start()

    def verify_network_stream(self, link):
        """Attempts to receive a frame from given link"""

        cap = cv2.VideoCapture(link)
        if not cap.isOpened():
            return False
        cap.release()
        return True

    def get_frame(self):
        """Reads frame, resizes, and converts image to pixmap"""

        while True:
            try:
                if self.capture.isOpened() and self.online:
                    # Read next frame from stream and insert into deque
                    status, frame = self.capture.read()
                    if status:
                        self.deque.append(frame)
                    else:
                        self.capture.release()
                        self.online = False
                else:
                    # Attempt to reconnect
                    print("attempting to reconnect", self.camera_stream_link)
                    self.load_network_stream()
                    self.spin(2)
                self.spin(0.001)
            except AttributeError:
                pass

    def spin(self, seconds):
        """Pause for set amount of seconds, replaces time.sleep so program doesnt stall"""

        time_end = time.time() + seconds
        while time.time() < time_end:
            QtGui.QApplication.processEvents()

    def set_frame(self):
        """Sets pixmap image to video frame"""

        if not self.online:
            self.spin(1)
            return

        if self.deque and self.online:
            # Grab latest frame
            frame = self.deque[-1]

            frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            h, w, ch = frame.shape
            bytesPerLine = ch * w

            # Convert to pixmap and set to video frame
            image = QtGui.QImage(frame, w, h, bytesPerLine, QtGui.QImage.Format_RGB888)
            pixmap = QtGui.QPixmap.fromImage(image.copy())
            self._pixmap_item.setPixmap(pixmap)
        self.fix_size()

    def mousePressEvent(self, event):
        super(CameraWidget, self).mousePressEvent(event)
        vp = event.pos()
        it = self.itemAt(vp)
        if it == self._pixmap_item:
            sp = self.mapToScene(vp)
            lp = it.mapFromScene(sp)
            self.clicked.emit(lp.toPoint())

    clicked = QtCore.pyqtSignal(QtCore.QPoint)

    def resizeEvent(self, event):
        self.fix_size()
        super().resizeEvent(event)

    def fix_size(self):
        self.fitInView(
            self._pixmap_item,
            QtCore.Qt.KeepAspectRatio
            if self.maintain_aspect_ratio
            else QtCore.Qt.IgnoreAspectRatio,
        )


class Window(QtGui.QWidget):
    def __init__(self, cam=None, parent=None):
        super(Window, self).__init__(parent)

        self.showMaximized()

        self.screen_width = self.width()
        self.screen_height = self.height()

        # Create camera widget
        print("Creating Camera Widget...")
        self.camera = CameraWidget(self.screen_width, self.screen_height, cam)

        lay = QtGui.QVBoxLayout(self)
        lay.setContentsMargins(0, 0, 0, 0)
        lay.setSpacing(0)
        lay.addWidget(self.camera)

        self.camera.clicked.connect(print)


camera = 0  # 'rtsp://admin:vaaan@123@192.168.1.51/Streaming/Channels/2'

if __name__ == "__main__":
    app = QtGui.QApplication([])
    win = Window(camera)
    sys.exit(app.exec_())
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61769666

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档