【opencv】示例-detect_blob.cpp

05e10ae22e0f10301f0f1ace0e13a56f.png

764203c69015800b0c0d6f58223f1868.png

6e2add132197607c548e86e92aae02c3.png

e197626577d5b4ba5e91c4bf366be8d0.png

ecc63488fee20b0fde586c7bd1f65959.png

0814de97e6dd604f81da14ff860a379f.png

d77827d8c37e379862cca7ac8b890bd5.png

e3efe6ee0ef4fd6b7b0039269e4dc7bf.png

// 导入所需的OpenCV头文件
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/features2d.hpp>
// 导入向量和映射容器
#include <vector>
#include <map>
// 导入输入输出流库
#include <iostream>


// 使用标准命名空间和OpenCV命名空间,避免在使用这些命名空间下的类型和函数时反复输入std::和cv::
using namespace std;
using namespace cv;




// 帮助函数,用于提供程序的使用说明
static void help(char** argv)
{
    cout << "\n This program demonstrates how to use BLOB to detect and filter region \n"
         << "Usage: \n"
         << argv[0]
         << " <image1(detect_blob.png as default)>\n"
         << "Press a key when image window is active to change descriptor";
}


// 函数Legende用于根据SimpleBlobDetector的参数pAct生成不同Blob检测条件的文字描述
static String Legende(SimpleBlobDetector::Params &pAct)
{
    // 创建一个空字符串s,用于存放最终生成的描述文字
    String s = "";
    // 如果启用了面积过滤器filterByArea
    if (pAct.filterByArea)
    {
        // 将最小面积minArea和最大面积maxArea转换成字符串表示,并追加到s中
        String inf = static_cast<const ostringstream&>(ostringstream() << pAct.minArea).str();
        String sup = static_cast<const ostringstream&>(ostringstream() << pAct.maxArea).str();
        s = " Area range [" + inf + " to  " + sup + "]";
    }
    // 如果启用了圆度过滤器filterByCircularity
    if (pAct.filterByCircularity)
    {
        // 将最小圆度minCircularity和最大圆度maxCircularity转换成字符串表示,并追加到s中
        String inf = static_cast<const ostringstream&>(ostringstream() << pAct.minCircularity).str();
        String sup = static_cast<const ostringstream&>(ostringstream() << pAct.maxCircularity).str();
        // 判断之前的描述文字s是否为空,如果为空则直接赋值,不为空则添加"AND"进行连接
        if (s.length() == 0)
            s = " Circularity range [" + inf + " to  " + sup + "]";
        else
            s += " AND Circularity range [" + inf + " to  " + sup + "]";
    }
    // 如果启用了颜色过滤器filterByColor
    if (pAct.filterByColor)
    {
        // 将Blob的颜色blobColor转换为整数并转换成字符串表示,然后追加到s中
        String inf = static_cast<const ostringstream&>(ostringstream() << (int)pAct.blobColor).str();
        // 判断之前的描述文字s是否为空,如果为空则直接赋值,不为空则添加"AND"进行连接
        if (s.length() == 0)
            s = " Blob color " + inf;
        else
            s += " AND Blob color " + inf;
    }
    // 如果启用了凸度过滤器filterByConvexity
    if (pAct.filterByConvexity)
    {
        // 将最小凸度minConvexity和最大凸度maxConvexity转换成字符串表示,并追加到s中
        String inf = static_cast<const ostringstream&>(ostringstream() << pAct.minConvexity).str();
        String sup = static_cast<const ostringstream&>(ostringstream() << pAct.maxConvexity).str();
        // 判断之前的描述文字s是否为空,如果为空则直接赋值,不为空则添加"AND"进行连接
        if (s.length() == 0)
            s = " Convexity range[" + inf + " to  " + sup + "]";
        else
            s += " AND  Convexity range[" + inf + " to  " + sup + "]";
    }
    // 如果启用了惯性比过滤器filterByInertia
    if (pAct.filterByInertia)
    {
        // 将最小惯性比minInertiaRatio和最大惯性比maxInertiaRatio转换成字符串表示,并追加到s中
        String inf = static_cast<const ostringstream&>(ostringstream() << pAct.minInertiaRatio).str();
        String sup = static_cast<const ostringstream&>(ostringstream() << pAct.maxInertiaRatio).str();
        // 判断之前的描述文字s是否为空,如果为空则直接赋值,不为空则添加"AND"进行连接
        if (s.length() == 0)
            s = " Inertia ratio range [" + inf + " to  " + sup + "]";
        else
            s += " AND  Inertia ratio range [" + inf + " to  " + sup + "]";
    }
    // 返回最终生成的Blob检测条件描述文字
    return s;
}






