抱歉参加聚会有点晚了。但是,如果我搜索“合并 opencv 轮廓”,我会发现这个;我认为应该有一个答案。
您可以通过以下方法之一合并任意两个轮廓:
- 获取每个轮廓的点列表
- 附加它们
- 强制将它们转换为 cv2 轮廓格式
- 如果您不太关心细节,请获取 cv2.convexHull 。
如果您不喜欢凸包的结果,因为轮廓的凹部分很重要,那么请按照以下方法操作:
- 获取每个轮廓的点列表
- 附加它们
- 获得一个共同中心
- 以中心为中心,按顺时针顺序对所有点进行排序
- 强制将它们转换为 cv2 轮廓格式
如果两个轮廓中有很多凹形,则当配方经过两个轮廓而忽略其原始结构时,可能会产生之字形图案。如果是这种情况,您需要遵循第三个秘诀:
- 获取每个轮廓的点列表
- 获得一个共同中心
- 删除每个轮廓中位于另一个轮廓内部的点
- 找到每个轮廓中最接近公共中心的点。
- 遍历列出的第一个轮廓,直到到达最近的点。
- 然后切换到另一个列表,从最近的点开始顺时针穿过另一个轮廓,直到用完
- 切换回第一个轮廓并附加其余的点。
- 强制将它们转换为 cv2 轮廓格式
下一个更复杂的情况是,如果轮廓之间有多个交叉点,并且您想要保留两者之间的孔。然后最好制作黑色图像并通过白色绘制轮廓cv2.fillPoly()
;然后通过以下方式恢复轮廓cv2.findContours()
我在这里概述了前两个食谱的一些步骤
获取每个轮廓的点列表:
import cv2
list_of_pts = []
for ctr in ctrs_to_merge
list_of_pts += [pt[0] for pt in ctr]
顺时针顺序排列点
我使用的功能MSeifert 的这个帖子真的很棒按顺时针顺序排列点
class clockwise_angle_and_distance():
'''
A class to tell if point is clockwise from origin or not.
This helps if one wants to use sorted() on a list of points.
Parameters
----------
point : ndarray or list, like [x, y]. The point "to where" we g0
self.origin : ndarray or list, like [x, y]. The center around which we go
refvec : ndarray or list, like [x, y]. The direction of reference
use:
instantiate with an origin, then call the instance during sort
reference:
https://stackoverflow.com/questions/41855695/sorting-list-of-two-dimensional-coordinates-by-clockwise-angle-using-python
Returns
-------
angle
distance
'''
def __init__(self, origin):
self.origin = origin
def __call__(self, point, refvec = [0, 1]):
if self.origin is None:
raise NameError("clockwise sorting needs an origin. Please set origin.")
# Vector between point and the origin: v = p - o
vector = [point[0]-self.origin[0], point[1]-self.origin[1]]
# Length of vector: ||v||
lenvector = np.linalg.norm(vector[0] - vector[1])
# If length is zero there is no angle
if lenvector == 0:
return -pi, 0
# Normalize vector: v/||v||
normalized = [vector[0]/lenvector, vector[1]/lenvector]
dotprod = normalized[0]*refvec[0] + normalized[1]*refvec[1] # x1*x2 + y1*y2
diffprod = refvec[1]*normalized[0] - refvec[0]*normalized[1] # x1*y2 - y1*x2
angle = atan2(diffprod, dotprod)
# Negative angles represent counter-clockwise angles so we need to
# subtract them from 2*pi (360 degrees)
if angle < 0:
return 2*pi+angle, lenvector
# I return first the angle because that's the primary sorting criterium
# but if two vectors have the same angle then the shorter distance
# should come first.
return angle, lenvector
center_pt = np.array(list_of_pts).mean(axis = 0) # get origin
clock_ang_dist = clockwise_angle_and_distance(origin) # set origin
list_of_pts = sorted(list_of_pts, key=clock_ang_dist) # use to sort
强制将点列表转换为 cv2 格式
import numpy as np
ctr = np.array(list_of_pts).reshape((-1,1,2)).astype(np.int32)
将它们与cv2.convexHull
instead
如果您使用它,则无需按顺时针顺序排列点。但是,凸包可能会丢失一些轮廓属性,因为它不会保留轮廓的凹角。
# get a list of points
# force the list of points into cv2 format and then
ctr = cv2.convexHull(ctr) # done.
我认为合并两个轮廓的函数应该是opencv库的内容。这个方法非常简单,遗憾的是许多使用 opencv 的程序员不得不编写这样的样板代码。