Jump to content
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 )? Или может существуют более удобные решения данной проблемы, при условии что быстродействие является критичным?

Share this post


Link to post
Share on other sites

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

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

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


  • Recently Browsing   0 members

    No registered users viewing this page.

×