从背景中分离人物

Isolating figures from a background

抱歉,我没有合适的术语来问这个问题,但简单来说,我有几张这样的图片。白色区域的大小并不总是相同,但大多是矩形的。颜色总是一样的。这是一张图片,我需要将数字从白色背景中分离出来,或者以不同的方式解释,我需要将黑色背景更改为白色...

并让它看起来像这样。

请注意,一些图形触及了白色与黑色相接的边缘。

工具、库或编程语言并不重要,只要能完成即可。

如果您的意思是用透明度替换白色(a.k.a。图像编辑器中的颜色到 alpha),神奇的公式是:

convert original.png ( -clone 0 -fill "#a0132e" -colorize 100 ) ( -clone 0,1 -compose difference -composite -separate +channel -evaluate-sequence max -auto-level ) -delete 1 -alpha off -compose over -compose copy_opacity -composite output.png

说明here

这是使用 Imagemagick 处理此图像的一种方法。你先 trim 黑色区域,然后将图像分成 3 个相等的部分,然后 trim 那些,然后展平到白色。 trim 和裁剪跟踪原始偏移量,因为我不使用 +repage 删除虚拟 canvas.

magick original.png -fuzz 5% -trim -crop 3x1@ -trim -background white -flatten result.png

https://www.imagemagick.org/Usage/crop/#crop_equal https://www.imagemagick.org/Usage/crop/#trim

@Mack wrote:

This method of trimming works on this particular image, but what happens when spacing is uneven? Is there a better way to do this without the trimming and cropping?

一种方法是将每个白色方块从背景中分离成单独的图像。我有一个 bash unix shell 脚本,multicrop2,可以做到这一点。但是对于这个图像,它会产生一个超大图像。例如:

magick original.png tmp.png
multicrop2 -b white tmp.png result.png

您可以舍弃此处显示的最后一个。

http://www.fmwconcepts.com/imagemagick/index.html

查看我的脚本 multicrop2

与目前一样,脚本会丢失每个输出图像的虚拟 canvas。但我也许可以添加一个参数来保留它,这样 3 个好的图像就可以被拼合成白色,这样单独的图像就会在适当的位置合并回白色背景。

有趣的问题!我假设你意识到你的小白 windows 你的符号没有水平对齐?我们稍后再谈。我有一个基于 "squeezebox" 或手风琴的有趣方法...

有 3 个部分,所以我会在每个部分下面做一条水平线将它们分开。


第 1 部分

从左右两侧一起挤压图像(如挤压框),直到它只有一个像素宽的列但与原始高度相同:

现在对列设置阈值,以便只有全黑的水平线保持黑色。水平线上任何有 window 或任何白色像素的地方都会变成白色。然后反转。

现在,使用最近邻采样将列拉伸(扩展那个 squeezebox)回到它的原始大小:


第 2 部分

现在再次做同样的事情,但将挤压盒旋转 90 度。基本上,我们要将图像压缩到 1 像素高,设置阈值并取反,然后拉伸(扩展垂直旋转的 squeezebox)直到它回到原来的高度:


第 3 部分

现在将原始图像与上面的两个黑白条纹图像放在一起,然后在每个像素位置选择最亮的像素:

代码如下所示:

#!/bin/bash

# Get width and height
read w h < <(identify -format "%w %h" image.png)
echo $w $h

magick image.png -threshold 50% \
   \( -clone 0 -resize 1x\! -threshold 1% -negate -scale ${w}x${h}\! \) \
   \( -clone 0 -resize x1\! -threshold 1% -negate -scale ${w}x${h}\! \) \
   -evaluate-sequence max result.png


好的,这还不错,而且不依赖于刚好有 3 个 windows。但是,正如我在开始时所说的那样,白色的小 windows 并没有在它们的顶部对齐,因此您会在 windows 周围得到人工制品 - 仅在水平方向上,因为在垂直方向上只有一个图像方向所以没有对齐。基本上,我建议做一点形态学,让你的 windows 顶部和底部的所有 3 个像素都变小,代码看起来像这样:

#!/bin/bash

# Get width and height
read w h < <(identify -format "%w %h" image.png)
echo $w $h

magick image.png -threshold 50% \
   \( -clone 0 -resize 1x\! -threshold 1% -negate -scale ${w}x${h}\! -morphology dilate rectangle:7x7 \) \
   \( -clone 0 -resize x1\! -threshold 1% -negate -scale ${w}x${h}\!                                  \) \
   -evaluate-sequence max result.png

