处理图像以查找外部轮廓

时间:2014-09-08 21:53:11

标签: python image-processing

我有数百张PNG图像,我必须生成相应的B& W图像,以显示对象的外部轮廓。源PNG图像具有Alpha通道,因此图像的“无对象”部分是100%透明的。

棘手的部分是,如果物体上有洞,则不应在轮廓中看到那些洞。因此,如果源图像是,例如,甜甜圈,相应的轮廓图像将是锯齿状的圆形线,中间没有同心的小线。

以下是示例图像,来源及其轮廓:enter image description here

是否有可以执行此操作的库或命令行工具?理想情况下,可以从Python中使用。

4 个答案:

答案 0 :(得分:11)

我同意amgaera。如果您想要查找轮廓,Python中的OpenCV是您可以使用的最佳工具之一。与他/她的帖子一样,使用findContours方法并使用RETR_EXTERNAL标志来获取形状的最外轮廓。这里有一些可重现的代码供您说明这一点。您首先需要安装OpenCV和NumPy才能实现此目的。

我不确定您使用的平台,但是:

  • 如果您正在使用Linux,只需在apt-getlibopencv-dev python-numpy(即sudo apt-get install libopencv-dev python-numpy)上执行brew install opencv即可。
  • 如果您使用的是Mac OS,请安装Homebrew,然后通过brew install numpy然后NumPy安装。
  • 如果你正在使用Windows,最好的方法就是通过Christoph Gohlke的Windows非官方Python软件包:http://www.lfd.uci.edu/~gohlke/pythonlibs/ - 检查OpenCV包并安装所有依赖项它要求,包括donut.png,你可以在这个页面找到。

无论如何,我拍了你的甜甜圈图片,我用甜甜圈提取了图像。换句话说,我创建了这个图像:

enter image description here

至于你的图像是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) 调用将关闭所有生成的窗口。

这就是我得到的(一旦你重新安排窗户,他们就会并排):

enter image description here


作为额外奖励,如果您想保存图片,只需运行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

<强>结果:

enter image description here

如果您要概述数百(或数千)个图像,我建议使用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

显示无效语法