// 主函数
int main(int argc, char *argv[])
{
    // 用于存储读取的文件名
    String fileName;
    // 创建命令行解析器,用于处理通过命令行传入的参数
    cv::CommandLineParser parser(argc, argv, "{@input |detect_blob.png| }{h help | | }");
    // 如果有"-h"或"--help"参数,显示帮助信息后结束程序
    if (parser.has("h"))
    {
        help(argv);
        return 0;
    }
    // 如果没有提供输入文件名参数,则使用默认的"detect_blob.png"
    fileName = parser.get<string>("@input");
    // 读取并存储图像
    Mat img = imread(samples::findFile(fileName), IMREAD_COLOR);
    // 如果读取失败或图像为空,则输出错误信息并结束程序
    if (img.empty())
    {
        cout << "Image " << fileName << " is empty or cannot be found\n";
        return 1;
    }


    // 初始化SimpleBlobDetector的默认参数
    SimpleBlobDetector::Params pDefaultBLOB;
    // 设置默认的BLOB检测器的参数
    // 设置SimpleBlobDetector的阈值步长
    pDefaultBLOB.thresholdStep = 10;
    // 设置SimpleBlobDetector的最小阈值
    pDefaultBLOB.minThreshold = 10;
    // 设置SimpleBlobDetector的最大阈值
    pDefaultBLOB.maxThreshold = 220;
    // 设置SimpleBlobDetector的最小重复性
    pDefaultBLOB.minRepeatability = 2;
    // 设置SimpleBlobDetector的BLOB之间的最小距离
    pDefaultBLOB.minDistBetweenBlobs = 10;
    pDefaultBLOB.filterByColor = false; // 不按颜色过滤
    pDefaultBLOB.blobColor = 0; // BLOB的默认颜色
    pDefaultBLOB.filterByArea = false; // 不按区域大小过滤
    pDefaultBLOB.minArea = 25; // 最小区域大小
    pDefaultBLOB.maxArea = 5000; // 最大区域大小
    pDefaultBLOB.filterByCircularity = false; // 不按圆度过滤
    pDefaultBLOB.minCircularity = 0.9f; // 最小圆度
    pDefaultBLOB.maxCircularity = (float)1e37; // 设置一个非常大的数,代表无上限
    pDefaultBLOB.filterByInertia = false; // 不按惯性比过滤
    pDefaultBLOB.minInertiaRatio = 0.1f; // 最小惯性比
    pDefaultBLOB.maxInertiaRatio = (float)1e37; // 设置一个非常大的数,代表无上限
    pDefaultBLOB.filterByConvexity = false; // 不按凸度过滤
    pDefaultBLOB.minConvexity = 0.95f; // 最小凸度
    pDefaultBLOB.maxConvexity = (float)1e37; // 设置一个非常大的数,代表无上限


    // 存储BLOB类型描述符的字符串向量
    vector<String> typeDesc;
    // 存储不同BLOB参数的向量
    vector<SimpleBlobDetector::Params> pBLOB;
    // BLOB参数向量的迭代器
    vector<SimpleBlobDetector::Params>::iterator itBLOB;
    // 初始化一个颜色调色板,用于给不同的BLOB着色
    vector< Vec3b >  palette;
    // 随机生成调色板中的颜色
    for (int i = 0; i<65536; i++)
    {
        uchar c1 = (uchar)rand();
        uchar c2 = (uchar)rand();
        uchar c3 = (uchar)rand();
        palette.push_back(Vec3b(c1, c2, c3));
    }
    // 调用help函数显示帮助信息
    help(argv);


    // 下面代码将创建不同参数的BLOB检测器,并显示它们的结果
    // 配置六种不同参数的BLOB检测器
    // 例如,第一个检测器我们要检测所有BLOB
    // 对每种类型描述符进行初始化,然后按不同的过滤条件修改参数


    // 将"BLOB"类型推入描述符类型向量
    typeDesc.push_back("BLOB");    // 参见OpenCV官方文档SimpleBlobDetector类的描述
    pBLOB.push_back(pDefaultBLOB); // 将默认BLOB参数推入参数向量
    pBLOB.back().filterByArea = true; // 启用面积过滤
    pBLOB.back().minArea = 1; // 设置筛选的最小面积
    pBLOB.back().maxArea = float(img.rows * img.cols); // 设置筛选的最大面积为图像的总面积
    
    // 第二个BLOB检测器的参数设置:要求检测面积在500到2900像素之间的区域
    typeDesc.push_back("BLOB"); // 类型描述符追加"BLOB"
    pBLOB.push_back(pDefaultBLOB); // 使用默认参数作为基础
    pBLOB.back().filterByArea = true; // 启用面积过滤
    pBLOB.back().minArea = 500; // 设置最小面积为500像素
    pBLOB.back().maxArea = 2900; // 设置最大面积为2900像素
    
    // 第三个BLOB检测器的参数设置:仅检测圆形物体
    typeDesc.push_back("BLOB"); // 类型描述符追加"BLOB"
    pBLOB.push_back(pDefaultBLOB); // 使用默认参数作为基础
    pBLOB.back().filterByCircularity = true; // 启用圆度过滤
    
    // 第四个BLOB检测器的参数设置:根据惯性比进行筛选
    typeDesc.push_back("BLOB"); // 类型描述符追加"BLOB"
    pBLOB.push_back(pDefaultBLOB); // 使用默认参数作为基础
    pBLOB.back().filterByInertia = true; // 启用惯性比过滤
    pBLOB.back().minInertiaRatio = 0; // 设置最小惯性比为0
    pBLOB.back().maxInertiaRatio = (float)0.2; // 设置最大惯性比为0.2
    
    // 第五个BLOB检测器的参数设置:根据凸度进行筛选
    typeDesc.push_back("BLOB"); // 类型描述符追加"BLOB"
    pBLOB.push_back(pDefaultBLOB); // 使用默认参数作为基础
    pBLOB.back().filterByConvexity = true; // 启用凸度过滤
    pBLOB.back().minConvexity = 0.; // 设置最小凸度为0
    pBLOB.back().maxConvexity = (float)0.9; // 设置最大凸度为0.9
    
    // 第六个BLOB检测器的参数设置:检测重心颜色为0的BLOB
    typeDesc.push_back("BLOB"); // 类型描述符追加"BLOB"
    pBLOB.push_back(pDefaultBLOB); // 使用默认参数作为基础
    pBLOB.back().filterByColor = true; // 启用颜色过滤
    pBLOB.back().blobColor = 0; // 设置筛选的BLOB颜色为0


    // 迭代器指向BLOB参数向量的起始位置
    itBLOB = pBLOB.begin();


    // 存储比较结果的向量
    vector<double> desMethCmp;
    // 创建Feature2D的智能指针,用于后续的特征检测
    Ptr<Feature2D> b;
    // 用于存储文本标签
    String label;
    // 循环遍历所有类型描述符
    vector<String>::iterator itDesc;
    for (itDesc = typeDesc.begin(); itDesc != typeDesc.end(); ++itDesc)
    {
        // 存储检测到的关键点
        vector<KeyPoint> keyImg1;
        // 对于BLOB类型描述符
        if (*itDesc == "BLOB")
        {
            b = SimpleBlobDetector::create(*itBLOB); // 创建BLOB检测器
            label = Legende(*itBLOB); // 生成描述字符串
            ++itBLOB; // 移动到下一个参数集
        }
        // 错误处理
        try
        {
            // 存储检测到的关键点
            vector<KeyPoint>  keyImg;
            vector<Rect>  zone;
            vector<vector <Point> >  region;
            // 创建用于描述的矩阵和结果显示的图像
            Mat     desc, result(img.rows, img.cols, CV_8UC3);
            // 如果是SimpleBlobDetector
            if (b.dynamicCast<SimpleBlobDetector>().get())
            {
                // 动态转换为SimpleBlobDetector
                Ptr<SimpleBlobDetector> sbd = b.dynamicCast<SimpleBlobDetector>();
                // 使用SimpleBlobDetector检测关键点
                sbd->detect(img, keyImg, Mat());
                // 绘制检测到的关键点
                drawKeypoints(img, keyImg, result);
                // 遍历关键点,并在结果图中用圆圈表示
                int i = 0;
                for (vector<KeyPoint>::iterator k = keyImg.begin(); k != keyImg.end(); ++k, ++i)
                    circle(result, k->pt, (int)k->size, palette[i % 65536]);
            }
            // 创建窗口显示结果
            namedWindow(*itDesc + label, WINDOW_AUTOSIZE);
            imshow(*itDesc + label, result);
            // 显示原始图像
            imshow("Original", img);
            // 等待用户响应
            waitKey();
        }
        catch (const Exception& e)
        {
            // 如果发生错误,则打印错误信息
            cout << "Feature : " << *itDesc << "\n";
            cout << e.msg << endl;
        }
    }
    // 程序正常退出
    return 0;
}

