0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

二值圖像的歐拉數計算公式

OpenCV學堂 ? 來源:OpenCV學堂 ? 作者:OpenCV學堂 ? 2022-06-30 11:08 ? 次閱讀

歐拉數定義

二值圖像分析中歐拉數重要的拓撲特征之一,在圖像分析與幾何對象識別中有著十分重要的作用,二值圖像的歐拉數計算公式表示如下:
E = N – H 其中
E表示計算得到歐拉數
N表示聯(lián)通組件的數目
H表示在聯(lián)通組件內部的洞的數目
下圖是二值圖像,白色背景,兩個對象、分析計算得到歐拉數的例子:

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

可以看到通過簡單的歐拉數屬性就可以對它們進行區(qū)分。左側對象中有兩個聯(lián)通區(qū)域,所以N=2,沒有洞孔區(qū)域,所以H=0, 計算得到歐拉數目為 2 – 0 = 。右側是大寫字母B,它只有一個聯(lián)通區(qū)域所以N = 1, 內部有兩個洞孔區(qū)域所以H = 2,最終計算得到歐拉數為 2 – 1 = -1。對于任意一個幾何形狀來說,如果我們要求得它的歐拉數,就首先要分析它的輪廓結構,然后根據輪廓層次結構計算得到N與H值。

歐拉數是圖像幾何識別中重要的屬性,舉例如下圖中三個英文字母

01f57b74-f7bf-11ec-ba43-dac502259ad0.png?對字母A來說它的內部有一個黑色孔洞,所以它的H=1,其本身是一個聯(lián)通組件所以N =1,最終計算得到歐拉數為 E = 1 -1 = 0,同樣可以計算B與C它們的歐拉數分布為-1與1,可見通過歐拉數屬性可以輕而易舉的區(qū)分ABC三個英文字母。

二:輪廓層次信息獲取

在OpenCV對二值圖像進行輪廓分析輸出的層次結構會保存在一個Vec4i的結構體中,這里有必要首先看一下輪廓發(fā)現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

上面的索引如果是負數就表示沒有相關層次信息,如果是非負數就表示有相關的層次關系信息。此外輪廓發(fā)現函數對輸入image圖像的要求必須滿足

  • 背景是黑色 ,0表示

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

三:歐拉數計算方法

有了輪廓的層次信息與每個輪廓的信息之后,嘗試遍歷每個輪廓,首先通過調用findContours就可以獲取二值圖像的輪廓層次信息,然后遍歷每個輪廓,進行層次遍歷,獲得每層子輪廓的總數,最終根據輪廓層級不同分為孔洞與連接輪廓的計數,二者想減得到每個獨立外層輪廓的歐拉數。

