Files
ADAS360/surround_view/capture_thread.py
2025-10-28 18:46:04 +08:00

115 lines
4.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import cv2
from PyQt5.QtCore import qDebug
from .base_thread import BaseThread
from .structures import ImageFrame
from .utils import gstreamer_pipeline
class CaptureThread(BaseThread):
def __init__(self,
device_id,
flip_method=2,
drop_if_full=True,
api_preference=cv2.CAP_GSTREAMER,
resolution=None,
use_gst=True,
parent=None):
"""
device_id: device number of the camera.
flip_method: 0 for identity, 2 for 180 degree rotation (if the camera is installed
up-side-down).
drop_if_full: drop the frame if buffer is full.
api_preference: cv2.CAP_GSTREAMER for csi cameras, usually cv2.CAP_ANY would suffice.
resolution: camera resolution (width, height).
"""
super(CaptureThread, self).__init__(parent)
self.device_id = device_id
self.flip_method = flip_method
self.use_gst = use_gst
self.drop_if_full = drop_if_full
self.api_preference = api_preference
self.resolution = resolution
self.cap = cv2.VideoCapture()
# an instance of the MultiBufferManager object,
# for synchronizing this thread with other cameras.
self.buffer_manager = None
def run(self):
if self.buffer_manager is None:
raise ValueError("This thread has not been binded to any buffer manager yet")
while True:
self.stop_mutex.lock()
if self.stopped:
self.stopped = False
self.stop_mutex.unlock()
break
self.stop_mutex.unlock()
# save capture time
self.processing_time = self.clock.elapsed()
# start timer (used to calculate capture rate)
self.clock.start()
# synchronize with other streams (if enabled for this stream)
self.buffer_manager.sync(self.device_id)
if not self.cap.grab():
continue
# retrieve frame and add it to buffer
_, frame = self.cap.retrieve()
img_frame = ImageFrame(self.clock.msecsSinceStartOfDay(), frame)
self.buffer_manager.get_device(self.device_id).add(img_frame, self.drop_if_full)
# update statistics
self.update_fps(self.processing_time)
self.stat_data.frames_processed_count += 1
# inform GUI of updated statistics
self.update_statistics_gui.emit(self.stat_data)
qDebug("Stopping capture thread...")
# 在surround-view-system-introduction/surround_view/capture_thread.py中修改connect_camera方法
def connect_camera(self):
# 如果设备ID是字符串且以rtsp开头则视为RTSP地址
if isinstance(self.device_id, str) and self.device_id.startswith('rtsp://'):
# 使用FFmpeg的H265解码方式打开RTSP流
# 降低延迟参数:-fflags nobuffer -flags low_delay -rtsp_transport tcp
ffmpeg_cmd = (
f"rtspsrc location={self.device_id} latency=0 ! "
"rtph265depay ! h265parse ! avdec_h265 ! "
"videoconvert ! video/x-raw,format=BGR ! appsink"
)
self.cap.open(ffmpeg_cmd, cv2.CAP_GSTREAMER)
elif self.use_gst:
options = gstreamer_pipeline(cam_id=self.device_id, flip_method=self.flip_method)
self.cap.open(options, self.api_preference)
else:
self.cap.open(self.device_id)
if not self.cap.isOpened():
qDebug(f"Cannot open camera {self.device_id}")
return False
# 设置分辨率RTSP流通常固定分辨率可根据实际情况调整
if self.resolution is not None:
width, height = self.resolution
self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, width)
self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height)
return True
def disconnect_camera(self):
# disconnect camera if it's already opened.
if self.cap.isOpened():
self.cap.release()
return True
# else do nothing and return
else:
return False
def is_camera_connected(self):
return self.cap.isOpened()