这段代码是使用OpenCV库编写的C++源码,用于演示如何通过SimpleBlobDetector类检测图像中的BLOB(Binary Large Object,二进制大对象),并根据不同参数过滤和显示检测到的区域。BLOB主要用于分割图像中具有不同特性(如面积、颜色、凸性等)的连续区域。代码中包括Blob检测参数的配置、随机颜色调色板的生成、关键点检测、过滤条件的文字描述生成、图像的显示以及异常处理。通过更改SimpleBlobDetector的参数,用户可以筛选满足特定条件的图像区域,比如特定大小、形状或颜色的物体。

b.dynamicCast<SimpleBlobDetector>().get()

0b3d47b0f59195b7de388f2629a8a3f1.png

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

阿里云租用服务器GPU配置报价单_1年_一个月_1小时价格表

阿里云GPU服务器租用价格表包括包年包月价格、一个小时收费以及学生GPU服务器租用费用&#xff0c;阿里云GPU计算卡包括NVIDIA V100计算卡、T4计算卡、A10计算卡和A100计算卡&#xff0c;GPU云服务器gn6i可享受3折优惠&#xff0c;阿里云服务器网aliyunfuwuqi.com分享阿里云GPU…

智能制造六大核心发展方向,驱动企业数字化转型

在制造过程中&#xff0c;智能制造展现出非凡的活力&#xff0c;它使人与智能机器的协同工作成为可能。这不仅将制造自动化的概念提升至一个新的层次&#xff0c;更将其扩展至柔性化、智能化和高度集成化的领域。通过这样的革新&#xff0c;我们得以实现数字化智能工厂的落地生…

Vue的学习之旅-part5

Vue的学习之旅-part5 虚拟DOM的原理用JS模拟DOM结构 vue的方法、计算属性、过滤器computed:{} 计算属性computed计算属性的完全体computed计算属性和methods方法的区别&#xff1a;过滤器&#xff1a;filters:{ 多个方法 } Vuex 状态管理模式 前几篇博客: Vue的学习之旅-part1 …

城市道路井盖破损丢失目标检测数据集VOC-1377张

数据集格式&#xff1a;Pascal VOC格式(不包含分割路径的txt文件和yolo格式的txt文件&#xff0c;仅仅包含jpg图片和对应的xml) 图片数量(jpg文件个数)&#xff1a;1377 标注数量(xml文件个数)&#xff1a;1377 标注类别数&#xff1a;4 标注类别名称:["jg","jg…

ARM64架构栈帧回溯

文章目录 前言一、栈帧简介二、demo演示 前言 请参考&#xff1a;ARM64架构栈帧以及帧指针FP 一、栈帧简介 假设下列函数调用&#xff1a; funb() {func() }funa() {funb() }main() {funa() }main函数&#xff0c;funa函数&#xff0c;funb函数都不是叶子函数&#xff0c;其…

AWS服务器有哪些优势?

作为一家总部在美国的公司&#xff0c;AWS为什么会受到中国企业的喜爱&#xff1f;他有什么优势&#xff1f;九河云作为AWS合作伙伴&#xff0c;将会带读者展现使用AWS的优势。 首先是作为跨国企业&#xff0c;AWS在全球有数十个区域节点&#xff0c;这种广泛的地域覆盖不仅有…

IDEA2023连接服务器docker并部署ruoyi-cloud-plus项目

文章目录 TCP 方式连接docker1. 服务器docker配置修改查看虚拟机中Docker配置文件位置修改配置文件重启docker服务关闭防火墙 2. idea安装docker插件3. idea连接docker服务 部署ruoyi-cloud-plus项目1. 项目环境说明2. 安装Centos73. 安装docker4. idea配置服务器SSH连接5. ide…

局域网内部使用的视频会议系统推荐

随着远程办公的普及和全球化的发展趋势&#xff0c;企业需要一个高效、灵活、安全的音视频会议解决方案&#xff0c;以支持远程办公的协同工作、跨地域沟通等需要。私有化音视频会议就是一个适合企业自身部署的解决方案。它不仅能够满足企业信息管理和保密的需求&#xff0c;而…

Latent Diffusion Models

Latent Diffusion Models(潜在扩散模型,LDMs)是一种生成模型,它结合了扩散模型和变分自动编码器(VAES)的优势,从文本或其他输入模式生成高质量图像。近年来,这些模型受到了相当大的关注,因为它们能够在保持对发电过程的控制的同时产生高度现实和多样化的产出。 Laten…

