使用 Python 从图像中屏蔽掉较大的不规则形状
Masked out large irregular shape from image with Python
objective是去除大的不规则区域,只保留图像中的字符。
例如,给定以下内容
和预期的 masked output
我的印象是这可以实现如下
import cv2
import numpy as np
from matplotlib import pyplot as plt
dpath='remove_bg1.jpg'
img = cv2.imread(dpath)
img_fh=img.copy()
cv2.bitwise_not(img_fh,img_fh)
ksize=10
kernel = np.ones((ksize,ksize),np.uint8)
erosion = cv2.erode(img_fh,kernel,iterations = 3)
invertx = cv2.bitwise_not(erosion)
masked = cv2.bitwise_not(cv2.bitwise_and(img_fh,invertx))
all_image=[img,invertx,masked]
ncol=len(all_image)
for idx, i in enumerate(all_image):
plt.subplot(int(f'1{ncol}{idx+1}')),plt.imshow(i)
plt.show()
产生
显然,上面的代码没有产生预期的结果。
我可以知道如何正确解决这个问题吗?
要删除不需要的斑点,我们必须创建一个遮罩,使其完全封闭。
流量:
- 反向二值化图像(这样你就有一个白色的前景与黑暗的背景)
- Dilate 图像(因为 blob 与字母 'A' 接触,它必须被隔离)
- 求面积最大的轮廓
- 在另一张单通道图像上绘制轮廓并加厚(膨胀)
- 像素分配:包含膨胀斑点的像素在原始图像上变为白色
代码:
im = cv2.imread('stained_text.jpg')
im2 = im.copy()
gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
# inverse binaraization
th = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
注意接触字母 'A' 的斑点区域。因此,为了隔离它,我们使用椭圆核
执行侵蚀
# erosion
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
erode = cv2.erode(th, kernel, iterations=2)
# find contours
contours, hierarchy = cv2.findContours(erode, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
# Contour of maximum area
c = max(contours, key = cv2.contourArea)
# create 1-channel image in black
black = np.zeros((im.shape[0], im.shape[1]), np.uint8)
# draw the contour on it
black = cv2.drawContours(black, [c], 0, 255, -1)
# perform dilation to have clean border
# we are using the same kernel
dilate = cv2.dilate(black, kernel, iterations = 3)
# assign the dilated area in white over the original image
im2[dilate == 255] = (255,255,255)
This was just one of the many possible ways on how to proceed. The key thing to note is how to isolate the blob.
objective是去除大的不规则区域,只保留图像中的字符。
例如,给定以下内容
和预期的 masked output
我的印象是这可以实现如下
import cv2
import numpy as np
from matplotlib import pyplot as plt
dpath='remove_bg1.jpg'
img = cv2.imread(dpath)
img_fh=img.copy()
cv2.bitwise_not(img_fh,img_fh)
ksize=10
kernel = np.ones((ksize,ksize),np.uint8)
erosion = cv2.erode(img_fh,kernel,iterations = 3)
invertx = cv2.bitwise_not(erosion)
masked = cv2.bitwise_not(cv2.bitwise_and(img_fh,invertx))
all_image=[img,invertx,masked]
ncol=len(all_image)
for idx, i in enumerate(all_image):
plt.subplot(int(f'1{ncol}{idx+1}')),plt.imshow(i)
plt.show()
产生
显然,上面的代码没有产生预期的结果。
我可以知道如何正确解决这个问题吗?
要删除不需要的斑点,我们必须创建一个遮罩,使其完全封闭。
流量:
- 反向二值化图像(这样你就有一个白色的前景与黑暗的背景)
- Dilate 图像(因为 blob 与字母 'A' 接触,它必须被隔离)
- 求面积最大的轮廓
- 在另一张单通道图像上绘制轮廓并加厚(膨胀)
- 像素分配:包含膨胀斑点的像素在原始图像上变为白色
代码:
im = cv2.imread('stained_text.jpg')
im2 = im.copy()
gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
# inverse binaraization
th = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
注意接触字母 'A' 的斑点区域。因此,为了隔离它,我们使用椭圆核
执行侵蚀# erosion
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
erode = cv2.erode(th, kernel, iterations=2)
# find contours
contours, hierarchy = cv2.findContours(erode, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
# Contour of maximum area
c = max(contours, key = cv2.contourArea)
# create 1-channel image in black
black = np.zeros((im.shape[0], im.shape[1]), np.uint8)
# draw the contour on it
black = cv2.drawContours(black, [c], 0, 255, -1)
# perform dilation to have clean border
# we are using the same kernel
dilate = cv2.dilate(black, kernel, iterations = 3)
# assign the dilated area in white over the original image
im2[dilate == 255] = (255,255,255)
This was just one of the many possible ways on how to proceed. The key thing to note is how to isolate the blob.