【问题标题】:Dilate image to remove gaps and get dilated contours in the original contours size扩张图像以消除间隙并获得原始轮廓大小的扩张轮廓
【发布时间】: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))

下面的图像是有时会发生错误的示例:对于某些形状或图像(输入),扩张的轮廓(第二张图片上的粗线)与原始形状的轮廓不匹配。扩张的轮廓应该与任何给定输入的原始形状相匹配。

Input: Original Shape

Bad Output: Original shape + dilated contours scaled in

【问题讨论】:

  • 您正在寻找侵蚀,膨胀的双重性。应用膨胀后,腐蚀会将对象的边缘向后移动,以便对象恢复其原始大小。但漏洞将保持关闭。这种膨胀+腐蚀的组合称为闭合,因为它闭合(填充)孔。
  • @CrisLuengo 谢谢!您可以将其发布为答案,以便我接受您的答案吗?
  • 随意自己写一个答案!

标签: python opencv image-processing computer-vision mathematical-morphology


【解决方案1】:

您可以简单地使用 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, 0), 2)
cv2.drawContours(image, [cnt_hull], -1, (0, 0, 255), 2)
cv2.imshow("Hull Image", image)

cv2.waitKey(0)
cv2.destroyAllWindows()

【讨论】:

  • 谢谢!我认为这对规则形状很有用,但在输入有斜线和不规则的情况下(例如上下倾斜的线),凸包和形状的轮廓之间会有额外的空间并且无法仅识别差距@VatsalParsaniya
猜你喜欢
  • 1970-01-01
  • 2020-11-15
  • 2022-01-10
  • 2021-01-05
  • 1970-01-01
  • 2020-02-27
  • 2019-02-01
  • 1970-01-01
  • 2012-10-26
相关资源
最近更新 更多