我想根据图像形状绘制轮廓蒙版(形状)。我正在使用opencv-python 版本 4.9.0.80。
所以当我们有这样的图像时。
我们想要这样的输出,里面不带图像。避免灰色背景(添加它是为了使基于图像形状的轮廓蒙版能够正确可见)。
我已经尝试过cv.convexHull()
,但结果并没有达到预期。
我正在尝试这段代码。
import cv2 as cv
import numpy as np
path = '/opt/boundary-remover/SW_test2-01.png'
# path = '/opt/boundary-remover/scaled_2x.png'
# Load image
src = cv.imread(cv.samples.findFile(path))
cv.imwrite('1_original.png', src)
# Convert image to gray and blur it
src_gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
cv.imwrite('2_gray.png', src_gray)
# Detect edges using Canny
canny_output = cv.Canny(src_gray, 100, 200)
cv.imwrite('3_canny.png', canny_output)
# Find contours
contours, _ = cv.findContours(canny_output, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_NONE)
# Combine all contours into a single contour
all_contours = np.concatenate(contours)
# Find the convex hull object for the combined contour
hull = cv.convexHull(all_contours)
# Draw the combined contour and its convex hull
drawing = np.zeros((canny_output.shape[0], canny_output.shape[1], 3), dtype=np.uint8)
color = (0, 255, 0) # Green color
# cv.drawContours(drawing, [all_contours], 0, color)
# cv.imwrite('4_all_contours.png', drawing)
cv.drawContours(drawing, [hull], 0, color)
cv.imwrite('5_hull.png', drawing)
cv.drawContours(drawing, [hull], -1, color, thickness=cv.FILLED)
cv.imwrite('7_filled.png', drawing)
2
3 个回答
3
如果我理解正确的话,你想从白色背景中删除符号吗?灰色背景图像是您想要的示例吗?我可以帮助掩蔽部分。您可以尝试图像膨胀。您可以在各个步骤之后绘制图像,以直观地了解正在发生的情况。基本上,我对图像进行了二值化,并通过形态学开口去除了小的椒盐噪声。然后,用圆形核对图像进行膨胀。这种膨胀将图像“涂抹”成您想要的图案。然后,我填充放大图像中的空白。这可能不是您的通用解决方案,但它确实适用于提供的两种情况。
import cv2 as cv
import numpy as np
def get_circular_kernel(diameter):
"""
Author: F.Wessels
https://stackoverflow.com/a/70886011/15279460
"""
mid = (diameter - 1) / 2
distances = np.indices((diameter, diameter)) - np.array([mid, mid])[:, None, None]
kernel = ((np.linalg.norm(distances, axis=0) - mid) <= 0).astype(int)
return kernel
src = cv.imread(path)
cv.imshow('Original', src)
# Convert image to gray and then binarize
src_gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
th, im_th = cv.threshold(src_gray, 240, 255, cv.THRESH_BINARY)
# remove small objects to 'clean' image
src_gray_c = cv.morphologyEx(~im_th, cv.MORPH_OPEN, (3,3))
# dilate image with a circular kernel
dilated_image = cv.dilate(src_gray_c, kernel=get_circular_kernel(20).astype(np.uint8), iterations=1)
# Author: Abid Rahman K
# https://stackoverflow.com/a/10317883/15279460
des = dilated_image.copy()
contour,hier = cv.findContours(des,cv.RETR_CCOMP,cv.CHAIN_APPROX_SIMPLE)
for cnt in contour:
cv.drawContours(des,[cnt],0,255,-1)
final = des.copy()
cv.imshow('Final', final)
cv.waitKey(0)
cv.destroyAllWindows()
图1
图2
1
-
感谢你的回答。我尝试过这种方法,但方式不同。问题是我们传递的直径为 20
get_circular_kernel(20)
。基本上,我们正在填补空白。它在这里工作,但如果我们传递高尺寸(2x 高度和宽度)的相同图像,它将不起作用。即使我们能够根据图像形状动态计算直径值,如果我们的图像是圆形(O),它也不起作用,因为间隙太大。
–
|
以下是 Python/OpenCV 方法的概述。不幸的是,我的 OpenCV 目前无法运行,所以我在 Imagemagick 中进行了处理。
read image
convert to gray
threshold on white to make a mask and invert so white is black and the rest is white
get the convex hull of the mask
get the contour of the convex hull
draw a white filled contour on a copy of the input (or a black background) for the convex hull
dilate the previous result (filled convex hull) about 10-20 pixels with a circular kernel. This will round the corners.
Put the dilated image into the alpha channel of the input
图像魔术代码:
Convert white to transparent and extract the alpha channel as a mask
Get the convex hull about the alpha channel and draw it filled with white over the input image.
Apply a circular morphology dilate kernel with size of 10 to the filled convex hull image
Add the result as the alpha channel to the image
magick image1.jpg -fuzz 15% -transparent white -alpha extract x.png
magick x.png -set option:hull "%[convex-hull]" -fill white -draw "polygon %[hull]" x2.png
magick x2.png -morphology dilate disk:10 x3.png
magick image1.jpg x3.png -compose copy_opacity -composite x4.png
阈值图像作为掩模
填充凸包
形态扩张凸包
结果 – 将膨胀的填充凸包放入输入的 Alpha 通道中
添加
这是第二张图像的结果。
阈值图像作为掩模
填充凸包
形态扩张凸包
结果 – 将膨胀的填充凸包放入输入的 Alpha 通道中
下载后看到有透明背景
附加2
如果删除凸包步骤,您将得到一个更好地遵循字母形状的白色边框。
- 临界点
- 扩张阈值
- 将扩张的阈值图像放入输入的 Alpha 通道中
对于 Image1——Imagemagick 代码
magick image1.jpg -fuzz 15% -transparent white -alpha extract z.png
magick z.png -morphology dilate disk:10 z2.png
magick image1.jpg z2.png -compose copy_opacity -composite z3.png
临界点:
膨胀:
结果1:
对于图像2:
临界点:
膨胀:
结果2:
7
-
凸包的问题是它没有圆形边缘,并且不适用于文本图像(查看第二个 Betset 文本图像;这是我分享的最终结果)。
– -
您忽略了这样一个事实:带有圆形内核的 10-20 像素的扩张会使角落变圆。我已经更正了我的图像以正确显示这一点。
– -
@NiRmaL 请参阅我上面的评论以及我上面答案中的更改。
– -
感谢您提供更清晰的信息,但在预期的输出中,我们需要一个基于图像形状的掩模。例如,如果应用 10 像素的内边距,则距所有外边缘的距离应为 10 像素。请检查我共享的预期输出中带有文本“Betset”的图像。凸包提供类似框架的输出,因此在“Betset”中,我们在 B_t__t 附近得到更多间隙(e_se 形成 Betset)。
–
-
@NiRmaL 看看我的答案、那个例子和代码。我将图像处理到阈值以获得蒙版并将其放入图像的 Alpha 通道中。您必须选择正确的阈值。如果使用 OpenCV,上限范围为纯白色,下限范围低于纯白色约 15%,请尝试使用 cv2.inRange。如果您仍然得到其他结果,请显示您的代码和阈值结果。
–
|
如果我根据您在这里所说的话正确理解您的问题:避免灰色背景,那么这是一种方法:
def replaceGrayWithWhite(im):
imGray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
mask = (imGray>250).astype(np.uint8)
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
maskFilled = cv2.drawContours(mask.copy(), contours, -1, 1, -1)
maskFilledInv = cv2.bitwise_not(maskFilled) - 254
'''
Took this from here: https://stackoverflow.com/a/38493075/16815358
'''
foreground = cv2.bitwise_or(im, im, mask=maskFilled)
background = 255*np.ones_like(im)
background = cv2.bitwise_and(background, background, mask=maskFilledInv)
final = cv2.bitwise_or(foreground, background)
return final
导入的是 numpy 和 opencv,结果如下:
4
-
不,我添加的灰色背景是为了使基于图像形状的轮廓蒙版能够正确可见。我已经更新了描述。
– -
所以你想从白色背景图像变成灰色背景图像吗?
– -
如果是这样,greenerpasture的答案应该适合你想要的
– -
谢谢。 Greenerpasture 的回答方法存在一些问题。我为此添加了评论。
–
|
–
–
|