import sys import cv2 import os import time from PyQt5.QtCore import QThread, pyqtSignal, QObject import face_recognition current_dir = os.path.dirname(__file__) share_code_dir = os.path.abspath(os.path.join(current_dir, '..', '..')) sys.path.append(share_code_dir) 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 # - * - coding:utf - 8 - * - # import sys # import cv2 # import os # import time # import subprocess # import face_recognition # import numpy as np # from PIL import Image, ImageDraw, ImageFont # from PyQt5.QtCore import QThread, pyqtSignal, QObject # from print_color import * # current_dir = os.path.dirname(__file__) # share_code_dir = os.path.abspath(os.path.join(current_dir, '..', '..')) # sys.path.append(share_code_dir) # DEFAULT_VIDEO_SLEEP_MS = 20 # # 定义路径常量 # npy_file_path = os.path.abspath(os.path.join(os.path.dirname(__file__), 'face_data/face_data.npy')) # image_folder_path = os.path.abspath(os.path.join(os.path.dirname(__file__), 'face_data')) # font_path = os.path.abspath(os.path.join(os.path.dirname(__file__), 'font/hanzi.ttc')) # def load_face_data(): # face_data = {} # try: # face_data = np.load(npy_file_path, allow_pickle=True).item() # print_debug_msg(f"Loaded {len(face_data)} face encodings from {npy_file_path}.") # except Exception as e: # print_error_msg(f"Error loading face encodings: {e}") # current_images = [f for f in os.listdir(image_folder_path) if f.endswith('.jpg')] # current_image_set = set(os.path.splitext(f)[0] for f in current_images) # known_image_set = set(face_data.keys()) # added_images = current_image_set - known_image_set # removed_images = known_image_set - current_image_set # for image_name in added_images: # image_path = os.path.join(image_folder_path, f"{image_name}.jpg") # try: # image = face_recognition.load_image_file(image_path) # face_encodings = face_recognition.face_encodings(image) # if face_encodings: # face_data[image_name] = face_encodings[0].tolist() # print_debug_msg(f"Added encoding for {image_name}.") # else: # print_warning_msg(f"[WARNING] No face detected in {image_name}.jpg.") # except Exception as e: # print_error_msg(f"[ERROR] Error processing {image_name}.jpg: {e}") # for removed_image in removed_images: # del face_data[removed_image] # print_debug_msg(f"Removed encoding for {removed_image}.") # np.save(npy_file_path, face_data) # print_debug_msg(f"Updated face data saved with {len(face_data)} entries.") # return face_data # class ImageProcessingThread(QThread): # processed_image_signal = pyqtSignal(object) # def __init__(self, frame=None): # super().__init__() # self.frame = frame # 添加 frame 参数 # self.face_encodings = [] # self.face_names = [] # self.face_locations = [] # self.face_data = load_face_data() # self.total_image_name = list(self.face_data.keys()) # self.total_face_encoding = [np.array(self.face_data[name]) for name in self.total_image_name] # def process_frame(self, frame): # """实时处理帧,匹配已知人脸""" # self.face_locations = face_recognition.face_locations(frame) # face_encodings = face_recognition.face_encodings(frame, self.face_locations) # names = [] # for face_encoding in face_encodings: # name = "Unknown" # face_distances = face_recognition.face_distance(self.total_face_encoding, face_encoding) # if face_distances.size > 0: # min_distance = np.min(face_distances) # best_match_index = np.argmin(face_distances) # if min_distance < self.dynamic_tolerance(): # 使用动态容忍度 # name = self.total_image_name[best_match_index] # names.append(name) # self.face_names = names # return frame # def dynamic_tolerance(self): # # 动态调整容忍度,可以基于一些规则来调整,如帧内错误率、识别准确率等 # error_rate = self.calculate_error_rate() # if error_rate > 0.1: # return 0.5 # 高容忍度以减少错误 # else: # return 0.4 # 适中容忍度 # def calculate_error_rate(self): # # 计算识别错误率,作为动态调整容忍度的依据 # total_faces = len(self.total_face_encoding) # unmatched_faces = sum(1 for name in self.face_names if name == "Unknown") # return unmatched_faces / total_faces if total_faces > 0 else 0 # def set_frame(self, frame): # self.frame = frame # def run(self): # while True: # if self.frame is not None: # self.process_frame(self.frame) # self.processed_image_signal.emit(self.frame) # time.sleep(0.01) # 控制帧率 # # 摄像头采集线程 # class CameraThread(QThread): # image_signal = pyqtSignal(object) # def __init__(self, camera_url, circuit_id: int = 0): # super().__init__() # self.camera_url = camera_url # self.face_detection: bool = True # 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.frame_count = 0 # self.fps_time = 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 is None: # self.terminate() # self.running = False # def run(self): # process_count = 0 # fps_time = 0 # face_thread = ImageProcessingThread() # face_thread.start() # self.match_count = 0 # 初始化匹配帧数计数器 # while self.running: # inform_msg = "Camera init start, URL = " + self.camera_url_str # print_inform_msg(inform_msg) # try: # self.cap = cv2.VideoCapture(self.camera_url) # 强制使用 BGR 格式 # if self.cap.isOpened(): # inform_msg = "Camera Init Success, URL = " + self.camera_url_str # self.is_emit = True # print_inform_msg(inform_msg) # else: # inform_msg = "Camera connection timeout, URL = " + self.camera_url_str # print_error_msg(inform_msg) # except Exception as e: # self.cap = None # inform_msg = "Camera Init Fail, URL = " + self.camera_url_str # print_error_msg(inform_msg) # base_time = time.time() # while self.running and self.cap: # 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() # if not ret: # break # face_thread.set_frame(frame) # 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: # 每隔1秒重新计算 FPS # self.fps = process_count # process_count = 0 # fps_time = 0 # if execution_time < 5: # frame: QObject = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) # for (top, right, bottom, left), name in zip(face_thread.face_locations, face_thread.face_names): # if name != "Unknown": # 只绘制已匹配的结果 # self.match_count += 1 # 计数成功匹配的帧 # # cv2.rectangle(frame, (left, top), (right, bottom), (0, 255, 0), 2) # # cv2.putText(frame, name, (left + 6, bottom - 6), cv2.FONT_HERSHEY_DUPLEX, 1.0, (255, 255, 255), 1) # # 将OpenCV图像转换为PIL图像格式(注意要转换色彩空间,OpenCV是BGR,PIL是RGB) # pil_image = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)) # draw = ImageDraw.Draw(pil_image) # # 这里选择合适的中文字体文件路径,比如系统自带的宋体(不同系统路径可能有差异),并设置字体大小 # font = ImageFont.truetype(font_path, 15) # # 在指定位置绘制中文 # draw.text((left + 12, bottom + 12), name, font=font, fill=(255, 255, 255)) # # 再将PIL图像转换回OpenCV图像格式 # frame = cv2.cvtColor(np.array(pil_image), cv2.COLOR_RGB2BGR) # cv2.rectangle(frame, (left, top), (right, bottom), (0, 255, 0), 2) # else: # name = "未在人脸库中,无操作权限" # pil_image = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)) # draw = ImageDraw.Draw(pil_image) # #设置字体大小 # font = ImageFont.truetype(font_path, 15) # # 在指定位置绘制中文 # draw.text((left + 12, bottom + 12), name, font=font, fill=(255, 255, 255)) # # 再将PIL图像转换回OpenCV图像格式 # frame = cv2.cvtColor(np.array(pil_image), cv2.COLOR_RGB2BGR) # cv2.rectangle(frame, (left, top), (right, bottom), (255, 0, 0), 2) # self.image_signal.emit(frame) # else: # err_message = "Camera read timeout, URL = " + self.camera_url_str # print_error_msg(err_message) # break # except Exception as e: # err_message = "Camera read exception, URL = " + self.camera_url_str # print_error_msg(err_message) # if self.running: # time.sleep(2) # break # if self.cap: # self.cap.release() # self.cap = None # print_inform_msg("Camera connection ended") # time.sleep(0.01)