【opencv】示例-detect_blob.cpp

news2024/11/24 2:44:09

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一文读懂传统服务器与云服务器的区别

传统服务器 传统服务器一般指的是物理服务器。物理服务器是独立存在的&#xff0c;无需与其他用户共享资源&#xff0c;拥有完全管理员权限和独立IP地址&#xff0c;安全稳定性高&#xff0c;性能优越。物理服务器与通用的计算机架构类似&#xff0c;由CPU、主板、内存条、硬…

区块链安全-----区块链基础

区块链是一种全新的信息网络架构 &#xff0c;是新一代信息基础设施 &#xff0c;是新型的价值交换方式、 分布式协 同生产机制以及新型的算法经济模式的基础。 区块链技术可以集成到多个领域。 区块链的主要用途 是作为加密货币的分布式总帐。 它在银行 &#xff0c;金融 &…

oracle数据库怎么查看当前登录的用户?

方法如下&#xff1a; 输入select * from dba_users; 即可。 常用语句&#xff1a; 一&#xff0c;查看数据库里面所有用户&#xff1a; select * from dba_users; 前提是你是有dba权限的帐号&#xff0c;如sys,system。 二&#xff0c;查看你能管理的所有用户&#xff1…

react17中配置webpack:使用@代表src目录

在vue的项目中可以使用表示src目录&#xff0c;使用该符号表示绝对路径&#xff0c;那么在react中想要使用怎么办呢&#xff1f; 在react中使用表示src目录是需要在webpack中配置的&#xff0c;在核心模块node_modules-》react-scripts-》config-》webpack.config.js中搜索找到…

python——列表(list)

