如何在Python中使用分水岭算法分割图像

4
如何在Python中使用分水岭算法对多个图像进行图像分割后将单个图像分离出来 附加的图像由4个图像组成,我们需要应用图像分割并从这些4个图像中分离出单个图像 enter image description here

我认为分水岭不适用于这种情况。 - Phung Duy Phong
请问您能否提供建议,如何解决这个问题。 - Ashish
2个回答

6

我们将首先进行泛洪填充

import cv2;
import numpy as np;

# Read image
im_in = cv2.imread("2SNAT.jpg", cv2.IMREAD_GRAYSCALE);

# Threshold.
# Set values equal to or above 220 to 0.
# Set values below 220 to 255.

th, im_th = cv2.threshold(im_in, 220, 255, cv2.THRESH_BINARY_INV);

# Copy the thresholded image.
im_floodfill = im_th.copy()

# Mask used to flood filling.
# Notice the size needs to be 2 pixels than the image.
h, w = im_th.shape[:2]
mask = np.zeros((h+2, w+2), np.uint8)

# Floodfill from point (0, 0)
cv2.floodFill(im_floodfill, mask, (0,0), 255);

# Invert floodfilled image
im_floodfill_inv = cv2.bitwise_not(im_floodfill)

# Combine the two images to get the foreground.
im_out = im_th | im_floodfill_inv

Filled image

然后找到轮廓并裁剪出来


注:该段文字为对图像处理的说明。
im, contours, hierarchy = cv2.findContours(im_out.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

final_contours = []
for contour in contours:
    area = cv2.contourArea(contour)
    if area > 1000:
        final_contours.append(contour)

剪裁步骤,同时在原始图像上绘制矩形。
counter = 0        
for c in final_contours:
    counter = counter + 1
# for c in [final_contours[0]]:
    peri = cv2.arcLength(c, True)
    approx = cv2.approxPolyDP(c, 0.01 * peri, True)
    x,y,w,h = cv2.boundingRect(approx)
    print(x, y, w, h)
    aspect_ratio = w / float(h)

    if (aspect_ratio >= 0.8 and aspect_ratio <= 4):
        cv2.rectangle(im_in,(x,y),(x+w,y+h),(0,255,0),2)
        cv2.imwrite('splitted_{}.jpg'.format(counter), im_in[y:y+h, x:x+w])
cv2.imwrite('rectangled_split.jpg', im_in)

Drawed square Result


@Ashish 我在这个领域不是专家,所以我的方法可能不是最好的,如果你需要更多解释,请评论。 - Phung Duy Phong
你干得好,伙计。我们几乎快要解决了。只是收到以下错误消息:
TypeError Traceback (most recent call last) <ipython-input-4-7d84b7e36ebb> in <module> ----> 1 contours,hierarchy = cv2.findContours(cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)TypeError:findContours()缺少必需的参数'method'(pos 3)
- Ashish
感谢您快速的帮助和回复,另外从第一个代码块的输出图像中,是否有可能仅获取单个图像,例如第一个图中的四个黄色阴影图像,这实际上是所需的(不带方框边界)? - Ashish
1
在Python中,行末的分号不是必需的。 - Matěj Šmíd
@Ashish,你使用的findContours代码行缺少图像输入的第一个参数,应该是这样的:im, contours, hierarchy = cv2.findContours(im_out.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)。另外,如果你想获取黄色阴影的图像,将这一行代码(裁剪并写入文件):cv2.imwrite('splitted_{}.jpg'.format(counter), im_in[y:y+h, x:x+w])改为cv2.imwrite('splitted_{}.jpg'.format(counter), im_out[y:y+h, x:x+w]) - Phung Duy Phong
此外,@nathancy的答案比我的更好。 - Phung Duy Phong

3

不使用分水岭算法,这里提供了一种使用阈值分割和形态学操作的简单方法。其思路是获取一个二进制图像,然后对每个对象进行形态学闭操作,将其合并为一个轮廓。然后我们找到轮廓,并使用Numpy切片提取/保存每个ROI。

下面是每个对象以绿色突出显示:

输入图像的描述

单独保存的对象

输入图像的描述 输入图像的描述 输入图像的描述 输入图像的描述

代码:

import cv2

# Load image, grayscale, Otsu's threshold
image = cv2.imread('1.jpg')
original = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

# Morph close
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (7,7))
close = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=3)

# Find contours and extract ROI
cnts = cv2.findContours(close, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
num = 0
for c in cnts:
    x,y,w,h = cv2.boundingRect(c)
    cv2.rectangle(image, (x, y), (x + w, y + h), (36,255,12), 2)
    ROI = original[y:y+h, x:x+w]
    cv2.imwrite('ROI_{}.png'.format(num), ROI)
    num += 1

cv2.imshow('image', image)
cv2.waitKey()

感谢 @nathancy。以上逻辑无法处理未正确对齐的图像。您能否建议如何处理图像 https://imgur.com/ngxJcow,以便得到我在图像中描述的两个单独的图像A和B。提前致谢。 - Ashish
如果它不是矩形对象,则必须使用位掩码。查找轮廓并将每个轮廓绘制到白色的空白掩码上,然后进行按位与操作以获取原始输入。从这里在掩码上找到边界框并提取ROI。 - nathancy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接