这个问题已经被问过了,但我还是不明白。我通过调用cv::findHomography
一组点来获得一个单应矩阵。我需要检查它是否相关。
所提出的方法是计算内点的最大重投影误差并将其与阈值进行比较。但是经过这样的过滤后,我不断得到疯狂的变换,对象边界框几乎变成一条直线或一些奇怪的非凸四边形,带有自相交等。
可以使用哪些约束来检查单应矩阵本身是否足够?
问问题
14605 次
2 回答
38
你的问题是数学问题。给定一个 3x3 的矩阵,决定它是否代表一个好的刚性变换。很难定义什么是“好”,但这里有一些线索可以帮助你
- 单应性应保持多边形点的方向。设计一个简单的测试。点 (0,0), (imwidth,0), (width,height), (0,height) 表示具有顺时针排列点的四边形。在这些点上应用单应性,看看它们是否仍然是顺时针排列的,如果它们变成逆时针方向,你的单应性正在翻转(镜像)有时仍然可以的图像。但是,如果你的点是乱序的,那么你就有一个“糟糕的单应性”
- 单应性不会过多地改变对象的比例。例如,如果您希望它将图像缩小或放大 X 倍,只需检查此规则。用单应性变换4个点(0,0),(imwidth,0),(width-1,height),(0,height)并计算四边形的面积(opencv计算多边形面积的方法)如果比率面积太大(或太小),您可能有错误。
- 良好的单应性通常使用较低的透视值。通常,如果图像的大小为 ~1000x1000 像素,则这些值应为 ~0.005-0.001。高透视会导致巨大的失真,这可能是一个错误。如果您不知道这些值的位置,请阅读我的帖子: 尝试理解仿射变换 。它解释了仿射变换数学,其他 2 个值是透视参数。
我认为如果您检查上述 3 个条件(条件 2 是最重要的),您将能够检测到大部分问题。祝你好运
于 2013-02-19T19:02:40.347 回答
1
编辑:这个答案与问题无关,但讨论可能对像我一样尝试使用匹配结果进行识别的人有所帮助!
这可能会帮助某人:
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();
}
于 2017-01-24T12:27:30.547 回答