Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
532 views
in Technique[技术] by (71.8m points)

image - Zhang-Suen thinning algorithm C#

I am trying to write a Zhang-Suen thinning algorithm in C# following this guideline, without processing the margins.

enter image description here

In the function 'zhangsuen', I am reading from the image 'imgUndo' and writting to the image 'img'. The pointers dataPtrOrigin_aux inside the for cycles are used to read the 9 pixels inside a 3x3 window such that dataPtrOrigin_aux5 is the central pixel of this window, and that window will move along the whole image, moving from left to right and from top to bottom. In each pixel, if the if the statements are verified to be true, the corresponding changes are made in the image to be written by the pointer dataPtrFinal.

Note that I stored the neighbours of the current pixel inside a 8 element array. As such, they will be stored following this order:

enter image description here

        internal static void zhangsuen(Image<Bgr, byte> img, Image<Bgr, byte> 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 < width; x++)
                    {

                            byte* dataPtrOrigin_aux1 = (byte*)(dataPtrUndo + (y - 1) * m.widthStep + (x - 1) * m.nChannels);
                            byte* dataPtrOrigin_aux2 = (byte*)(dataPtrUndo + (y - 1) * m.widthStep + (x) * m.nChannels);
                            byte* dataPtrOrigin_aux3 = (byte*)(dataPtrUndo + (y - 1) * m.widthStep + (x + 1) * m.nChannels);
                            byte* dataPtrOrigin_aux4 = (byte*)(dataPtrUndo + (y) * m.widthStep + (x - 1) * m.nChannels);
                            byte* dataPtrOrigin_aux5 = (byte*)(dataPtrUndo + (y) * m.widthStep + (x) * m.nChannels);
                            byte* dataPtrOrigin_aux6 = (byte*)(dataPtrUndo + (y) * m.widthStep + (x + 1) * m.nChannels);
                            byte* dataPtrOrigin_aux7 = (byte*)(dataPtrUndo + (y + 1) * m.widthStep + (x - 1) * m.nChannels);
                            byte* dataPtrOrigin_aux8 = (byte*)(dataPtrUndo + (y + 1) * m.widthStep + (x) * m.nChannels);
                            byte* dataPtrOrigin_aux9 = (byte*)(dataPtrUndo + (y + 1) * m.widthStep + (x + 1) * m.nChannels);


                        if (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 <= 7; i++)
                                {
                                    if (neighbours[i] == 0)
                                        blackn++;

                                    if (neighbours[sequence[i]] - neighbours[sequence[i + 1]] == 255) //número de transi??es de branco para preto, seguindo a ordem do vector sequence
                                        numtransitions++;
                                }


                                if ((blackn >= 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++;

            }


        }
    }

As I end reading the first image and writing the changes to the image 'img' (As soon as the cycle for (y = 0; y < height; y++) ends I want the image I have just written to be the one I will read in the next cycle so that further thinning is made. I tried to accomplish this with the line

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

Although at some value of counter that is greater than 0 (depends on the image that is read) I get an error that says that protected memory has been tried to be written which indicates I have tried to write outside of the image limits, but I don't understand why. Is it the last attribution to dataPtrUndo that I am doing erroneously?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Here is my C# implementation of Zhang-Suen thinning algorithm

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...