不显示 PyQt 的视频帧的坐标
Coordinates of a video frame not of display PyQt
我正在尝试使用 PyQt 制作视频流应用程序,我希望在单击视频帧而不是显示器时获取视频帧点的坐标。我的意思是如果我的相机分辨率是 640*480 而我的显示器分辨率是 1920*1080 那么当我点击显示器右下角时我应该得到 (640, 480)
相机代码:
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
这是我的 window 代码:
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_())
不要使用 QLabel 来显示图像,因为很难映射坐标,而是使用 QGraphicsPixmapItem:
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_())
我正在尝试使用 PyQt 制作视频流应用程序,我希望在单击视频帧而不是显示器时获取视频帧点的坐标。我的意思是如果我的相机分辨率是 640*480 而我的显示器分辨率是 1920*1080 那么当我点击显示器右下角时我应该得到 (640, 480)
相机代码:
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
这是我的 window 代码:
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_())
不要使用 QLabel 来显示图像,因为很难映射坐标,而是使用 QGraphicsPixmapItem:
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_())