【灵境矩阵】零代码创建AI智能体之行业词句助手

欢迎来到《小5讲堂》 这是《灵境矩阵》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。 温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 目录 创建智能体选择创建方式零代码 基础配置头像名称简介指令开场白…

从零开始写 Docker(十)---实现 mydocker logs 查看容器日志

本文为从零开始写 Docker 系列第十篇&#xff0c;实现类似 docker logs 的功能&#xff0c;使得我们能够查查看容器日志。 完整代码见&#xff1a;https://github.com/lixd/mydocker 欢迎 Star 推荐阅读以下文章对 docker 基本实现有一个大致认识&#xff1a; 核心原理&#x…

git push报错remote: Please remove the file from history and try again

原因&#xff1a;上传文件超过100M&#xff0c;找到此文件删除即可。 1、查看是哪个文件过大&#xff0c;此处对用红框里面的 a6de1336c67c3bac77757c5eff8c8001823f7c92&#xff0c;得到具体的文件名称 git rev-list --objects --all | grep a6de1336c67c3bac77757c5eff8c80…

Pytest自动化测试框架完美结合Allure

简介 Allure Framework是一种灵活的、轻量级、多语言测试报告工具。 不仅可以以简洁的网络报告形式非常简洁地显示已测试的内容&#xff0c; 而且还允许参与开发过程的每个人从日常执行中提取最大程度的有用信息和测试。 从开发/测试的角度来看&#xff1a; Allure报告可以…

静音检测电路芯片D3703F——工 作 电 压 范 围 宽 : 3.2V ~ 16.0V,可以用于汽 车 音 响 系 统

概 述 &#xff1a; D3703F 是 一 块 汽 车 音 响 静 音 检 测 电 路 。 用 于 音 响 系 统 检 测 在 放 音 或 快 进 / 退 时 进 行 静 音 检 测 。 D3703F 的 的 电 压 范 围 &#xff1a; 3.2V &#xff5e; 16V &#xff0c; 信 号 检 测 和 静 音 时 间 可 通 过 外 围…

私有化即时通讯软件,WorkPlus提供的私有化、安全通讯解决方案

在当今信息化快速发展的时代&#xff0c;安全问题已经成为各行各业关注的焦点。特别是在金融、政府单位和芯片等关键行业&#xff0c;信息安全的重要性不言而喻。这些行业涉及到大量的敏感数据和关键信息&#xff0c;一旦发生泄露&#xff0c;可能会对国家安全、企业利益甚至个…

JavaSE——常用API进阶二(2/8)-BigDecimal(BigDecimal的常见构造器、常用方法,用法示例,使用规范)

目录 BigDecimal BigDecimal的常见构造器、常用方法 用法示例 使用规范 在进行浮点型运算时&#xff0c;直接使用“ - * / ”可能会出现运算结果失真&#xff0c;例如&#xff1a; System.out.println(0.1 0.2); System.out.println(1.0 - 0.32); System.out.println(1.…

IO流【内存流、打印流、随机访问流】;初识网络编程

day37 IO流 继day36 各种流 对象流 day36 内存流 class ByteArrayInputStream – 内存输入流 class ByteArrayOutputStream – 内存输出流 注意&#xff1a; 内存流是程序和内存交互&#xff0c;跟文件无关内存流是程序到内存的通道&#xff0c;是关闭不掉的 应用场景&#x…

互联网轻量级框架整合之设计模式

反射技术 Java的反射技术能够通过配置类的全限定名、方法和参数完成对象的初始化&#xff0c;甚至反射某些方法&#xff0c;大大的增强了Java的可配置型&#xff0c;这也是Spring IoC的底层原理&#xff0c;Java的反射技术覆盖面很广&#xff0c;包括对象构建、反射方法、注解、…

(Java)数据结构——图(第七节)Folyd实现多源最短路径

前言 本博客是博主用于复习数据结构以及算法的博客&#xff0c;如果疏忽出现错误&#xff0c;还望各位指正。 Folyd实现原理 中心点的概念 感觉像是充当一个桥梁的作用 还是这个图 我们常在一些讲解视频中看到&#xff0c;就比如dist&#xff08;-1&#xff09;&#xff0…

石子合并(区间dp)-java

石子合并问题是经典的区间dp问题&#xff0c;我们需要枚举中间端点k的情况从而来推出dp数组的值。 文章目录 前言 一、石子合并问题 二、算法思路 1.问题思路 2.状态递推公式 二、代码如下 代码如下&#xff08;示例&#xff09;&#xff1a; 2.读入数据 3.代码运行结果如下&am…