背景:pyqt5無法顯示opencv繪制的標簽和mask;我們在使用YOLO做實例分割做推理時,會使用opencv做后處理結果繪制(含標簽繪制和掩碼繪制);結果opencv繪制的解碼卻無法在pyqt的解碼上面顯示。pyqt轉換代碼如下:
def convert_frame_to_pixmap(self, frame):"""將OpenCV幀轉換為QPixmap,特別優化mask顯示"""if frame is None:return QPixmap()# 轉換顏色空間(OpenCV的BGR轉Qt的RGB)frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)# 確保數據類型正確if frame_rgb.dtype != np.uint8:frame_rgb = cv2.normalize(frame_rgb, None, 0, 255, cv2.NORM_MINMAX, dtype=cv2.CV_8U)# 確保內存連續性if not frame_rgb.flags.contiguous:frame_rgb = np.ascontiguousarray(frame_rgb)h, w, c = frame_rgb.shape# 創建QImage - 使用更可靠的參數qimg = QImage(frame_rgb.data,w,h,frame_rgb.strides[0], # 直接使用數組的步長QImage.Format_RGB888)# 確保圖像不被修改時共享數據,提高性能qimg = qimg.copy()# 轉換為QPixmap并按比例縮放pixmap = QPixmap.fromImage(qimg)return pixmap.scaled(self.display_label.width(),self.display_label.height(),Qt.KeepAspectRatio,Qt.SmoothTransformation)
解決: 在使用opencv的imshow可視化看到標簽和掩碼的結果后,把問題定位在轉換和傳輸。
如果要在qyqt上面顯示,首先需要通過pyqt的yqtSignal函數將opencv處理后的幀數據進行傳輸,然后再將其轉換為pyqt的QPixmap。
在轉換階段排查了很久,后來發現不是這個問題。然后問題就定位到傳輸中和傳輸前。傳輸中也不可能,因為能夠顯示圖像,只是無法顯示標簽和掩碼。
來到轉換前,這部分的實現是通過處理函數先處理,再將處理后的幀數據傳給pyqt的信號槽。最開始是這樣實現的:
self.process_frame(frame)
self.update_frame_signal.emit(frame)
self.process_finished_signal.emit()
打斷點測試,發現問題出在這,因為frame數據的標簽和掩碼在傳給信號槽之前會丟失。于是改變寫法,換成下面這種更加穩健的寫法,就把這個問題解決了。當然這是我代碼實現的疏忽。
frame, results = self.process_frame(frame)
self.update_frame_signal.emit(frame)
self.process_finished_signal.emit()