OpenCV細化算法簡單解析

細化算法它的原理也很簡單:html

      咱們對一副二值圖像進行骨架提取,就是刪除不須要的輪廓點,只保留其骨架點。假設一個像素點,咱們定義該點爲p1,則它的八鄰域點p2->p9位置以下圖所示,該算法考慮p1點鄰域的實際狀況,以便決定是否刪除p1點。假設咱們處理的爲二值圖像,背景爲黑色,值爲0,要細化的前景物體像素值爲1。算法

 

image

 

算法的描述以下:測試

  

首先複製源圖像到目地圖像,而後創建一個臨時圖像,接着執行下面操做:spa

 

1. 把目地圖像複製給臨時圖像,對臨時圖像進行一次掃描,對於不爲0的點,若是知足如下四個條件,則在目地圖像中刪除該點(就是設置該像素爲0),這裏p2,…,p9是對應位置的像素灰度值(其爲1或者0)。3d

 

   a. 2<= p2+p3+p4+p5+p6+p7+p8+p9<=6code

 

    大於等於2會保證p1點不是端點或孤立點,由於刪除端點和孤立點是不合理的,小於等於6保證p1點是一個邊界點,而不是一個內部點。等於0時候,周圍沒有等於1的像素,因此p1爲孤立點,等於1的時候,周圍只有1個灰度等於1的像素,因此是端點(注:端點是周圍有且只能有1個值爲1的像素)。htm

 

image

 

 

 

   b. p2->p9的排列順序中,01模式的數量爲1,好比下面的圖中,有p2p3 => 01, p6p7=>01,因此該像素01模式的數量爲2。blog

 

image

 

     之因此要01模式數量爲1,是要保證刪除當前像素點後的連通性。好比下面的圖中,01模式數量大於1,若是刪除當前點p1,則連通性不能保證。圖片

 

image

 

    c. P2*p4*p6 = 0ip

 

    d. p4*p6*p8 = 0

 

image

 

      在第一次子迭代中,只是移去東南的邊界點,而不考慮西北的邊界點,注意p4,p6出現了2次,就是說它們有一個爲0,則c,d就知足。

 

2. 接下來,把目地圖像再次複製到臨時圖像,接着對臨時圖像進行一次掃描,若是不爲0的點它的八鄰域知足如下4個條件,則在目地圖像中刪除該點(就是設置該像素爲0)

 

    a. 2<= p2+p3+p4+p5+p6+p7+p8+p9<=6

 

    b. p2->p9的排列順序中,01模式的數量(這裏假設二值圖非零值爲1)爲1。

 

    c. p2*p4*p8 = 0

 

    d. p2*p6*p8 = 0

 

image

 

第二次迭代則相反,會移去西北的邊界點,注意p2,p8出現了2次,就是說它們有一個爲0,則c,d就知足。

 

 

 

執行完上面兩個步驟後,就完成了一次細化算法,咱們能夠屢次迭代執行上述過程,獲得最終的骨架圖。

 

 

 

細化算法代碼以下:

以上部分原理是轉載(邁克老狼2012)http://www.cnblogs.com/mikewolf2002/p/3321732.html

接下來發布的是在我電腦上經過的測試代碼:

