简体   繁体   English

在python 2.7中使用opencv 2.4查找最大的连接组件

[英]finding largest connected component using opencv 2.4 in python 2.7

I am writing code in python 2.7.12 using opencv '2.4.9.1'. 我正在使用opencv'2.4.9.1'在python 2.7.12中编写代码。
I have a 2d numpy array containing values in range [0,255]. 我有一个二维numpy数组,其中包含[0,255]范围内的值。
My aim is to find largest region containing value in range[x,y] 我的目标是找到包含范围[x,y]中的值的最大区域
I found How to use python OpenCV to find largest connected component in a single channel image that matches a specific value? 我发现了如何使用python OpenCV在单个通道图像中查找与特定值匹配的最大连接组件? as pretty well-explained . 相当好解释。 Only, the catch is - it is meant for opencv 3 . 唯一的收获是-它是针对opencv 3的。

I can try to write a function of this type 我可以尝试编写这种类型的函数
[pseudo code] [伪代码]

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] [/伪代码]

Such an approach will not be efficient, I think. 我认为,这种方法不会有效。
Can you suggest functions for doing the same with my setup ? 您能建议对我的设置执行相同操作的功能吗?
Thanks. 谢谢。

Happy to see my answer linked! 很高兴看到我的答案链接! Indeed, connectedComponentsWithStats() and even connectedComponents() are OpenCV 3+ functions, so you can't use them. 实际上, connectedComponentsWithStats()甚至connectedComponents()都是OpenCV 3+函数,因此您不能使用它们。 Instead, the easy thing to do is just use findContours() . 相反,简单的事情就是使用findContours()

You can calculate moments() of each contour, and included in the moments is the area of the contour. 您可以计算每个轮廓的moments() ,并且这些力矩中包括轮廓的面积。

Important note: The OpenCV function findContours() uses 8-way connectivity, not 4-way (ie it also checks diagonal connectivity, not just up, down, left, right). 重要说明: OpenCV函数findContours()使用8向连通性,而不是4向连通性(即,它还检查对角线连通性,而不仅仅是向上,向下,向左,向右)。 If you need 4-way, you'd need to use a different approach. 如果您需要4路,则需要使用其他方法。 Let me know if that's the case and I can update.. 让我知道是否是这样,我可以进行更新。

In the spirit of the other post, here's the general approach: 本着另一篇文章的精神,这是一般的方法:

  1. Binarize your image with the thresholds you're interested in. 将图像与您感兴趣的阈值二值化。
  2. Run cv2.findContours() to get the contour of each distinct component in the image. 运行cv2.findContours()以获取图像中每个不同组件的轮廓。
  3. For each contour, calculate the cv2.moments() of the contour and keep the maximum area contour ( m00 in the dict returned from moments() is the area of the contour). 对于每个轮廓,计算轮廓的cv2.moments()并保持最大面积轮廓(从moments()返回的dict中的m00是轮廓的面积)。
  4. Either keep the contour as a list of points if that's what you need, otherwise draw them on a new blank image if you want it as a mask. 如果需要,可以将轮廓保留为点列表,如果想要将其作为遮罩,则将其绘制在新的空白图像上。

I lack creativity today, so you get the cameraman as our example image as you didn't provide one. 我今天缺乏创造力,因此您没有提供摄影师作为我们的示例图像。

import cv2
import numpy as np

img = cv2.imread('cameraman.png', cv2.IMREAD_GRAYSCALE)

摄影师

Now, let's binarize to get some separated blobs: 现在,让我们二进制化一些分离的斑点:

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

二进制摄影师

Now let's find the contours. 现在让我们找到轮廓。

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]

Now for the main bit; 现在是主要部分; looping through the contours and finding the largest one: 遍历轮廓并找到最大的轮廓:

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

So now we have an index max_contour_index of the largest contour by area, so you can access the largest contour directly just by doing contours[max_contour_index] . 因此,现在我们有了按面积计算的最大轮廓的索引max_contour_index ,因此您只需执行contours[max_contour_index]即可直接访问最大轮廓。 You could of course just sort the contours list by the contour area and grab the first (or last, depending on sort order). 当然,您可以按轮廓区域对contours列表进行排序,然后抓取第一个(或最后一个,具体取决于排序顺序)。 If you want to make a mask of the one component, you can use 如果要制作一个组件的遮罩,可以使用

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

Note the -1 will fill the contour as opposed to outlining it. 请注意,-1将填充轮廓,而不是对其进行轮廓绘制。 Here's an example drawing the contour over the original image: 这是在原始图像上绘制轮廓的示例:

贴标签的摄影师

Looks about right. 看起来不错。

All in one function: 多合一功能:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM