【发布时间】:2021-06-12 07:46:57
【问题描述】:
我正在尝试消除图像中任何给定形状的间隙或孔洞。
我遵循的替代方法是:我对图像进行阈值处理以获得二值图像并应用膨胀来消除间隙,但这会导致形状变大。如何将这些扩张的轮廓缩放为与原始图像的轮廓相同的大小?或者我可以扩大图像并以某种方式仍然具有与原始形状相同的大小?有没有更好的选择?
我曾尝试应用扩张然后在扩张图像的轮廓中进行缩放,但无法以始终导致扩张轮廓与原始轮廓具有相同大小的方式进行操作(有时扩张和缩放的轮廓与原始轮廓具有相同的大小,有时不是)。
另外,我如何确保以始终消除原始图像间隙的方式应用膨胀,无论其形状有多大或多小?我意识到,有时膨胀会以一种间隙仍然可见但最小化而不是消除的方式发生,这不是目标。
这是我到现在为止的:
import sys
from pathlib import Path
from PIL import Image
from PIL import ImageCms
from PIL import ImageFile
ImageFile.LOAD_TRUNCATED_IMAGES = True
Image.MAX_IMAGE_PIXELS = 99999999999999
import numpy as np
import cv2
import numpy
img_path = 'input.png'
def cmyk_to_rgb(cmyk_img):
img = Image.open(cmyk_img)
if img.mode == "CMYK":
img = ImageCms.profileToProfile(img, "Color Profiles\\USWebCoatedSWOP.icc", "Color Profiles\\sRGB_Color_Space_Profile.icm", outputMode="RGB")
return cv2.cvtColor(numpy.array(img), cv2.COLOR_RGB2BGR)
def cv_threshold(img, thresh=254, maxval=255, type=cv2.THRESH_BINARY_INV):
if len(img.shape) == 3:
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
threshed = cv2.threshold(img, thresh, maxval, type)[1]
return threshed
def find_contours(img, to_gray=None):
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (11,11))
morphed = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
contours = cv2.findContours(morphed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
return contours[-2]
def mask_from_contours(ref_img, contours):
mask = numpy.zeros(ref_img.shape, numpy.uint8)
mask = cv2.drawContours(mask, contours, -1, (255,255,255), 24)
return cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
def dilate_mask(mask, kernel_size=10):
kernel = numpy.ones((kernel_size,kernel_size), numpy.uint8)
dilated = cv2.dilate(mask, kernel, iterations=1)
return dilated
def draw_contours(src_img, contours):
canvas = cv2.drawContours(src_img.copy(), contours, 0, (0,255,0), 24)
x, y, w, h = cv2.boundingRect(contours[-1])
cv2.rectangle(canvas, (x,y), (x+w,y+h), (0,0,255), 2)
return canvas
def scale_contour(cnt, scale):
M = cv2.moments(cnt)
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
cnt_norm = cnt - [cx, cy]
cnt_scaled = cnt_norm * scale
cnt_scaled = cnt_scaled + [cx, cy]
cnt_scaled = cnt_scaled.astype(np.int32)
return cnt_scaled
#GET ORIGINAL CONTOURS
orig_img = cmyk_to_rgb(str(img_path))
orig_threshed = cv_threshold(orig_img, 254,255, type=cv2.THRESH_BINARY_INV)
orig_contours= find_contours(orig_threshed)
orig_mask = mask_from_contours(orig_img, orig_contours)
orig_output = draw_contours(orig_img, orig_contours)
#GET DILATED CONTOURS
dilated_mask = dilate_mask(orig_mask, 80)
dilated_contours= find_contours(dilated_mask)
dilated_output = draw_contours(orig_img, dilated_contours)
#Just to observe dilation effect
RGBimage = cv2.cvtColor(dilated_output, cv2.COLOR_BGR2RGB)
pilImage = Image.fromarray(RGBimage)
pilImage.save('dilation.png', dpi=(300,300))
# SCALE DILATED CONTOURS
cnt_scaled = scale_contour(dilated_contours[0], 0.95)
im_copy = orig_img.copy()
cv2.drawContours(im_copy, [cnt_scaled], -1, (50, 50, 50), 24)
RGBimage = cv2.cvtColor(im_copy, cv2.COLOR_BGR2RGB)
pilImage = Image.fromarray(RGBimage)
#Output
pilImage.save('output.png', dpi=(300,300))
下面的图像是有时会发生错误的示例:对于某些形状或图像(输入),扩张的轮廓(第二张图片上的粗线)与原始形状的轮廓不匹配。扩张的轮廓应该与任何给定输入的原始形状相匹配。
【问题讨论】:
-
您正在寻找侵蚀,膨胀的双重性。应用膨胀后,腐蚀会将对象的边缘向后移动,以便对象恢复其原始大小。但漏洞将保持关闭。这种膨胀+腐蚀的组合称为闭合,因为它闭合(填充)孔。
-
@CrisLuengo 谢谢!您可以将其发布为答案,以便我接受您的答案吗?
-
随意自己写一个答案!
标签: python opencv image-processing computer-vision mathematical-morphology