0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

二值图像的欧拉数计算公式

OpenCV学堂 来源:OpenCV学堂 作者:OpenCV学堂 2022-06-30 11:08 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

欧拉数定义

二值图像分析中欧拉数重要的拓扑特征之一,在图像分析与几何对象识别中有着十分重要的作用,二值图像的欧拉数计算公式表示如下:
E = N – H 其中
E表示计算得到欧拉数
N表示联通组件的数目
H表示在联通组件内部的洞的数目
下图是二值图像,白色背景,两个对象、分析计算得到欧拉数的例子:

01d926cc-f7bf-11ec-ba43-dac502259ad0.png

可以看到通过简单的欧拉数属性就可以对它们进行区分。左侧对象中有两个联通区域,所以N=2,没有洞孔区域,所以H=0, 计算得到欧拉数目为 2 – 0 = 。右侧是大写字母B,它只有一个联通区域所以N = 1, 内部有两个洞孔区域所以H = 2,最终计算得到欧拉数为 2 – 1 = -1。对于任意一个几何形状来说,如果我们要求得它的欧拉数,就首先要分析它的轮廓结构,然后根据轮廓层次结构计算得到N与H值。

欧拉数是图像几何识别中重要的属性,举例如下图中三个英文字母

01f57b74-f7bf-11ec-ba43-dac502259ad0.png 对字母A来说它的内部有一个黑色孔洞,所以它的H=1,其本身是一个联通组件所以N =1,最终计算得到欧拉数为 E = 1 -1 = 0,同样可以计算B与C它们的欧拉数分布为-1与1,可见通过欧拉数属性可以轻而易举的区分ABC三个英文字母。

二:轮廓层次信息获取

在OpenCV对二值图像进行轮廓分析输出的层次结构会保存在一个Vec4i的结构体中,这里有必要首先看一下轮廓发现API及其相关参数的解释:

voidcv::findContours(
InputOutputArrayimage,
OutputArrayOfArrayscontours,
OutputArrayhierarchy,
intmode,
intmethod,
Pointoffset=Point()
)
image参数表示输入的二值图像
contours表示所有的轮廓信息,每个轮廓是一系列的点集合
hierarchy表示对应的每个轮廓的层次信息,我们就是要用它实现对最大轮廓欧拉数的分析
mode表示寻找轮廓拓扑的方法,如果要寻找完整的层次信息,要选择参数RETR_TREE
method表示轮廓的编码方式,一般选择简单链式编码,参数CHAIN_APPROX_SIMPLE
offset表示是否有位移,一般默认是0

上面的参数中最重要的是hierarchy信息,它的输出是vector每个轮廓对应的Vec4i结构体里面四个值解释如下:

02138222-f7bf-11ec-ba43-dac502259ad0.png

上面的索引如果是负数就表示没有相关层次信息,如果是非负数就表示有相关的层次关系信息。此外轮廓发现函数对输入image图像的要求必须满足

  • 背景是黑色 ,0表示

  • 对象或者前景是白色,1表示

三:欧拉数计算方法

有了轮廓的层次信息与每个轮廓的信息之后,尝试遍历每个轮廓,首先通过调用findContours就可以获取二值图像的轮廓层次信息,然后遍历每个轮廓,进行层次遍历,获得每层子轮廓的总数,最终根据轮廓层级不同分为孔洞与连接轮廓的计数,二者想减得到每个独立外层轮廓的欧拉数。

二值化与轮廓发现的代码如下:

Matgray,binary;
cvtColor(src,gray,COLOR_BGR2GRAY);
threshold(gray,binary,0,255,THRESH_BINARY|THRESH_OTSU);
vectorhireachy;
vector<vector>contours;
findContours(binary,contours,hireachy,RETR_TREE,CHAIN_APPROX_SIMPLE,Point());

获取同层轮廓的代码如下:

vector<int>current_layer_holes(vector<Vec4i>layers,intindex){
intnext=layers[index][0];
vector<int>indexes;
indexes.push_back(index);
while(next>=0){
indexes.push_back(next);
next=layers[next][0];
}
returnindexes;
}

使用队列迭代寻找遍历每层的代码如下:

while(!nodes.empty()){
//当前层总数目
if(index%2==0){//联通组件对象
n_total+=nodes.size();
}
else{//孔洞对象
h_total+=nodes.size();
}
index++;
//计算下一层所有孩子节点
intcurr_ndoes=nodes.size();
for(intn=0;n< curr_ndoes; n++) {
        intvalue=nodes.front();
nodes.pop();
//获取下一层节点第一个孩子
intchild=hireachy[value][2];
if(child>=0){
nodes.push(child);
}
}
}

四:运行与测试结果

测试图一(ABC)与运行结果:

022be9de-f7bf-11ec-ba43-dac502259ad0.jpg

测试图二与运行结果

024b4b1c-f7bf-11ec-ba43-dac502259ad0.jpg

