You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyQt5实时视频流裁剪异常:QImage显示扭曲如何解决?

问题:PyQt5摄像头帧裁剪后显示扭曲/错位

我开发了一个PyQt5 GUI应用,功能是从摄像头读取帧,在帧上选择一块小区域,后续只显示该区域。我已经正确选中区域并存储为QRect,但裁剪帧用于显示和后续处理时,实时视频有时显示正常,但大多数时候会出现扭曲——画面倾斜,原本的右角变成左角,而且本该在视频中间的粉色圆圈位置也错了。

相关代码(Worker1类)

from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtGui import QImage
import cv2 as cv

class Worker1(QThread):
    ImageUpdate = pyqtSignal(QImage)

    def __init__(self, canvas, selection):
        super().__init__()
        self.ThreadActive = True
        self.canvas = canvas
        self.anim = None
        self.selection = selection

    def run(self):
        Capture = cv.VideoCapture(0)

        old_closest_contour = None
        d_tresh = 300
        P_color = (0, 255, 0)
        global i
        i = 0

        while self.ThreadActive:
            i += 1
            ret, frame = Capture.read()
            if ret:
                if self.selection is None or self.selection.isEmpty():
                    cropped_frame = frame
                else:
                    a = int(self.selection.x())
                    b = int(self.selection.y())
                    width = int(self.selection.width())
                    height = int(self.selection.height())
                    #print(str(a) + " " + str(b) + " " + str(width) + " " + str(height))
                    cropped_frame = frame[b: b + height, a: a + width].copy()
                    #print(cropped_frame.shape[1])
                    #print(cropped_frame.shape[0])

                ### other processing lines, those are not relevant in the displaying ###

                Image = cv.cvtColor(cropped_frame, cv.COLOR_BGR2RGB)
                img = cv.medianBlur(Image, 25)

                cv.circle(img, (x, y), r, P_color, 1)
                cv.circle(img, (x, y), 4, P_color, -1)
                cv.circle(img, point, 0, (255, 0, 255), 10)

                ConvertToQtFormat = QImage(img.data, img.shape[1], img.shape[0], QImage.Format_RGB888)
                self.ImageUpdate.emit(ConvertToQtFormat)

        Capture.release()

问题排查与解决方案

1. QImage内存对齐问题(最可能导致扭曲)

当前创建QImage时未指定bytesPerLine参数,当图像行字节数不是4的倍数时,QImage会自动按4字节对齐,直接导致画面错位、扭曲。

修正代码:

# 替换原QImage创建代码
ConvertToQtFormat = QImage(img.data, img.shape[1], img.shape[0], img.strides[0], QImage.Format_RGB888)

img.strides[0]是OpenCV图像每行的实际字节数,传递给QImage后能保证内存布局完全匹配,避免对齐错误。

2. 坐标映射不匹配问题

如果GUI显示控件对摄像头帧做了缩放(比如拉伸适配控件大小),选中的QRect是基于控件的坐标,和原始摄像头帧的坐标不对应,裁剪区域自然会出错。

解决方法:

  • 获取摄像头原始帧尺寸:
    frame_width = Capture.get(cv.CAP_PROP_FRAME_WIDTH)
    frame_height = Capture.get(cv.CAP_PROP_FRAME_HEIGHT)
    
  • 获取GUI控件尺寸:
    canvas_width = self.canvas.width()
    canvas_height = self.canvas.height()
    
  • 计算缩放比例并转换坐标:
    scale_x = frame_width / canvas_width
    scale_y = frame_height / canvas_height
    a = int(self.selection.x() * scale_x)
    b = int(self.selection.y() * scale_y)
    width = int(self.selection.width() * scale_x)
    height = int(self.selection.height() * scale_y)
    
    注意要确保转换后的坐标不超出原始帧范围(比如a + width不能大于frame_width)。

3. 线程安全问题

self.selection如果在主线程中修改,子线程直接读取可能拿到半更新的错误值,导致裁剪区域随机错乱。

解决方法:

  • 用pyqtSignal在主线程更新selection时发送给子线程,子线程维护私有变量接收更新;
  • 或者用QMutex加锁,读取和修改self.selection时都加锁保护。

内容的提问来源于stack exchange,提问作者zoltnu.wxkejt6l0

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 20:15:05