OpenCV多线程编程:从单线程到双线程的视频处理
前言多年前刚刚接触Opencv还没有AI那个时候第一次处理视频的时候仅仅通过usb摄像头显示都还可以但是通过rtsp等网络方式的方法接入在显示图像的过程再处理点什么那简直是卡通过网上搜索建议使用多线程处理然后一堆代码终于从里面理清了最近也有同事遇到同样的问题我说让看代码他说里面掺杂了太多业务不太好看明白所以才有了这篇文章从最简单的方法实现多线程处理视频流不参与任何业务。一个负责获取视频帧一个负责处理使用最简单的实践达到目的。同理的思想用于在一个系统之上我开发了一个QT快速开发系统也是使用最简单不掺杂任何业务的实现避免其他人为了吃顿饭还要买个锅碗瓢盆QT快速开发框架一、最简单的摄像头显示程序让我们从最基础的版本开始一个单线程程序直接从摄像头读取并显示画面。基础版本代码#includeiostream#includeopencv2/opencv.hppusingnamespacestd;intmain(){// 打开摄像头默认摄像头编号0cv::VideoCapturecap(0);if(!cap.isOpened()){cerrError: Could not open camera!endl;return-1;}cv::Mat frame;while(true){capframe;// 读取一帧if(frame.empty()){cerrError: Empty frame!endl;break;}cv::imshow(Camera,frame);// 显示画面charkeycv::waitKey(1);if(keyq||keyQ){break;// 按q键退出}}cap.release();cv::destroyAllWindows();return0;}基础版本的特点优点简单直接易于理解缺点所有操作都在一个线程中执行如果添加复杂的图像处理会导致画面卡顿二、尝试使用线程初学者可能会尝试将摄像头读取放入单独的线程#includeiostream#includeopencv2/opencv.hpp#includethreadusingnamespacestd;voidcaptureThread(){cv::VideoCapturecap(0);if(!cap.isOpened()){std::cerrError: Could not open camera!std::endl;return;}cv::Mat frame;while(true){capframe;if(frame.empty())break;cv::imshow(Camera,frame);// 错误在子线程中显示charkeycv::waitKey(1);if(keyq||keyQ)break;}cap.release();cv::destroyAllWindows();}intmain(){threadcaptureVideo(captureThread);captureVideo.join();return0;}三、再进一步使用双线程实现#includeiostream#includeopencv2/opencv.hpp#includethread#includemutex#includeatomicusingnamespacestd;// 共享数据cv::Mat sharedFrame;mutex mtx;atomicboolrunning(true);// 线程1负责捕获视频帧voidcaptureThread(){cv::VideoCapturecap(0);if(!cap.isOpened()){cerrError: Could not open camera!endl;runningfalse;return;}cv::Mat frame;while(running){capframe;if(frame.empty()){cerrError: Empty frame!endl;break;}// 使用互斥锁保护共享数据lock_guardmutexlock(mtx);frame.copyTo(sharedFrame);}cap.release();}// 线程2负责处理和显示voiddisplayAndProcessThread(){cv::namedWindow(Camera,cv::WINDOW_AUTOSIZE);while(running){cv::Mat frame;// 获取最新的帧{lock_guardmutexlock(mtx);if(!sharedFrame.empty()){sharedFrame.copyTo(frame);}}if(!frame.empty()){// 在这里添加你的图像处理代码 // 示例1添加文字string textHello OpenCV!;cv::putText(frame,text,cv::Point(50,50),cv::FONT_HERSHEY_SIMPLEX,1.0,cv::Scalar(0,255,0),2);// 示例2添加时间戳信息cv::putText(frame,Press q to quit,cv::Point(10,frame.rows-10),cv::FONT_HERSHEY_SIMPLEX,0.5,cv::Scalar(0,0,255),1);// 显示处理后的画面cv::imshow(Camera,frame);}// 检查退出条件charkeycv::waitKey(30);if(keyq||keyQ){runningfalse;break;}}cv::destroyAllWindows();}intmain(){coutProgram started. Press q to quit.endl;// 创建两个线程threadcapture(captureThread);threaddisplay(displayAndProcessThread);// 等待线程结束display.join();capture.join();coutProgram terminated.endl;return0;}四、代码解析1. 线程同步机制mutex mtx;// 互斥锁防止数据竞争atomicboolrunning;// 原子变量控制线程结束互斥锁确保同一时刻只有一个线程访问共享数据原子变量安全地在多线程间传递状态信息2. 线程分工线程职责说明captureThread捕获视频帧持续从摄像头读取存入共享变量displayAndProcessThread处理和显示获取帧添加特效显示画面3. 关键代码说明// 保护共享数据的访问{lock_guardmutexlock(mtx);// 自动加锁解锁frame.copyTo(sharedFrame);// 安全的拷贝}五、进阶添加更多图像处理效果你可以在显示线程中添加各种OpenCV特效// 在显示线程的处理部分添加// 1. 转为灰度图cv::Mat gray;cv::cvtColor(frame,gray,cv::COLOR_BGR2GRAY);// 2. 边缘检测cv::Mat edges;cv::Canny(gray,edges,50,150);// 3. 人脸检测需要haar cascade文件// cv::CascadeClassifier faceCascade;// faceCascade.load(haarcascade_frontalface_default.xml);// vectorcv::Rect faces;// faceCascade.detectMultiScale(gray, faces);// 4. 添加帧率显示staticintframeCount0;staticautostartTimechrono::steady_clock::now();frameCount;autocurrentTimechrono::steady_clock::now();autoelapsedchrono::duration_castchrono::seconds(currentTime-startTime).count();if(elapsed1){doublefpsframeCount/elapsed;coutFPS: fpsendl;frameCount0;startTimecurrentTime;}六、总结单线程 vs 双线程对比特性单线程双线程实现复杂度简单中等响应性好极好处理复杂任务会卡顿流畅CPU利用率一般更好代码可维护性简单良好多线程编程要点正确使用互斥锁保护共享数据避免死锁注意加锁顺序使用原子变量控制线程状态确保主线程等待子线程结束OpenCV的显示操作必须在主线程需要一份无污染的代码不包含任何业务QT快速开发框架
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2429145.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!