Tl; DR:如何测量轮廓所包围的区域而不仅仅是轮廓线本身
我想在下面的图像中找到对象的轮廓,并且有一个适用于大多数情况的代码。
阈值和自适应阈值处理不能可靠地工作。我使用Canny边缘检测并检查区域以确保我找到了正确的轮廓。但是,偶尔会有一个间隙无法通过形态学闭合来闭合,形状是正确的,但该区域是轮廓线而不是整个物体。
我通常使用convexHull,因为它返回对象周围的轮廓。然而,在这种情况下,物体沿顶部向内弯曲并且凸出的船体不再是该区域的良好近似。
我尝试使用approxPolyDP,但返回的区域是轮廓线而不是对象。
如何让approxPolyDP在对象周围返回类似的闭合轮廓,就像使用convexHull函数一样?
使用上图说明这个代码:
import cv2
img = cv2.imread('Img_0.jpg',0)
cv2.imshow('Original', img)
edges = cv2.Canny(img,50,150)
cv2.imshow('Canny', edges)
contours, hierarchy = cv2.findContours(edges,cv2.cv.CV_RETR_EXTERNAL,cv2.cv.CV_CHAIN_APPROX_NONE)
cnt = contours[1] #I have a function to do this but for simplicity here by hand
M = cv2.moments(cnt)
print('Area = %f \t' %M['m00'], end="")
cntHull = cv2.convexHull(cnt, returnPoints=True)
cntPoly=cv2.approxPolyDP(cnt, epsilon=1, closed=True)
MHull = cv2.moments(cntHull)
MPoly = cv2.moments(cntPoly)
print('Area after Convec Hull = %f \t Area after apporxPoly = %f \n' %(MHull['m00'], MPoly['m00']), end="")
x, y =img.shape
size = (w, h, channels) = (x, y, 1)
canvas = np.zeros(size, np.uint8)
cv2.drawContours(canvas, cnt, -1, 255)
cv2.imshow('Contour', canvas)
canvas = np.zeros(size, np.uint8)
cv2.drawContours(canvas, cntHull, -1, 255)
cv2.imshow('Hull', canvas)
canvas = np.zeros(size, np.uint8)
cv2.drawContours(canvas, cntPoly, -1, 255)
cv2.imshow('Poly', canvas)
代码的输出是
Area = 24.500000 Area after Convec Hull = 3960.500000 Area after apporxPoly = 29.500000
答案 0 :(得分:1)
这是来自geosensor.net的非常有前途的ppt,它讨论了几种算法。我的建议是使用半径有限的摆臂法。
另一个完全没有经过测试的离墙概念是按行和列扫描图像(更多方向增加精度)和线交叉点之间区域的颜色:
_______
/-------\
/---------\
--------+---------+------ (fill between 2 intersections)
| |
|
--------+---------------- (no fill between single intersection)
\
-------
随着扫描的线方向数量增加(超过90度和45度),最大误差将减小。获得最终区域就像像素数一样简单。