OpenCV學習(16) 細化算法(4)


本章我們學習Rosenfeld細化算法,參考資料:http://yunpan.cn/QGRjHbkLBzCrn

在開始學習算法之前,我們先看下連通分量,以及4連通性,8連通性的概念:

http://www.imageprocessingplace.com/downloads_V3/root_downloads/tutorials/contour_tracing_Abeer_George_Ghuneim/connectivity.html

假設我們有二值圖,背景像素值為0,前景像素值為1。

我們使用下面的八鄰域表示法:

172059~1

     對於前景點像素p1, 如果p2=0,則p1 稱作北部邊界點。如果p6=0,p1稱作南部邊界點,p4=0,p1稱作東部邊界點,p8=0,p1稱作西部邊界點。

image

p1周圍8個像素的值都為0,則p1為孤立點,如果周圍8個像素有且只有1個像素值為1,則此時p1稱作端點。

另外還要了解的一個概念就是8 simple。

就是我們把p1的值設置為0后,不會改變周圍8個像素的8連通性。

下面的三個圖中,如果p1=0后,則會改變8連通性image

而下面的則不會改邊8連通性,此時可以稱像素p1是8 simple

image

Rosenfeld細化算法描述如下:

1. 掃描所有像素,如果像素是北部邊界點,且是8simple,但不是孤立點和端點,刪除該像素。

2. 掃描所有像素,如果像素是南部邊界點,且是8simple,但不是孤立點和端點,刪除該像素。

3. 掃描所有像素,如果像素是東部邊界點,且是8simple,但不是孤立點和端點,刪除該像素。

4. 掃描所有像素,如果像素是西部邊界點,且是8simple,但不是孤立點和端點,刪除該像素。

執行完上面4個步驟后,就完成了一次迭代,我們重復執行上面的迭代過程,直到圖像中再也沒有可以刪除的點后,退出迭代循環。

算法代碼如下:

void gThin::cvRosenfeld(cv::Mat& src, cv::Mat& dst)
{

if(src.type()!=CV_8UC1)
{
printf("只能處理二值或灰度圖像\n");
return;
}
//非原地操作時候,copy src到dst
if(dst.data!=src.data)
{
src.copyTo(dst);
}

int i, j, n;
int width, height;
//之所以減1,是方便處理8鄰域,防止越界
width = src.cols -1;
height = src.rows -1;
int step = src.step;
int p2,p3,p4,p5,p6,p7,p8,p9;
uchar* img;
bool ifEnd;
cv::Mat tmpimg;
int dir[4] = {-step, step, 1, -1};

while(1)
{
//分四個子迭代過程,分別對應北,南,東,西四個邊界點的情況
ifEnd = false;
for(n =0; n < 4; n++)
{
dst.copyTo(tmpimg);
img = tmpimg.data;
for(i = 1; i < height; i++)
{
img += step;
for(j =1; j<width; j++)
{
uchar* p = img + j;
//如果p點是背景點或者且為方向邊界點,依次為北南東西,繼續循環
if(p[0]==0||p[dir[n]]>0) continue;
p2 = p[-step]>0?1:0;
p3 = p[-step+1]>0?1:0;
p4 = p[1]>0?1:0;
p5 = p[step+1]>0?1:0;
p6 = p[step]>0?1:0;
p7 = p[step-1]>0?1:0;
p8 = p[-1]>0?1:0;
p9 = p[-step-1]>0?1:0;
//8 simple判定
int is8simple = 1;
if(p2==0&&p6==0)
{
if((p9==1||p8==1||p7==1)&&(p3==1||p4==1||p5==1))
is8simple = 0;
}
if(p4==0&&p8==0)
{
if((p9==1||p2==1||p3==1)&&(p5==1||p6==1||p7==1))
is8simple = 0;
}
if(p8==0&&p2==0)
{
if(p9==1&&(p3==1||p4==1||p5==1||p6==1||p7==1))
is8simple = 0;
}
if(p4==0&&p2==0)
{
if(p3==1&&(p5==1||p6==1||p7==1||p8==1||p9==1))
is8simple = 0;
}
if(p8==0&&p6==0)
{
if(p7==1&&(p3==9||p2==1||p3==1||p4==1||p5==1))
is8simple = 0;
}
if(p4==0&&p6==0)
{
if(p5==1&&(p7==1||p8==1||p9==1||p2==1||p3==1))
is8simple = 0;
}
int adjsum;
adjsum = p2 + p3 + p4+ p5 + p6 + p7 + p8 + p9;
//判斷是否是鄰接點或孤立點,0,1分別對於那個孤立點和端點
if(adjsum!=1&&adjsum!=0&&is8simple==1)
{
dst.at<uchar>(i,j) = 0; //滿足刪除條件,設置當前像素為0
ifEnd = true;
}

}
}
}

//printf("\n");
//PrintMat(dst);
//PrintMat(dst);
//已經沒有可以細化的像素了,則退出迭代
if(!ifEnd) break;
}

}

程序結果:

image

imageimage

程序代碼:工程FirstOpenCV11


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM