在python2.7中使用opencv2.4查找最大连接组件

2024-04-27 03:03:55 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在使用opencv“2.4.9.1”用python2.7.12编写代码。
我有一个2d numpy数组,其值在[0255]范围内。
我的目标是找到[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 !

[/伪代码]

我认为这样的方法不会有效率。
你能为我的设置提供一些功能建议吗?
谢谢。


Tags: ofto代码insizegetifvalue
1条回答
网友
1楼 · 发布于 2024-04-27 03:03:55

很高兴看到我的答案连在一起!实际上,connectedComponentsWithStats()甚至connectedComponents()都是opencv3+函数,所以不能使用它们。相反,简单的方法是使用findContours()。在

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

重要提示:OpenCV函数findContours()使用8路连接,而不是4路连接(即,它还检查对角线连接,而不仅仅是上、下、左、右)。如果你需要4路,你就需要使用不同的方法。如果是这样的话请告诉我,我可以更新。。在

根据另一篇文章的精神,以下是一般方法:

  1. 用您感兴趣的阈值对图像进行二值化。在
  2. 运行cv2.findContours()以获取图像中每个不同组件的轮廓。在
  3. 对于每个轮廓,计算轮廓的cv2.moments(),并保持最大面积轮廓(moments()返回的dict中的m00是轮廓的面积)。在
  4. 如果你需要的话,要么把轮廓作为一个点的列表,要么把它们画在一个新的空白图像上,如果你想要它作为一个遮罩。在

我今天缺乏创造力,所以您得到了the cameraman作为示例图像,因为您没有提供。在

import cv2
import numpy as np

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

Cameraman

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

^{pr2}$

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

相关问题 更多 >