Sobel邊緣檢測和邊緣細化

本文详细介绍了Sobel边缘检测以及基于减法和邻域分析的图像细化方法。通过两次Sobel边缘检测和减法运算可以实现图像细化,但可能导致信息丢失。通过调整邻域分析中的阈值K,可以控制细化程度并减少杂点干扰。最后,通过二值化处理可以提高细化的对比度,得到清晰的边缘细化结果。
摘要由CSDN通过智能技术生成

http://blog.csdn.net/cay22/article/details/5590974 


在對圖像進行邊緣檢測處理時,得到的結果並不是理想的邊緣,而是一幅灰度圖像。有時在進行圖像識別的時候需要獲得圖像的單點寬邊緣,這就需要對邊緣檢測的結果進行細化增強。

Sobel邊緣細化的原理

圖像的邊緣檢測處理可以簡單理解為提取圖像中區域的輪廓。圖像中區域的劃分以像素灰度為依據,每個區域中的像素灰度大致相同,而區域之間的邊界就稱為邊緣,尋找這些邊緣就是圖像邊緣檢測的目的。

圖像邊緣檢測的結果直觀地看類似圖像的骨架,對圖像邊緣檢測結果的細化是圖像邊緣細化很好的示例,如圖11-27所示,其中a為原始圖像,b為a圖像的Sobel邊緣檢測結果。

圖11-27  圖像的邊緣檢測示例

從圖11-27中可以看出,Sobel邊緣檢測的結果能用線條較好地描述圖像,源圖像中對比度較高的區域在結果圖中體現為高灰度的像素,簡單地說就是對源圖像進行了「描邊」操作。在進行圖像細化時,最直接的思路就是對線條寬度進行縮減,然而圖像中的線條往往是不規則的,這使得直接對線條進行處理的方法很難實現。

換一種思路,如果把Sobel邊緣檢測結果中的輪廓線條看作一個高灰度區域,那麼如果能夠對這個區域的邊緣進行某種切割,使這個區域收縮,就可以實現圖像線條的細化。考慮對Sobel邊緣檢測的結果S1再次進行Sobel邊緣檢測,則可以得到一幅雙線條的邊緣圖像S2,而S2中雙線條所覆蓋的區域正好是S1中高灰度區域的邊緣,如果用從S1中去除S2中的高灰度部分,得到的結果就恰好是S1的一個細化結果。這樣的細化過程可以進行多次,進行次數越多,得到的細化圖像線條就越細,但同時圖像的信號強度也就越弱。圖11-28中a、b顯示了對圖11-27中a分別進行一次和兩次邊緣檢測的結果,c顯示了對a、b進行減法運算的結果。

 

圖11-28  圖像的邊緣檢測和減法細化

從圖中不難看出,雖然通過兩次邊緣檢測和減法運算可以使邊緣圖像被很大程度地細化,然而代價卻是圖像信息的大量丟失。為了彌補這一缺陷,可以對圖像進行多次邊緣檢測,然後得到多組減法結果,並將這些結果相加。通過這樣的方法可以在一定程度上對細化結果進行增強,然而也很容易為細化結果引入雜點。

圖像的細化同樣可以利用鄰域分析的方法來完成,考慮在圖像的3×3鄰域中,如果鄰域內有5個以上的可見像素,那麼此鄰域中一定包含寬度超過1像素的線條,而如果此鄰域中僅有3個或3個以下的可見像素,那麼此鄰域中一定只包含單點寬度的線條。圖11-29中列舉了幾種不同鄰域像素的情況,其中1表示可見像素,0表示背景,分析可知a中鄰域可見像素只有3個,所以一定不包含寬度超過1的線條,而b中鄰域的可見像素數目大於5個,所以b中一定包含寬度超過1的線條,c、d中鄰域的可見像素數目都在3~5之間,c中鄰域包含寬度超過1的線條,而d中鄰域卻不包含。

 

圖11-29  圖像鄰域像素情況

在圖像細化中,如果能夠根據鄰域內像素灰度情況,判定鄰域的中心像素存在的必要性,那麼基於鄰域分析的圖像細化處理就不難實現。在灰度圖像的處理中,像素不能簡單地用存在或不存在來描述,這為圖像細化的鄰域帶來了一定的麻煩。在灰度圖像中,若定義背景色為0灰度,那麼灰度越高的像素越容易被人眼感知,對圖像也就越重要,在圖像細化中應優先保留。

