PyQt5调用OpenCV缩放视频首帧显示到QLabel出现画面畸变问题
问题原因
- 核心原因:QImage与OpenCV Mat的行字节对齐规则不匹配
OpenCV读取的Mat格式图像是连续存储的,每行字节数为宽度 × 通道数;而Qt的QImage.Format_RGB888格式默认按4字节对齐每行,当你缩放后的图像宽度不是4的倍数时,直接传入frame.data构造QImage会出现行数据偏移,最终表现为图像扭曲变形。 - 次要潜在问题:缩放逻辑存在边界漏洞
现有仅比较原图宽高的缩放逻辑,未考虑缩放后的另一维度可能超出QLabel的显示边界,极端宽高比的图像缩放后若超出控件范围,若后续开启QLabel的scaledContents属性会被强制拉伸导致变形。
解决方法
修改getFirstFrame方法的缩放和QImage构造逻辑:
- 优化缩放逻辑:通过计算宽高两个方向的缩放比例,取最小值确保缩放后的图像完整容纳在QLabel内,不会超出边界。
- 构造QImage时显式传入每行字节数参数,对齐OpenCV的存储规则,避免对齐偏差。
修改后的代码片段
def getFirstFrame(self,video): if video != "": # 若接收到有效视频路径,执行如下操作 # 直接在方法内获取控件实际尺寸,避免全局变量误差 viewWidth = self.viewData.width() viewHeight = self.viewData.height() vid = cv.VideoCapture(video) # 为视频创建VideoCapture对象 ret, self.frame = vid.read() # 获取视频的第一帧 if not ret: # 加读取失败校验,避免崩溃 return frame = cv.cvtColor(self.frame,cv.COLOR_BGR2RGB) height,width = frame.shape[:2] # 优化缩放逻辑:取最小缩放比例保证图像完整容纳在QLabel内 scale_w = viewWidth / width scale_h = viewHeight / height final_scale = min(scale_w, scale_h) new_w = int(width * final_scale) new_h = int(height * final_scale) frame = cv.resize(frame, (new_w, new_h),cv.INTER_LINEAR) # 显式传入每行字节数,对齐OpenCV的存储规则,解决对齐导致的畸变 bytes_per_line = new_w * 3 Qframe = QtGui.QImage(frame.data, new_w, new_h, bytes_per_line, QtGui.QImage.Format_RGB888) self.viewData.setPixmap(QtGui.QPixmap.fromImage(Qframe))
内容的提问来源于stack exchange,提问作者Yan Ming
相关产品推荐
相关产品推荐

