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

时间:2018-01-14 16:28:18

标签: opencv

我试图测量轮廓的长度:

enter image description here

绿线是在轮廓上计算的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

编辑:

这是原始轮廓:

enter image description here

以下是要点:

[[[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的长度)。

2 个答案:

答案 0 :(得分:3)

首先让我们把问题放到一个简单的测试中:

让我们创建一条线并计算欧氏距离和arcLength。

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

正如你所看到的,arcLength增加了一倍......发生了什么?该函数实际上在点之间实现了微小的欧几里德距离......所以,如果你有一个完美的线并且按照正确的顺序你会得到相同的结果(或者真的很接近),但如果一个点出现故障,它可能会给出有些不同。

几位评论:

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

您可以尝试进行近似聚合以获得更少的点并轻松查看正在发生的事情,或者如果您使用findCountours获得轮廓,那么您可以使用CV_CHAIN_APPROX_SIMPLE来压缩它并查看它有什么问题

我希望这可以解决你的疑问,如果不是给我留言。

答案 1 :(得分:2)

如果您逐一检查轮廓中的点,您会发现其中大约一半是相同的。

前十名:

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

最后十点:

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

签入图片:

enter image description here

您可以找到right-topleft-bottomright-top的分数。

也就是说,虽然轮廓代表一条线,但它的面积为零,但它是doubled line,它的arclen是霍夫找到的距离的两倍。

102分,在set之后,只剩下52分。

如果您知道它是一条线,那么执行set,然后对points in the set进行排序,然后再次计算arclen,它不会加倍。

英语不好。