五:完整源代码

#include
#include

usingnamespacecv;
usingnamespacestd;

vector<int>current_layer_holes(vectorlayers,intindex);

intmain(intargc,char**argv){
Matsrc=imread("D:/holes.png");
if(src.empty()){
printf("couldnotloadimage...
");
return-1;
}
namedWindow("input",CV_WINDOW_AUTOSIZE);
imshow("input",src);

Matgray,binary;
cvtColor(src,gray,COLOR_BGR2GRAY);
threshold(gray,binary,0,255,THRESH_BINARY|THRESH_OTSU);

vectorhireachy;
vector<vector>contours;
findContours(binary,contours,hireachy,RETR_TREE,CHAIN_APPROX_SIMPLE,Point());
Matresult=Mat::zeros(src.size(),src.type());
for(size_tt=0;t< contours.size(); t++) {
        intnext=hireachy[t][0];//nextatthesamehierarchicallevel
intprev=hireachy[t][1];//prevatthesamehierarchicallevel
intchild=hireachy[t][2];//firstchild
intparent=hireachy[t][3];//parent
printf("next%d,previous%d,children:%d,parent:%d
",next,prev,child,parent);
drawContours(result,contours,t,Scalar(0,255,0),2,8);
//startcalculateeulernumber
inth_total=0;
intn_total=1;
intindex=1;
vector<int>all_children;
if(child>=0&&parent< 0){
//计算当前层
queue<int>nodes;
vector<int>indexes=current_layer_holes(hireachy,child);
for(inti=0;i< indexes.size(); i++) {
                nodes.push(indexes[i]);
            }
            while(!nodes.empty()){
//当前层总数目
if(index%2==0){//联通组件对象
n_total+=nodes.size();
}
else{//孔洞对象
h_total+=nodes.size();
}
index++;
//计算下一层所有孩子节点
intcurr_ndoes=nodes.size();
for(intn=0;n< curr_ndoes; n++) {
                    intvalue=nodes.front();
nodes.pop();
//获取下一层节点第一个孩子
intchild=hireachy[value][2];
if(child>=0){
nodes.push(child);
}
}
}
printf("holenumber:%d
",h_total);
printf("connectionnumber:%d
",n_total);
//计算欧拉数
inteuler_num=n_total-h_total;
printf("numberofeuler:%d
",euler_num);
drawContours(result,contours,t,Scalar(0,0,255),2,8);
//显示欧拉数
Rectrect=boundingRect(contours[t]);
putText(result,format("euler:%d",euler_num),rect.tl(),FONT_HERSHEY_SIMPLEX,1.0,Scalar(255,255,0),2,8);
}
if(child< 0&&parent< 0){
printf("holenumber:%d
",h_total);
printf("connectionnumber:%d
",n_total);
inteuler_num=n_total-h_total;
printf("numberofeuler:%d
",euler_num);
drawContours(result,contours,t,Scalar(255,0,0),2,8);
Rectrect=boundingRect(contours[t]);
putText(result,format("euler:%d",euler_num),rect.tl(),FONT_HERSHEY_SIMPLEX,1.0,Scalar(255,255,0),2,8);
}

}

imshow("result",result);
waitKey(0);
return0;
}

vector<int>current_layer_holes(vectorlayers,intindex){
intnext=layers[index][0];
vector<int>indexes;
indexes.push_back(index);
while(next>=0){
indexes.push_back(next);
next=layers[next][0];
}
returnindexes;
}

PS:代码未经更多严格测试,仅供参考!

审核编辑 :李倩


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 二值图像
    +关注

    关注

    0

    文章

    14

    浏览量

    8927
  • OpenCV
    +关注

    关注

    33

    文章

    652

    浏览量

    45176
  • 欧拉
    +关注

    关注

    1

    文章

    16

    浏览量

    1947

原文标题:OpenCV轮廓层次分析实现欧拉数计算

文章出处:【微信号:CVSCHOOL,微信公众号:OpenCV学堂】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    基于开源的宇航级嵌入式星载操作系统成功在轨运行

    支撑宇航级场景的硬核实力,更代表基于开源的星载操作系统在高可靠、强实时的空间智能场景中迈出里程碑式一步,为中国商业航天自主创新发展筑牢智底座。
    的头像 发表于 05-19 09:28 444次阅读

    开源社区正式发布openEuler Embedded 26.03版本

    近日,开源社区正式发布openEuler Embedded 26.03版本。新版本基于开源社区Intelligence BooM开源全栈,成功孵化IB-Robot具身智能机器人
    的头像 发表于 04-22 10:47 533次阅读

    身为电子工程师必会的十九个电路计算公式

    LDO、MOS管的实战公式,覆盖硬件设计的核心场景,看完记得收藏,以后做项目绝对用得上!一、电容选型计算、串联电容三、并联电容四、感抗
    的头像 发表于 04-04 12:07 265次阅读
    身为电子工程师必会的十九个电路<b class='flag-5'>计算公式</b>

    labview之自定义计算公式

    最近给网友解决问题的时候,对方提出来,想要一个可以填写计算公式,然后数据进来后自动进行计算,从而得出转换完的数据,由此和大家进行一个分享。 废话不多说我们直接上例程Demo,示例如下: Demo 详情请参考公众号:上位机知识分享LABVIEW
    的头像 发表于 03-01 10:11 790次阅读
    labview之自定义<b class='flag-5'>计算公式</b>

    开源助力制造企业在OT领域智化转型

    多重挑战,新一代操作系统成为破局关键。OpenAtom openEuler(简称“openEuler”或“开源”),正以其开源开放、高可用、高安全的特性,成为OT深度IT化进程中的坚实底座。
    的头像 发表于 12-29 13:49 655次阅读
    开源<b class='flag-5'>欧</b><b class='flag-5'>拉</b>助力制造企业在OT领域<b class='flag-5'>数</b>智化转型

    CW32F0看门狗定时时长计算公式及举例

    看门狗定时时长计算公式: T = ( 4×2PRS / f )×( ARR + 1 ) 其中,f 为时钟源 RC10K 的频率,PRS 为预分频系数,ARR 为重载。 故,当时钟源 RC10K
    发表于 12-15 07:46

    串行时钟发生器的计算公式

    串行时钟发生器用来产生 I2C 通信的波特率时钟 SCL。串行时钟发生器采用 PCLK 作为输入时钟,通过 1 个 8bit的计数器计数,输出所需波特率的 I2C 时钟信号。 SCL 时钟频率计算公式
    发表于 12-08 08:16

    长城汽车5搭载禾赛科技激光雷达开启预售

    近期,长城汽车品牌宣布旗下全新 A 级纯电 SUV 5 正式开启预售,共推出五款车型,预售价区间为 10.98 万–14.28 万。其中,480km 激光雷达版和 580km
    的头像 发表于 11-21 10:49 1101次阅读

    使用Otsu阈值算法将灰度图像

    Otsu 算法是由日本学者OTSU于1979年提出的一种对图像进行化的高效算法,又称“最大类间方差法”。当我们对一个图象进行化操作的
    发表于 10-28 06:49

    贴片电容的精度是怎么计算出来的?

    贴片电容的精度通过 实际电容与标称电容的偏差范围 计算得出,其核心计算逻辑和关键要点如下: 一、精度定义与计算公式 贴片电容的精度表示实
    的头像 发表于 10-11 15:01 1890次阅读
    贴片电容的精度是怎么<b class='flag-5'>计算</b>出来的?

    测斜仪数据计算方法解析:从公式理解到智能应用

    测斜仪作为工程安全监测的重要设备,其测量数据的准确计算直接关系到结构物安全状态的判断。南京峟思将系统为大家介绍测斜仪数据的计算原理与方法,帮助用户更好地理解监测数据的产生过程。测斜仪计算公式详解当被
    的头像 发表于 09-28 13:30 931次阅读
    测斜仪数据<b class='flag-5'>计算</b>方法解析:从<b class='flag-5'>公式</b>理解到智能应用

    开源社区AI联合工作组正式成立

    近日,2025开放原子开源生态大会——开源生态分论坛在北京国家会议中心期顺利举办。来自产、学、研、用领域的社区成员与开发者齐聚一堂,共探南北向生态拓展与国际协作,深入解析AI生态使能与落地、边
    的头像 发表于 07-28 17:20 1502次阅读

    电力变压器空载及短路功率因数计算公式及应用

    的定义得出: PF=P/S。 P为有功功率,S为视在功率。 上述功率因数计算公式只有在已知有功功率和视在功率(或电压和电流的有效)的情况下才能使用。 对于一般的电力设备而言,不同的工作点下有不同的功率因数。因此,许多设备会在铭牌上标识额定运行状态下
    的头像 发表于 07-15 10:00 4608次阅读
    电力变压器空载及短路功率因数<b class='flag-5'>计算公式</b>及应用

    如何计算孔板流量计和平衡流量计的流量?计算公式一样吗?

    平衡流量计与孔板流量计作为差压式流量计的典型代表,虽均基于压力差与流量的数学关系进行计算,但是平衡流量计计算公式和孔板流量计的计算公式大不相同,其核心公式、参数修正及适用场景存在显著差
    的头像 发表于 07-09 13:54 1254次阅读
    如何<b class='flag-5'>计算</b>孔板流量计和平衡流量计的流量?<b class='flag-5'>计算公式</b>一样吗?

    自己动手绕线圈电感详细计算公式(建议收藏!)

    *2.047)+(40*3.74)}]÷2.047=19圈空心电感计算公式:L(mH)=(0.08D.D.N.N)/(3D+9W+10H)D------线圈直径N------线圈匝数d-----线径H----
    发表于 05-28 16:57