import sys import cv2 import time from PyQt5.QtCore import QThread, pyqtSignal, QObject sys_path = sys.path[0].replace("\\", "/") sys_path_linux = sys.path[0] + "/../.." if sys_path_linux not in sys.path: sys.path.append(sys_path_linux) from print_color import * DEFAULT_VIDEO_SLEEP_MS = 20 # 图像处理线程 class ImageProcessingThread(QThread): processed_image_signal = pyqtSignal(object) def __init__(self): super().__init__() def run(self): while True: # 在这里添加图像处理代码 # 这里暂时只是将图像传递给下一个线程 time.sleep(0.01) self.processed_image_signal.emit(None) # 摄像头采集线程 class CameraThread(QThread): image_signal = pyqtSignal(object) def __init__(self, camera_url, circuit_id: int = 0): super().__init__() self.camera_url = camera_url # 摄像头url地址, 整数 或者 字符串 self.face_detection: bool = False if isinstance(camera_url, int): self.camera_url_str = str(camera_url) else: self.camera_url_str = camera_url self.cap: cv2.VideoCapture = None self.running: bool = True self.fps = 0 self.cycle_limit = DEFAULT_VIDEO_SLEEP_MS self.cycle_ms = 0 self.circuit_id = circuit_id # 摄像头对应的回路, 组合开关每一个回路都有对应的摄像头 self.is_signal_connect = False self.is_emit = False self.set_video_cycle_ms(2000) def signal_connect(self, slot_func): self.image_signal.connect(slot_func) self.is_signal_connect = True def signal_disconnect(self): # 判断信号是否已连接 if self.is_signal_connect: self.image_signal.disconnect() self.is_signal_connect = False def set_video_cycle_ms(self, cycle_ms: int = 10): if self.cycle_limit != cycle_ms: if cycle_ms <= DEFAULT_VIDEO_SLEEP_MS: self.cycle_limit = DEFAULT_VIDEO_SLEEP_MS else: self.cycle_limit = cycle_ms # 新建函数,改变函数延时方法 def change_camera_url(self, camera_url: str): if self.circuit_id == camera_url: self.set_video_cycle_ms(DEFAULT_VIDEO_SLEEP_MS) else: self.set_video_cycle_ms(1000) def close(self): if self.cap == None: # 初始化一直未完成 self.terminate() self.running = False def run(self): process_count = 0 fps_time = 0 while self.running == True: inform_msg = "cameral init start, url = " + self.camera_url_str print_inform_msg(inform_msg) try: if isinstance(self.camera_url, int): # 在 Windows 平台下,使用默认的 cv2.VideoCapture 接口 self.cap = cv2.VideoCapture(self.camera_url, cv2.CAP_DSHOW) else: # 在 Linux 平台下,使用默认的 cv2.VideoCapture 接口 self.cap = cv2.VideoCapture(self.camera_url) if self.cap != None: inform_msg = "cameral Init Success, url = " + self.camera_url_str self.is_emit = True print_inform_msg(inform_msg) else: inform_msg = "cameral connection timeout, url = " + self.camera_url_str print_inform_msg(inform_msg) except Exception as e: self.cap = None inform_msg = "cameral camera Init Fail, url = " + self.camera_url_str print_error_msg(inform_msg) base_time = time.time() while self.running and self.cap != None: # 延时20ms time.sleep(DEFAULT_VIDEO_SLEEP_MS / 1000) if self.cycle_ms + DEFAULT_VIDEO_SLEEP_MS < self.cycle_limit: self.cycle_ms += DEFAULT_VIDEO_SLEEP_MS self.cap.grab() # 抛弃多余的帧,保持最新帧 continue else: self.cycle_ms = 0 try: ret, frame = self.cap.read() cur_time = time.time() execution_time = cur_time - base_time base_time = cur_time process_count += 1 fps_time += execution_time if fps_time >= 1: self.fps = process_count process_count = 0 fps_time = 0 if execution_time < 5: image_object: QObject = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) self.image_signal.emit(image_object) else: # 时间差大于5秒, 表示网络可能中断过, 退出并重新连接 err_message = "cameral read timeout, url = " + self.camera_url_str print_error_msg(err_message) break except Exception as e: err_message = "cameral read timeout, url = " + self.camera_url_str self.is_emit = False print_error_msg(err_message) if self.running == True: time.sleep(2) break print_inform_msg("cameral connection End") time.sleep(0.01) if self.cap != None: self.cap.release() self.cap = None