細化算法它的原理也很簡單:html
咱們對一副二值圖像進行骨架提取,就是刪除不須要的輪廓點,只保留其骨架點。假設一個像素點,咱們定義該點爲p1,則它的八鄰域點p2->p9位置以下圖所示,該算法考慮p1點鄰域的實際狀況,以便決定是否刪除p1點。假設咱們處理的爲二值圖像,背景爲黑色,值爲0,要細化的前景物體像素值爲1。算法
算法的描述以下:測試
首先複製源圖像到目地圖像,而後創建一個臨時圖像,接着執行下面操做: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
b. p2->p9的排列順序中,01模式的數量爲1,好比下面的圖中,有p2p3 => 01, p6p7=>01,因此該像素01模式的數量爲2。blog
之因此要01模式數量爲1,是要保證刪除當前像素點後的連通性。好比下面的圖中,01模式數量大於1,若是刪除當前點p1,則連通性不能保證。圖片
c. P2*p4*p6 = 0ip
d. p4*p6*p8 = 0
在第一次子迭代中,只是移去東南的邊界點,而不考慮西北的邊界點,注意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
第二次迭代則相反,會移去西北的邊界點,注意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類。