Реализация трансформации Hough Line

Я пытаюсь реализовать Hough Line Transform.

Ввод. Я использую следующее изображение в качестве ввода. Ожидается, что эта единственная линия произведет только одно пересечение синусоидальных волн на выходе.

введите описание изображения здесь

Желаемое поведение. ожидается, что мой исходный код выдаст следующий вывод, так как он был сгенерирован образцом приложения платформы AForge.

введите описание изображения здесь

Здесь мы можем увидеть:

  1. размерность вывода идентична входному изображению.
  2. пересечение синусоидальных волн видно почти в центре.
  3. картина пересечения волн очень мала и проста.

Настоящее поведение. Мой исходный код производит следующий вывод, который отличается от вывода, сгенерированного AForge.

введите описание изображения здесь

  • пересечение не в центре.
  • образцы волны также различны.

Почему мой код производит другой вывод?

,

Исходный код

Я сам написал следующий код. Ниже приведен минимальный, полный и проверяемый исходный код.

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

1 ответ

Решение

Я решил проблему по этой ссылке. Исходный код по этой ссылке - лучший, который я когда-либо встречал.

введите описание изображения здесь

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

Просто посмотрите на этот код C++ и этот код C#. Так сложно и грязно, что мой мозг был арестован. Особенно C++. Я никогда не ожидал, что кто-то будет хранить 2D-значения в одномерном массиве.

Другие вопросы по тегам