从轮廓中找到旋转的矩形
Finding rotated rectangle from contour
我正在尝试使用 OpenCV 从图像中识别和提取相当明显的区域。到目前为止,通过使用一个阈值和一系列的膨胀和腐蚀,我可以成功地找到我需要的区域的轮廓。
但是,我尝试使用 minAreaRect
作为旋转和裁剪的先驱,但未能生成包含输入轮廓的矩形。
contours, hierarchy = cv2.findContours(morph.copy() ,cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contour = contours[0]
draw = cv2.cvtColor(morph, cv2.COLOR_GRAY2BGR)
cv2.drawContours(draw, [contour], 0, (0,255,0), 2)
rotrect = cv2.minAreaRect(contour)
box = cv2.cv.BoxPoints(rotrect)
box = numpy.int0(box)
cv2.drawContours(draw, [box], 0, (0,0,255), 2)
cv2.imshow('image', draw); cv2.waitKey(0)
这是输出示例:
其中红色笔划是 rect
,绿色笔划是 contour
。我本以为红色笔划会包含绿色笔划。
很遗憾,我无法提供输入图像。
我最终通过实施我自己的旋转卡尺程序来找到最小矩形来解决这个问题。它使用凸包来确定候选旋转。
def p2abs(point):
return math.sqrt(point[0] ** 2 + point[1] ** 2)
def rotatePoint(point, angle):
s, c = math.sin(angle), math.cos(angle)
return (p[0] * c - p[1] * s, p[0] * s + p[1] * c)
def rotatePoints(points, angle):
return [rotatePoint(point, angle) for point in points]
points = map(lambda x: tuple(x[0]), contour)
convexHull = map(lambda x: points[x], scipy.spatial.ConvexHull(numpy.array(points)).vertices)
minArea = float("inf")
minRect = None
for i in range(len(hull)):
a, b = convexHull[i], convexHull[i - 1]
ang = math.atan2(b[0] - a[0], b[1] - a[1])
rotatedHull = rotatePoints(convexHull, ang)
minX = min(map(lambda p: p[0], rotatedHull))
maxX = max(map(lambda p: p[0], rotatedHull))
minY = min(map(lambda p: p[1], rotatedHull))
maxY = max(map(lambda p: p[1], rotatedHull))
area = (maxX - minX) * (maxY - minY)
if area < minArea:
minArea = area
rotatedRect = [(minX, minY), (minX, maxY), (maxX, maxY), (maxX, minY)]
minRect = rotatePoints(rotatedRect, -ang)
_, topLeft = min([(p2abs(p), i) for p, i in zip(range(4), minRect)])
rect = minrect[topLeft:] + minrect[:topLeft]
我正在尝试使用 OpenCV 从图像中识别和提取相当明显的区域。到目前为止,通过使用一个阈值和一系列的膨胀和腐蚀,我可以成功地找到我需要的区域的轮廓。
但是,我尝试使用 minAreaRect
作为旋转和裁剪的先驱,但未能生成包含输入轮廓的矩形。
contours, hierarchy = cv2.findContours(morph.copy() ,cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contour = contours[0]
draw = cv2.cvtColor(morph, cv2.COLOR_GRAY2BGR)
cv2.drawContours(draw, [contour], 0, (0,255,0), 2)
rotrect = cv2.minAreaRect(contour)
box = cv2.cv.BoxPoints(rotrect)
box = numpy.int0(box)
cv2.drawContours(draw, [box], 0, (0,0,255), 2)
cv2.imshow('image', draw); cv2.waitKey(0)
这是输出示例:
其中红色笔划是 rect
,绿色笔划是 contour
。我本以为红色笔划会包含绿色笔划。
很遗憾,我无法提供输入图像。
我最终通过实施我自己的旋转卡尺程序来找到最小矩形来解决这个问题。它使用凸包来确定候选旋转。
def p2abs(point):
return math.sqrt(point[0] ** 2 + point[1] ** 2)
def rotatePoint(point, angle):
s, c = math.sin(angle), math.cos(angle)
return (p[0] * c - p[1] * s, p[0] * s + p[1] * c)
def rotatePoints(points, angle):
return [rotatePoint(point, angle) for point in points]
points = map(lambda x: tuple(x[0]), contour)
convexHull = map(lambda x: points[x], scipy.spatial.ConvexHull(numpy.array(points)).vertices)
minArea = float("inf")
minRect = None
for i in range(len(hull)):
a, b = convexHull[i], convexHull[i - 1]
ang = math.atan2(b[0] - a[0], b[1] - a[1])
rotatedHull = rotatePoints(convexHull, ang)
minX = min(map(lambda p: p[0], rotatedHull))
maxX = max(map(lambda p: p[0], rotatedHull))
minY = min(map(lambda p: p[1], rotatedHull))
maxY = max(map(lambda p: p[1], rotatedHull))
area = (maxX - minX) * (maxY - minY)
if area < minArea:
minArea = area
rotatedRect = [(minX, minY), (minX, maxY), (maxX, maxY), (maxX, minY)]
minRect = rotatePoints(rotatedRect, -ang)
_, topLeft = min([(p2abs(p), i) for p, i in zip(range(4), minRect)])
rect = minrect[topLeft:] + minrect[:topLeft]