当前位置: 首页 > news >正文

如何使用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

参考

相关文章:

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

前言 需求&#xff1a; 1、如何使用OpenCV捕抓Windows电脑上USB摄像头的流、 2、采用多线程 3、获知当前摄像头的帧率。 这个需求&#xff0c;之前就有做了&#xff0c;但是由于出现了一个问题&#xff0c;人家摄像头的帧率目前都可以达到60帧/s 了&#xff0c;而我的程序…...

电子应用设计方案86:智能 AI背景墙系统设计

智能 AI 背景墙系统设计 一、引言 智能 AI 背景墙系统旨在为用户创造一个动态、个性化且具有交互性的空间装饰体验&#xff0c;通过融合先进的技术和创意设计&#xff0c;提升室内环境的美观度和功能性。 二、系统概述 1. 系统目标 - 提供多种主题和风格的背景墙显示效果&…...

【《python爬虫入门教程11--重剑无峰168》】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 【《python爬虫入门教程11--selenium的安装与使用》】 前言selenium就是一个可以实现python自动化的模块 一、Chrome的版本查找&#xff1f;-- 如果用edge也是类似的1.chrome…...

.net core 线程锁,互斥锁,自旋锁,混合锁

线程锁、互斥锁、自旋锁和混合锁是多线程编程中的重要概念&#xff0c;它们用于控制对共享资源的访问&#xff0c;避免数据竞争和不一致性。每种锁有其特定的适用场景和特点。我们来逐一解释它们&#xff0c;并进行比较。 1. 线程锁&#xff08;Thread Lock&#xff09; 线程…...

【DevOps】Jenkins项目发布

Jenkins项目发布 文章目录 Jenkins项目发布前言资源列表基础环境一、Jenkins发布静态网站1.1、项目介绍1.2、部署Web1.3、准备gitlab1.4、配置gitlab1.5、创建项目1.6、推送代码 二、Jenkins中创建gitlab凭据2.1、创建凭据2.2、在Jenkins中添加远程主机2.3、获取gitlab项目的UR…...

C# OpenCV机器视觉:霍夫变换

在一个阳光灿烂得近乎放肆的午后&#xff0c;阿强的实验室就像被施了魔法的科学城堡&#xff0c;到处闪耀着神秘的科技光芒。阿强呢&#xff0c;像个即将踏上惊险征程的探险家&#xff0c;一屁股坐在那堆满奇奇怪怪设备的桌前&#xff0c;眼神中透露出按捺不住的兴奋劲儿&#…...

Kraft模式安装Kafka(含常规、容器两种安装方式)

一、#创作灵感# 公司使用Kafka的软件项目较多&#xff0c;故写技术笔记巩固知识要点 二、软件环境 - Kafka 3.9.0 官方下载地址&#xff1a;Kafka 3.9.0 - Docker Desktop 4.37 容器图形化工具 官方下载地址&#xff1a;Docker Desktop 4.37 特别说明 - Docker Desktop…...

Linux驱动开发(16):输入子系统–电容触摸驱动实验

有关电容触摸的基础知识内容可以参考野火STM32相关教程&#xff0c;这里只介绍电容触摸驱动的相关内容。 本章配套源码、设备树以及更新固件位于“~/embed_linux_driver_tutorial_imx6_code/linux_driver/touch_scream_GTxxx”目录下。 触摸面板通过双面胶粘在显示屏上&#…...

《深入浅出HTTPS​​​​​​​​​​​​​​​​​》读书笔记(24):椭圆曲线密码学

《深入浅出HTTPS​​​​​​​​​​》读书笔记&#xff08;24&#xff09;&#xff1a;椭圆曲线密码学 为了保证DH的密钥对不被破解&#xff0c;提升安全性的主要手段就是增加密钥对的长度&#xff0c;但是长度越长&#xff0c;性能越低。 为了解决性能问题&#xff0c;需要…...

现代光学基础5

