使用std::atomic存储cv::Mat引发Qt编译错误的技术问询
问题解决思路
一、编译错误原因及修复
你遇到的无法用MainWindow*初始化QMainWindow*类型参数错误,本质是std::atomic<cv::Mat>的用法不合法:
std::atomic仅支持**可平凡复制(Trivially Copyable)**的类型,而cv::Mat内部包含动态分配的内存指针、引用计数等非平凡成员,不满足std::atomic的模板要求。- 当类中包含非法成员变量时,编译器对类的类型推导会出现异常,进而影响
setupUi(this)的参数匹配。
修复方案
放弃std::atomic<cv::Mat>的用法,改用以下线程安全的帧共享方式:
方案1:互斥锁+普通cv::Mat
在MainWindow中声明普通的cv::Mat成员,配合std::mutex或QMutex保证线程安全:class MainWindow : public QMainWindow { Q_OBJECT private: cv::Mat current_frame; std::mutex frame_mutex; public: // 写帧线程(采集线程) void capture_frame() { cv::Mat temp_frame = ...; // 从摄像头采集帧 std::lock_guard<std::mutex> lock(frame_mutex); current_frame = temp_frame.clone(); // 克隆避免原数据被覆盖 } // 显示线程 void show_frame_on_screen() { cv::Mat display_frame; { std::lock_guard<std::mutex> lock(frame_mutex); display_frame = current_frame.clone(); } // 用Qt或OpenCV显示display_frame } // 录制线程 void record_frames() { cv::VideoWriter writer(...); while(recording) { cv::Mat record_frame; { std::lock_guard<std::mutex> lock(frame_mutex); record_frame = current_frame.clone(); } if(!record_frame.empty()) { writer.write(record_frame); } } } };方案2:优化现有std::queue方案
你当前用的std::queue<cv::Mat>可以通过以下方式降低帧率损耗:- 限制队列最大长度,避免内存堆积:比如超过10帧就丢弃最早的帧,防止采集速度远快于录制速度导致内存占用过高。
- 使用
cv::Mat的移动语义:入队时用std::move(temp_frame)代替直接赋值,减少内存拷贝开销:std::lock_guard<std::mutex> lock(queue_mutex); if(frame_queue.size() > 10) { frame_queue.pop(); } frame_queue.push(std::move(temp_frame)); - 录制线程批量取帧,减少锁的竞争频率。
二、帧率下降的优化建议
针对树莓派4的硬件特性,还可以做这些优化:
- 降低采集分辨率:如果不需要高分辨率,将摄像头采集分辨率设为720p甚至480p,减少每一帧的数据量。
- 使用硬件加速:OpenCV在Raspbian上可以启用MMAL硬件加速,编译时加入
-DWITH_MMAL=ON参数,调用摄像头时用cv::CAP_V4L2后端,提升采集效率。 - 分离显示和录制的线程优先级:在Qt中给录制线程设置较低优先级,保证显示线程的资源优先性:
QThread* record_thread = new QThread; RecordWorker* worker = new RecordWorker; worker->moveToThread(record_thread); record_thread->setPriority(QThread::LowPriority); record_thread->start(); - 避免在显示线程做耗时操作:显示前的图像预处理(如缩放、格式转换)尽量放到采集线程完成,减少显示线程的负担。
内容的提问来源于stack exchange,提问作者Jorge Augusto Wilchen
相关产品推荐
相关产品推荐