概念 列表一般使用在一次性存储多个数据 语法 lst[数据1&#xff0c;数据2&#xff0c;.....]方法 #mermaid-svg-flVxgVdpSqFaZyrF {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-flVxgVdpSqFaZyrF .error-icon{…

【2024最新博客美化教程重置版】一分钟教会你在博客页面中加入javascript点击出弹出文字效果!

&#x1f680; 个人主页 极客小俊 ✍&#x1f3fb; 作者简介&#xff1a;程序猿、设计师、技术分享 &#x1f40b; 希望大家多多支持, 我们一起学习和进步&#xff01; &#x1f3c5; 欢迎评论 ❤️点赞&#x1f4ac;评论 &#x1f4c2;收藏 &#x1f4c2;加关注 我们可以在博客…

利用正射影像对斜射图像进行反向投影

在图像投影和映射领域,有两种类型的投影:正向投影和反向投影。正向投影涉及使用内部方向(即校准相机参数)将 3D 点(例如地面上的物体)投影到 2D 图像平面上。另一方面,向后投影是指根据 2D 图像确定地面物体的 3D 坐标的过程。 为了匹配倾斜图像和正射影像并确定相机位置…

[C++][算法基础]有向图拓扑排序(拓扑)

给定一个 n 个点 m 条边的有向图&#xff0c;点的编号是 1 到 n&#xff0c;图中可能存在重边和自环。 请输出任意一个该有向图的拓扑序列&#xff0c;如果拓扑序列不存在&#xff0c;则输出 −1。 若一个由图中所有点构成的序列 A 满足&#xff1a;对于图中的每条边 (x,y)&a…

FreeAskInternet:本地AI搜索引擎,一周收获6.4K Star

简介 FreeAskInternet是一个完全免费&#xff0c;私人和本地运行的搜索聚合器和答案生成使用LLM&#xff0c;无需GPU。用户可以提出一个问题&#xff0c;系统通过搜索进行多引擎搜索&#xff0c;并将搜索结果合并到ChatGPT3.5 LLM中&#xff0c;根据搜索结果生成答案。所有进程…

一、OpenCvSharp环境搭建

一、Visual Studio 创建新项目 二、选择Windows窗体应用&#xff08;.NET Framework&#xff09; 直接搜索模板&#xff1a;Windows窗体应用(.NET Framework) 记得是C#哈&#xff0c;别整成VB(Visual Basic)了 PS&#xff1a;若搜索搜不到&#xff0c;直接点击安装多个工具和…

C++感受4-HelloWorld中文版——认识编码

及时了解“编码”对编写代码的影响&#xff0c;是中国程序员越早知道越好的知识点。 一分钟了解什么叫“编码”和“解码”&#xff1b;通过实际演示&#xff0c;充分理解中文Windows下&#xff0c;C源代码编码需要注意的地方&#xff1b;通过 -finput-charsetutf8 等 g 编译配置…

四、Consul服务注册与发现

一、Consul服务注册与发现 1、为什么引入 微服务所在的IP地址和端口号硬编码到订单微服务中&#xff0c;会存在非常多的问题 &#xff08;1&#xff09;如果订单微服务和支付微服务的IP地址或者端口号发生了变化&#xff0c;则支付微服务将变得不可用&#xff0c;需要同步修改…

【科技】2024最新微信机器人一键部署教程

外话 话说上次写文章好像又过了几个月了…… 其实还是因为马上小升初的各种密考&#xff0c;其它地方不知道&#xff0c;反正广东这块名校基本上都得密考考进去 笔者连考几次都惨不忍睹…… 不过5月份会有一个信息技术特长生招生&#xff0c;看看能不能吧~ 正文 先说&#xff…

新质生产力与智能制造:推动制造业转型升级的双引擎

引言 随着科技的不断进步和全球制造业的快速发展&#xff0c;新质生产力与智能制造成为推动制造业转型升级的关键驱动力。新质生产力强调的是以科技创新和制度创新为核心&#xff0c;通过提高生产效率和经济效益来推动经济发展。而智能制造则是利用现代信息技术&#xff0c;实现…

Python | Leetcode Python题解之第24题两两交换链表中的节点

题目&#xff1a; 题解&#xff1a; class Solution:def swapPairs(self, head: ListNode) -> ListNode:dummyHead ListNode(0)dummyHead.next headtemp dummyHeadwhile temp.next and temp.next.next:node1 temp.nextnode2 temp.next.nexttemp.next node2node1.next…

【稳定检索|投稿优惠】2024年生物学与智能计算国际会议 (ICBIC 2024)

2024年生物学与智能计算国际会议 (ICBIC 2024) 2024 International Conference on Biology and Intelligent Computing 【会议简介】 2024年生物学与智能计算国际会议即将在上海召开。本次会议旨在汇聚生物学与智能计算领域的专家学者&#xff0c;共同探讨两者交叉融合的前沿…

一文带你搞懂软件开发/怎么开发?哪些常见陷阱?如何避坑?

引言 在当今数字化时代&#xff0c;软件开发已成为推动科技进步和商业发展的重要引擎。然而&#xff0c;软件开发并非一帆风顺&#xff0c;其中蕴藏着许多陷阱和挑战。如何避免这些陷阱&#xff0c;提高软件开发的效率和质量&#xff0c;成为开发者们面临的重要问题 本文将深入…

关于Ansible的模块 ⑦

转载说明&#xff1a;如果您喜欢这篇文章并打算转载它&#xff0c;请私信作者取得授权。感谢您喜爱本文&#xff0c;请文明转载&#xff0c;谢谢。 在继《关于Ansible的模块 ①》、《关于Ansible的模块 ②》、《关于Ansible的模块 ③》与《关于Ansible的模块 ④》、《关于ansib…

NVMe 基础

NVMe&#xff08;Non-Volatile Memory Express&#xff09;是一种高速、低延迟的I/O接口协议&#xff0c;专为闪存存储设备设计&#xff0c;包括固态硬盘&#xff08;SSD&#xff09;和其他非易失性存储设备。NVMe协议是为取代早期的AHCI&#xff08;Advanced Host Controller …

bufbomb 报错 ./stdio-common/vfprintf-internal.c: No such file or directory.

注意&#xff1a;此方法针对HUST特供 bufbomb 的 level2&#xff0c;其它情况不保证有效。 有同学可能发现&#xff0c;当跳入bang函数时&#xff0c;无论是gdb还是直接执行&#xff0c;都会出现以下报错 其实若是再仔细排查一下&#xff0c;会发现实际上只有跳到 <bang0&…