问题描述
我有数百个PNG图像,必须为它们生成相应的B& W图像,以显示对象的外部轮廓. PNG源图像具有Alpha通道,因此图像的无对象"部分是100%透明的.
I have hundreds of PNG images for which I have to generate corresponding B&W images that show the outer outline of the object. The source PNG image has alpha channel, so the "no object" parts of the image are 100% transparent.
棘手的部分是,如果对象中有孔,则不应在轮廓中看到这些孔.因此,如果源图像是甜甜圈,则相应的轮廓图像将是锯齿状的圆形线,中间没有同心的较小线.
The tricky part is that if the object has holes in it, those should not be seen in the outline. So, if the source image is, say, donut, the respective contour image would be a jagged circular line with no concentric smaller line in the middle.
以下是示例图像,源及其轮廓:
Here is an example image, source and its contour:
有没有可以执行此操作的库或命令行工具?理想情况下,可以在Python中使用某些东西.
Is there any library or command-line tool that can do this? Ideally, something that could be used from Python.
推荐答案
我同意amgaera.如果要查找轮廓,Python中的OpenCV是可以使用的最佳工具之一.与他/她的帖子一样,使用 方法,并使用RETR_EXTERNAL
标志获取形状的最外轮廓.这里有一些可复制的代码供您说明这一点.首先,您需要安装OpenCV和 NumPy
才能执行此操作.
I agree with amgaera. OpenCV in Python is one of the best tools you can use if you want to find contours. As with his/her post, use the findContours
method and use the RETR_EXTERNAL
flag to get the outer most contour of the shape. Here's some reproducible code for you to illustrate this point. You first need to install OpenCV and NumPy
to get this going.
我不确定您使用的是哪个平台,但是:
I'm not sure what platform you're using, but:
- 如果您使用的是Linux,只需在
libopencv-dev
和python-numpy
(即sudo apt-get install libopencv-dev python-numpy
)上执行apt-get
. - 如果使用的是Mac OS,请先安装Homebrew,然后再通过
brew install opencv
和brew install numpy
进行安装. - 如果您使用Windows,最好的方法是通过Christoph Gohlke针对Windows的非官方Python软件包:
http://www.lfd.uci.edu/~gohlke/pythonlibs/
-检查OpenCV软件包并安装它要求的所有依赖项,包括NumPy
,您可以在此页面上找到.
- If you're using Linux, simply do an
apt-get
onlibopencv-dev
andpython-numpy
(i.e.sudo apt-get install libopencv-dev python-numpy
). - If you're using Mac OS, install Homebrew, then install via
brew install opencv
thenbrew install numpy
. - If you're using Windows, the best way to get this to work is through Christoph Gohlke's unofficial Python packages for Windows:
http://www.lfd.uci.edu/~gohlke/pythonlibs/
- Check the OpenCV package and install all of the dependencies it is asking for, includingNumPy
which you can find on this page.
无论如何,我都拍摄了您的甜甜圈图像,并且只提取了带有甜甜圈的图像.换句话说,我创建了这张图片:
In any case, I took your donut image, and I extracted just the image with the donut. In other words, I created this image:
对于您的图像是PNG并具有Alpha通道,实际上并不重要.只要此图像中仅包含一个对象,我们实际上根本不需要访问Alpha通道.下载该图像后,将其另存为donut.png
,然后继续运行以下代码:
As for your images being PNG and having an alpha channel, that actually doesn't matter. So long as you have only a single object contained in this image, we actually don't need tho access the alpha channel at all. Once you download this image, save it as donut.png
, then go ahead and run this code:
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()
让我们慢慢看一下代码.首先,我们导入OpenCV和NumPy软件包.我将NumPy导入为np
,如果您到处都看到numpy
文档和教程,他们会这样做以最大程度地减少打字. OpenCV和NumPy可以相互配合,这就是为什么您需要同时安装两个软件包的原因.然后,我们使用imread
读取图像.我将标志设置为0
,以使图像变为灰度,使事情变得简单.加载图像后,然后运行findContours
,此函数的输出将输出包含两个内容的元组:
Let's go through the code slowly. First we import the OpenCV and NumPy packages. I imported NumPy as np
, and if you look at numpy
docs and tutorials everywhere, they do this to minimize typing. OpenCV and NumPy work with each other, which is why you need to install both packages. We then read in the image using imread
. I set the flag to be 0
to make the image grayscale to make things simple. Once I load in the image, I then run findContours
, and the output of this function outputs a tuple of two things:
-
contours
-这是一个数组结构,可为您提供图像中检测到的每个轮廓的(x,y)
坐标. -
hierarchy
-其中包含有关检测到的轮廓的其他信息,例如拓扑,但是为了这篇文章,我们跳过它.
contours
- This is an array structure that gives you the(x,y)
co-ordinates of each contour detected in your image.hierarchy
- This contains additional information about the contours you've detected, like the topology, but let's skip this for the sake of this post.
请注意,我指定了RETR_EXTERNAL
来检测对象的最外轮廓.我还指定了CHAIN_APPROX_NONE
标志,以确保获得没有任何近似的完整轮廓.一旦检测到轮廓,我们将创建一个全黑的新输出图像.这将包含我们检测到的甜甜圈的外部轮廓.创建此图像后,我们将运行 drawContours
方法.您指定要在其中显示轮廓的图像,之前创建的轮廓结构,并且-1
标志指示绘制图像中的所有轮廓.如果一切顺利,则应该只检测到一个轮廓.然后,指定希望轮廓显示的颜色.就我们而言,我们希望它是白色的.之后,指定要绘制轮廓的厚度.我选择了3像素的厚度.
Take note that I specified RETR_EXTERNAL
to detect the outer most contour of the object. I also specify the CHAIN_APPROX_NONE
flag to ensure we get the full contour without any approximations. Once we detect the contours, we create a new output image that is entirely black. This will contain our detected outer contour of the donut. Once we create this image, we run the drawContours
method. You specify the image you want to show the contours in, the contours structure that was created from earlier, and the -1
flag says to draw all of the contours in the image. If it all works out, you should only have one contour detected. You then specify what colour you want the contour to look like. In our case, we want this to be white. After, you specify how thick you want the contour to be drawn. I chose a thickness of 3 pixels.
我们要做的最后一件事就是显示结果.我叫 imshow
以显示原始甜甜圈图像的外观(灰度)以及输出轮廓的外观. imshow
并非故事的结局.调用cv2.waitKey(0)
之前,您将看不到任何输出.这就是说,您可以无限期显示图像,直到您按下一个键为止.按下某个键后,cv2.destroyAllWindows()
调用会关闭所有生成的窗口.
Last thing we want to do is show what the results look like. I call imshow
to show what the original donut image looks like (grayscale) and what the output contour looks like. imshow
isn't the end of the story. You won't see any output until you invoke cv2.waitKey(0)
. What this is saying now is you can display the images indefinitely until you push a key. Once you press on a key, the cv2.destroyAllWindows()
call closes all of the windows that were spawned.
这就是我得到的(一旦您重新排列窗户,使其并排放置):
This is what I get (once you rearrange the windows so that they're side-by-side):
作为额外的奖励,如果您要保存图像,只需运行 imwrite
保存图像.您可以指定要写入的图像的名称以及要访问的变量.因此,您将执行以下操作:
As an additional bonus, if you want to save the image, you just run imwrite
to save the image. You specify the name of the image you want to write, and the variable you are accessing. As such, you would do something like:
cv2.imwrite('contour.png', out)
然后,您将该轮廓图像保存到名为contour.png
的文件中.
You'll then save this contour image to file which is named contour.png
.
这应该足以让您入门.
This should be enough to get you started.
祝你好运!
这篇关于处理图像以找到外部轮廓的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!