1


简而言之,我想找出具有主要颜色的像素的坐标。

具体来说,我想实现以下目标:

  1. 找到主要颜色。主要是指图像中大多数像素具有的颜色(我使用直方图实现了它)

  2. 在获得这种颜色(在我的情况下是黑色)之后,我想找到一个黑色的像素,并且它只被黑色像素包围。基本上,黑色最集中区域的中心。

到目前为止,我只能获得主要颜色。

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

4

4 回答 4

4

(更新以消除一些弱点)

首先,找到你的主要颜色。您似乎已经知道如何执行此操作,因此我跳过此步骤。(我也没有为此检查或验证您的代码......)

您的代码有一些弱点:

  1. 你只清理了x.txt,而不清理你的x1.txt.

  2. | 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 方形内核)。在该步骤之后,在生成的图像中,只有那些像素将保持纯黑色,这些像素在原始图像中仅被黑色像素包围。

第三,使所有非黑色像素变白:通过对图像应用 - 操作。(另请参阅“形态学”,尤其是“侵蚀”。)这会通过将所有非黑色颜色变为白色来消除图像中的所有其他颜色,并简化对纯黑色像素的搜索。(注意:这不适用于不包含至少一个纯黑色像素的 3x3 像素区域的 src.png 文件...-fill white +opaque black -fill white -opaque black

第四:我们必须考虑图像边界上的像素(这些像素没有 8 个邻居!),因此我们将颜色“无”分配给这些像素-virtual-pixel none

我将使用名为“logo:”的 ImageMagick 内置特殊图片来演示我的方法:

convert logo: logo.png

正如您很容易看到的那样,该图像以白色作为其主要颜色。(所以我切换了这个例子的代码,使所有白色像素变黑......)

到目前为止的命令行:

convert                                                \
   logo:                                               \
  -virtual-pixel none                                  \
   $(for i in {1..2}; do echo " -blur 1x65535 "; done) \
  -fill black                                          \
  -opaque white                                        \
   2_blur-logo-virtpixnone.png

这是并排的2张图片:

  • 左侧的 logo.png
  • 2_blur-log-virtpixnone.png 在右边

 

第五: 皮革,冲洗,重复。

现在让我们应用该算法的更多迭代,例如 100、500、1000 和 1300,并且还对结果应用注释,以便我们知道哪个图像是哪个:

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

正如您可以清楚地看到的那样,我的算法使黑色区域收敛到您在查看原始图像时直觉猜测为白色区域的“中心”的那个点logo.png

 

 

一旦你得到一个没有黑点的输出图像,你就太频繁地迭代了。返回一个迭代。:-)

现在应该只有非常有限数量的符合您标准的候选像素。

于 2012-08-14T09:00:37.850 回答
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
于 2015-04-15T15:07:46.097 回答
0

这只是一个预感而不是一个完整的答案,但您可以先使用模糊滤镜对图像进行预处理。那么模糊图像中的黑色像素在原始图像中一定有黑色邻域。

不过,这不适用于任意颜色。

于 2012-08-13T21:23:13.327 回答
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
于 2014-11-03T11:25:37.427 回答