如何解决扩张图像以去除间隙并获得原始轮廓尺寸的扩张轮廓
我正在尝试去除图像中任何给定形状的间隙或孔洞。
我遵循的替代方法是:我对图像进行阈值处理以获得二值图像并应用膨胀来消除间隙,但这会导致形状变大。如何将这些扩张的轮廓缩放到与原始图像的轮廓相同的大小?或者我可以以某种方式放大图像并仍然具有与原始形状相同的大小吗?有没有更好的选择?
我曾尝试应用扩张,然后在扩张图像的轮廓中进行缩放,但一直无法以一种总是导致扩张轮廓与原始轮廓具有相同大小的方式来做到这一点(有时扩张的轮廓并且缩放后的轮廓与原始轮廓的大小相同,有时不同)。
此外,我如何确保以始终消除原始图像间隙的方式应用扩张,无论其形状有多大?我意识到有时扩张的方式是间隙仍然可见但最小化而不是消除,这不是目标。
这就是我目前所拥有的:
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(),(0,0),24)
x,y,w,h = cv2.boundingRect(contours[-1])
cv2.rectangle(canvas,(x,y),(x+w,y+h),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,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],(50,50,50),24)
RGBimage = cv2.cvtColor(im_copy,cv2.COLOR_BGR2RGB)
pilImage = Image.fromarray(RGBimage)
#Output
pilImage.save('output.png',300))
下面的图像是有时会发生的错误示例:对于某些形状或图像(输入),扩张的轮廓(第二张图片上的粗线)与原始形状的轮廓不匹配。扩张的轮廓应该与任何给定输入的原始形状相匹配。
Bad Output: Original shape + dilated contours scaled in
解决方法
您可以简单地使用 ConvexHull 概念来填补空白。
在 Hull Image
中,您可以看到一条红线轮廓,它是您想要的蓝线轮廓的 convex hull
。
import cv2
image = cv2.imread("image.png")
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
_,threshold = cv2.threshold(gray,100,255,cv2.THRESH_BINARY_INV)
cv2.imshow("Threshold",threshold)
contours,hierarchy = cv2.findContours(threshold,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
contour = max(contours,key=cv2.contourArea)
cnt_hull = cv2.convexHull(contour)
cv2.drawContours(image,[contour],-1,(255,0),2)
cv2.drawContours(image,[cnt_hull],(0,255),2)
cv2.imshow("Hull Image",image)
cv2.waitKey(0)
cv2.destroyAllWindows()
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。