二值圖像中封閉孔洞的高效填充算法(附源碼)。


  寫具體類容之前先吐槽一下。

     我一直寫技術文檔,雖然水平不怎么樣,但是基本上我寫的都還是比較實際的東西,也是自己投入了很多精力做的東西。有些可能沒有開源,有些人覺得對他沒有什么幫助,而我認為真正做技術的有能力的對於業內的東西,面對沒有處理過的問題,只要有人隨便點撥一下,基本上就能夠找到解決方案,授人以漁而非授人以魚才是重點。不過我心里不平衡的一點就是,無論是在CSDN還是博客園,得到人們參與評價和推薦的最多的很少有純技術性的文章出現,像我這樣從不寫些八卦的東西的,覺得很是失望。

     不排除我寫的東西比較淺顯,或者用詞不合適,不能滿足讀者的口味,不過還是希望博客園及廣大的博主能對技術性的博文多一份關心、多一份支持。

     鑒於心情不好,這篇文章只是簡單的說說這個算法的過程。

     在對圖像二值化后,不管用的是什么二值算法,總會存在一些瑕疵,這個時候我們就需要進行一些列的處理,去除那些我們不想要的糟粕,這類方法其實有很多,比如去除孤點、去除孤枝等等,這里介紹下去除封閉孔洞的一種算法。

     首先,注意我們這里是去除封閉孔洞,何謂封閉孔洞?我們認為如果一個特征的邊緣完全被另外一個特征包圍,則認為其為一個封閉的特征,比如在下圖中:

                                                

     1所標注處就是封閉的孔洞,2所標注極為開式孔洞。

     對於識別來說,很多情況下,我們希望能夠把這些封閉孔洞用周邊的特征來填充,從而減少特征的數量。

     一種直覺的想法就是,用FloodFill,不過如果直接用FloodFill,我們無法直接定位那些未知需要進行種子填充的, 但是Gabriel Landini, G.Landini 在2008年5月給我們寫了個非常簡單的代碼實現了這一過程(原始代碼是JAVA的,話說JAVA的算法代碼改為C#基本就不要做什么改動啊):

    public static void FillHole(FastBitmap Bmp)
    {
        int X, Y;
        int Width,Height,Stride;
        byte * Pointer;
        Width = Bmp.Width; Height = Bmp.Height; Pointer = Bmp.Pointer; Stride = Bmp.Stride;
        for (Y=0;Y<Height;Y++)
        {
            Pointer=Bmp.Pointer + Y*Stride;
            if (Pointer[0]==0) FloodFill(Bmp,0,Y);
            if (Pointer[Width-1]==0) FloodFill(Bmp,Width-1,Y);
        }
        for (X=0;X<Width;X++)
        {
            Pointer=Bmp.Pointer + X;
            if (Pointer[0]==0) FloodFill(Bmp,X,0);
            if (Pointer[(Height-1)*Stride]==0) FloodFill(Bmp,X,Height-1);
        }
            for (Y = 0; Y < Height; Y++)
            {
                Pointer = Bmp.Pointer + Y * Stride;
                for (X = 0; X < Width; X++)
                {
                    if (Pointer[X] == 127)
                        Pointer[X] = 0;
                    else
                        Pointer[X] = 255;
                }
            }
      }

 

     算法的過程很簡單,先水平方向取起點和終點為種子點,進行種子填充,然后再垂直方向進行。不要以為需要有那么多次種子填充的過程,算法速度就很慢,由於在每次種子填充前,都有個判斷條件,而該判斷條件,隨着前面種子填充的過程的進行,將越來越難以滿足。
     算法具體的原理留給有興趣的人思考,直接使用的人就完全不用去管他,知道他有這個功能就OK了。

     關於FloodFill算法的實現,多少年來也不知道有多少個版本的代碼,能從網上找到的99%的都是些垃圾代碼,真正的優秀代碼作者一般都會留着,我這也是從網上找了一段代碼,敷衍了事把,雖然我這里有非常好的這個函數。願意學習的自然會去改進的。

     下面我們來看一下填充的效果:

           

                      原圖                        二值圖                           填充后的圖    

     至於是要填充掉前景的孔洞還是背景的孔洞這可能需要作者自己判斷了。

     如果我們要去掉指定面積小於指定值得孔洞,而保留大於的,你知道該怎么辦嗎?

     關於FloodFill函數,我在稍微展開一下吧,一般情況下這個函數都是用的四領域或者八領域的區域生長法實現的,如果能充分掌握該函數的編寫,可以實現很多功能,比如PS的連續的魔術棒功能、比如二值圖像的去除噪點、漫畫分割、一些識別上等等,舉例如下:

    一、連續的魔術棒

          

    

    二、清除二值圖像的孤點

   

  是不是感覺和這里的填充孔洞類似,不過兩者還是有所區別的。

    三、PCB板的某個元器件的定位                          

      

 

    好了,不擴展了,對填充孔洞有興趣的朋友可以從這里下載源碼:http://files.cnblogs.com/Imageshop/FillHole.rar

  希望看過認為好的朋友多多支持。 

 

*********************************作者: laviewpbt   時間: 2013.9.8       聯系QQ:  33184777  轉載請保留本行信息************************


免責聲明!

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



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