不调用QImage::scaled()在QML渲染QImage时程序崩溃问题求助
崩溃原因排查及修复方案
核心崩溃原因
- 绘制时硬编码的源矩形越界访问
你在paint方法中固定了源矩形为800x550,当你不调用scaled时,原始QImage的分辨率小于800x550的情况下,drawImage会尝试访问图像实际范围外的内存地址,直接触发越界崩溃。 - OpenCV转QImage的浅拷贝导致野指针
常规的Mat转QImage实现会直接复用cv::Mat的底层数据缓冲区,不会做深拷贝:- 你构造
cv::Mat时直接引用了外部缓冲区m_pBufForSaveImage - 当你调用
scaled时,返回的是全新的深拷贝QImage,不再依赖原缓冲区 - 不调用
scaled时,QImage仍然绑定原cv::Mat的缓冲区,一旦采集线程更新/释放了m_pBufForSaveImage,渲染线程读取QImage时就会访问野指针崩溃
- 你构造
- 线程安全问题
摄像头采集逻辑通常运行在子线程,你直接在子线程调用单例的setM_Image修改UI相关属性,没有做跨线程同步,也可能触发内存访问冲突。
修复方案
1. 修正绘制逻辑的源矩形
修改paint方法,动态获取当前QImage的尺寸作为源矩形范围,不要硬编码固定尺寸:
void MyImage::paint(QPainter *painter) { QRectF target(0.0, 0.0, 800.0, 550.0); // 动态获取图像实际尺寸作为源区域 QRectF source(0.0, 0.0, m_Image.width(), m_Image.height()); painter->setRenderHint(QPainter::Antialiasing, true); painter->drawImage(target, this->m_Image, source); }
2. 转换QImage时强制深拷贝
Mat转QImage后调用copy()方法,让QImage持有独立的数据缓冲区,不依赖原始采集缓冲区:
QImage Qimag = MatImageToQt(image).copy(); // 强制深拷贝 // 不需要scaled时直接传入即可 // Qimag = Qimag.scaled(image.cols*0.33,image.rows*0.27,Qt::IgnoreAspectRatio,Qt::SmoothTransformation); MyImage *myimg = MyImage::instance(); myimg->setM_Image(Qimag);
3. 优化跨线程数据传递
不要在子线程直接调用UI对象的方法,改用信号槽传递QImage,Qt会自动处理隐式共享的线程安全。
内容的提问来源于stack exchange,提问作者Ning
相关产品推荐
相关产品推荐

