Algoritmo di dimagrimento Zhang-Suen C #

Sto cercando di scrivere un algoritmo di diradamento di Zhang-Suen in C # seguendo questa linea guida, senza elaborare i margini.

inserisci la descrizione dell'immagine qui

Nella funzione ‘zhangsuen’, sto leggendo dall’immagine ‘imgUndo’ e scrivendo sull’immagine ‘img’. I puntatori dataPtrOrigin_aux all’interno dei cicli for vengono utilizzati per leggere i 9 pixel all’interno di una finestra 3×3 in modo che dataPtrOrigin_aux5 sia il pixel centrale di questa finestra e tale finestra si sposterà sull’intera immagine, spostandosi da sinistra a destra e dall’alto verso il basso. In ogni pixel, se le affermazioni sono verificate come vere, le modifiche corrispondenti vengono apportate nell’immagine che deve essere scritta dal puntatore dataPtrFinal.

Si noti che ho memorizzato i vicini del pixel corrente all’interno di un array di 8 elementi. In quanto tali, verranno memorizzati seguendo questo ordine:

inserisci la descrizione dell'immagine qui

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++; } } } 

Mentre finisco di leggere la prima immagine e scrivo le modifiche all’immagine ‘img’ (non appena il ciclo per (y = 0; y <altezza; y ++) termina voglio che l'immagine che ho appena scritto sia quella che voglio leggere nel prossimo ciclo in modo che venga effettuato un ulteriore diradamento. Ho cercato di farlo con la linea

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

Sebbene ad un valore di contatore maggiore di 0 (dipende dall’immagine che viene letta) viene visualizzato un errore che dice che è stata tentata la scrittura di una memoria protetta che indica che ho provato a scrivere al di fuori dei limiti dell’immagine, ma io non capisco perché È l’ultima attribuzione a dataPtrUndo che sto facendo erroneamente?

    Ecco la mia implementazione in C # dell’algoritmo di diradamento di Zhang-Suen

     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; } 

    la risposta di bwang22 funziona. Una specie di. Ma con due problemi: non fa le iterazioni finché non si verificano più cambiamenti. E fa una copia superficiale della matrice .. I due problemi cooperano per così dire, annullandosi a vicenda, risultando in un diradamento, ma non il migliore.

    Ecco il codice corretto, che offre un risultato più bello:

    Primi due metodi per convertire da Immagine a bool [] [] e viceversa; le funzioni non sono ottimizzate per la velocità; se ne hai bisogno vai per lockbits / non sicuro ..:

     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; } 

    Ora il codice di diradamento corretto, in gran parte più o meno invariato dalla risposta di 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; } 

    Ho mantenuto il flag pari originale, ma lo chiamo confrontando un numero di step. E ho salvato alcuni personaggi usando i bool direttamente ..

    Finalmente una funzione per ottenere una copia profonda dell'array 2d nidificato:

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

    Ecco come chiamarlo, usando due PictureBox:

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

    Appendo un'immagine di prova.

    screenshot dimagrante