不妨借助統計排序濾波器的思想,在決定中心像素是否保留的時候,先對鄰域內像素按灰度進行排序,設定閾值K若鄰域的中心像素在序列中的次序小於K則說明中心像素在鄰域內較為重要需要被保留,否則就對中心像素進行刪除。這樣處理就限制了處理結果中每個鄰域內僅包含的可見像素數目,對於3×3鄰域,若設定K為3,則可限制圖像細化的結果中盡可能只包含寬度為1的線條。在實踐中可以通過調整K的值來控制細化的程度。如圖11-30所示,其中a為圖像的Sobel邊緣檢測結果,bc為利用鄰域分析的方法分別選取K=3、K=5對a進行細化的結果。

 

圖11-30  利用鄰域分析對圖像進行細化

經過邊緣細化的圖像常常存在低灰度的雜點干擾,同時,為了提高圖像邊緣細化結果的對比度,可以對圖像進行二值化處理,最終得到清晰的邊緣細化結果。

11.6.2  Sobel邊緣細化的編程實現

有關圖像的邊緣檢測算法實現將在本書第13章中給出,這裡只對細化部分的算法進行實現。

1.利用減法實現圖像的細化

由於圖像細化中的各方法可以自由組合,這裡只給出各方法的實現,讀者在使用時只用自行安排方法的調用順序即可。

/********************************************************

* 把線性存儲的像素轉化為二維數組形式

* 參數: image為線性存儲的像素,width、height為圖像的長寬

* 方法實現見11.1.3小節

********************************************************/

BYTE** CreatImage(BYTE* image, unsigned int width, unsigned int height, int bt=4);

/**************************************************

* 功能: 獲得圖像灰度,采用直接對RGB求平均值的方法

* 參數: imageBuf為目標圖像,x、y為要取得像素的坐標

* 方法實現見11.1.1小節

**************************************************/

BYTE GetAsh(BYTE** imageBuf0, int x, int y);

/**************************************************

* 功能: 設定指定位置的像素灰度

* 參數: imageBuf為目標圖像,x、y為要設定像素的坐標

* 方法實現見11.1.3小節

**************************************************/

void SetPixelXY(BYTE** imageBuf1, int x, int y, int a);

/******************************************************************

* 功能: Sobel邊緣檢測

* 參數: image0為原圖形,image1為要減去的圖像

*       w、h為圖像的寬和高

*       當type為true時,差分結果取水平和垂直方向差分中較大者,

*       否則取平均值(方法實現見本書第13章)

******************************************************************/

void SideSobel(BYTE* image0, BYTE* image1,

unsigned int w, unsigned int h, bool type);

/******************************************************************

* 功能: 對圖像進行二值化處理

* 參數: image0為原圖形,image1為處理的結果圖像

*       w、h為圖像的寬和高

*       K為閾值

******************************************************************/

void ToTwoValue(BYTE* image0, BYTE* image1, unsigned int w, unsigned int h,

int K)

{

    //將圖像轉化為矩陣形式

    BYTE** imageBuf0 = CreatImage(image0, w, h);

    BYTE** imageBuf1 = CreatImage(image1, w, h);

    int x,y;

    //依次對源圖像的每個像素進行處理

    for(y=0; y<h; y++)

        for(x=0; x<w; x++)

        {

            //如果當前點已經為單點,則在結果圖中用黑色標記

            if( GetAsh(imageBuf0,x,y) >=K )

            {

                SetPixelXY (imageBuf1,x,y,255 );

            }

            //如果當前點不是單點,則在結果圖中用白色標記

            else

            {

                SetPixelXY(imageBuf1,x,y,0);

            }

        }

    //清理內存

    free(imageBuf0);

    free(imageBuf1);

}

/**************************************************************************

* 功能: 對兩幅圖像進行減法運算

* 參數: image0為原圖形,image1為要減去的圖像

*       w、h為圖像的寬和高

**************************************************************************/

void Subtract(BYTE* image0, BYTE* image1, unsigned int w, unsigned int h)

{

    //將圖像轉化為矩陣形式

    BYTE** imageBuf0 = CreatImage(image0, w, h);

    BYTE** imageBuf1 = CreatImage(image1, w, h);

    int x,y;

    int a;

    //依次對源圖像的每個像素進行處理

    for(y=0; y<h; y++)

        for(x=0; x<w; x++)

        {

            //取得源圖像灰度

            a=GetAsh(imageBuf0,x,y);

            //進行減法運算

            a=a-GetAsh(imageBuf1,x,y);

            //過限處理

            a = a>255?255:a;   

            a = a<0?0:a;

            SetPixelXY(imageBuf1,x,y,a);

        }

    //清理內存

    free(imageBuf0);

    free(imageBuf1);

}

/**************************************************************************

* 功能: 對兩幅圖像進行加法運算

* 參數: image0為原圖形,image1為要減去的圖像

*       w、h為圖像的寬和高

**************************************************************************/

void AshAdd(BYTE* image0, BYTE* image1, unsigned int w, unsigned int h)