rectangle:7x7 更改为更大的数字,以便在 window 边缘周围增加 trim 像素。基本上它将 trim 顶部和底部的像素数减半。所以 rectangle:7x7 会让你的 window 顶部和底部变小 3 个像素,而 rectangle:15x15 会让它们变小 7 个像素。这是 Anthony Thyssen 关于如何使用 ImageMagick 的优秀页面的 link - 尤其是形态学。

这是另一种可能适用于您的其他图像的方法...克隆,然后将小白色 windows 扩大(放大)7 个像素,然后再次腐蚀它们,反转并选择最亮的像素:

convert image.png \( +clone -morphology dilate square:7x7 -morphology erode square:7x7 -negate \) -evaluate-sequence max  result.png

这是另一个想法...

convert image.png -threshold 50% \
   \( +clone -morphology edgeout square:3x3 -write step1.png \
      -fill red -draw 'color 0,0 floodfill' -write step2.png \
      -fill black +opaque red -fill black   -write step3.png \
      -opaque red                           -write step4.png \
      -morphology dilate square:3x3         -write step5.png \
   \) -evaluate-sequence max result.png

这是步骤 1-5 和结果。您可以从代码中删除所有 -write stepX.png 部分,它们只是为了让您看到我在做什么:

步骤 1 - "show me all the pixels around the edges of the white areas"

步骤2 - "flood fill with red from the top-left corner now we have proper edges to our windows so that the flood doesn't "泄漏进入windows

步骤 3 - "make everything that is not red into black"

步骤 4 - "make everything that is red into white"

步骤 5 - "make the white shapes a fraction larger"

结果 - "at every pixel location, pick the pixel that is lightest out of the current and original image"

马克的形态学方法比这个简单一点。所以我建议将它作为迄今为止最好的方法。但这里有一个类似的方法(有点像他最后两种方法的混合体)可能会引起人们的兴趣。我已经包含 +write tmpX.png 来显示步骤。那些可以删除。 (使用 Imagemagick 6.9.9.33 的 Unix 语法)

convert original.png \
\( -clone 0 -morphology edgeout square:3 -negate +write tmp1.png \) \
\( -clone 0 -morphology dilate square:3 \
-morphology edge square:3 +write tmp2.png \) \
-delete 0 \
-evaluate-sequence max \
result.png

第 1 行:读取输入

第 2 行 - tmp1.png:使用 morphology edgeout 将图像转换为白色背景上周围有黑框的黑色曲线(如 Mark 的其他示例)。

第 3 行和第 4 行 - tmp2.png:使用形态学膨胀(去除曲线)和边缘在黑色背景上围绕白色区域创建一个白色轮廓框。

第 6 行和第 7 行:result.png 使用 tmp2.png 通过逐个像素地取两个图像之间的最大值来删除 tmp1.png 中的黑框。

为了比较,这里是我简化了一点的马克的优雅方法:

convert original.png \
\( +clone -morphology close square:3 -negate +write tmp1.png \) \
-evaluate-sequence max \
result.png

第 1 行:读取输入

第2行:- tmp1.png:使用morphology close(与dilate和erode相同)创建一个黑框来替换原来的白色区域,包括黑色曲线。正方形大小可以低至 3,但不能低于 3。曲线末端越小越少。

第 3 行:通过逐像素计算两个图像之间的最大值,去除原始图像中除曲线之外的所有黑色。

这里有一个稍微不同的解决方案,它使用高斯模糊作为形态学运算符。我用了pyvips,但在magick中重做很容易。

这个想法是,如果您使用相当大的 sigma 进行 gaussblur,然后阈值 > 0,您将通过高斯半径扩展所有白色,从而填充线条。

巧妙的一点是,这可以第二次使用,阈值翻转以完全按照您扩张的量进行侵蚀。只需第二次模糊相同的量,但现在执行 != 255 并且您将拥有背景的形状!按位或与您的原始图像进行解决。

import sys
import pyvips

im = pyvips.Image.new_from_file(sys.argv[1], access="sequential")

bg = im.gaussblur(2) > 0
bg = bg.gaussblur(2) != 255

im |= bg

im = im.write_to_file(sys.argv[2])

然后:

python characters.py ~/pics/characters.png x.png

品牌:

它的一个很好的特点是没有泛滥,因此您可以流式传输图像。它适用于任何大小的图像并且需要很少的内存。

这是使用 Imagemagick 的另一种相当简单的形态学方法 (bottomhat)。在这种情况下,内核大小需要至少为 4。参见 https://www.imagemagick.org/Usage/morphology/#bottom-hat

输入:

convert source.png -morphology bottomhat octagon:4 -negate result.png