本文主要實現了改進Zhang Suen細化算法的C#實現,相關論文 :“牟少敏,杜海洋,蘇平,查緒恆,陳光藝.一種改進的快速並行細化算法[J].微電子學與計算機,2013,(第1期)” 。這篇論文中關於Zhang Suen細化算法的描述,貌似存在問題。本文的算法中的意思是兩次標記的點迭代后同時刪除。而zhang快速算法,是分為兩步刪除邊界點的。第一步迭代之后,已經做標記的點就需要刪除了。如果兩步可以放在一起刪除的話,為什么不在一次迭代中將幾個條件一起判斷呢
一:Zhang-Suen細化算法介紹
Zhang-Suen細化算法通常是一個迭代算法,整個迭代過程分為兩步:
Step One:循環所有前景像素點,對符合如下條件的像素點標記為刪除:
1. 2 <= N(p1) <=6
2. S(P1) = 1
3. P2 * P4 * P6 = 0
4. P4 * P6 * P8 = 0
其中N(p1)表示跟P1相鄰的8個像素點中,為前景像素點的個數
S(P1)表示從P2 ~ P9 ~ P2像素中出現0~1的累計次數,其中0表示背景,1表示前景
完整的P1 ~P9的像素位置與舉例如下:
其中 N(p1) = 4, S(P1) = 3, P2*P4*P6=0*0*0=0, P4*P6*P8=0*0*1=0, 不符合條件,無需標記為刪除。
Step Two:跟Step One很類似,條件1、2完全一致,只是條件3、4稍微不同,滿足如下條件的像素P1則標記為刪除,條件如下:
1. 2 <= N(p1) <=6
2. S(P1) = 1
3. P2 * P4 * P8 = 0
4. P2 * P6 * P8 = 0
循環上述兩步驟,直到兩步中都沒有像素被標記為刪除為止,輸出的結果即為二值圖像細化后的骨架。
二:代碼實現步驟
#region 改進 Zhang-Suen algorithm public Bitmap zhang_thinimage_improve(Bitmap bmp) { int imgWidth = bmp.Width; int imgHeight = bmp.Height; byte[,] BinaryArray = new byte[imgHeight, imgWidth]; int depth = Bitmap.GetPixelFormatSize(bmp.PixelFormat); if (depth != 1)//判斷位深度 { int threshold = 0; BinaryArray = ToBinaryArray(bmp, out threshold); } else { BinaryArray = BinaryBitmapToBinaryArray(bmp); } int[] Zhangmude = new int[9]; //int deletecount = 0; List<Point> deletelist = new List<Point>(); while (true) { for (int y = 1; y < imgHeight-1; y++) { for (int x = 1; x < imgWidth-2; x++) { if (BinaryArray[y, x] == 0) { Zhangmude[0] = 1; if (BinaryArray[y - 1, x] == 0) Zhangmude[1] = 1; else Zhangmude[1] = 0; if (BinaryArray[y - 1, x + 1] == 0) Zhangmude[2] = 1; else Zhangmude[2] = 0; if (BinaryArray[y, x + 1] == 0) Zhangmude[3] = 1; else Zhangmude[3] = 0; if (BinaryArray[y + 1, x + 1] == 0) Zhangmude[4] = 1; else Zhangmude[4] = 0; if (BinaryArray[y + 1, x] == 0) Zhangmude[5] = 1; else Zhangmude[5] = 0; if (BinaryArray[y + 1, x - 1] == 0) Zhangmude[6] = 1; else Zhangmude[6] = 0; if (BinaryArray[y, x - 1] == 0) Zhangmude[7] = 1; else Zhangmude[7] = 0; if (BinaryArray[y - 1, x - 1] == 0) Zhangmude[8] = 1; else Zhangmude[8] = 0; int whitepointtotal = 0; for (int k = 1; k < 9; k++) { //得到1的個數 whitepointtotal = whitepointtotal + Zhangmude[k]; } if ((whitepointtotal >= 2) && (whitepointtotal <= 6)) { //得到01的個數 int ap = 0; if ((Zhangmude[1] == 0) && (Zhangmude[2] == 1)) ap++; if ((Zhangmude[2] == 0) && (Zhangmude[3] == 1)) ap++; if ((Zhangmude[3] == 0) && (Zhangmude[4] == 1)) ap++; if ((Zhangmude[4] == 0) && (Zhangmude[5] == 1)) ap++; if ((Zhangmude[5] == 0) && (Zhangmude[6] == 1)) ap++; if ((Zhangmude[6] == 0) && (Zhangmude[7] == 1)) ap++; if ((Zhangmude[7] == 0) && (Zhangmude[8] == 1)) ap++; if ((Zhangmude[8] == 0) && (Zhangmude[1] == 1)) ap++; //計算bp int bp = 0; bp += Zhangmude[1]; bp += Zhangmude[2] << 1; bp += Zhangmude[3] << 2; bp += Zhangmude[4] << 3; bp += Zhangmude[5] << 4; bp += Zhangmude[6] << 5; bp += Zhangmude[7] << 6; bp += Zhangmude[8] << 7; if (ap == 1 || bp == 65 || bp == 5 || bp == 20 || bp == 80 || bp == 13 || bp == 22 || bp == 52 || bp == 133 || bp == 141 || bp == 54) { if ((Zhangmude[1] * Zhangmude[3] * Zhangmude[5] == 0) && (Zhangmude[3] * Zhangmude[5] * Zhangmude[7] == 0)) { deletelist.Add(new Point(y, x)); } } } } } } if (deletelist.Count() == 0) break; foreach (var deleteItem in deletelist) { BinaryArray[deleteItem.X, deleteItem.Y] = 255; } deletelist.Clear(); for (int y = 1; y < imgHeight-1; y++) { for (int x = 1; x < imgWidth-1; x++) { if (BinaryArray[y, x] == 0) { Zhangmude[0] = 1; if (BinaryArray[y - 1, x] == 0) Zhangmude[1] = 1; else Zhangmude[1] = 0; if (BinaryArray[y - 1, x + 1] == 0) Zhangmude[2] = 1; else Zhangmude[2] = 0; if (BinaryArray[y, x + 1] == 0) Zhangmude[3] = 1; else Zhangmude[3] = 0; if (BinaryArray[y + 1, x + 1] == 0) Zhangmude[4] = 1; else Zhangmude[4] = 0; if (BinaryArray[y + 1, x] == 0) Zhangmude[5] = 1; else Zhangmude[5] = 0; if (BinaryArray[y + 1, x - 1] == 0) Zhangmude[6] = 1; else Zhangmude[6] = 0; if (BinaryArray[y, x - 1] == 0) Zhangmude[7] = 1; else Zhangmude[7] = 0; if (BinaryArray[y - 1, x - 1] == 0) Zhangmude[8] = 1; else Zhangmude[8] = 0; int whitepointtotal = 0; for (int k = 1; k < 9; k++) { //得到1的個數 whitepointtotal = whitepointtotal + Zhangmude[k]; } if ((whitepointtotal >= 2) && (whitepointtotal <= 6)) { //得到01的個數 int ap = 0; if ((Zhangmude[1] == 0) && (Zhangmude[2] == 1)) ap++; if ((Zhangmude[2] == 0) && (Zhangmude[3] == 1)) ap++; if ((Zhangmude[3] == 0) && (Zhangmude[4] == 1)) ap++; if ((Zhangmude[4] == 0) && (Zhangmude[5] == 1)) ap++; if ((Zhangmude[5] == 0) && (Zhangmude[6] == 1)) ap++; if ((Zhangmude[6] == 0) && (Zhangmude[7] == 1)) ap++; if ((Zhangmude[7] == 0) && (Zhangmude[8] == 1)) ap++; if ((Zhangmude[8] == 0) && (Zhangmude[1] == 1)) ap++; //計算bp int bp = 0; bp += Zhangmude[1]; bp += Zhangmude[2] << 1; bp += Zhangmude[3] << 2; bp += Zhangmude[4] << 3; bp += Zhangmude[5] << 4; bp += Zhangmude[6] << 5; bp += Zhangmude[7] << 6; bp += Zhangmude[8] << 7; if (ap == 1 || bp == 65 || bp == 5 || bp == 20 || bp == 80 || bp == 13 || bp == 22 || bp == 52 || bp == 133 || bp == 141 || bp == 54) { if ((Zhangmude[1] * Zhangmude[3] * Zhangmude[7] == 0) && (Zhangmude[1] * Zhangmude[5] * Zhangmude[7] == 0)) { deletelist.Add(new Point(y, x)); } } } } } } if (deletelist.Count() == 0) break; foreach (var deleteItem in deletelist) { BinaryArray[deleteItem.X, deleteItem.Y] = 255; } deletelist.Clear(); } Bitmap dstBmp = BinaryArrayToBinaryBitmap(BinaryArray); return dstBmp; } #endregion
還有一個問題需要注意,找到要刪除的點之后不能立即刪除,而是把找到的點做標記,等第一步全部遍歷完之后才刪除標記的點。同樣第二步也是這樣。
下面是實驗結果:

本文借鑒了兩篇博客,下面是原文地址:
https://blog.csdn.net/u011941438/article/details/54628836
https://blog.csdn.net/jia20003/article/details/52142992
