Opencv arcLength()和contourArea()返回意外值

Opencv arcLength()和contourArea()返回意外值,opencv,Opencv,我试图测量轮廓的长度: 绿线是在轮廓上计算的HoughLineP。通过计算绿线上的欧几里德距离,我得到了153.88。但是,轮廓上的arcLength()给出了364.71,此时它应该比HoughLineP长约1/8。为什么arcLength()返回的长度几乎是轮廓长度的两倍?这是我的密码: def euclid_distance(line): dx = line[0] - line[2] dy = line[1] - line[3] return math.sqrt(

我试图测量轮廓的长度:

绿线是在轮廓上计算的HoughLineP。通过计算绿线上的欧几里德距离,我得到了
153.88
。但是,轮廓上的
arcLength()
给出了
364.71
,此时它应该比HoughLineP长约1/8。为什么
arcLength()
返回的长度几乎是轮廓长度的两倍?这是我的密码:

def euclid_distance(line):
    dx = line[0] - line[2]
    dy = line[1] - line[3]
    return math.sqrt(dx*dx + dy*dy)

_, contours, hierarchy = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contour = contours[1]
cnt_perimeter = cv2.arcLength(contour, False)

lines_p = cv2.HoughLinesP(mat_cnt, 1, np.pi/180, 30, minLineLength=10, maxLineGap=5)

line_dist = 0
for lp in lines_p:
    for l in lp:
        x1,y1,x2,y2 = l
        cv2.line(mat_cnt,(x1,y1),(x2,y2),(0,200,0),2)
        line_dist += euclid_distance(l)
print cnt_perimeter, line_dist, contour.size
--
364.710676908 153.883072493 204
编辑:

这是原始轮廓:

以下是要点:

[[[386, 477]], [[385, 478]], [[378, 478]], [[377, 479]], [[373, 479]], [[372, 480]], [[368, 480]], [[367, 481]], [[361, 481]], [[360, 482]], [[355, 482]], [[354, 483]], [[348, 483]], [[347, 484]], [[342, 484]], [[341, 485]], [[336, 485]], [[335, 486]], [[329, 486]], [[328, 487]], [[324, 487]], [[323, 488]], [[317, 488]], [[316, 489]], [[311, 489]], [[310, 490]], [[306, 490]], [[305, 491]], [[299, 491]], [[298, 492]], [[293, 492]], [[292, 493]], [[287, 493]], [[286, 494]], [[279, 494]], [[278, 495]], [[275, 495]], [[274, 496]], [[269, 496]], [[268, 497]], [[263, 497]], [[262, 498]], [[255, 498]], [[254, 499]], [[249, 499]], [[248, 500]], [[241, 500]], [[240, 501]], [[220, 501]], [[219, 502]], [[216, 502]], [[219, 502]], [[220, 501]], [[240, 501]], [[241, 500]], [[248, 500]], [[249, 499]], [[254, 499]], [[255, 498]], [[262, 498]], [[263, 497]], [[268, 497]], [[269, 496]], [[274, 496]], [[275, 495]], [[278, 495]], [[279, 494]], [[286, 494]], [[287, 493]], [[292, 493]], [[293, 492]], [[298, 492]], [[299, 491]], [[305, 491]], [[306, 490]], [[310, 490]], [[311, 489]], [[316, 489]], [[317, 488]], [[323, 488]], [[324, 487]], [[328, 487]], [[329, 486]], [[335, 486]], [[336, 485]], [[341, 485]], [[342, 484]], [[347, 484]], [[348, 483]], [[354, 483]], [[355, 482]], [[360, 482]], [[361, 481]], [[367, 481]], [[368, 480]], [[372, 480]], [[373, 479]], [[377, 479]], [[378, 478]], [[385, 478]], [[386, 477]], [[390, 477]]]
另外,使用以下代码返回的轮廓区域为
0.0

approx = cv2.approxPolyDP(contour, 5, True)
print cv2.contourArea(approx)
---
0.0

为什么等高线面积这么小?直线部分已经是154(HoughLineP的长度)。

首先让我们对这个问题进行一个简单的测试:

让我们创建一条直线并计算欧几里德距离和弧长

import cv2
import numpy as np

a = np.array([(1,1), (2,2), (3,3), (4,4), (5,5), (6,6), (7,7)])

cv2.arcLength(a, False) # Prints 8.485281229019165
math.sqrt((7-1) * (7-1) + (7-1) * (7-1)) # prints 8.48528137423857
他们两个(几乎)相等

那么,有什么不对呢?我唯一的解释是,你的观点不在一条直线上,或者几乎不在一条直线上

例如,让我们将上一个示例中的直线中的点(0,0)添加到数组的末尾

a = np.array([(1,1), (2,2), (3,3), (4,4), (5,5), (6,6), (7,7), (0,0)])
cv2.arcLength(a, False) # prints 18.38477635383606
math.sqrt((7-0) * (7-0) + (7-0) * (7-0)) # 9.899494936611665
如你所见,弧长增加了一倍。。。发生了什么事?这个函数实际上会计算点之间的最小欧几里德距离。。。所以,如果你有一条完美的线,并且顺序正确,你会得到相同的结果(或者非常接近),但是如果有一点不符合顺序,它可能会给出不同的结果

几句话:

用欧几里得距离得到153。。。然后,你的线条在某些部分比1个像素厚,得到204个点(考虑到每个像素至少1个点),这意味着轮廓可以检测到一条线条中的2条线条,这意味着你将获得更多的周长

您可以尝试使用近似多边形来获得较少的点并轻松查看发生的情况,或者如果使用FindCountors获得轮廓,则可以使用
CV\u CHAIN\u近似\u SIMPLE
对其进行压缩,并查看其错误


我希望这能消除你的疑虑,如果不只是给我留下评论的话。

如果你一个接一个地检查等高线中的点,你会发现它们中大约有一半是相同的

前十名:

[[257 113]  <-- 0
 [256 114]  <-- 1
 [249 114]  <-- 2
 [248 115]  <-- 3
 [244 115]
 [243 116]
 [239 116]
 [238 117]
 [232 117]
 [231 118]]
...

[[257 113]好吧,这是一个轮廓,即包围那条线的多边形。因此,我希望轮廓的周长(这是您正在计算的)大约是那条线长度的2倍,大致如此。@DanMašek但在他的代码中,flag
closed=False
cv2.arcLength(轮廓,False)
。发布原始图像。@消音器是的,但轮廓有204个点,所以“未闭合”位可能会产生非常小的差异。一个要复制的样本图像肯定会有用。@DanMašek但如果直线长度为154,那么轮廓不应该至少有300个点吗?你如何确定非闭合位是小的?我不认为边界点的顺序是个问题。但是你怎么会认为line大于1像素?当然,轮廓中的点比直线部分的长度多,但轮廓不是多边形吗?一条直线周围的多边形的点应该比直线上的点多。@JohnMunroe正是我的观点,如果有一条直线周围的多边形作为轮廓,它可能会绕直线旋转,或者按Z字形旋转haps…然而,你会有更多的长度。并不总是一个多边形,这取决于你是如何找到它的,如果你压缩它或类似的东西,但它很可能是一个…然后,每段长度加在一起将超过开始/结束长度,对于一条直线周围的多边形,它的大小至少应该是y的两倍你计算周长时使用的不是最大长度。但是我检查了轮廓的
contourArea()
,它是
0.0
(请参见编辑)。但是多边形或线条周围的任何形状不应该有正面积吗?@johnmurroe可能是由于近似多边形…尝试计算没有它的面积
contourArea(contour)
也给出了
0.0
。我应该补充一点,原始图像是一条精明的边缘,因此轮廓环绕着一条线。不确定这是否会产生差异。
[[232 117]
 [238 117]
 [239 116]
 [243 116]
 [244 115]  
 [248 115]  <-- 3
 [249 114]  <-- 2
 [256 114]  <-- 1
 [257 113]  <-- 0
 [261 113]]