Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

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

c# - Hough Line Transform implementation

I am trying to implement Hough Line Transform.

Input. I am using the following image as input. This single line is expected to produce only one intersection of sine waves in the output.

enter image description here

Desired behavior. my source code is expected to produce the following output as it was generated by the sample application of AForge framework.

enter image description here

Here, we can see:

  1. the dimension of the output is identical to the input image.
  2. the intersection of sine waves are seen at almost at the center.
  3. the intersection pattern of waves is very small and simple.

Present behavior. My source code is producing the following output which is different than that of the output generated by AForge.

enter image description here

  • the intersection is not at the center.
  • the wave patterns are also different.

Why is my code producing a different output?

.

Source Code

I have written the following code myself. The following is a Minimal, Complete, and Verifiable source code.

public class HoughMap
{
    public int[,] houghMap { get; private set; }
    public int[,] image { get; set; }

    public void Compute()
    {
        if (image != null)
        {
            // get source image size
            int inWidth = image.GetLength(0);
            int inHeight = image.GetLength(1);

            int inWidthHalf = inWidth / 2;
            int inHeightHalf = inHeight / 2;

            int outWidth = (int)Math.Sqrt(inWidth * inWidth + inHeight * inHeight);
            int outHeight = 180;
            int outHeightHalf = outHeight / 2;

            houghMap = new int[outWidth, outHeight];

            // scanning through each (x,y) pixel of the image--+
            for (int y = 0; y < inHeight; y++)               //|
            {                                                //|
                for (int x = 0; x < inWidth; x++)//<-----------+
                {
                    if (image[x, y] != 0)//if a pixel is black, skip it.
                    {
                        // We are drawing some Sine waves. So, it may 
                        // vary from -90 to +90 degrees.
                        for (int theta = -outHeightHalf; theta < outHeightHalf; theta++)
                        {
                            double rad = theta * Math.PI / 180;
                            // respective radius value is computed
                            //int radius = (int)Math.Round(Math.Cos(rad) * (x - inWidthHalf) - Math.Sin(rad) * (y - inHeightHalf));
                            //int radius = (int)Math.Round(Math.Cos(rad) * (x + inWidthHalf) - Math.Sin(rad) * (y + inHeightHalf));
                            int radius = (int)Math.Round(Math.Cos(rad) * (x) - Math.Sin(rad) * (outHeight - y));

                            // if the radious value is between 1 and 
                            if ((radius > 0) && (radius <= outWidth))
                            {
                                houghMap[radius, theta + outHeightHalf]++;
                            }
                        }
                    }
                }
            }
        }
    }
}

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        Bitmap bitmap = (Bitmap)pictureBox1.Image as Bitmap;

        int[,] intImage = ToInteger(bitmap);

        HoughMap houghMap = new HoughMap();
        houghMap.image = intImage;
        houghMap.Compute();

        int[,] normalized = Rescale(houghMap.houghMap);

        Bitmap hough = ToBitmap(normalized, bitmap.PixelFormat);

        pictureBox2.Image = hough;
    }

    public static int[,] Rescale(int[,] image)
    {
        int[,] imageCopy = (int[,])image.Clone();

        int Width = imageCopy.GetLength(0);
        int Height = imageCopy.GetLength(1);

        int minVal = 0;
        int maxVal = 0;

        for (int j = 0; j < Height; j++)
        {
            for (int i = 0; i < Width; i++)
            {
                double conv = imageCopy[i, j];

                minVal = (int)Math.Min(minVal, conv);
                maxVal = (int)Math.Max(maxVal, conv);
            }
        }

        int minRange = 0;
        int maxRange = 255;

        int[,] array2d = new int[Width, Height];

        for (int j = 0; j < Height; j++)
        {
            for (int i = 0; i < Width; i++)
            {
                array2d[i, j] = (maxRange - minRange) * (imageCopy[i,j] - minVal) / (maxVal - minVal) + minRange;
            }
        }

        return array2d;
    }

    public int[,] ToInteger(Bitmap input)
    {
        int Width = input.Width;
        int Height = input.Height;

        int[,] array2d = new int[Width, Height];

        for (int y = 0; y < Height; y++)
        {
            for (int x = 0; x < Width; x++)
            {
                Color cl = input.GetPixel(x, y);

                int gray = (int)Convert.ChangeType(cl.R * 0.3 + cl.G * 0.59 + cl.B * 0.11, typeof(int));

                array2d[x, y] = gray;
            }
        }

        return array2d;
    }

    public Bitmap ToBitmap(int[,] image, PixelFormat pixelFormat)
    {
        int[,] imageCopy = (int[,])image.Clone();

        int Width = imageCopy.GetLength(0);
        int Height = imageCopy.GetLength(1);

        Bitmap bitmap = new Bitmap(Width, Height, pixelFormat);

        for (int y = 0; y < Height; y++)
        {
            for (int x = 0; x < Width; x++)
            {
                int iii = imageCopy[x, y];

                Color clr = Color.FromArgb(iii, iii, iii);

                bitmap.SetPixel(x, y, clr);
            }
        }

        return bitmap;
    }
}

See Question&Answers more detail:os

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

1 Reply

0 votes
by (71.8m points)

I have solved the problem from this link. The source code from this link is the best one I have ever came across.

enter image description here

public class HoughMap
{
    public int[,] houghMap { get; private set; }
    public int[,] image { get; set; }

    public void Compute()
    {
        if (image != null)
        {
            // get source image size
            int Width = image.GetLength(0);
            int Height = image.GetLength(1);

            int centerX = Width / 2;
            int centerY = Height / 2;

            int maxTheta = 180;
            int houghHeight = (int)(Math.Sqrt(2) * Math.Max(Width, Height)) / 2;
            int doubleHeight = houghHeight * 2;
            int houghHeightHalf = houghHeight / 2;
            int houghWidthHalf = maxTheta / 2;

            houghMap = new int[doubleHeight, maxTheta];

            // scanning through each (x,y) pixel of the image--+
            for (int y = 0; y < Height; y++)                 //|
            {                                                //|
                for (int x = 0; x < Width; x++)//<-------------+
                {
                    if (image[x, y] != 0)//if a pixel is black, skip it.
                    {
                        // We are drawing some Sine waves.  
                        // It may vary from -90 to +90 degrees.
                        for (int theta = 0; theta < maxTheta; theta++)
                        {
                            double rad = theta *Math.PI / 180;
                            // respective radius value is computed
                            int rho = (int)(((x - centerX) * Math.Cos(rad)) + ((y - centerY) * Math.Sin(rad)));

                            // get rid of negative value
                            rho += houghHeight;

                            // if the radious value is between 
                            // 1 and twice the houghHeight 
                            if ((rho > 0) && (rho <= doubleHeight))
                            {
                                houghMap[rho, theta]++;
                            }
                        }
                    }
                }
            }
        }
    }
}

Just look at this C++ code, and this C# code. So, complicated and messy that my brain got arrested. Especially, the C++ one. I never anticipated someone to store 2D values in a 1D array.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...