如何使用OpenCV进行抓图-多线程

前言

需求:

1、如何使用OpenCV捕抓Windows电脑上USB摄像头的流、

2、采用多线程

3、获知当前摄像头的帧率。

这个需求,之前就有做了,但是由于出现了一个问题,人家摄像头的帧率目前都可以达到60帧/s 了,而我的程序获取的却还只能获取20帧/s ,那么肯定就是存在问题了。所以,目前采用了一些办法进行解决,能充分发挥其60帧/s 的优势,并能打出帧率。下面开始详细阐述。

正文

一、环境

1、Win10

2、Qt 5.8.0 MSVC2015

3、OpenCV VS2015编译的

二、效果展示

请添加图片描述

三、关键代码

1、抓图线程:

bool CCameraCaptureThd::Init()
{int index = 5;while (true){m_bInit = m_capture.open(0+cv::CAP_DSHOW, cv::CAP_ANY);  // 打开默认摄像头m_capture.set(cv::CAP_PROP_FRAME_WIDTH, 1280);m_capture.set(cv::CAP_PROP_FRAME_HEIGHT, 720);m_capture.set(cv::CAP_PROP_FOURCC, cv::VideoWriter::fourcc('M', 'J', 'P', 'G'));if (m_bInit){return true;}else{index--;QThread::sleep(1);if (index < 0){qDebug() << "--> Failed to initialize camera!";return false;}}}return true;
}void CCameraCaptureThd::StartCapture()
{m_bCapture = true;double dExpore = m_capture.get(cv::CAP_PROP_EXPOSURE);double dBrightness = m_capture.get(cv::CAP_PROP_BRIGHTNESS);qDebug() << "---> dExpore:"<<dExpore<<"||"<<dBrightness;
}void CCameraCaptureThd::StopCapture()
{m_bCapture = false;
}bool CCameraCaptureThd::SetCameraBrightness(const int &_iBrightness)
{bool bRet = false;if (false == m_capture.isOpened()){return bRet;}qDebug() << "---> CCameraCaptureThd::SetCameraBrightness _iBrightness:"<<_iBrightness;bRet = m_capture.set(cv::CAP_PROP_BRIGHTNESS, _iBrightness);double dBrightness = m_capture.get(cv::CAP_PROP_BRIGHTNESS);qDebug() << "---> CCameraCaptureThd dBrightness:"<<dBrightness;return bRet;
}bool CCameraCaptureThd::SetCameraExposure(const int &_iExposure)
{bool bRet = false;if (false == m_capture.isOpened()){return bRet;}qDebug() << "---> CCameraCaptureThd::SetCameraExposure _iExposure:"<<_iExposure;bRet = m_capture.set(cv::CAP_PROP_EXPOSURE, _iExposure);double dExpore = m_capture.get(cv::CAP_PROP_EXPOSURE);qDebug() << "---> CCameraCaptureThd dExpore:"<<dExpore;return bRet;
}void CCameraCaptureThd::run()
{std::thread captureThread(&CCameraCaptureThd::captureThreadFunc, this);captureThread.detach();  // 捕获线程独立运行while (!m_bExit){cv::Mat frame;{std::unique_lock<std::mutex> lock(m_mtxQueue);if (m_frameQueue.empty()){m_cvQueue.wait(lock, [this] { return !m_frameQueue.empty() || m_bExit; });}if (m_bExit) break;frame = m_frameQueue.front();m_frameQueue.pop();}if (!frame.empty()){processFrame(frame);calculateFps(); // 每处理一帧计算一次 FPS}}
}void CCameraCaptureThd::captureThreadFunc()
{while (!m_bExit){cv::Mat frame;if (m_capture.isOpened() && m_bCapture){m_capture.read(frame);if (frame.empty() || !_CheckMat(frame)){if (!m_bWrongCamera){emit SIGNAL_CameraWrong();m_bWrongCamera = true;}continue;}std::lock_guard<std::mutex> lock(m_mtxQueue);if (m_frameQueue.size() >= m_maxQueueSize){m_frameQueue.pop();  // 丢弃旧帧}m_frameQueue.push(frame);m_cvQueue.notify_one();}QThread::msleep(m_iImageCaptureSleepTime);}
}void CCameraCaptureThd::processFrame(const cv::Mat& frame)
{cv::Mat processedFrame;frame.copyTo(processedFrame);cv::cvtColor(processedFrame, processedFrame, cv::COLOR_BGR2RGB);cv::flip(processedFrame, processedFrame, 1);  // Y 轴翻转QImage img = QImage((uint8_t*)processedFrame.data, processedFrame.cols, processedFrame.rows, QImage::Format_RGB888).copy();//qDebug() << "---> processFrame:"<<QDateTime::currentMSecsSinceEpoch();emit SIGNAL_UpdateRgbImage(img);
}void CCameraCaptureThd::calculateFps()
{++m_frameCount;auto now = std::chrono::steady_clock::now();double elapsedTime = std::chrono::duration_cast<std::chrono::milliseconds>(now - m_startTime).count();if (elapsedTime >= 1000.0) // 每秒更新一次 FPS{m_currentFps = m_frameCount * (1000.0 / elapsedTime);m_frameCount = 0;m_startTime = now;qDebug() << "Current FPS:" << m_currentFps;emit SIGNAL_FrameRate(m_currentFps);}
}bool CCameraCaptureThd::_CheckMat(const cv::Mat& mat)
{return !mat.empty() && mat.cols > 0 && mat.rows > 0;
}

最关键的就是run里面的函数了。

四、遇到的问题

1、帧率怎么都上不去

解决方案:更改了相机打开时的设置

更改成这样:

m_bInit = m_capture.open(0+cv::CAP_DSHOW, cv::CAP_ANY);  // 打开默认摄像头
m_capture.set(cv::CAP_PROP_FRAME_WIDTH, 1280);
m_capture.set(cv::CAP_PROP_FRAME_HEIGHT, 720);
m_capture.set(cv::CAP_PROP_FOURCC, cv::VideoWriter::fourcc('M', 'J', 'P', 'G'));

如果是这样的,帧率就会上不去:

m_capture.set(cv::CAP_PROP_FOURCC, cv::VideoWriter::fourcc('M', 'J', 'P', 'G'));
m_bInit = m_capture.open(0+cv::CAP_DSHOW, cv::CAP_ANY);  // 打开默认摄像头
m_capture.set(cv::CAP_PROP_FRAME_WIDTH, 1280);
m_capture.set(cv::CAP_PROP_FRAME_HEIGHT, 720);

通过查询,问题的原因应该在:

属性设置的顺序如何影响帧率

  1. 属性的优先级问题
    • 摄像头通常优先处理某些属性。例如:
      • 分辨率 (FRAME_WIDTH, FRAME_HEIGHT) 是基础属性,影响图像传感器的输出格式。
      • 编码格式 (FOURCC) 决定图像流的压缩方式。
    • 如果先设置分辨率,然后设置编码格式,编码器会根据新分辨率重新调整帧率。
    • 反之,如果先设置编码格式,随后更改分辨率,驱动可能无法实时适配,导致性能下降。
  2. 驱动和硬件内部调整机制
    • 摄像头驱动程序在每次设置参数时,可能会重新协商帧率。例如:
      • 设置分辨率后,驱动需要查询硬件支持的最大帧率。
      • 如果在分辨率设置之前先设置编码格式,驱动可能会选择一个默认分辨率(通常较低),随后改变分辨率会导致帧率调整。
  3. 参数依赖性问题
    • 某些参数依赖于其他参数。例如:
      • 不同的编码格式支持的最大帧率和分辨率是不同的。
      • MJPG(Motion JPEG)通常支持高分辨率和高帧率,但 YUV 格式可能性能较低。
  4. 初始化次序影响驱动的行为
    • 驱动可能在第一次设置后锁定某些参数。如果设置顺序错误,后续参数可能不会生效,或需要额外的时间重新初始化。
    • 例如,先设置编码格式再设置分辨率,可能触发两次完整的驱动初始化。

正确的设置顺序建议

为了确保帧率最大化,可以按照以下顺序设置参数:

  1. 设置分辨率
    • 首先设置分辨率 (FRAME_WIDTHFRAME_HEIGHT),确保摄像头硬件和驱动调整到正确的传感器输出。
  2. 设置帧率(如果需要):
    • 如果特定帧率是关键要求,可以尝试显式设置帧率(cv::CAP_PROP_FPS)。
  3. 设置编码格式
    • 最后设置编码格式 (FOURCC),以确保基于之前设置的分辨率和帧率进行编码。

还有另一个原因,就是我抓图与处理的线程处于同一个,这样也会拉低整个线程处理的效率。

2、调整USB摄像头的亮度与曝光,出现意外情况

若不按照先调曝光再调增益的顺序,有可能出现调整曝光错乱的情况,原因未知。

目前按照的逻辑是,若想亮起来,则为:曝光:0 + 亮度:64

若想暗下来,则为:曝光:-13 + 亮度:-64

五、资源

https://github.com/calorsol/QtDemo/tree/master/OpenCVCaptureTest

参考

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/502118.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

NLP CH3复习

CH3 3.1 几种损失函数 3.2 激活函数性质 3.3 哪几种激活函数会发生梯度消失 3.4 为什么会梯度消失 3.5 如何解决梯度消失和过拟合 3.6 梯度下降的区别 3.6.1 梯度下降&#xff08;GD&#xff09; 全批量&#xff1a;在每次迭代中使用全部数据来计算损失函数的梯度。计算成本…

01 数据分析介绍及工具准备

数据分析介绍及工具准备 一、工具准备二、下载和使用Anaconda三、jupyter notebook常用快捷键 一、工具准备 数据科学库 NumPy&#xff0c;SciPy&#xff0c;Pandas&#xff0c;Scikit-Learn 数据可视化库 Matplotlib&#xff0c;Seaborn 编译器 Jupyter Notebook 数据科…

机组的概述

计算机系统组成 硬件系统和软件系统 计算机硬件 1.冯诺依曼机基本思想 特点 1.采用“存储程序”工作方式 2.硬件系统由运算器&#xff0c;存储器&#xff0c;控制器&#xff0c;输入输出设备组成 3.指令和数据存在存储器中&#xff0c;形式无区别 4.指令和数据用二进制代…

Windows应用开发-解析MP4视频文件(第1部分)

下载本应用 本Windows应用解析MP4视频文件&#xff0c;以表格的方式显示MP4文件结构。并可以将结果保存到bmp图片。 使用方法 选择“打开MP4视频文件”菜单项&#xff0c;打开MP4文件&#xff0c;就可以获得如下图像&#xff1a; box的每一项&#xff0c;用3个矩形表示&…

Scala_【4】流程控制

第四章 分支控制if-else单分支双分支多分支返回值嵌套分支 For循环控制包含边界不包含边界循环守卫循环步长嵌套循环循环返回值 While循环Break友情链接 分支控制if-else 单分支 双分支 多分支 返回值 嵌套分支 For循环控制 Scala也为for循环这一常见的控制结构提供了非常多的…

电商Google广告:2025年提升转化率的5种策略

展望 2025 年&#xff0c;Google 广告领域将迎来一系列显著变化&#xff0c;这些趋势对于提升广告转化率至关重要&#xff0c;值得我们提前关注与布局。 智能化程度持续加深&#xff0c;用户搜索习惯愈发精细&#xff0c;广告格式推陈出新&#xff0c;视频广告势头正猛...那么…

一文大白话讲清楚TCP连接的三次握手和断开连接的四次挥手的原理

文章目录 一文大白话讲清楚TCP连接的三次握手和断开连接的四次挥手的原理1.TCP建立连接需要3次握手1.1 先讲个你兄弟的故事1.2 TCP 3次握手1.2 TCP 3次握手8件事1.3 TCP握手能不能是两次 2. TCP 断开连接要4次挥手2.1 还回到你兄弟的故事上2.2 TCP 4次挥手2.2 TCP4次挥手4件事2…

基于springboot的课程作业管理系统(源码+数据库+文档)

亲测完美运行带论文&#xff1a;文末获取源码 文章目录 项目简介&#xff08;论文摘要&#xff09;运行视频包含的文件列表&#xff08;含论文&#xff09;前端运行截图后端运行截图 项目简介&#xff08;论文摘要&#xff09; 随着科学技术的飞速发展&#xff0c;社会的方方面…

【ArcGIS微课1000例】0136:制作千层饼(DEM、影像、等高线、山体阴影图层)

文章目录 一、效果展示二、数据准备三、制作过程1. 打开软件2. 制作DEM图层3. 制作影像层4. 制作TIN层5. 制作等高线层四、注意事项一、效果展示 二、数据准备 订阅专栏后,从专栏配套案例数据包中的0136.rar中获取。 1. dem 2. 影像 3. 等高线 4. tin 三、制作过程 1. 打开软…

蓝桥杯备赛:C++基础,顺序表和vector(STL)

目录 一.C基础 1.第一个C程序&#xff1a; 2.头文件&#xff1a; 3.cin和cout初识&#xff1a; 4.命名空间&#xff1a; 二.顺序表和vector&#xff08;STL&#xff09; 1.顺序表的基本操作&#xff1a; 2.封装静态顺序表&#xff1a; 3.动态顺序表--vector&#xff1a;…

探索AI在地质科研绘图中的应用:ChatGPT与Midjourney绘图流程与效果对比

文章目录 个人感受一、AI绘图流程1.1 Midjourney&#xff08;1&#xff09;环境配置&#xff08;2&#xff09;生成prompt&#xff08;3&#xff09;完善prompt&#xff08;4&#xff09;开始绘图&#xff08;5&#xff09;后处理 1.2 ChatGPT不合理的出图结果解决方案 二、主题…

融合表面信息和等变扩散的分子对接模型 SurfDock - 评测

SurfDock 是一个几何扩散模型&#xff0c;蛋白质序列、三维结构图、以及表面结构等结构特征&#xff0c;采用的是非欧里几何的范式处理小分子的旋转、平移以及扭转。 SurfaceDock 以蛋白口袋作为条件&#xff0c;从 rdkit 生成的随机小分子构象开始&#xff0c;对平移、旋转、扭…

CSS——2.书写格式一

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title></title></head><body><!--css书写中&#xff1a;--><!--1.css 由属性名:属性值构成--><!--style"color: red;font-size: 20px;&quo…

R机器学习:神经网络算法的理解与实操,实例解析

神经网络算法是一种模仿生物神经网络&#xff08;尤其是人脑&#xff09;结构和功能的算法。它由大量相互连接的节点&#xff08;称为神经元&#xff09;组成&#xff0c;这些神经元组织成层&#xff0c;通过传递信号来处理信息。神经网络算法在机器学习、人工智能等领域中扮演…

【C++】B2092 开关灯

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 &#x1f4af;前言&#x1f4af;题目描述和解析题目描述输入格式输出格式解析 &#x1f4af;实现代码对比&#xff1a;我的做法和老师的做法我的代码实现代码分析优点问题 老师的代码实现代码分析 &#x…

【PS不常见教程】实操篇之通道抠图-抠黑色背景的图片

观前小提示&#xff1a;本文内容为我原创成果&#xff0c;若您需要转载或引用其中图片或文字内容&#xff0c;请记得标注来源是“璞子的家”哦&#xff0c;感谢您的尊重&#xff0c;理解与支持&#xff0c;谢谢啦&#xff01; 如果没看过之前的文章&#xff0c;可以先看之前的两…

STM32完全学习——使用定时器1精确延时

一、定时器的相关配置 首先一定要是递减定时器&#xff0c;递增的不太行&#xff0c;控制的不够准确&#xff0c;其次在大于10微秒的延时是非常准确的&#xff0c;小于的话&#xff0c;就没有那没准&#xff0c;但是凑合能用。误差都在一个微秒以内。使用高级定时器也就是时钟…

【Cesium】三、实现开场动画效果

文章目录 实现效果实现方法实现代码组件化 实现效果 实现方法 Cesium官方提供了Camera的flyTo方法实现了飞向目的地的动画效果。 官方API&#xff1a;传送门 这里只需要用到目的地&#xff08;destination&#xff09;和持续时间&#xff08;duration&#xff09;这两个参数…

【游戏设计原理】47 - 超游戏思维

对于这条原理&#xff0c;我首先想到的是开放世界&#xff0c;或者探索性游戏&#xff0c;这是最能包容各类玩家的游戏类型。这类游戏定义了基本规则&#xff0c;玩家的可操作性很强。就像上图里的沙池一样&#xff0c;里面有滑梯&#xff0c;是规则性比较明确的&#xff0c;而…

DeepSeek v3为何爆火?如何用其集成Milvus搭建RAG?

最近&#xff0c;DeepSeek v3&#xff08;一个MoE模型&#xff0c;拥有671B参数&#xff0c;其中37B参数被激活&#xff09;模型全球爆火。 作为一款能与Claude 3.5 Sonnet&#xff0c;GPT-4o等模型匹敌的开源模型DeepSeek v3不仅将其算法开源&#xff0c;还放出一份扎实的技术…