編譯環境爲win7+VS2015+OpenCV3.0

 

  1 void cvThin(IplImage* src, IplImage* dst, int iterations)
  2 {
  3     //此時的src是一個二值化的圖片  
  4     CvSize size = cvGetSize(src);
  5     cvCopy(src, dst);
  6 
  7     int n = 0, i = 0, j = 0;
  8     for (n = 0; n < iterations; n++)//開始進行迭代  
  9     {
 10         IplImage* t_image = cvCloneImage(dst);
 11         for (i = 0; i < size.height; i++)
 12         {
 13             for (j = 0; j < size.width; j++)
 14             {
 15                 if (CV_IMAGE_ELEM(t_image, uchar, i, j) == 1)
 16                 {
 17                     int ap = 0;
 18                     int p2 = (i == 0) ? 0 : CV_IMAGE_ELEM(t_image, uchar, i - 1, j);
 19                     int p3 = (i == 0 || j == size.width - 1) ? 0 : CV_IMAGE_ELEM(t_image, uchar, i - 1, j + 1);
 20                     if (p2 == 0 && p3 == 1)
 21                     {
 22                         ap++;
 23                     }
 24 
 25                     int p4 = (j == size.width - 1) ? 0 : CV_IMAGE_ELEM(t_image, uchar, i, j + 1);
 26                     if (p3 == 0 && p4 == 1)
 27                     {
 28                         ap++;
 29                     }
 30 
 31                     int p5 = (i == size.height - 1 || j == size.width - 1) ? 0 : CV_IMAGE_ELEM(t_image, uchar, i + 1, j + 1);
 32                     if (p4 == 0 && p5 == 1)
 33                     {
 34                         ap++;
 35                     }
 36 
 37                     int p6 = (i == size.height - 1) ? 0 : CV_IMAGE_ELEM(t_image, uchar, i + 1, j);
 38                     if (p5 == 0 && p6 == 1)
 39                     {
 40                         ap++;
 41                     }
 42 
 43                     int p7 = (i == size.height - 1 || j == 0) ? 0 : CV_IMAGE_ELEM(t_image, uchar, i + 1, j - 1);
 44                     if (p6 == 0 && p7 == 1)
 45                     {
 46                         ap++;
 47                     }
 48 
 49                     int p8 = (j == 0) ? 0 : CV_IMAGE_ELEM(t_image, uchar, i, j - 1);
 50                     if (p7 == 0 && p8 == 1)
 51                     {
 52                         ap++;
 53                     }
 54 
 55                     int p9 = (i == 0 || j == 0) ? 0 : CV_IMAGE_ELEM(t_image, uchar, i - 1, j - 1);
 56                     if (p8 == 0 && p9 == 1)
 57                     {
 58                         ap++;
 59                     }
 60                     if (p9 == 0 && p2 == 1)
 61                     {
 62                         ap++;
 63                     }
 64 
 65                     if ((p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) > 1 && (p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) < 7)
 66                     {
 67                         if (ap == 1)
 68                         {
 69                             if (!(p2 && p4 && p6))
 70                             {
 71                                 if (!(p4 && p6 && p8))
 72                                 {
 73                                     CV_IMAGE_ELEM(dst, uchar, i, j) = 0;//設置目標圖像中像素值爲0的點  
 74                                 }
 75                             }
 76                         }
 77                     }
 78 
 79                 }
 80             }
 81         }
 82 
 83         cvReleaseImage(&t_image);
 84 
 85         t_image = cvCloneImage(dst);
 86         for (i = 0; i < size.height; i++)
 87         {
 88             for (int j = 0; j < size.width; j++)
 89             {
 90                 if (CV_IMAGE_ELEM(t_image, uchar, i, j) == 1)
 91                 {
 92                     int ap = 0;
 93                     int p2 = (i == 0) ? 0 : CV_IMAGE_ELEM(t_image, uchar, i - 1, j);
 94                     int p3 = (i == 0 || j == size.width - 1) ? 0 : CV_IMAGE_ELEM(t_image, uchar, i - 1, j + 1);
 95                     if (p2 == 0 && p3 == 1)
 96                     {
 97                         ap++;
 98                     }
 99                     int p4 = (j == size.width - 1) ? 0 : CV_IMAGE_ELEM(t_image, uchar, i, j + 1);
100                     if (p3 == 0 && p4 == 1)
101                     {
102                         ap++;
103                     }
104                     int p5 = (i == size.height - 1 || j == size.width - 1) ? 0 : CV_IMAGE_ELEM(t_image, uchar, i + 1, j + 1);
105                     if (p4 == 0 && p5 == 1)
106                     {
107                         ap++;
108                     }
109                     int p6 = (i == size.height - 1) ? 0 : CV_IMAGE_ELEM(t_image, uchar, i + 1, j);
110                     if (p5 == 0 && p6 == 1)
111                     {
112                         ap++;
113                     }
114                     int p7 = (i == size.height - 1 || j == 0) ? 0 : CV_IMAGE_ELEM(t_image, uchar, i + 1, j - 1);
115                     if (p6 == 0 && p7 == 1)
116                     {
117                         ap++;
118                     }
119                     int p8 = (j == 0) ? 0 : CV_IMAGE_ELEM(t_image, uchar, i, j - 1);
120                     if (p7 == 0 && p8 == 1)
121                     {
122                         ap++;
123                     }
124                     int p9 = (i == 0 || j == 0) ? 0 : CV_IMAGE_ELEM(t_image, uchar, i - 1, j - 1);
125                     if (p8 == 0 && p9 == 1)
126                     {
127                         ap++;
128                     }
129                     if (p9 == 0 && p2 == 1)
130                     {
131                         ap++;
132                     }
133                     if ((p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) > 1 && (p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9) < 7)
134                     {
135                         if (ap == 1)
136                         {
137                             if (p2*p4*p8 == 0)
138                             {
139                                 if (p2*p6*p8 == 0)
140                                 {
141                                     CV_IMAGE_ELEM(dst, uchar, i, j) = 0;
142                                 }
143                             }
144                         }
145                     }
146                 }
147 
148             }
149 
150         }
151         cvReleaseImage(&t_image);
152     }
153 
154 }

 

細化結果由於個人圖不方便展現,你們能夠參考邁克老狼2012的哦,效果是很像的,他採用的mat類,而我採用的iplimage類。

相關文章
相關標籤/搜索