【问题标题】:How to separate images using watershed algorithm in Python如何在 Python 中使用分水岭算法分离图像
【发布时间】:2020-01-09 06:39:41
【问题描述】:

如何在 Python 中使用分水岭算法在图像分割后在多个图像中分离单个图像 附加图像由 4 张图像组成,我们需要从中应用图像分割并将单个图像从这 4 张图像中分离出来

【问题讨论】:

  • 我认为分水岭不适用于此案
  • 能否请教一下,如何解决。

标签: python opencv image-processing computer-vision data-science


【解决方案1】:

我们会先填满它

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

然后找到轮廓并裁剪出来

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)

【讨论】:

  • @Ashish 我不是该领域的专家,所以我的方法可能不是最好的,如果您需要更多解释,请发表评论,
  • 你成功了,伙计。我们几乎接近解决方案。刚刚收到以下错误消息:-------------------------------------------- -------------------------------- TypeError Traceback (最近一次调用最后一次) in ----> 1 轮廓,层次结构 = cv2.findContours(cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) 2 3 final_contours = [] 4 用于轮廓中的轮廓:5 区域 = cv2.contourArea(contour) 类型错误:findContours( ) 缺少必需的参数“方法”(位置 3)
  • 感谢 Buddy 的快速帮助和响应,同样从第一个代码块的输出图像中,是否可以仅从第一个图中单独获取单个图像本身,例如四个黄色阴影图像,这实际上是实际上需要(不是方形边界)
  • Python 中不需要行尾的分号
  • @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])
【解决方案2】:

这里没有使用分水岭,而是使用阈值 + 形态学操作的简单方法。这个想法是获得一个二值图像,然后执行 morph close 以将每个对象组合为单个轮廓。然后我们找到轮廓并使用 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。上述逻辑不适用于未正确对齐的图像。您能否建议如何使用图像imgur.com/ngxJcow,以便我在图像中描述了两个单独的图像 A 和 B。提前致谢
  • 如果它不是矩形对象,则必须使用按位掩码。查找轮廓并将每个轮廓绘制到白色的空白蒙版上,然后按位绘制 - 并使用原始输入。从这里找到遮罩上的边界框并提取 ROI
猜你喜欢
  • 1970-01-01
  • 2020-07-27
  • 1970-01-01
  • 2019-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-12
相关资源
最近更新 更多