我有数百张PNG图像,我必须生成相应的B& W图像,以显示对象的外部轮廓。源PNG图像具有Alpha通道,因此图像的“无对象”部分是100%透明的。
棘手的部分是,如果物体上有洞,则不应在轮廓中看到那些洞。因此,如果源图像是,例如,甜甜圈,相应的轮廓图像将是锯齿状的圆形线,中间没有同心的小线。
以下是示例图像,来源及其轮廓:
是否有可以执行此操作的库或命令行工具?理想情况下,可以从Python中使用。
答案 0 :(得分:11)
我同意amgaera。如果您想要查找轮廓,Python中的OpenCV是您可以使用的最佳工具之一。与他/她的帖子一样,使用findContours
方法并使用RETR_EXTERNAL
标志来获取形状的最外轮廓。这里有一些可重现的代码供您说明这一点。您首先需要安装OpenCV和NumPy
才能实现此目的。
我不确定您使用的平台,但是:
apt-get
和libopencv-dev
python-numpy
(即sudo apt-get install libopencv-dev python-numpy
)上执行brew install opencv
即可。 brew install numpy
然后NumPy
安装。 http://www.lfd.uci.edu/~gohlke/pythonlibs/
- 检查OpenCV包并安装所有依赖项它要求,包括donut.png
,你可以在这个页面找到。无论如何,我拍了你的甜甜圈图片,我用甜甜圈提取了图像。换句话说,我创建了这个图像:
至于你的图像是PNG并且有alpha通道,这实际上并不重要。只要您在此图片中只包含一个对象,我们实际上根本不需要访问Alpha通道。下载此图像后,将其另存为import cv2 # Import OpenCV
import numpy as np # Import NumPy
# Read in the image as grayscale - Note the 0 flag
im = cv2.imread('donut.png', 0)
# Run findContours - Note the RETR_EXTERNAL flag
# Also, we want to find the best contour possible with CHAIN_APPROX_NONE
contours, hierarchy = cv2.findContours(im.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
# Create an output of all zeroes that has the same shape as the input
# image
out = np.zeros_like(im)
# On this output, draw all of the contours that we have detected
# in white, and set the thickness to be 3 pixels
cv2.drawContours(out, contours, -1, 255, 3)
# Spawn new windows that shows us the donut
# (in grayscale) and the detected contour
cv2.imshow('Donut', im)
cv2.imshow('Output Contour', out)
# Wait indefinitely until you push a key. Once you do, close the windows
cv2.waitKey(0)
cv2.destroyAllWindows()
,然后继续运行此代码:
np
让我们慢慢浏览一下代码。首先,我们导入OpenCV和NumPy包。我将NumPy导入为numpy
,如果你到处查看imread
个文档和教程,他们会这样做以尽量减少输入。 OpenCV和NumPy相互协作,这就是你需要安装这两个软件包的原因。然后,我们使用0
读取图像。我将标志设置为findContours
以使图像灰度化使事情变得简单。一旦我加载到图像中,然后运行contours
,此函数的输出将输出两个元组的元组:
(x,y)
- 这是一个数组结构,可以为您提供图像中检测到的每个轮廓的hierarchy
坐标。RETR_EXTERNAL
- 其中包含有关您已检测到的轮廓的其他信息,例如拓扑,但为了这篇文章,请跳过此内容。请注意,我指定CHAIN_APPROX_NONE
来检测对象的最外轮廓。我还指定了-1
标志,以确保我们得到完整的轮廓而没有任何近似值。一旦我们检测到轮廓,我们就会创建一个完全黑色的新输出图像。这将包含我们检测到的甜甜圈外轮廓。创建此图片后,我们运行drawContours
方法。您可以指定要在其中显示轮廓的图像,从之前创建的轮廓结构,以及imshow
标记用于绘制图像中的所有轮廓。如果一切顺利,您应该只检测到一个轮廓。然后指定轮廓看起来的颜色。在我们的例子中,我们希望这是白色的。之后,指定要绘制轮廓的厚度。我选择了3像素的厚度。
我们要做的最后一件事是展示结果的样子。我打电话给imshow
来显示原始甜甜圈图像的样子(灰度)以及输出轮廓的样子。 cv2.waitKey(0)
并不是故事的结局。在调用cv2.destroyAllWindows()
之前,您不会看到任何输出。现在说的是你可以无限制地显示图像,直到你按下一个键。按下某个键后,cv2.imwrite('contour.png', out)
调用将关闭所有生成的窗口。
这就是我得到的(一旦你重新安排窗户,他们就会并排):
作为额外奖励,如果您想保存图片,只需运行imwrite
即可保存图片。您可以指定要写入的图像的名称以及要访问的变量。因此,您可以执行以下操作:
contour.png
然后,您将此轮廓图像保存到名为{{1}}的文件中。
这应该足以让你入门。
祝你好运!答案 1 :(得分:6)
OpenCV具有findContours功能,可以完全满足您的需求。您需要将轮廓检索模式设置为CV_RETR_EXTERNAL
。要加载图片,请使用imread功能。
答案 2 :(得分:4)
我建议使用here免费提供的ImageMagick。无论如何,它包含在许多Linux发行版中。它还提供Python,Perl,PHP,C / C ++绑定。
我只是在下面的命令行中使用它。
convert donut.png -channel A -morphology EdgeOut Diamond +channel -fx 'a' -negate output.jpg
基本上,-channel A
选择alpha(透明度)并应用形态学来提取不透明区域的轮廓。然后+channel
告诉ImageMagick我现在再次处理所有频道。 -fx
是一个自定义函数(运算符),我在其中将输出图像的每个像素设置为a
- 修改后的Alpha通道中的alpha值。
<强>被修改强>
以下可能比使用上述fx
运算符更快:
convert donut.png -channel RGBA -separate -delete 0-2 -morphology EdgeOut Diamond -negate output.png
<强>结果:强>
如果您要概述数百(或数千)个图像,我建议使用here提供的GNU Parallel。然后它将使用您的所有CPU核心来快速完成工作。你的命令看起来像这样 - 但是请先备份并继续复制,直到你掌握它为止!
parallel convert {} -channel A -morphology EdgeOut Diamond +channel -fx 'a' -negate {.}.jpg ::: *.png
这表示要使用:::
之后的所有内容作为要处理的文件。然后并行使用所有可用内核,转换每个PNG文件并将其名称更改为相应的JPEG文件作为输出文件名。
答案 3 :(得分:0)
convert donut.png -channel RGBA -separate -delete 0-2 -morphology EdgeOut Diamond -negate output.png
显示无效语法