Zhang-Suen细化算法C#

我正在尝试按照本指南在C#中编写Zhang-Suen细化算法,而不处理边距。

在此处输入图像描述

在函数’zhangsuen’中,我正在从图像’imgUndo’中读取并写入图像’img’。 for循环内的指针dataPtrOrigin_aux用于读取3×3窗口内的9个像素,这样dataPtrOrigin_aux5就是该窗口的中心像素,该窗口将沿着整个图像移动,从左到右,从上到下移动。 在每个像素中,如果validation语句是否为真,则在由指针dataPtrFinal写入的图像中进行相应的改变。

请注意,我将当前像素的邻居存储在8个元素数组中。 因此,它们将按照以下顺序存储:

在此处输入图像描述

internal static void zhangsuen(Image img, Image imgUndo) { unsafe { MIplImage m = img.MIplImage; //Image to be written. MIplImage mUndo = imgUndo.MIplImage; //Image to be read. byte* dataPtrFinal = (byte*)m.imageData.ToPointer(); byte* dataPtrUndo = (byte*)mUndo.imageData.ToPointer(); int width = img.Width; //Width of the image. int height = img.Height; //Height of the image. int nChan = m.nChannels; //3 channels (R, G, B). int wStep = m.widthStep; //Total width of the image (including padding). int padding = wStep - nChan * width; //Padding at the end of each line. int x, y, i; int[] neighbours = new int[8]; //Store the value of the surrounding neighbours in this array. int step; //Step 1 or 2. int[] sequence = { 1, 2, 4, 7, 6, 5, 3, 0, 1 }; int blackn = 0; //Number of black neighbours. int numtransitions = 0; //Number of transitions from white to black in the sequence specified by the array sequence. int changed = 1; //Just so it enters the while. bool isblack = false; int counter = 0; while(changed > 0) { changed = 0; if (counter % 2 == 0) //We want to read all the pixels in the image before going to the next step step = 1; else step = 2; for (y = 0; y < height; y++) { for (x = 0; x  0 && y > 0 && x < width - 1 && y < height - 1) { if (dataPtrOrigin_aux5[0] == 0) isblack = true; if (isblack) { neighbours[0] = dataPtrOrigin_aux1[0]; neighbours[1] = dataPtrOrigin_aux2[0]; neighbours[2] = dataPtrOrigin_aux3[0]; neighbours[3] = dataPtrOrigin_aux4[0]; neighbours[4] = dataPtrOrigin_aux6[0]; neighbours[5] = dataPtrOrigin_aux7[0]; neighbours[6] = dataPtrOrigin_aux8[0]; neighbours[7] = dataPtrOrigin_aux9[0]; for(i = 0; i = 2 && blackn <= 6) && numtransitions == 1) { if (step == 1 && (neighbours[1] == 255 || neighbours[4] == 255 || neighbours[6] == 255) && (neighbours[4] == 255 || neighbours[6] == 255 || neighbours[3] == 255)) { dataPtrFinal[0] = 255; dataPtrFinal[1] = 255; dataPtrFinal[2] = 255; changed++; } if (step == 2 && (neighbours[1] == 255 || neighbours[4] == 255 || neighbours[3] == 255) && (neighbours[1] == 255 || neighbours[6] == 255 || neighbours[3] == 255)) { dataPtrFinal[0] = 255; dataPtrFinal[1] = 255; dataPtrFinal[2] = 255; changed++; } } } } dataPtrFinal += nChan; isblack = false; blackn = 0; numtransitions = 0; } dataPtrFinal += padding; } dataPtrUndo = (byte*)m.imageData.ToPointer(); //Change the image to be read to the one that has just been written. counter++; } } } 

当我结束读取第一张图像并将更改写入图像’img’时(一旦(y = 0; y <height; y ++)的循环结束,我想要我刚才写的图像就是我想要的图像在下一个循环中读取,以便进一步细化。我试图用线完成此操作

 dataPtrUndo = (byte*)m.imageData.ToPointer(); 

虽然计数器的某个值大于0(取决于读取的图像)但是我得到一个错误,表示已经尝试写入受保护的内存,这表示我已经尝试在图像限制之外写入,但是我不明白为什么。 它是我错误地执行dataPtrUndo的最后归因吗?

这是我对Zhang-Suen细化算法的C#实现

 public static bool[][] ZhangSuenThinning(bool[][] s) { bool[][] temp = s; bool even = true; for (int a = 1; a < s.Length-1; a++) { for (int b = 1; b < s[0].Length-1; b++) { if (SuenThinningAlg(a, b, temp, even)) { temp[a][b] = false; } even = !even; } } return temp; } static bool SuenThinningAlg(int x, int y, bool[][] s, bool even) { bool p2 = s[x][y - 1]; bool p3 = s[x + 1][y - 1]; bool p4 = s[x + 1][y]; bool p5 = s[x + 1][y + 1]; bool p6 = s[x][y + 1]; bool p7 = s[x - 1][y + 1]; bool p8 = s[x - 1][y]; bool p9 = s[x - 1][y - 1]; int bp1 = NumberOfNonZeroNeighbors(x, y, s); if (bp1 >= 2 && bp1 <= 6)//2nd condition { if (NumberOfZeroToOneTransitionFromP9(x, y, s) == 1) { if (even) { if (!((p2 && p4) && p8)) { if (!((p2 && p6) && p8)) { return true; } } } else { if (!((p2 && p4) && p6)) { if (!((p4 && p6) && p8)) { return true; } } } } } return false; } static int NumberOfZeroToOneTransitionFromP9(int x, int y, bool[][]s) { bool p2 = s[x][y - 1]; bool p3 = s[x + 1][y - 1]; bool p4 = s[x + 1][y]; bool p5 = s[x + 1][y + 1]; bool p6 = s[x][y + 1]; bool p7 = s[x - 1][y + 1]; bool p8 = s[x - 1][y]; bool p9 = s[x - 1][y - 1]; int A = Convert.ToInt32((p2 == false && p3 == true)) + Convert.ToInt32((p3 == false && p4 == true)) + Convert.ToInt32((p4 == false && p5 == true)) + Convert.ToInt32((p5 == false && p6 == true)) + Convert.ToInt32((p6 == false && p7 == true)) + Convert.ToInt32((p7 == false && p8 == true)) + Convert.ToInt32((p8 == false && p9 == true)) + Convert.ToInt32((p9 == false && p2 == true)); return A; } static int NumberOfNonZeroNeighbors(int x, int y, bool[][]s) { int count = 0; if (s[x-1][y]) count++; if (s[x-1][y+1]) count++; if (s[x-1][y-1]) count++; if (s[x][y+1]) count++; if (s[x][y-1]) count++; if (s[x+1][y]) count++; if (s[x+1][y+1]) count++; if (s[x+1][y-1]) count++; return count; } 

bwang22的答案有效。 有点。 但有两个问题:在没有更多变化发生之前,它不进行迭代。 它做了一个浅的arrays副本。两个问题合作可以说,相互抵消,导致变薄,但不是最好看的。

这是更正后的代码,它可以提供更好看的结果:

前两种方法从Image转换为bool [] []并返回; function没有优化速度; 如果你需要那个去lockbits /不安全..:

 public static bool[][] Image2Bool(Image img) { Bitmap bmp = new Bitmap(img); bool[][] s = new bool[bmp.Height][]; for (int y = 0; y < bmp.Height; y++ ) { s[y] = new bool[bmp.Width]; for (int x = 0; x < bmp.Width; x++) s[y][x] = bmp.GetPixel(x, y).GetBrightness() < 0.3; } return s; } public static Image Bool2Image(bool[][] s) { Bitmap bmp = new Bitmap(s[0].Length, s.Length); using (Graphics g = Graphics.FromImage(bmp)) g.Clear(Color.White); for (int y = 0; y < bmp.Height; y++) for (int x = 0; x < bmp.Width; x++) if (s[y][x]) bmp.SetPixel(x, y, Color.Black); return (Bitmap)bmp; } 

现在修正的细化代码,其中大部分或多或少与bwang22的答案不变:

 public static bool[][] ZhangSuenThinning(bool[][] s) { bool[][] temp = ArrayClone(s); // make a deep copy to start.. int count = 0; do // the missing iteration { count = step(1, temp, s); temp = ArrayClone(s); // ..and on each.. count += step(2, temp, s); temp = ArrayClone(s); // ..call! } while (count > 0); return s; } static int step(int stepNo, bool[][] temp, bool[][] s) { int count = 0; for (int a = 1; a < temp.Length - 1; a++) { for (int b = 1; b < temp[0].Length - 1; b++) { if (SuenThinningAlg(a, b, temp, stepNo == 2)) { // still changes happening? if (s[a][b]) count++; s[a][b] = false; } } } return count; } static bool SuenThinningAlg(int x, int y, bool[][] s, bool even) { bool p2 = s[x][y - 1]; bool p3 = s[x + 1][y - 1]; bool p4 = s[x + 1][y]; bool p5 = s[x + 1][y + 1]; bool p6 = s[x][y + 1]; bool p7 = s[x - 1][y + 1]; bool p8 = s[x - 1][y]; bool p9 = s[x - 1][y - 1]; int bp1 = NumberOfNonZeroNeighbors(x, y, s); if (bp1 >= 2 && bp1 <= 6) //2nd condition { if (NumberOfZeroToOneTransitionFromP9(x, y, s) == 1) { if (even) { if (!((p2 && p4) && p8)) { if (!((p2 && p6) && p8)) { return true; } } } else { if (!((p2 && p4) && p6)) { if (!((p4 && p6) && p8)) { return true; } } } } } return false; } static int NumberOfZeroToOneTransitionFromP9(int x, int y, bool[][] s) { bool p2 = s[x][y - 1]; bool p3 = s[x + 1][y - 1]; bool p4 = s[x + 1][y]; bool p5 = s[x + 1][y + 1]; bool p6 = s[x][y + 1]; bool p7 = s[x - 1][y + 1]; bool p8 = s[x - 1][y]; bool p9 = s[x - 1][y - 1]; int A = Convert.ToInt32((!p2 && p3 )) + Convert.ToInt32((!p3 && p4 )) + Convert.ToInt32((!p4 && p5 )) + Convert.ToInt32((!p5 && p6 )) + Convert.ToInt32((!p6 && p7 )) + Convert.ToInt32((!p7 && p8 )) + Convert.ToInt32((!p8 && p9 )) + Convert.ToInt32((!p9 && p2 )); return A; } static int NumberOfNonZeroNeighbors(int x, int y, bool[][] s) { int count = 0; if (s[x - 1][y]) count++; if (s[x - 1][y + 1]) count++; if (s[x - 1][y - 1]) count++; if (s[x][y + 1]) count++; if (s[x][y - 1]) count++; if (s[x + 1][y]) count++; if (s[x + 1][y + 1]) count++; if (s[x + 1][y - 1]) count++; return count; } 

我保留了原始的偶数标记,但是通过比较步骤编号来调用它。 我直接使用bools保存了几个字符..

最后一个函数来获取嵌套的2d数组的深层副本:

 public static T[][] ArrayClone(T [][] A) { return A.Select(a => a.ToArray()).ToArray(); } 

这是使用两个PictureBox调用它的方法:

 pictureBox1.Image = Image.FromFile("D:\\RCdemo.png"); bool[][] t = Image2Bool(pictureBox1.Image); t = ZhangSuenThinning(t); pictureBox2.Image = Bool2Image(t); 

我附上一张测试图片。

细化截图