OpenCV,C ++:两点之间的距离

19

我们正在尝试制作一个游戏,当玩家在摄像头前形成一组特定的手势时,函数将被执行。为了处理图像,我们使用OpenCV 2.3。

在图像处理过程中,我们试图找到两点之间的距离。 我们已经知道可以用勾股定理很容易地完成这个任务,但是众所周知,勾股定理需要大量的计算资源,我们希望以尽可能低的资源消耗完成这项任务。

我们想知道是否存在OpenCV内置函数或C++标准库函数,可以处理两点之间的低资源消耗计算。 我们有这些点的坐标,它们是像素值(当然)。

额外信息: 以往的经验告诉我们,OpenCV和其他库都经过了重度优化。例如,我们试图通过for循环遍历每个像素来更改相机实时图像流的RGB值。但这给我们提供了低帧率输出。相反,我们决定使用OpenCV内置函数,这样就能获得高帧率的输出。


1
过早的优化?如果你不需要精确的距离,而只是一些距离度量,那么你可以不用平方根。但请确保它是导致性能问题的函数。 - Bart
1
你需要距离还是平方距离可以吗?勾股定理中最昂贵的部分是计算平方根,如果你可以不用它,那么只需进行几次乘法即可。 - David Rodríguez - dribeas
也许我没有理解这个图示,但是如果两条虚线的长度相同(也就是说,两点之间的距离在任何情况下都是相同的),那么没有平方根也不会有任何影响。旋转情况也不会改变这一点。 - Bart
我试图通过这个例子来展示旋转确实很重要,并且在使用欧几里得距离(带有平方根和“乘方”符号)、点线或简单的长度近似值dist = |x_a - x_b| + |y_a - y_b|时会产生不同的结果。 - Marc Pilgaard
请使用另一个图像托管服务,以免将来出现存储过期的问题。当前链接的Imageshack图像无法访问。 - StockB
显示剩余3条评论
4个回答

46

你应该尝试这个

cv::Point a(1, 3);
cv::Point b(5, 6);
double res = cv::norm(a-b);//Euclidian distance

1
我正在尝试获取两个彩色点(红色和绿色)之间的距离,一旦它们几乎重叠或距离小于0.1毫米,我需要捕获图像。我正在使用norm函数(cv::norm(cv::Point(rposX, rposY)-cv::Point(bposX, bposY));),但它返回的值是100多,即使点非常接近。如何将norm返回值转换为毫米或任何其他单位? - AmJa

23

正如你正确指出的,有一个OpenCV函数可以完成你的一部分工作 :)

(还要检查另一种方法)

它被称为magnitude(),它会为您计算距离。如果您有一个超过4个向量的向量要计算距离,它将使用SSE(我认为)来加快速度。

现在,问题是它只计算幂的平方,你必须手动计算差异。(请查看文档)。但是,如果您也使用OpenCV函数进行计算,它应该很快。

Mat pts1(nPts, 1, CV_8UC2), pts2(nPts, 1, CV_8UC2);
// populate them
Mat diffPts = pts1-pts2;
Mat ptsx, ptsy;
// split your points in x and y vectors. maybe separate them from start
Mat dist;
magnitude(ptsx, ptsy, dist); // voila!

另一种方法是使用非常快的sqrt函数:

// 15 times faster than the classical float sqrt. 
// Reasonably accurate up to root(32500)
// Source: http://supp.iar.com/FilesPublic/SUPPORT/000419/AN-G-002.pdf

unsigned int root(unsigned int x){
    unsigned int a,b;
    b     = x;
    a = x = 0x3f;
    x     = b/x;
    a = x = (x+a)>>1;
    x     = b/x;
    a = x = (x+a)>>1;
    x     = b/x;
    x     = (x+a)>>1;
    return(x);  
}

这似乎是我们正在寻找的东西,但我有两个问题(我目前不在我的小组旁边,实际上也不是坐在图像处理程序旁边的人)。 'Mat'不是旧版OpenCV语法的一部分吗?2.0或其他版本? 此外,快速平方根似乎是一个很好的解决方案!如果我们无法让'Magnitude();'正常工作,我们可能会坚持使用它。 - Marc Pilgaard
我不知道距离,但这里有另一个函数可以给出距离(只是提一下来反弹这个想法)。cvInitLineIterator() 返回连接两点的线上像素数。然而它也存储了遇到的线上像素 - 这就是我们使用它的原因。长度是一个“副作用”。http://opencv.willowgarage.com/documentation/drawing_functions.html#initlineiterator - AruniRC
1
Mat是一种新的做事方式。CvMat和IplImage是C语法的一部分。 - Sam
你的快速平方根的答案看起来很合理,但它无法测量小于100的整数值。我们正在谈论与正常sqrt()和root()之间5个整数值的差异,直到需要计算100+的值。 - Marc Pilgaard
1
sqrt approx仅仅是一个近似值,你必须确保它符合你的需求。评论中的链接包含算法的详细描述和准确度图表。 - Sam
Java开发者们记得要使用java.lang.Math,而不是自己实现power或者平方根。 - ZZ 5

4

这应该是一条评论,但我没有足够的声望(50?)| -(因此我将其发布为答案。

在你的问题的评论中,人们试图告诉你的是,如果只涉及比较距离,那么你可以简单地使用 d =(dx * dx + dy * dy)=(x1-x2)(x1-x2)+(y1-y2)(y1-y2) 从而避免平方根。但你当然不能跳过平方升高。


主要问题是,我们将会有很多缺陷和很多比较。如果我们要比较的值有太大的偏移量,我们要么会得到错误的输出,要么就需要花费很多时间来优化我们的比较算法以匹配不同的偏移量。 - Marc Pilgaard

1

勾股定理是最快的方法,而且它并不像你想象的那么昂贵。以前因为要开方运算,所以费用比较高。但现代处理器通常可以在几个周期内完成。

如果你真的需要速度,可以使用图形卡上的OpenCL进行图像处理。


也许它不会消耗太多资源,但这是我们第一次处理图像,并且我们试图在其旁边运行游戏。最终的资源消耗对我们来说是未知的,因此我们试图保持谨慎。OpenCL可能是一个解决方案,但我们没有必要的时间去探索它 :) - Marc Pilgaard

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接