简而言之,我想找出一个主色的像素的坐标。
具体来说,我希望实现以下目标:
找到主要颜色。占主导地位的是指图像中大部分像素的颜色(我使用直方图实现了它)
获得这种颜色(在我的情况下是黑色)后,我想找到一个黑色的像素,它只被黑色像素包围。基本上是黑色最集中区域的中心。
直到现在,我才能获得主要颜色。
convert src.png -format %c histogram:info: > x.txt
cat x.txt | awk '{print $1}' | sed 's/://g' > x1.txt
h=$(sort -n x1.txt | tail -1)
cat x.txt | grep "$h"
rm -rf x.txt
结果:
169211: ( 0, 0, 0,255) #000000 black
现在,我也可以获得黑色的所有坐标
convert src.png txt: | grep black
469,799: ( 0, 0, 0,255) #000000 black
470,799: ( 0, 0, 0,255) #000000 black
471,799: ( 0, 0, 0,255) #000000 black
472,799: ( 0, 0, 0,255) #000000 black
473,799: ( 0, 0, 0,255) #000000 black
474,799: ( 0, 0, 0,255) #000000 black
475,799: ( 0, 0, 0,255) #000000 black
476,799: ( 0, 0, 0,255) #000000 black
477,799: ( 0, 0, 0,255) #000000 black
478,799: ( 0, 0, 0,255) #000000 black
...
但是我需要一个黑色像素的随机坐标,它位于一个只有黑色像素的地方......
我正在使用Linux和Imagemagick版本6.6.5
答案 0 :(得分:4)
首先,找到你的主要颜色。您似乎已经知道如何执行此操作,因此我跳过此步骤。 (我也没有检查或验证你的代码......)
您的代码存在一些缺点:
您只清理x.txt
,而不是x1.txt
。
您应该从第二个命令中删除| sed 's/://g'
部分。它会从您的变量中删除:
冒号,但这会导致h=21
(而不是h=21:
)导致您grep "$h"
找到所有这些行:
1: (221, 86, 77) #DD564D srgb(221,86,77)
1: (221,196,192) #DDC4C0 srgb(221,196,192)
1: (221,203,197) #DDCBC5 srgb(221,203,197)
[...]
21: (255,255,255) #FFFFFF white
如果你保持h=21:
,你会找到你要找的那一行! (验证示例:使用内置的rose:
图片代替src.png
来查看我的意思。)
第二,在图片上应用极少量的模糊,方法是将每个像素及其每个位置的8个周围像素取平均值:-blur 1x65535
(此操作使用3x3平方内核)。在该步骤之后,在得到的图像中,仅那些像素将保持纯黑色,其仅被原始图像中的黑色像素包围。
第三次,将所有非黑色像素设为白色:对图像应用 -fill white +opaque black
-fill white -opaque black
- 操作。 (另请参阅"Morphology",特别是"Erosion"。)通过将所有非黑色颜色设置为白色,简化了对纯黑色像素的搜索,从图像中删除了所有其他颜色。 (注意:这对于这样的src.png文件不起作用,这些文件不包含至少一个带有纯黑色像素的3x3像素区域...... )
第四:我们必须考虑图像边框上的像素(这些像素没有8个邻居!),因此我们使用{为它们指定颜色'none' {1}}。
我将使用名为“logo:”的ImageMagick内置特殊图片来演示我的方法:
-virtual-pixel none
正如您可以很容易看到的,此图像以白色为主导颜色。 (所以我切换这个例子的代码,使所有白色像素变黑......)
到目前为止命令行:
convert logo: logo.png
以下是两张并排的图片:
第五: 皮革,冲洗,重复。
现在让我们再应用这个算法的几次迭代,比如100,500,1000和1300,并且还允许对结果应用注释,这样我们就知道哪个图像是哪个:
convert \
logo: \
-virtual-pixel none \
$(for i in {1..2}; do echo " -blur 1x65535 "; done) \
-fill black \
-opaque white \
2_blur-logo-virtpixnone.png
正如你可以清楚地看到的那样,我的算法使得黑色区域朝向那个位置收敛,当你查看原始for j in 100 500 1000 1300; do
convert \
logo: \
-virtual-pixel none \
$(for i in $(seq 1 ${j}); do echo " -blur 1x65535 "; done) \
-fill black \
-opaque white \
-gravity NorthEast -annotate +10+10 "$j iterations" \
${j}_blur-logo-virtpixnone.png
done
时,你已经直观地猜测它是白色区域的“中心”:
一旦你到达没有留下黑点的输出图像,你就经常迭代一次。返回一次迭代。 :-)
现在应该只有非常有限数量的候选像素符合您的标准。
答案 1 :(得分:1)
我喜欢这种使用欧几里德距离形态学的方法 - 它让向导看起来很恶魔(!)并在一秒钟内运行!
convert logo: -virtual-pixel none \
-morphology Distance Euclidean \
-auto-level -channel GB \
-threshold 85% 85.png
并且95%和99%的阈值可以获得这些:
而且,如果你想要文本坐标:
convert logo: -virtual-pixel none -morphology Distance Euclidean -auto-level -threshold 99% txt:- | grep white
151,328: (255,255,255,1) #FFFFFF white
152,328: (255,255,255,1) #FFFFFF white
答案 2 :(得分:0)
这只是一种预感,而不是一个完整的答案,但您可以先使用模糊滤镜预处理图像。然后,模糊图像中黑色的像素必须在原始图像中具有黑色邻域。
但这对任意颜色都不起作用。
答案 3 :(得分:0)
这是一个不同的想法,只需几分之一秒......
如果您正在寻找大的黑色区域,请反复将图像平铺为越来越小的图块,直到您获得完全黑色的图块,然后选择该图块的中心。这是一个显示收敛的小视频。该过程正在查看半透明的红色区域,直到发现只包含黑色的区域。
以下是代码:
#!/bin/bash
# Set interesting pixels to black, others to white
convert logo: -fill black +opaque white -negate start.png
# Now tile, into 4,9,16,25 till we get a tile that is fully black
for i in $(seq 2 8); do
rm tmp*.png 2> /dev/null
convert -crop ${i}x${i}@ start.png tmp%d.png
for f in tmp*png; do
mean=$(identify -format "%[mean]" "$f")
if [ "$mean" = "0" ]; then
j=$((i*i))
echo "$f" of $j tiles
exit
fi
done
done
输出是这样的:
tmp6.png of 9 tiles