在python 2.7

时间:2018-04-03 00:54:44

标签: python opencv

我正在使用opencv' 2.4.9.1'来编写python 2.7.12中的代码 我有一个2d numpy数组,其中包含范围[0,255]中的值 我的目标是找到范围[x,y]中包含值的最大区域 我发现 How to use python OpenCV to find largest connected component in a single channel image that matches a specific value?很好地解释了。 唯一的问题是 - 它适用于opencv 3。

我可以尝试编写这种类型的函数
[伪代码]

def get_component(x,y,list):
  append x,y to list
  visited[x][y]=1
 if(x+1<m && visited[x+1][y]==0)
  get_component(x+1,y,list)
 if(y+1<n && visited[x][y+1]==0)
  get_component(x,y+1,list)
 if(x+1<m)&&(y+1<n)&&visited[x+1][y+1]==0
  get_component(x+1,y+1,list)
 return

MAIN
biggest_component = NULL
biggest_component_size = 0
low = lowest_value_in_user_input_range
high = highest_value_in_user_input_range
matrix a = gray image of size mxn
matrix visited = all value '0' of size mxn
for x in range(m):
 for y in range(n):
  list=NULL
  if(a[x][y]>=low) && (a[x][y]<=high) && visited[x][y]==1:
   get_component(x,y,list)
   if (list.size>biggest_component_size)
    biggest_component = list
Get maximum x , maximum y , min x and min y from above list containing coordinates of every point of largest component to make rectangle R .
Mission accomplished !

[/ pseudo code]

我认为这种方法效率不高 你可以建议我的设置功能吗?
感谢。

1 个答案:

答案 0 :(得分:2)

很高兴看到我的答案相关联!实际上,connectedComponentsWithStats()甚至connectedComponents()都是OpenCV 3+函数,因此您无法使用它们。相反,最简单的方法就是使用findContours()

您可以计算每个轮廓的moments(),并且包含在矩中的是轮廓的面积。

重要说明: OpenCV函数findContours()使用8路连接,而不是4路(即它还检查对角线连接,而不仅仅是向上,向下,向左,向右)。如果您需要4路,则需要使用不同的方法。如果是这种情况,请告诉我,我可以更新..

本着另一篇文章的精神,这是一般方法:

  1. 使用您感兴趣的阈值对图像进行二值化。
  2. 运行cv2.findContours()以获取图像中每个不同组件的轮廓。
  3. 对于每个轮廓,计算轮廓的cv2.moments()并保持最大区域轮廓(从m00返回的dict中的moments()是轮廓区域。
  4. 如果您需要,请将轮廓保留为点列表,否则,如果您想将其作为蒙版,则将它们绘制在新的空白图像上。
  5. 我今天缺乏创造力,所以你得到the cameraman作为我们的示例图像,因为你没有提供。

    import cv2
    import numpy as np
    
    img = cv2.imread('cameraman.png', cv2.IMREAD_GRAYSCALE)
    

    Cameraman

    现在,让我们二进制化以获得一些分离的blob:

    bin_img = cv2.inRange(img, 50, 80)
    

    Binary Cameraman

    现在让我们找到轮廓。

    contours = cv2.findContours(bin_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[0]
    
    # For OpenCV 3+ use: 
    # contours = cv2.findContours(bin_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[1]
    

    现在为主要位;循环遍历轮廓并找到最大的轮廓:

    max_area = 0
    max_contour_index = 0
    for i, contour in enumerate(contours):
        contour_area = cv2.moments(contour)['m00']
        if contour_area > max_area:
            max_area = contour_area
            max_contour_index = i
    

    所以现在我们有一个区域最大轮廓的索引max_contour_index,所以你可以直接访问最大轮廓contours[max_contour_index]。您当然可以按轮廓区域对contours列表进行排序,然后抓取第一个(或最后一个,取决于排序顺序)。如果要制作单个组件的掩码,可以使用

    cv2.drawContours(new_blank_image, contours, max_contour_index, color=255, thickness=-1)
    

    注意-1将填充轮廓而不是概述轮廓。这是一个在原始图像上绘制轮廓的示例:

    Labeled Cameraman

    看起来正确。

    一体化功能:

    def largest_component_mask(bin_img):
        """Finds the largest component in a binary image and returns the component as a mask."""
    
        contours = cv2.findContours(bin_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[0]
        # should be [1] if OpenCV 3+
    
        max_area = 0
        max_contour_index = 0
        for i, contour in enumerate(contours):
            contour_area = cv2.moments(contour)['m00']
            if contour_area > max_area:
                max_area = contour_area
                max_contour_index = i
    
        labeled_img = np.zeros(bin_img.shape, dtype=np.uint8)
        cv2.drawContours(labeled_img, contours, max_contour_index, color=255, thickness=-1)
    
        return labeled_img