总结自老师的讲义 yt5 开卷考试复习资料&#xff1a;光探测器与光伏技术 目录 光探测器&#xff08;Photodetector&#xff09; 工作原理二极管电路连接方式响应度&#xff08;Responsivity&#xff09;微弱光检测超导纳米线单光子探测光电二极管噪声 太阳能电池&#xff0…...

力扣hot100——贪心

121. 买卖股票的最佳时机 class Solution { public:int maxProfit(vector<int>& a) {if (a.size() 1) return 0;int ans 0;int mi a[0];for (int i 1; i < a.size(); i) {ans max(ans, a[i] - mi);mi min(mi, a[i]);}return ans;} };55. 跳跃游戏 class S…...

vue3如何实现防抖?

第一 防抖就是我们设置一个调用时间&#xff0c;点击后设置时间开始倒计时&#xff0c;如果再次点击会重新倒计时 npm或yarn安装&#xff1a; npm install lodash <template><div click"debouncedInputHandler"><button>打印</button>…...

西安电子科技大学初/复试笔试、面试、机试成绩占比

西安电子科技大学初/复试笔试、面试、机试成绩占比 01通信工程学院 02电子工程学院 03计算机科学与技术学院 04机电工程学院 06经济与管理学院 07数学与统计学院 08人文学院 09外国语学院 12生命科学与技术学院 13空间科学与技术学院 14先进材料与纳米科技学院 15网络与信息安…...

spring mvc源码学习笔记之六

pom.xml 内容如下 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/P…...

树莓派4b如何连接ov7670摄像头

在树莓派4B上连接和使用OV7670摄像头是一项具有一定技术挑战的任务。这是因为OV7670摄像头是一个原始的CMOS摄像头模块,它通过并行接口与主机通信,而树莓派的GPIO接口通常用于串行接口(如I2C、SPI、UART)通信,不直接支持并行摄像头接口。因此,需要一些额外的硬件和软件工…...

[微服务]分布式搜索Java客户端

快速入门 使用RestClient客户端进行数据搜索可以分为两步 构建并发起请求 代码解读&#xff1a; 第一步&#xff0c;创建SearchRequest对象&#xff0c;指定索引库名第二步&#xff0c;利用request.source()构建DSL&#xff0c;DSL中可以包含查询、分页、排序、高亮等 query…...

如何使用 `uiautomator2` 控制 Android 设备并模拟应用操作_VIVO手机

在 Android 自动化测试中,uiautomator2 是一个非常强大的工具,能够帮助我们通过 Python 控制 Android 设备执行各种操作。今天,我将通过一个简单的示例,介绍如何使用 uiautomator2 控制 Android 设备,执行特定的应用启动、广告跳过以及其他 UI 操作。此示例的目标是自动化…...

在Ubuntu 18.04.6 LTS安装OpenFace流程

一、修改配置:将gcc8&#xff0c;g8作为默认选项 sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-8 100 sudo update-alternatives --config gcc 选择版本&#xff0c;再查看gcc --version sudo update-alternatives --install /usr/bin/g g /usr/bin/g-…...

C 语言的整型提升问题

目录 引言 一、什么是整型提升 二、为什么会有整型提升 三、整型提升的规则 四、整型提升的影响 五、如何避免整型提升带来的问题 六、总结 引言 在 C 语言中&#xff0c;整型提升&#xff08;Integer Promotion&#xff09;是一个常常被忽视但却非常重要的概念。理解整…...

第0章 机器人及自动驾驶SLAM定位方法全解析及入门进阶学习建议

嗨&#xff0c;各位同学大家好&#xff01;笔者自985硕士毕业后&#xff0c;在机器人算法领域已经深耕 7 年多啦。这段时间里&#xff0c;我积累了不少宝贵经验。本专栏《机器人工程师带你从零入门SLAM》将结合下面的SLAM知识体系思维导图及多年的工作实战总结&#xff0c;将逐…...

video.js视频播放上手

