【问题标题】:imagemagick get a co-ordinate for pixel with most common colorimagemagick 获取具有最常见颜色的像素的坐标
【发布时间】:2015-04-15 23:07:46
【问题描述】:


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

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

  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 版

【问题讨论】:

  • 我不明白您对“最常见颜色”的定义。您能否重新表述您的问题,并详细说明您想要实现的目标?
  • 好的,但仍然令人困惑的是,您还谈到了“黑色像素的随机坐标,其周围只有黑色像素”...

标签: imagemagick


【解决方案1】:

(更新以消除一些弱点)

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

你的代码有一些弱点:

  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,看看我的意思。)

第二,在图像上应用非常少量的blur,方法是对每个位置的每个像素及其周围的 8 个像素进行平均:-blur 1x65535(此操作使用一个 3x3 的正方形内核)。在该步骤之后,在生成的图像中,只有那些像素将保持纯黑色,原始图像中仅被黑色像素包围。

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

第四:我们必须考虑图像边界上的像素(这些像素没有 8 个邻居!),因此我们用 @ 为这些像素分配颜色“无” 987654344@.

我将使用名为“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

这是两张并排的图片:

  • 左侧的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 时直觉猜测为白色区域“中心”的那个点:

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

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

【讨论】:

  • 哇...干得好...非常感谢!!
  • @abarik:呵呵……我喜欢挑战,这就是其中之一:-)
【解决方案2】:

我喜欢这种使用欧几里得距离形态学的方法 - 它使巫师看起来相当恶魔(!)并且运行不到一秒钟!

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

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

      这是一个在几分之一秒内运行的不同想法......

      如果您正在寻找较大的黑色区域,请反复将图像平铺成越来越小的图块,直到获得全黑的图块,然后选择该图块的中心。这是一个显示收敛的小视频。该过程正在查看半透明的红色区域,直到找到仅包含黑色的区域。

      代码如下:

      #!/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
      

      【讨论】:

      • 这是一个很好的第一次迭代。但是在像您一样找到黑色区域之后:(1)不能保证该图块是最大可能的黑色图块(2)即使那样,图块的中心也不一定是图像内最大的连续黑色区域的中心
      • @KurtPfeifle 是的,我同意它不是“绝对最佳”的黑色像素 - 虽然它很快,并且确实提供了一个非常好的黑色像素,周围有大量其他类似的黑色像素。我的建议是,如果不需要您的解决方案的优雅和精确,它可能“足够好”。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-07-17
      • 2011-05-24
      • 2015-05-04
      • 1970-01-01
      • 2016-04-30
      • 2021-12-13
      • 2019-09-18
      相关资源
      最近更新 更多