Перейти к содержимому
Compvision.ru
Sergiy01

Emgu CV. Преобразование Хафа находит неправильные линии

Recommended Posts

Доброе время суток! Необходимо распознать автомобильный номер на изображении, для увеличения точности решил трансформировать номер так, будто камера смотрит прямо на него. Для выполнения задачи решил найти верхнюю и левую линии, и из них рассчитать углы, но столкнулся с проблемой.

Метод CvInv oke.HoughLines находит большое количество линий, но даже при увеличении порога правильная линия попадается редко.Hough.png.1b18d3812ec336cd8e6305f910bf331e.png

Написал аналог данного метода C# но для поиска только самой явной линии, однако он страдает той же проблемой.MyHough.png.cca65a5c3bcb6f5f4aec7638f4c348cc.png

Разница где то в 15 градусов, если "докинуть" их вручную выходит почти правильно.MyHoughPlus15.png.621b7b8502c552a82a5c839e942e5a05.png

За основу алгоритма был взят CvInv oke.HoughLines, сам метод:

public static unsafe LineSegment2D FindBestLineD(Mat input, double minTheta, double maxTheta, double theta, int rho)
        {
            int width = input.Width;
            int height = input.Height;

            int max_rho = (int)Math.Sqrt(width * width + height * height);
            int min_rho = -max_rho;

            int thetaCount = (int)((maxTheta - minTheta) / theta);
            int rhoCount = (int)(((max_rho - min_rho) + 1) / rho);

            double[] thetaArr = new double[thetaCount];
            double tmp = minTheta;

            double[] sinTheta = new double[thetaCount];
            double[] cosTheta = new double[thetaCount];

            for (int i = 0; i < thetaCount; i++)
            {
                thetaArr = tmp;
                sinTheta = Math.Sin(tmp);
                cosTheta = Math.Cos(tmp);

                tmp += theta;
            }

            int[,] accum = new int[rhoCount, thetaCount];

            Bitmap bitmap = input.Bitmap;
            BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat);

            byte* Pixels = (byte*)bitmapData.Scan0.ToPointer();
            int stride = bitmapData.Stride;
            int shift = 0;

            for (int h = 0; h < height; h++)
            {
                shift = stride * h;
                for (int w = 0; w < width; w++)
                {
                    if (Pixels[shift + w] != 0)
                    {
                        for (int i = 0; i < thetaCount; i++)
                        {
                            int r = (int)(h * sinTheta + w * cosTheta);
                            r += rhoCount / 2;
                            accum[r, i]++;
                        }
                    }
                }
            }

            bitmap.UnlockBits(bitmapData);

            int MaxValue = 0;
            int BestRho = 0;
            double BestTheta = 0;

            for (int t = 0; t < thetaArr.Length; t++)
            {
                for (int r = 0; r < rhoCount; r++)
                {
                    if (accum[r, t] > MaxValue)
                    {
                        MaxValue = accum[r, t];
                        BestTheta = thetaArr[t];
                        BestRho = r - rhoCount / 2;
                    }
                }
            }
            //BestTheta += theta * 15;
            var pt1 = new Point();
            var pt2 = new Point();
            var a = Math.Cos(BestTheta);
            var b = Math.Sin(BestTheta);
            var x0 = a * BestRho;
            var y0 = b * BestRho;
            pt1.X = (int)Math.Round(x0 + input.Width * (-b));
            pt1.Y = (int)Math.Round(y0 + input.Height * (a));
            pt2.X = (int)Math.Round(x0 - input.Width * (-b));
            pt2.Y = (int)Math.Round(y0 - input.Height * (a));
            return new LineSegment2D(pt1, pt2);
        }

Если бы проблема была только с ним, продолжал бы сам искать ошибку, но предложенный в библиотеке вариант тоже "недокручивает" градусы.

Есть ли у кого предположение с чем может быть связан данный феномен, может ли быть тому причиной малый размер изображения (ширина до 200 px )? Или может существуют более удобные решения данной проблемы, при условии что быстродействие является критичным?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Не знаю, что там скроется внутри в шарповом коде, но в OpenCV есть  HoughLines (Standard Hough Line Transform) и  HoughLinesP (Probabilistic Hough Line Transform). Так второй вариант работает намного лучше. А в opencv_contrib есть ещё и более быстрый вариант FastHoughTransform.

Ещё есть cv::LineSegmentDetector, который и быстрый, и может находить короткие отрезки. В общем, я бы сначала поэкспериментировал с тем, что есть.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте учётную запись или войдите для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать учётную запись

Зарегистрируйтесь для создания учётной записи. Это просто!

Зарегистрировать учётную запись

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас


  • Сейчас на странице   0 пользователей

    Нет пользователей, просматривающих эту страницу

×