从外部轮廓创建遮罩以删除图像背景

时间:2020-02-20 12:11:21

标签: opencv image-processing

我具有单个对象(标本)的图像,该图像是无法控制的背景色。该post的建议已解决了该问题。如果从垂直角度拍摄图像,则该代码可以很好地工作。

但是,我还有另一个问题。一些图像是从无法控制的角度拍摄的。我上面提到的帖子中的现有代码返回了意外结果。例如,给定原始图像

original

结果为result

我修改该代码的想法是从外部轮廓制作遮罩,然后在原始遮罩和遮罩之间按位应用。但是我不知道如何从外部轮廓制作遮罩。我可以提出您的建议吗?

1 个答案:

答案 0 :(得分:1)

您可以使用以下解决方案(尽管并不能很好地分离样本):

  • 使用cv2.floodFill确实将彩色背景替换为黑色背景。
  • 使用“关闭”形态学操作去除floodFill之后留下的一些不需要的伪像。
  • 阈值结果,并找到最大轮廓。
  • 使用following post
  • 中的代码使轮廓平滑
  • 从“平滑的”轮廓构建遮罩,然后应用遮罩。

这是代码:

import numpy as np
import cv2
from scipy.interpolate import splprep, splev

orig_im = cv2.imread("specimen1.jpg")

im = orig_im.copy()

h, w = im.shape[0], im.shape[1]

# Seed points for floodFill (use two points at each corner for improving robustness)
seedPoints = ((0, 0), (10, 10), (w-1, 0), (w-1, 10), (0, h-1), (10, h-1), (w-1, h-1), (w-10, h-10))

# Fill background with black color
for seed in seedPoints:
    cv2.floodFill(im, None, seedPoint=seed, newVal=(0, 0, 0), loDiff=(5, 5, 5), upDiff=(5, 5, 5))

# Use "close" morphological operation
im = cv2.morphologyEx(im, cv2.MORPH_OPEN, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (10,10)));

#Convert to Grayscale, and then to binary image.
gray = cv2.cvtColor(im, cv2.COLOR_RGB2GRAY)
ret, thresh_gray = cv2.threshold(gray, 5, 255, cv2.THRESH_BINARY)

#Find contours
_, contours, _ = cv2.findContours(thresh_gray, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
c = max(contours, key=cv2.contourArea) # Get the largest contour

# Smooth contour
# https://agniva.me/scipy/2016/10/25/contour-smoothing.html
x,y = c.T
x = x.tolist()[0]
y = y.tolist()[0]
tck, u = splprep([x,y], u=None, s=1.0, per=1)
u_new = np.linspace(u.min(), u.max(), 20)
x_new, y_new = splev(u_new, tck, der=0)
res_array = [[[int(i[0]), int(i[1])]] for i in zip(x_new,y_new)]
smoothened = np.asarray(res_array, dtype=np.int32)

# For testing
test_im = orig_im.copy()
cv2.drawContours(test_im, [smoothened], 0, (0, 255, 0), 1)

# Build a mask
mask = np.zeros_like(thresh_gray)
cv2.drawContours(mask, [smoothened], -1, 255, -1)

# Apply mask
res = np.zeros_like(orig_im)
res[(mask > 0)] = orig_im[(mask > 0)]

# Show images for testing
cv2.imshow('test_im', test_im)
cv2.imshow('res', res)
cv2.imshow('mask', mask)
cv2.waitKey(0)
cv2.destroyAllWindows()

备注:
我认为解决方案不是很可靠。
您可能需要使用迭代方法(例如逐渐增加loDiffhiDiff参数以匹配给定图像的最佳参数)。


结果:

第一个标本:

test_im:
enter image description here

遮罩:
enter image description here

res:
enter image description here


第二个标本:

test_im:
enter image description here

遮罩:
enter image description here

res:
enter image description here


第三标本:

res:
enter image description here