二值化與輪廓發(fā)現的代碼如下:

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){//聯(lián)通組件對象
n_total+=nodes.size();
}
else{//孔洞對象
h_total+=nodes.size();
}
index++;
//計算下一層所有孩子節(jié)點
intcurr_ndoes=nodes.size();
for(intn=0;nintvalue=nodes.front();
nodes.pop();
//獲取下一層節(jié)點第一個孩子
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;tintnext=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&&parent0){
//計算當前層
queue<int>nodes;
vector<int>indexes=current_layer_holes(hireachy,child);
for(inti=0;iwhile(!nodes.empty()){
//當前層總數目
if(index%2==0){//聯(lián)通組件對象
n_total+=nodes.size();
}
else{//孔洞對象
h_total+=nodes.size();
}
index++;
//計算下一層所有孩子節(jié)點
intcurr_ndoes=nodes.size();
for(intn=0;nintvalue=nodes.front();
nodes.pop();
//獲取下一層節(jié)點第一個孩子
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(child0&&parent0){
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:代碼未經更多嚴格測試,僅供參考!

審核編輯 :李倩


聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 二值圖像
    +關注

    關注

    0

    文章

    14

    瀏覽量

    8708
  • OpenCV
    +關注

    關注

    29

    文章

    623

    瀏覽量

    41177
  • 歐拉
    +關注

    關注

    1

    文章

    13

    瀏覽量

    1811

原文標題:OpenCV輪廓層次分析實現歐拉數計算

文章出處:【微信號:CVSCHOOL,微信公眾號:OpenCV學堂】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    VCA820的增益計算公式是什么?

    我看了手冊,貌似VCA820沒有給出增益計算公式,請解答!!謝謝
    發(fā)表于 09-26 06:43

    工業(yè)鏡頭焦距計算公式

    掌握工業(yè)鏡頭焦距計算公式是確保工業(yè)視覺系統(tǒng)高效、準確運行的重要一步。
    的頭像 發(fā)表于 09-25 16:36 ?275次閱讀
    工業(yè)鏡頭焦距<b class='flag-5'>計算公式</b>

    請問VCA820的增益計算公式是什么?

    VCA820的增益計算公式是什么?就是輸入與增益之間的計算公式。官網資料里面好像沒有介紹,不知道是不是我看的不夠仔細
    發(fā)表于 09-06 08:04

    示波器周期的計算公式

    示波器作為電子測量領域的重要工具,其能夠直觀地顯示電壓信號隨時間變化的波形,對于電路分析、信號檢測等領域具有不可替代的作用。在示波器的使用中,我們經常需要計算信號的周期,以了解信號的特性。本文將詳細介紹示波器周期的計算公式及其應用,并通過實例進行說明,以期為讀者提供更為深
    的頭像 發(fā)表于 05-17 17:25 ?1535次閱讀

    電能的計算公式 電能的計算公式中時間的單位

    電能是電力消耗的度量,它表示單位時間內消耗的電功率。電能的計算公式為: 電能(E)= 電功率(P)× 時間(t) 其中,電功率可以通過以下公式計算: 電功率(P)= 電壓(U)× 電流(I) 通過
    的頭像 發(fā)表于 02-22 10:00 ?8969次閱讀

    功率的計算公式w怎么求

    功率的計算公式是根據物理學中的定義和公式推導而來的,下面將介紹功率的概念、單位以及計算公式。 一、功率的基本概念 在物理學中,功率是描述物體進行功的速率。它表示單位時間內所做的功。功率越高,表示單位
    的頭像 發(fā)表于 01-17 11:12 ?3449次閱讀

    電流計算公式簡單方法

    電流計算公式是描述電流與電壓和電阻之間的關系的數學公式。根據歐姆定律,電流通過一個導體時與電壓成正比,與電阻成反比。這意味著,當電壓增加或電阻減小時,電流也會增加。 電流的計算公式是I = V/R
    的頭像 發(fā)表于 01-16 14:28 ?7692次閱讀

    單相電機功率計算公式

    單相電機是一種常見的電動機類型,廣泛應用于家用電器、小型機械設備和辦公設備等領域。在實際應用中,正確計算單相電機的功率是非常重要的。本文將詳細介紹單相電機功率的計算公式,并對其背后的原理和相關概念
    的頭像 發(fā)表于 01-16 10:16 ?3281次閱讀

    永磁電機計算公式是什么

    、磁場強度、磁鏈和電流之間的關系。下面將分別介紹這些公式。 電磁轉矩(Te)的計算公式 電磁轉矩是永磁電機產生的機械轉矩,計算公式為: Te = Kc * B * Ia * sin(θm - θa) 其中,Kc是定子槽
    的頭像 發(fā)表于 01-11 10:38 ?5139次閱讀

    電機扭矩的計算公式和轉速計算公式

    在電機學中,電機轉速和扭矩是非常重要的參數,在實際應用中,電機轉速和扭矩的計算公式也使用得非常頻繁,本文詳細介紹扭矩的計算公式和轉速計算公式
    發(fā)表于 12-25 09:41 ?4178次閱讀

    階巴特沃斯濾波器電路截止頻率計算公式

    階巴特沃斯濾波器是一種常用于電子電路中的濾波器,它能夠通過改變截止頻率來實現對信號的濾波功能。在本文中,我們將詳細介紹階巴特沃斯濾波器的截止頻率的計算公式。 截止頻率的計算公式
    的頭像 發(fā)表于 12-15 11:23 ?7882次閱讀

    LTC7545具體的增益計算公式是什么?

    LTC7545按照下面的電路連接,這個是非官方標準的接法,想問下具體的增益計算公式是什么,VOUT和VIN以及數字code之間的關系。
    發(fā)表于 12-04 07:27

    if函數如何嵌套計算公式

    嵌套if函數可以在Excel等電子表格軟件中實現復雜的條件判斷和計算公式。本文將詳細介紹if函數的嵌套使用方法,包括語法、常見應用場景和實例演示等,以及注意事項和進階技巧。 一、if函數的基本語法
    的頭像 發(fā)表于 11-30 16:55 ?5593次閱讀

    rc充放電時間計算公式

    電子發(fā)燒友網站提供《rc充放電時間計算公式.zip》資料免費下載
    發(fā)表于 11-20 14:27 ?5次下載
    rc充放電時間<b class='flag-5'>計算公式</b>

    電氣計算公式和實例說明

    掌握實用的計算公式是電氣工作者應具備的能力,但公式繁多應用時查找不方便,下面將整理和收集的一些常用的實用公式和口訣整理出來,并用實例說明和解釋。
    的頭像 發(fā)表于 11-17 14:46 ?834次閱讀