html案例 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><title>videojs视频播放</title> </head> <link href"https://cdnjs.cloudflare.com/ajax/libs/video.js/7.3.0/video-js.min.cs…...

【LLM-Agent】Building effective agents和典型workflows

note Anthropic的工程经验&#xff1a; 大道至简&#xff0c;尽量维护系统的简洁&#xff1b;尽量让过程更加透明&#xff08;因为你依赖的是LLM的决策&#xff0c;如果只看输出不看过程&#xff0c;很容易陷入难以debug的情况&#xff09;&#xff1b;对LLM需要调用的工具&am…...

《量子比特大阅兵:不同类型量子比特在人工智能领域的优劣势剖析》

在科技的前沿&#xff0c;量子比特与人工智能的融合正开启一扇全新的大门。不同类型的量子比特&#xff0c;如超导、离子阱、光量子等&#xff0c;在与人工智能结合时展现出独特的优势与劣势。 超导量子比特 超导量子比特是目前应用较为广泛且研究相对成熟的量子比特类型。它…...

《探秘开源大模型:AI 世界的“超级引擎”》

《探秘开源大模型:AI 世界的“超级引擎”》 一、开源大模型崛起之路二、开源大模型发展历程回顾(一)早期奠基:理论突破与初步实践(二)快速发展:百花齐放的模型格局(三)当下态势:走向成熟与多元融合三、开源大模型核心技术剖析(一)Transformer 架构:基石之稳(二)…...

el-table行列转换简单版,仅限单行数据

原始数据格式如下&#xff0c;如果不是此格式&#xff0c;请转换成以下格式在进行以下操作 [{ label: name, value: Tom },{ label: age, value: 25 },{ label: country, value: UK } ]代码如下 <template><el-table :data"tableData" style"width: …...

2025年1月4日蜻蜓q旗舰版st完整开源·包含前后端所有源文件·开源可商用可二开·优雅草科技·优雅草kir|优雅草星星|优雅草银满|优雅草undefined

2025年1月4日蜻蜓q旗舰版st完整开源包含前后端所有源文件开源可商用可二开优雅草科技优雅草kir|优雅草星星|优雅草银满|优雅草undefined 产品介绍&#xff1a; 本产品主要贡献者优雅草科技优雅草kir|优雅草星星|优雅草银满|优雅草undefined-青史留名&#xff0c;时光如川浪淘…...

SQL把字符串按逗号分割成记录

在 SQL 中&#xff0c;可以通过以下方法将字符串按逗号分割&#xff0c;并将每个分割的值作为单独的记录插入到结果集中。以下是针对不同数据库系统的实现方法&#xff1a; 1. 使用 STRING_SPLIT&#xff08;SQL Server 2016&#xff09; STRING_SPLIT 是 SQL Server 提供的内置…...

C#设计模式(行为型模式):观察者模式

C#设计模式&#xff1a;观察者模式&#xff0c;让对象间通信更优雅 在软件开发中&#xff0c;我们经常会遇到一个对象的状态发生改变&#xff0c;其他对象需要自动更新或做出相应反应的场景。例如&#xff1a; GUI事件处理&#xff1a; 当用户点击按钮时&#xff0c;按钮需要…...

pytorch镜像源

我以为的 pip install torch2.3.1cu118 torchvision0.18.1cu118 torchaudio2.3.1cu118 -f https://download.pytorch.org/whl/torch_stable.html实际上&#xff0c;有很多加速方案 为提高下载速度可以使用国内的镜像源来安装与 CUDA 11.8 兼容的 PyTorch。 方法 1&#xff1a…...

Verilog语法之常用行为级语法

摘要&#xff1a;本文主要介绍了一些在verilog中的行为级语法&#xff0c;并且提供了大量的运行实际例子&#xff0c;可以通过这些例子感受行为级语法在仿真中的巨大作用。 概述&#xff1a;行为级语法是RTL级的上一层&#xff0c;或者说是比RTL级更高级的语法&#xff0c;其语…...