首页 > 解决方案 > 如何使用 Python OpenCV 在图像中获得泛滥区域及其边界?

问题描述

我有一张像这样的图像,它只有黑白:

迷宫的图像

我想只获得带有边框的图像的淹没区域cv2.floodfill,就像这样(请原谅我的绘画技巧):

在此处输入图像描述

这是我当前的代码:

    # Copy the image.
    im_floodfill = cv2.resize(actual_map_image, (500, 500)).copy()

    # Floodfill from point (X, Y)
    cv2.floodFill(im_floodfill, None, (X, Y), (255, 255, 255))

    # Display images.
    cv2.imshow("Floodfilled Image", im_floodfill)
    cv2.waitKey(0)

我得到的输出等于原始图像。我怎样才能只得到有边界的洪水区域?

编辑:我想从“竞技场”内的任何点填充,比如图像中的红点(X,Y)。我希望只有竞技场内小圆圈的外边界和外墙的内边界。

EDIT2:我已经完成了一半:

# Resize for test purposes 
    actual_map_image = cv2.resize(actual_map_image, (1000, 1000))
    actual_map_image = cv2.cvtColor(actual_map_image, cv2.COLOR_BGR2GRAY)

    h, w = actual_map_image.shape[:2]
    flood_mask = np.zeros((h+2, w+2), dtype=np.uint8)
    connectivity = 8
    flood_fill_flags = (connectivity | cv2.FLOODFILL_FIXED_RANGE | cv2.FLOODFILL_MASK_ONLY | 255 << 8) 

    # Copy the image.
    im_floodfill = actual_map_image.copy()

    # Floodfill from point inside arena, not inside a black dot
    cv2.floodFill(im_floodfill, flood_mask, (h/2 + 20, w/2 + 20), 255, None, None, flood_fill_flags)

    borders = []
    for i in range(len(actual_map_image)):
        borders.append([B-A for A,B in zip(actual_map_image[i], flood_mask[i])])

    borders = np.asarray(borders)
    borders = cv2.bitwise_not(borders)

    # Display images.
    cv2.imshow("Original Image", cv2.resize(actual_map_image, (500, 500)))
    cv2.imshow("Floodfilled Image", cv2.resize(flood_mask, (500, 500)))
    cv2.imshow("Borders", cv2.resize(borders, (500, 500)))

    cv2.waitKey(0)

我明白了:

在此处输入图像描述

但是,我觉得这是获取边界的错误方式,而且它们是不完整的。

标签: pythonopencv

解决方案


我认为最简单,最快的方法是用中灰色填充竞技场。然后只提取灰色像素并找到它们的边缘。看起来像这样,但请记住,超过一半的行是注释和调试语句 :-)

#!/usr/bin/env python3

import cv2

# Load image as greyscale to use 1/3 of the memory and processing time
im = cv2.imread('arena.png', cv2.IMREAD_GRAYSCALE)

# Floodfill arena area with value 128, i.e. mid-grey
floodval = 128
cv2.floodFill(im, None, (150,370), floodval)
# DEBUG cv2.imwrite('result-1.png', im)

# Extract filled area alone
arena = ((im==floodval) * 255).astype(np.uint8)
# DEBUG cv2.imwrite('result-2.png', arena)

# Find edges and save
edges = cv2.Canny(arena,100,200)
# DEBUG cv2.imwrite('result-3.png',edges)

以下是调试输出的 3 个步骤,显示处理顺序:

result-1.png 看起来像这样:

在此处输入图像描述

result-2.png 看起来像这样:

在此处输入图像描述

result-3.png 看起来像这样:

在此处输入图像描述


顺便说一句,您不必编写任何 Python 代码来执行此操作,因为您可以使用 ImageMagick 在终端中执行此操作,ImageMagick包含在大多数 Linux 发行版中,可用于 macOS 和 Windows。这里使用的方法和我上面Python中使用的方法完全对应:

magick arena.png -colorspace gray               \
   -fill gray -draw "color 370,150 floodfill"   \
   -fill white +opaque gray -canny 0x1+10%+30% result.png

推荐阅读