Как проверить правильность полученной матрицы гомографии?

Этот вопрос уже был спросил, но я до сих пор этого не понимаю. Я получаю гомографическую матрицу, вызывая cv::findHomography из набора точек. Мне нужно проверить, подходит ли это или нет.
Предлагаемый метод состоит в том, чтобы вычислить максимальную ошибку перепечатки для линеек и сравнить ее с порогом. Но после такой фильтрации я продолжаю получать безумные преобразования с объектной ограничивающей коробкой, преобразующейся почти в прямую линию или какой-то странный невыпуклый четырехугольник, с самопересечениями и т.д.
Какие ограничения могут быть использованы для проверки правильности самой матрицы гомографии

Ответы

Ответ 1

Ваш вопрос математичен. Учитывая, что матрица 3x3 определяет, является ли она хорошей жесткой трансформацией. Трудно определить, что "хорошо", но вот некоторые подсказки, которые могут вам помочь.

  • Гомография должна сохранять направление полигональных точек. Проведите простой тест. точки (0,0), (imwidth, 0), (ширина, высота), (0, высота) представляют собой четырехугольник с расположенными по часовой стрелке точками. Примените гомографию к этим точкам и посмотрите, по-прежнему ли они расположены по часовой стрелке, если они вращаются против часовой стрелки. Ваша гомография переворачивает (зеркалирует) изображение, которое иногда по-прежнему в порядке. Но если ваши очки не в порядке, чем у вас есть "плохая гомография".
  • Гомография не слишком сильно изменяет масштаб объекта. Например, если вы ожидаете, что оно сократится или увеличит изображение с коэффициентом до X, просто проверьте это правило. Преобразуйте 4 точки (0,0), (imwidth, 0), (ширина-1, высота), (0, высота) с помощью гомографии и вычислите площадь четырехугольника (opencv-метод вычисления площади многоугольника), если отношение областей слишком велико (или слишком мало), вероятно, у вас есть ошибка.
  • Хорошая гомография обычно использует низкие значения перспективы. Обычно, если размер изображения составляет ~ 1000x1000 пикселей, эти значения должны быть ~ 0,005-0,001. Высокая перспектива приведет к огромным искажениям, которые, вероятно, являются ошибкой. Если вы не знаете, где находятся эти значения, прочитайте мой пост: пытается понять Аффинное преобразование , Он объясняет математику аффинного преобразования, а остальные 2 - перспективные параметры.

Я думаю, что если вы проверите условие выше 3 (условие 2 является самым важным), вы сможете обнаружить большинство проблем. Удачи.

Ответ 2

Изменить: этот ответ не имеет отношения к вопросу, но обсуждение может быть полезно для тех, кто пытается использовать соответствующие результаты для распознавания, как я сделал!

Это может помочь кому-то:

Point2f[] objCorners = { new Point2f(0, 0),
    new Point2f(img1.Cols, 0),
    new Point2f(img1.Cols, img1.Rows),
    new Point2f(0, img1.Rows) };

Point2d[] sceneCorners = MyPerspectiveTransform3(objCorners, homography);
double marginH = img2.Width * 0.1d;
double marginV = img2.Height * 0.1d;
bool homographyOK = isInside(-marginH, -marginV, img2.Width + marginH, img2.Height + marginV, sceneCorners);
if (homographyOK)
    for (int i = 1; i < sceneCorners.Length; i++)
        if (sceneCorners[i - 1].DistanceTo(sceneCorners[i]) < 1)
        {
            homographyOK = false;
            break;
        }
if (homographyOK)
    homographyOK = isConvex(sceneCorners);
if (homographyOK)
    homographyOK = minAngleCheck(sceneCorners, 20d);




     private static bool isInside(dynamic minX, dynamic minY, dynamic maxX, dynamic maxY, dynamic coors)
        {
            foreach (var c in coors)
                if ((c.X < minX) || (c.Y < minY) || (c.X > maxX) || (c.Y > maxY))
                    return false;
            return true;
        }      
        private static bool isLeft(dynamic a, dynamic b, dynamic c)
        {
            return ((b.X - a.X) * (c.Y - a.Y) - (b.Y - a.Y) * (c.X - a.X)) > 0;
        }
        private static bool isConvex<T>(IEnumerable<T> points)
        {
            var lst = points.ToList();
            if (lst.Count > 2)
            {
                bool left = isLeft(lst[0], lst[1], lst[2]);
                lst.Add(lst.First());
                for (int i = 3; i < lst.Count; i++)
                    if (isLeft(lst[i - 2], lst[i - 1], lst[i]) != left)
                        return false;
                return true;
            }
            else
                return false;
        }
        private static bool minAngleCheck<T>(IEnumerable<T> points, double angle_InDegrees)
        {
            //20d * Math.PI / 180d
            var lst = points.ToList();
            if (lst.Count > 2)
            {                
                lst.Add(lst.First());
                for (int i = 2; i < lst.Count; i++)
                {
                    double a1 = angleInDegrees(lst[i - 2], lst[i-1]);
                    double a2 = angleInDegrees(lst[i], lst[i - 1]);
                    double d = Math.Abs(a1 - a2) % 180d;

                    if ((d < angle_InDegrees) || ((180d - d) < angle_InDegrees))
                        return false;
                }
                return true;
            }
            else
                return false;
        }
        private static double angleInDegrees(dynamic v1, dynamic v2)
        {
            return (radianToDegree(Math.Atan2(v1.Y - v2.Y, v1.X - v2.X))) % 360d;
        }
        private static double radianToDegree(double radian)
        {
            var degree = radian * (180d / Math.PI);
            if (degree < 0d)
                degree = 360d + degree;

            return degree;
        }
        static Point2d[] MyPerspectiveTransform3(Point2f[] yourData, Mat transformationMatrix)
        {
            Point2f[] ret = Cv2.PerspectiveTransform(yourData, transformationMatrix);
            return ret.Select(point2fToPoint2d).ToArray();
        }  

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