{

    //將圖像轉化為矩陣形式

    BYTE** imageBuf0 = CreatImage(image0, w, h);

    BYTE** imageBuf1 = CreatImage(image1, w, h);

    int x,y,c;

    int a;

    //依次對源圖像的每個像素進行處理

    for(y=0; y<h; y++)

        for(x=0; x<w; x++)

        {

            //取得源圖像灰度

            a=GetAsh(imageBuf0,x,y);

            //進行減法運算

            a=a+GetAsh(imageBuf1,x,y);

            //過限處理

            a = a>255?255:a;   

            a = a<0?0:a;

            SetPixelXY(imageBuf1,x,y,a);

        }

    //清理內存

    free(imageBuf0);

    free(imageBuf1);

}

2.利用鄰域分析實現圖像的細化

/***************************************************************************

* 把線性存儲的像素轉化為二維數組形式

* 參數: image為線性存儲的像素,width、height為圖像的長寬

* 方法實現見11.1.3小節

***************************************************************************/

BYTE** CreatImage(BYTE* image, unsigned int width, unsigned int height, int bt=4);

/**************************************************

* 功能: 獲得圖像灰度,采用直接對RGB求平均值的方法

* 參數: imageBuf為目標圖像,x、y為要取得像素的坐標

* 方法實現見11.1.1小節

**************************************************/

BYTE GetAsh(BYTE** imageBuf0, int x, int y);

/**************************************************

* 功能: 設定指定位置的像素灰度

* 參數: imageBuf為目標圖像,x、y為要設定像素的坐標

* 方法實現見11.1.3小節

**************************************************/

void SetPixelXY(BYTE** imageBuf1, int x, int y, int a);

/******************************************************************

* 功能: 對圖像進行二值化處理

* 參數: image0為原圖形,image1為處理的結果圖像

*       w、h為圖像的寬和高

*       K為閾值

* 方法實現見「利用減法實現圖像的細化」一節

******************************************************************/

void ToTwoValue(BYTE* image0, BYTE* image1, unsigned int w, unsigned int h,

int K)

/**************************************************

* 功能: 判斷當前鄰域的中心像素是否該保留

* 參數: imageBuf為目標圖像,w、h為圖像大小

*       x、y為當前采樣窗口中心像素的坐標

*       K為閾值

**************************************************/

bool IsOnePoint(BYTE** imageBuf0, int w, int h, int x, int y, int K)

{

    int i,j,k;                  

    int px,py; 

    int a;    //用來保存中心像素灰度

    a=GetAsh(imageBuf0,x,y);

    k=0;      //計數器

    //從采樣窗口中依次取得每個像素的灰度

    for(i=0; i<3; i++)

        for(j=0; j<3; j++)

        {

            py=y-1+i;

            px=x-1+j;

            //如果該像素灰度大於中心像素則計數器加1

            if(GetAsh(imageBuf0,px,py)>a)

            {

                k++;

            }

        }

    //如果中心像素灰度值處於鄰域內前三位,則認為此中心像素已經為單點

    if(k<K)

        return true;

    else

        return false;

}

/**************************************************************************

* 功能: 對圖像進行單點化處理

* 參數: image0為原圖形,image1為處理的結果圖像

*       w、h為圖像的寬和高

*       K為閾值

**************************************************************************/

void ToOnePointWide(BYTE* image0, BYTE* image1,

unsigned int w, unsigned int h, int K)

{

    //將圖像轉化為矩陣形式

    BYTE** imageBuf0 = CreatImage(image0, w, h);

    BYTE** imageBuf1 = CreatImage(image1, w, h);

    int x,y,c;

    int a;

    //依次對源圖像的每個像素進行處理

    for(y=1; y<h-1; y++)

        for(x=1; x<w-1; x++)

        {

            //如果當前點已經為單點 則在結果圖中用黑色標記

            if( IsOnePoint(imageBuf0,w,h,x,y,K) )

            {

                SetPixelXY(imageBuf1,x,y,GetAsh(imageBuf0,x,y) );

            }

            //如果當前點不是單點 則在結果圖中用白色標記

            else

            {

                SetPixelXY(imageBuf1,x,y,0);

            }

        }

    //清理內存

    free(imageBuf0);

    free(imageBuf1);

}

圖11-31為經過二值化處理的圖像邊緣細化結果,其中a為源圖像,b為處理結果。

 

圖11-31 二值化處理後的圖像邊緣細化結果

本節通過Sobel邊緣細化介紹了兩種全新的圖像增強處理思路,本節內容的重點並不是邊緣增強算法本身,而是幫助讀者拓寬思路,在數字圖像處理中,沒有標准化的算法或研究思路,算法創新才是學習的關鍵。

 

 

 

 http://book.csdn.net/bookfiles/974/10097430295.shtml

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值