我创建了一个可以使用OpenCV实时预测性别的神经网络(CNN),一切运行良好,但是,当我运行代码时,OpenCV出现了严重的延迟,我的网络摄像头性能并不差,以下是我的代码
'''使用卷积神经网络(CNN)和Cv2进行实时人脸性别识别,这里我们预测训练好的模型'''from tensorflow.keras.preprocessing.image import img_to_arrayfrom tensorflow.keras.models import load_modelimport numpy as npimport cv2import osimport cvlib as cvimport imutils# 加载模型model = load_model('gender_detection.model')# 打开网络摄像头并初始化摄像头webcam = cv2.VideoCapture(0, cv2.CAP_DSHOW)classes = ['hombre', 'mujer']# 遍历帧while webcam.isOpened(): # 从网络摄像头读取帧 status, frame = webcam.read() #webcam.set(cv2.CAP_PROP_FPS, 1000) frame = cv2.flip(frame, 1) # 应用人脸检测 face, confidence = cv.detect_face(frame) # 这检测摄像头中有无脸部,cvlib执行此操作,但不检测是否为男性,这是神经网络的任务 # 遍历检测到的人脸 for idx, f in enumerate(face): # 获取人脸矩形的角点 # 只有当cvlib检测到人脸时才会绘制矩形,使用上面提供的变量 startX, startY = f[0], f[1] endX, endY = f[2], f[3] # 在人脸上绘制矩形 cv2.rectangle(frame, (startX, startY), (endX, endY), (0,255,0), 2) # 裁剪检测到的人脸区域 face_crop = np.copy(frame[startY:endY, startX:endX]) if face_crop.shape[0] < 10 or face_crop.shape[1] < 10: continue # 预处理性别检测模型 face_crop = cv2.resize(face_crop, (96,96)) face_crop = face_crop.astype("float") / 255.0 face_crop = img_to_array(face_crop) face_crop = np.expand_dims(face_crop, axis=0) # 应用性别检测模型 conf = model.predict(face_crop)[0] # 获取最大准确度的标签 idx = np.argmax(conf) label = classes[idx] label = "{}: {:.2f}".format(label, conf[idx] * 100) Y = startY - 10 if startY - 10 > 10 else startY + 10 # 在人脸矩形上方写入标签和置信度 cv2.putText(frame, label, (startX, Y), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0,255,0), 2) # 显示输出 cv2.imshow("Gender Detection", frame) # 按下"Q"键停止 if cv2.waitKey(1) & 0xFF == ord('q'): break#释放资源webcam.release()cv2.destroyAllWindows()
我还尝试使用cv2.CAP_PROB_FPS,但这只有一点帮助,并不明显。
回答:
我在使用OpenCV视频捕获进行文本检测时也遇到了同样的问题。这不是网络摄像头的质量问题,而是因为OpenCV只能以您在性别检测中处理帧的速度显示它们。我找到的解决方案是使用多线程。
您可以为OpenCV视频捕获创建一个线程,然后为图像处理创建另一个线程。需要注意的是,您无法在不更改图像处理本身的情况下神奇地加速图像处理过程。处理需要多长时间就需要多长时间。您可以做的是让OpenCV独立工作,并将帧发送到一个交换类,然后让图像处理按自己的节奏获取帧,而CV2继续正常运行。
这是我用于OCR图像处理的类的一个(简化)版本。您可以看到在start()方法中,我创建了一个指向ocr()过程的线程。这就是您可以放置性别识别过程的地方。
class OCR: # def __init__(self, exchange: VideoStream, language=None): def __init__(self): self.exchange = None # 初始化OCR的相关内容,这些内容与我的示例无关,但请注意,它 # 接受一个名为exchange的VideoStream类,这是该类获取帧进行处理的地方 def start(self): Thread(target=self.ocr, args=()).start() return self def set_exchange(self, video_stream): self.exchange = video_stream def ocr(self): while not self.stopped: if self.exchange is not None: frame = self.exchange.frame # # # OCR相关代码放在这里
现在这是VideoStream类,它以自己的节奏在不同的线程中获取帧。然后,图像处理类(OCR)可以按自己的节奏获取这些帧,两者互不影响性能。
class VideoStream: """用于CV2视频捕获的类。start()方法将创建一个新线程来读取视频流""" def __init__(self, src=0): self.stream = cv2.VideoCapture(src) (self.grabbed, self.frame) = self.stream.read() # self._boxes = None self.stopped = False def start(self): Thread(target=self.get, args=()).start() return self def get(self): while not self.stopped: (self.grabbed, self.frame) = self.stream.read() def get_video_dimensions(self): width = self.stream.get(cv2.CAP_PROP_FRAME_WIDTH) height = self.stream.get(cv2.CAP_PROP_FRAME_HEIGHT) return int(width), int(height) def stop_process(self): self.stopped = True
然后您可以像往常一样进行CV2的imshow循环。
exchange = VideoStream(0).start()ocr = OCR().start()ocr.set_exchange(exchange) while True: # 开始一个循环,用于实时OCR显示 pressed_key = cv2.waitKey(1) & 0xFF if pressed_key == ord('q'): stop_stream_ocr(exchange, ocr) break frame = exchange.frame cv2.imshow("Video Get Frame", frame) cps1.increment()
请注意,您无法真正控制CV2在其内部工作中决定使用哪个线程,但这种方法将允许您以网络摄像头的自然帧率显示视频,同时图像处理在后台进行。