Qt在子线程中使用QLabel显示Pixmap的问题

本文档描述了在使用Qt进行多线程编程时遇到的一个问题:在子线程中通过QLabel显示来自摄像头的视频流导致Segment Fault。作者详细介绍了问题背景,包括尝试使用QCamera+QCameraViewFinder和QCamera+QGraphicsVideoItem+QGraphicsView失败的情况,以及最终选择OpenCV+QLabel的方案。问题在于不同线程对QLabel的setPixmap方法的并发访问。解决方案是将设置Pixmap的操作改为信号槽机制,确保线程安全。通过在子线程中发射信号,并在主线程的QLabel上绑定槽函数,成功避免了错误。
摘要由CSDN通过智能技术生成

我的需求:

捕获摄像头的视频数据流并实时显示在QLabel上(在子线程中运行)

我的方案:

在分别使用QCamera+QCameraViewFinder QCamera+QGraphicsVideoItem+QGaphicsView未果(涉及到摄像头旋转问题,去Qt的官方社区提问了,他们建议我重写QAbstractVideoSurface  话题链接:https://forum.qt.io/topic/112657/how-can-i-rotate-qcameraviewfinder-to-90-degree)后,我选择使用OpenCV+QLabel来显示我的视频流。

问题描述:

程序在笔记本上运行正常,当我把它放到工控机上时(配置非常低),运行一会儿就会出现Segment Fault,经调试发现这个错误抛出点在libQt5Gui.so.5上,且是在主线程中抛出,这另我十分费解,后来终于解决了这个问题。

解决方法:

这个问题的关键点在于:多个线程同时访问一个内存空间,并且你没法用互斥锁去解决它(抛出点在动态链接库中)。

直到我逛Qt的官方文档时才注意到一点:QLabel的setPixap是个Slot函数,顿时就恍然大悟,这一刻觉得自己无比愚蠢。

我的子线程是继承的QThread,所以把run()函数里的setPixmap()方法修改为信号的发射就ok了,然后在构造函数里把信号绑定到QLabel的setPixmap()上,再去运行就不会报错了。

因为使用信号槽是线程安全的,当跨线程连接信号槽时,connection的默认连接类型为Qt::QueuedConnection,看官方解释:The slot is invoked when control returns to the event loop of the receiver’s thread. The slot is executed in the receiver’s thread.

代码:

run函数中的图像捕获与信号发射

        //capture image
        cv::Mat cap_img;
        cap.read(cap_img);

        //convert image to QImage
        cv::Mat mat_show;
        cv::cvtColor(cap_img,mat_show,CV_BGR2RGB);
        QImage img_show(mat_show.data,mat_show.cols,mat_show.rows,QImage::Format::Format_RGB888);

        //set rotation
        img_show = img_show.transformed(QTransform().rotate(rotation_angle));

        //display image
        emit captured_image(QPixmap::fromImage(img_show));

构造函数中的connect(别忘记在头文件中定义此信号)

connect(this,SIGNAL(captured_image(const QPixmap &)),_dis_lb,SLOT(setPixmap(const QPixmap &)));

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值