我的需求:
捕获摄像头的视频数据流并实时显示在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 &)));