如何使用PyQt6显示Python OpenCV图像(Numpy数组)?
PyQt6加载OpenCV图像失真问题修复
你遇到的图像变形问题和格式选择无关,Format_BGR888确实是OpenCV默认BGR三通道图像对应的正确QImage格式,问题出在QImage构造时的参数传错:
- 硬编码写死了400×400的尺寸,没有使用
cv2.imread读取到的图像实际宽高,只要输入图不是刚好400×400就会出现拉伸 - 没有传入
bytesPerLine(每行步长/字节数)参数,PyQt6对图像内存布局的校验比旧版PyQt严格,缺省这个参数会导致内存读取行错位,直接出现斜向拉伸、色偏的失真效果 - 直接传入NumPy数组的内存指针没有做深拷贝,一旦OpenCV侧的NumPy数组内存被回收,QImage会出现野指针问题,显示花屏
原始输入图像:
当前代码运行得到的失真效果:
正确实现代码
修复核心是从NumPy数组动态取图像真实高宽、计算对应格式的每行字节数,构造QImage后做深拷贝绑定内存:
from PyQt6.QtWidgets import QApplication, QWidget, QMainWindow, QLabel, QHBoxLayout, QGridLayout from PyQt6.QtGui import QImage, QPixmap import sys import cv2 class DisplayImageWidget(QWidget): def __init__(self): super(DisplayImageWidget, self).__init__() self.image = cv2.imread('2.png') # 从numpy数组读取真实的图像高、宽、通道数 img_h, img_w, img_ch = self.image.shape # BGR888三通道格式每行字节数 = 宽度 * 通道数 bytes_per_line = img_ch * img_w # 传入正确参数构造QImage,调用copy()拷贝内存避免悬空指针 q_img = QImage(self.image.data, img_w, img_h, bytes_per_line, QImage.Format.Format_BGR888).copy() self.frame = QLabel() self.frame.setPixmap(QPixmap.fromImage(q_img)) self.layout = QHBoxLayout(self) self.layout.addWidget(self.frame) if __name__ == '__main__': app = QApplication([]) main_window = QMainWindow() main_window.setWindowTitle('Video Frame Acquisition') main_window.setFixedSize(500, 500) central_widget = QWidget() main_layout = QGridLayout() central_widget.setLayout(main_layout) main_window.setCentralWidget(central_widget) display_image_widget = DisplayImageWidget() main_layout.addWidget(display_image_widget, 0, 0) main_window.show() sys.exit(app.exec())
补充说明
针对不同的OpenCV图像格式,对应调整QImage格式和行字节数计算逻辑即可:
- 灰度单通道图:格式用
QImage.Format.Format_Grayscale8,行字节数为img_w - BGRA四通道透明图:格式用
QImage.Format.Format_BGRA8888,行字节数为img_w * 4
内容的提问来源于stack exchange,提问作者nathancy
相关产品推荐
相关产品推荐

