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

C++基于opencv的视频质量检测--遮挡检测

文章目录

    • 0.引言
    • 1. 原始代码分析
      • 1.1 存在的问题
    • 2. 优化方案
    • 3. 优化后的代码
    • 4. 代码详细解读
      • 4.1. 输入检查
      • 4.2. 图像预处理
      • 4.3. 高斯模糊
      • 4.4. 梯度计算
      • 4.5. 计算梯度幅值和方向
      • 4.6. 边缘检测
      • 4.7. 计算边缘密度
      • 4.8. 估计遮挡程度
      • 4.9. 限定结果范围
      • 4.10. 返回结果

0.引言

视频质量遮挡检测已在C++基于opencv4的视频质量检测中有所介绍,本文将详细介绍其优化版本。

1. 原始代码分析

首先,我们来看遮挡检测的原始代码:

#include <opencv2/opencv.hpp>
#include <vector>/*** @brief 检测图像中的遮挡情况。* @param [in] srcImg 输入的图像* @return 返回一个double类型的数值,范围为0到1。数值越接近1,表示图像中的遮挡程度越高。*/
double blockDetect(const cv::Mat& srcImg) {if (srcImg.empty()) {return -1.0;  // 如果输入图像为空,返回-1表示错误}cv::Mat grayImg, edges;cv::cvtColor(srcImg, grayImg, cv::COLOR_BGR2GRAY);cv::GaussianBlur(grayImg, grayImg, cv::Size(3, 3), 0);cv::Canny(grayImg, edges, 0, 0);std::vector<std::vector<cv::Point>> contours;std::vector<cv::Vec4i> hierarchy;// 初始轮廓检测cv::findContours(edges, contours, hierarchy, cv::RETR_CCOMP, cv::CHAIN_APPROX_SIMPLE);int initialContourCount = static_cast<int>(hierarchy.size());// 细化后的轮廓检测cv::Canny(grayImg, edges, 0, 15);cv::findContours(edges, contours, hierarchy, cv::RETR_CCOMP, cv::CHAIN_APPROX_SIMPLE);int refinedContourCount = static_cast<int>(hierarchy.size());// 防止除以零的情况if (initialContourCount == 0) {initialContourCount = 1;}double occlusionLevel = 1.0 - static_cast<double>(refinedContourCount) / static_cast<double>(initialContourCount);return occlusionLevel;
}

1.1 存在的问题

  1. Canny边缘检测的阈值设置不合理:在Canny函数中,阈值设为00,以及015,这可能导致边缘检测结果不可靠。

  2. 错误处理不够明确:当输入图像为空时,返回-1.0,但这个值可能与正常的遮挡程度值混淆。

2. 优化方案

针对上述问题,我们对代码进行如下优化:

  • 自适应阈值设置:根据图像的特性动态设置Canny边缘检测的阈值,提高边缘检测的可靠性。

  • 提高代码可读性:增加详细的注释,使用更具描述性的变量名,提升代码的可读性和可维护性。

  • 算法改进:使用Sobel算子计算梯度,基于边缘密度来判断遮挡程度,获得更准确的结果。

3. 优化后的代码

#include <opencv2/opencv.hpp>
#include <vector>/*** @brief 检测图像中的遮挡情况。* @param srcImg 输入的图像* @return 如果成功,返回一个介于0到1之间的double类型值,值越接近1表示遮挡程度越高;*         如果输入图像为空,返回-1.0。*/
double occlusionDetect(const cv::Mat& srcImg) {if (srcImg.empty()) {// 输入图像为空return -1.0;}// 将图像转换为灰度图cv::Mat grayImg;if (srcImg.channels() == 3) {cv::cvtColor(srcImg, grayImg, cv::COLOR_BGR2GRAY);} else {grayImg = srcImg.clone();}// 对灰度图进行高斯模糊,减少噪声cv::GaussianBlur(grayImg, grayImg, cv::Size(5, 5), 0);// 使用Sobel算子计算梯度cv::Mat gradX, gradY;cv::Sobel(grayImg, gradX, CV_64F, 1, 0, 3);cv::Sobel(grayImg, gradY, CV_64F, 0, 1, 3);// 计算梯度幅值和方向cv::Mat magnitude, angle;cv::cartToPolar(gradX, gradY, magnitude, angle, true);// 对梯度幅值进行阈值化,得到边缘图double maxVal;cv::minMaxLoc(magnitude, nullptr, &maxVal);cv::Mat edges;cv::threshold(magnitude, edges, 0.1 * maxVal, 255, cv::THRESH_BINARY);// 计算边缘密度double edgeDensity = cv::countNonZero(edges) / static_cast<double>(edges.total());// 根据边缘密度估计遮挡程度(假设遮挡区域边缘密度较低)double occlusionLevel = 1.0 - edgeDensity;// 将结果限定在0到1之间occlusionLevel = std::clamp(occlusionLevel, 0.0, 1.0);return occlusionLevel;
}

4. 代码详细解读

开始
输入图像是否为空
返回 std::nullopt
转换为灰度图 grayImg
高斯模糊处理
计算梯度 gradX 和 gradY
计算梯度幅值和方向
获取最大值 maxVal
阈值化得到 edges
计算边缘密度 edgeDensity
计算遮挡程度 occlusionLevel
限定 occlusionLevel 在0到1之间
返回 occlusionLevel

4.1. 输入检查

if (srcImg.empty()) {return std::nullopt;
}
  • 目的:确保输入的图像有效。
  • 说明:如果输入图像为空,函数返回std::nullopt,明确表示错误状态。

4.2. 图像预处理

cv::Mat grayImg;
if (srcImg.channels() == 3) {cv::cvtColor(srcImg, grayImg, cv::COLOR_BGR2GRAY);
} else {grayImg = srcImg.clone();
}
  • 目的:将彩色图像转换为灰度图像。
  • 说明:灰度图像降低了计算复杂度,适用于后续的梯度和边缘检测。

4.3. 高斯模糊

cv::GaussianBlur(grayImg, grayImg, cv::Size(5, 5), 0);
  • 目的:平滑图像,减少噪声对梯度计算的影响。
  • 参数解释
    • cv::Size(5, 5):高斯核的大小,可根据需要调整。
    • 0:高斯核在x方向的标准差,设为0表示根据核大小自动计算。

4.4. 梯度计算

cv::Mat gradX, gradY;
cv::Sobel(grayImg, gradX, CV_64F, 1, 0, 3);
cv::Sobel(grayImg, gradY, CV_64F, 0, 1, 3);
  • 目的:计算图像在x和y方向的梯度。
  • 参数解释
    • CV_64F:使用64位浮点型,确保梯度值的精度。
    • 1, 00, 1:指定导数的阶数,分别计算x和y方向的一阶导数。
    • 3:Sobel核的大小。

4.5. 计算梯度幅值和方向

cv::Mat magnitude, angle;
cv::cartToPolar(gradX, gradY, magnitude, angle, true);
  • 目的:将梯度的x和y分量转换为极坐标形式,得到梯度的幅值和方向。
  • 参数解释
    • true:将角度值转换为度数(0-360),否则为弧度。

4.6. 边缘检测

double maxVal;
cv::minMaxLoc(magnitude, nullptr, &maxVal);
cv::Mat edges;
cv::threshold(magnitude, edges, 0.1 * maxVal, 255, cv::THRESH_BINARY);
  • 目的:通过阈值化梯度幅值,提取边缘。
  • 步骤
    • 使用cv::minMaxLoc获取梯度幅值的最大值maxVal
    • 设定阈值为0.1 * maxVal,将高于此阈值的像素设为255(白色),其余设为0(黑色)。

4.7. 计算边缘密度

double edgeDensity = cv::countNonZero(edges) / static_cast<double>(edges.total());
  • 目的:计算边缘像素占总像素的比例。
  • 说明:边缘密度反映了图像中边缘信息的丰富程度。

4.8. 估计遮挡程度

double occlusionLevel = 1.0 - edgeDensity;
  • 目的:根据边缘密度估计遮挡程度。
  • 假设:遮挡区域的边缘密度较低,因此边缘密度越小,遮挡程度越高。

4.9. 限定结果范围

occlusionLevel = std::clamp(occlusionLevel, 0.0, 1.0);
  • 目的:确保遮挡程度在有效范围内。

4.10. 返回结果

return occlusionLevel;
  • 说明:返回的occlusionLeveldouble类型,范围在0到1之间。
  • 无遮挡图像occlusionLevel值接近于0,表示遮挡程度低。
  • 遮挡图像occlusionLevel值接近于1,表示遮挡程度高。

相关文章:

C++基于opencv的视频质量检测--遮挡检测

文章目录 0.引言1. 原始代码分析1.1 存在的问题 2. 优化方案3. 优化后的代码4. 代码详细解读4.1. 输入检查4.2. 图像预处理4.3. 高斯模糊4.4. 梯度计算4.5. 计算梯度幅值和方向4.6. 边缘检测4.7. 计算边缘密度4.8. 估计遮挡程度4.9. 限定结果范围4.10. 返回结果 0.引言 视频质…...

手机玩潜水员戴夫?GameViewer远程如何随时随地玩潜水员戴夫教程

如果你是潜水员戴夫的忠实玩家&#xff0c;你知道如何在手机上玩潜水员戴夫吗&#xff1f;潜水员戴夫是一个以神秘蓝洞为背景的海洋冒险游戏。在这个游戏里你白天可以在美丽的大海里打鱼&#xff0c;晚上可以经营寿司店。现在这个游戏也能实现用手机随时随地畅玩了&#xff01;…...

UE5 喷射背包

首选创建一个输入操作 然后在输入映射中添加&#xff0c;shift是向上飞&#xff0c;ctrl是向下飞 进入人物蓝图中编写逻辑&#xff0c;变量HaveJatpack默认true&#xff0c;Thrust为0 最后...

【Vue3】第三篇

Vue3学习第三篇 01. 组件组成02. 组件嵌套关系03. 组件注册方式04. 组件传递数据Props05. 组件传递多种数据类型06. 组件传递Props校验07. 组件事件08. 组件事件配合v-model使用09. 组件数据传递10. 透传Attributes 01. 组件组成 在vue当中&#xff0c;组件是最重要的知识&…...

c++二级指针

如果要通过函数改变一个指针的值&#xff0c;要往函数中传入指针的指针 如果要通过函数改变一个变量的值&#xff0c;那就要往函数中传入这个变量的地址 改变a的值和b的值 #include <iostream>using namespace std;void swap(int* a, int* b) {int temp *a;*a *b;*b …...

客户端存储 — IndexedDB 实现分页查询

前言 相信 IndexedDB 大家都有过了解&#xff0c;但是不一定每个人都有过实践&#xff0c;并且其中涉及到事务、游标等概念&#xff0c;会导致在初次使用时会有些不适应&#xff0c;那么本文会通过 IndexedDB 实现分页查询的形式进行实践&#xff0c;在开始之前&#xff0c;可…...

logback 如何将日志输出到文件

如何作 将日志输出到文件需要使用 RollingFileAppender&#xff0c;该 Appender 必须定义 rollingPolicy &#xff0c;另外 rollingPollicy 下必须定义 fileNamePattern 和 encoder <appender name"fileAppender" class"ch.qos.logback.core.rolling.Rollin…...

Files.newBufferedReader和Files.readAllLines

在Java中&#xff0c;Files.newBufferedReader 和 Files.readAllLines 都是用于从文件中读取数据的工具方法&#xff0c;但它们的使用场景和功能有所不同。下面我将详细解释这两个方法的含义、用途、区别、优缺点以及各自的使用场景。 1. Files.newBufferedReader 含义和用途…...

MySQL 数据库备份与恢复全攻略

MySQL 数据库备份与恢复全攻略 引言 在现代应用中&#xff0c;数据库是核心组件之一。无论是个人项目还是企业级应用&#xff0c;数据的安全性和完整性都至关重要。为了防止数据丢失、损坏或意外删除&#xff0c;定期备份数据库是必不可少的。本文将详细介绍 MySQL 数据库的备…...

Appium中的api(一)

目录 1.基础python代码准备 1--参数的一些说明 2--python内所要编写的代码 解释 2.如何获取包名和界面名 1-api 2-完整代码 代码解释 3.如何关闭驱动连接 4.安装卸载app 1--卸载 2--安装 5.判断app是否安装 6.将应用放到后台在切换为前台的时间 7.UIAutomatorViewer的使用 1--找…...

【AI辅助设计】没错!训练FLUX LoRA就这么简单!

前言 得益于开源社区的力量&#xff0c;在各位大佬的努力下&#xff0c;现在16G VRAM的家用电脑也可以训练FLUX的LoRA了 &#x1f44f;。 今天我使用fluxgym这个方法&#xff0c;训练LoRA&#xff0c;并记录过程。 篇幅有限&#xff0c;这里就不一一展示了&#xff0c;有需要的…...

Mac 下安装FastDFS

首先我们需要下载相对应的安装包&#xff1a; libfastcommonFastDFS 下载完成后我们先将其解压到桌面。 1.安装libfastcommon 我们进入到libfastcommon-master目录中执行./make.sh和sudo ./make.sh install&#xff0c;具体代码如下&#xff1a; 2.安装FastDFS 同安装libfa…...

人工智能的未来:重塑生活与工作的变革者

随着人工智能&#xff08;AI&#xff09;技术的快速发展&#xff0c;我们正处于一个前所未有的变革时代。AI不仅在医疗、企业运营和日常生活中发挥着重要作用&#xff0c;而且正在重新定义我们的生活和工作方式。本文将探讨人工智能技术的应用前景以及它如何改变我们的生活和工…...

【微服务】Java 对接飞书多维表格使用详解

目录 一、前言 二、前置操作 2.1 开通企业飞书账户 2.2 确保账户具备多维表操作权限 2.3 创建一张测试用的多维表 2.4 获取飞书开放平台文档 2.5 获取Java SDK 三、应用App相关操作 3.1 创建应用过程 3.2 应用发布过程 3.3 应用添加操作权限 四、多维表应用授权操作…...

学习threejs,使用粒子实现下雪特效

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.Points简介1.11 ☘️…...

unity3d——Time

在Unity3D中&#xff0c;Time类是一个非常重要的工具类&#xff0c;它提供了一系列与时间相关的属性和方法&#xff0c;帮助开发者在游戏中实现各种时间相关的操作。以下是一些Time类常用的方法及其示例&#xff1a; 一、常用属性 Time.time 含义&#xff1a;表示从游戏开始到…...

天地图实现海量聚合marker--uniapp后端详细实现

本文章详细的讲解了前后端代码来 实现uniapp天地图功能的实现 以及 后端海量数据的聚合查询 和网格算法实现思路。 并对当数据量增加和用户频繁请求接口时可能导致服务器负载过高做了前后端优化。 前端uniapp&#xff1a; 实现了天地图的行政区划边界/地图切换/比例尺/海量数…...

Bug | 项目中数据库查询问题

问题描述 理论上&#xff0c;点击查询后&#xff0c;表头应当显示中文。而不是上面的在数据库中的表头【如上图示】 正常点击查询后&#xff0c;如果没有输入值&#xff0c;应当是查询所有的信息。 原因分析&#xff1a; 这里是直接使用SELECT * 导致的。例如&#xff1a; S…...

C++入门基础知识129—【关于C 库函数 - time()】

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///C爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于C 库函数 - time()的相关内容&#xff0…...

大文件秒传,分片上传,断点续传

大文件分片上传 一 功能描述 1.文件通过web端分片多线程上传到服务端&#xff0c;然后web端发起分片合并&#xff0c;完成大文件分片上传功能 2.上传过的大文件&#xff0c;实现秒传 3.上传过程中&#xff0c;服务异常退出&#xff0c;实现断点续传 二 流程图 三 代码运行…...

服务器硬防的应用场景都有哪些?

服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式&#xff0c;避免服务器受到各种恶意攻击和网络威胁&#xff0c;那么&#xff0c;服务器硬防通常都会应用在哪些场景当中呢&#xff1f; 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...

学校招生小程序源码介绍

基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码&#xff0c;专为学校招生场景量身打造&#xff0c;功能实用且操作便捷。 从技术架构来看&#xff0c;ThinkPHP提供稳定可靠的后台服务&#xff0c;FastAdmin加速开发流程&#xff0c;UniApp则保障小程序在多端有良好的兼…...

c++ 面试题(1)-----深度优先搜索(DFS)实现

操作系统&#xff1a;ubuntu22.04 IDE:Visual Studio Code 编程语言&#xff1a;C11 题目描述 地上有一个 m 行 n 列的方格&#xff0c;从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子&#xff0c;但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...

第一篇:Agent2Agent (A2A) 协议——协作式人工智能的黎明

AI 领域的快速发展正在催生一个新时代&#xff0c;智能代理&#xff08;agents&#xff09;不再是孤立的个体&#xff0c;而是能够像一个数字团队一样协作。然而&#xff0c;当前 AI 生态系统的碎片化阻碍了这一愿景的实现&#xff0c;导致了“AI 巴别塔问题”——不同代理之间…...

基于Docker Compose部署Java微服务项目

一. 创建根项目 根项目&#xff08;父项目&#xff09;主要用于依赖管理 一些需要注意的点&#xff1a; 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件&#xff0c;否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...

【C语言练习】080. 使用C语言实现简单的数据库操作

080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...

AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机

这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机&#xff0c;因为在使用过程中发现 Airsim 对外部监控相机的描述模糊&#xff0c;而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置&#xff0c;最后在源码示例中找到了&#xff0c;所以感…...

Vite中定义@软链接

在webpack中可以直接通过符号表示src路径&#xff0c;但是vite中默认不可以。 如何实现&#xff1a; vite中提供了resolve.alias&#xff1a;通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...

ubuntu系统文件误删(/lib/x86_64-linux-gnu/libc.so.6)修复方案 [成功解决]

报错信息&#xff1a;libc.so.6: cannot open shared object file: No such file or directory&#xff1a; #ls, ln, sudo...命令都不能用 error while loading shared libraries: libc.so.6: cannot open shared object file: No such file or directory重启后报错信息&…...

网页端 js 读取发票里的二维码信息(图片和PDF格式)

起因 为了实现在报销流程中&#xff0c;发票不能重用的限制&#xff0c;发票上传后&#xff0c;希望能读出发票号&#xff0c;并记录发票号已用&#xff0c;下次不再可用于报销。 基于上面的需求&#xff0c;研究了OCR 的方式和读PDF的方式&#xff0c;实际是可行的&#xff…...