python - 如何在opencv中合并轮廓?

标签 python opencv artificial-intelligence

好吧,伙计们,我从事这个项目已经有一段时间了。

我正在构建这个玩 chrome 恐龙游戏的机器人。所以我尝试了其他方法来检测诸如 matchTemplate 之类的字符,甚至制作了自己的算法来定位对象,但我最喜欢这个(findcontours)。

这是我所拥有的:

What my program sees

谁能帮我找出我应该如何合并仙人掌的两个矩形?

img = screen_cap()
roi = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(roi,127, 255, 0)
im2, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
first = True
for cnt in contours:
    area = cv2.contourArea(cnt)
    if area > 200: #filtering contours
        x,y,w,h = cv2.boundingRect(cnt)
        if w/h < 4: # filtering even more
            cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)

最佳答案

很抱歉来晚了一点。但是,如果我用谷歌搜索“合并 opencv 轮廓”,我会发现这个;我认为应该有一个答案。
您可以通过这些配方之一合并任何两个轮廓:

  • 获取每个轮廓的点列表
  • 附加它们
  • 将它们强制转换为 cv2 轮廓格式
  • 如果您不太关心细节,请获取 cv2.convexHull 。

  • 如果您不喜欢 convexHull 的结果,因为轮廓的凹面部分很重要,请改用以下方法:
  • 获取每个轮廓的点列表
  • 附加它们
  • 得到一个共同的中心
  • 围绕中心按顺时针顺序对所有点进行排序
  • 将它们强制转换为 cv2 轮廓格式

  • 如果两个轮廓中有很多凹形,这可能会产生锯齿形图案,因为配方会通过两个轮廓而不考虑它们的原始结构。如果是这种情况,您需要遵循第三个秘诀:
  • 获取每个轮廓的点列表
  • 得到一个共同的中心
  • 删除每个轮廓在另一个轮廓内的点
  • 在每个轮廓中找到最接近公共(public)中心的点。
  • 穿过列出的第一个轮廓,直到您到达最近的点。
  • 然后切换到另一个列表,从最近的点开始顺时针穿过另一个轮廓,直到用完
  • 切换回第一个轮廓并附加其余的点。
  • 将它们强制转换为 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]
    
    顺时针顺序点
    我使用this really great posting of 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 合并反而
    如果您使用它,则无需顺时针排列点。但是,convexHull 可能会丢失一些轮廓属性,因为它不会保留轮廓的凹角。
    # get a list of points
    # force the list of points into cv2 format and then
    ctr = cv2.convexHull(ctr) # done.
    
    我认为合并两个轮廓的功能应该是opencv库的内容。这个方法很简单,很遗憾许多使用 opencv 的程序员将不得不对其进行样板代码。

    关于python - 如何在opencv中合并轮廓?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44501723/

    相关文章:

    python动态调用类

    python - 图像处理算法设计 : how to get front images from an angled camera?

    c++ - 传递 mat 引用时出现 opencv malloc 错误

    python - OR 函数的感知器不收敛

    artificial-intelligence - 感知器中阈值的意义是什么?

    python - 嵌套结构连接

    python - "Sourcing"来自另一个的 Python 文件

    python - 如何运行当前行并在 VS Code 中前进? ( window )

    opencv - 将 Libraw 格式转换为 cv::Mat

    machine-learning - Google Cloud Vision API(标签),有多少种可能的标签?