使用ImageMagick查找每行中的第一个黑色像素

时间:2015-03-05 03:26:33

标签: imagemagick

对于图像中的每一行,我想找到该行中的第一个黑色(或第一个非白色)像素。例如,对于这样的图像:

enter image description here

我希望输出如下:

0
1
0

或者接近我能解析的东西。我认为可能有一种方法可以用subimage-search做到这一点,但我不太清楚如何做。有什么指针吗?

2 个答案:

答案 0 :(得分:5)

您不需要 subimage-search 来实现目标。问题可以简化为 文本解析

1。基本

考虑这一点:您可以告诉ImageMagick将任何图像转换为文本表示,其中包含每个像素的确切颜色信息。 示例:

convert wizard: textwizard.txt

wizard:是一个可用于测试目的的所有ImageMagick安装的内置图像。)

是的,就这么简单!只需添加.txt后缀即可请求此图像“格式”。的结果:

# ImageMagick pixel enumeration: 480,640,255,srgb
0,0: (255,255,255)  #FFFFFF  white
1,0: (255,255,255)  #FFFFFF  white
2,0: (255,255,255)  #FFFFFF  white
[....]
47,638: (246,247,249)  #F6F7F9  srgb(246,247,249)
48,638: (246,247,249)  #F6F7F9  srgb(246,247,249)
47,639: (236,235,236)  #ECEBEC  srgb(236,235,236)
48,639: (230,228,218)  #E6E4DA  srgb(230,228,218)
[....]
476,639: (255,255,255)  #FFFFFF  white
477,639: (255,255,255)  #FFFFFF  white
478,639: (255,255,255)  #FFFFFF  white
479,639: (255,255,255)  #FFFFFF  white

如果您查看输出的第一行,您会注意到ImageMagick使用它来详细说明有关图像的一些特殊信息:

# ImageMagick pixel enumeration: 480,640,255,srgb

这意味着:

  • 图像宽度为480像素,
  • 图像高640像素,
  • 图像使用范围0-255表示每个通道的颜色信息(相当于8位颜色深度),
  • 图像是在sRGB色彩空间中构建的

其他行由4列组成:

  1. 格式为(N,M)的第一列表示各个像素的确切位置为(row_number,column_number)(行号和列号的索引从零开始 - 第1行表示为0,第2行表示为1。)
  2. 其他三列,冗余地,每个列都保存完全相同的信息,每个列都有不同的表示法:第1列中给出的像素的确切颜色值。(最后一列将使用人类可读的名称,如果ImageMagick知道一个颜色值......)
  3.   

    作为旁注:你可以使用原始图像的这种文本表示(有或没有一些额外的修改)来重新创建一个真实的图像:

    convert textwizard.txt wizard.jpg
    
         

    2。选择特定行

    您应该知道可以使用以下语法选择图像的特定区域:

    image.png[WIDTHxHEIGHT+X_OFFSET+Y_OFFSET]
    

    因此,要仅选择特定行,您可以将HEIGHT设置为1。要完全获取任何行,请将X-OFFSET设置为0。要获取特定行,请相应地设置Y-OFFSET

    为了获得索引为47的行的值(对于上面使用的内置wizard:图像),我们可以这样做:

    convert wizard:[640x1+0+47] row47.txt
    
    cat row47.txt
     # ImageMagick pixel enumeration: 480,1,255,srgb
     0,0: (255,255,255)  #FFFFFF  white
     1,0: (255,255,255)  #FFFFFF  white
     2,0: (255,255,255)  #FFFFFF  white
     [....]
     428,0: (82,77,74)     #524D4A  srgb(82,77,74)
     429,0: (169,167,168)  #A9A7A8  srgb(169,167,168)
     430,0: (232,231,228)  #E8E7E4  srgb(232,231,228)
     432,0: (246,247,249)  #F6F7F9  srgb(246,247,249)
     [....]
     476,0: (255,255,255)  #FFFFFF  white
     477,0: (255,255,255)  #FFFFFF  white
     478,0: (255,255,255)  #FFFFFF  white
     479,0: (255,255,255)  #FFFFFF  white
    

    如果您不希望文本输出在文件中,但打印在标准输出通道上,则可以执行以下操作:

    convert wizard:[480x1+0+47] txt:-
    

    3。将它们拼接在一起

    根据以上信息片段,可以采用此任务的方法很明确:

    1. 遍历图像的所有像素行。
    2. 将每个像素的颜色值输出为文本。
    3. 查找第一个非白色像素并保留其位置信息。
    4. 4。可能的脚本(OS X,Linux,Unix)

      以下是可以使用的Bash脚本的主要部分:

      # Define some image specific variables (width, height, ...)
      image=${1}
      number_of_columns=$(identify -format '%W' ${image}) 
      width=${number_of_columns}                        # just an alias
      number_of_rows=$(identify -format '%H' ${image})
      height=${number_of_rows}                          # just an alias
      max_of_indices=$(( ${height} -1 ))
      
      # Loop through all rows and grep for first non-white pixel
      for i in $(seq 0 ${max_of_indices}); do
         echo -n "Row ${i} :  " ;
         convert ${image}[${width}x1+0+${i}] txt:- \
           | grep -v enumeration                   \
           | grep -v '#FFFFFF' -m 1                \
         || echo "All WHITE pixels in row!"  
      done
      

      -v white将取消选择包含字符串white的所有行。 -m 1参数将返回最多1个匹配项(即第一个匹配项)。

      它会很慢,但它会起作用。

答案 1 :(得分:3)

我会使用内置的棋盘图案来完成这样的事情:

convert -size 100x100 pattern:checkerboard -auto-level board.png

enter image description here

#!/bin/bash
convert wizard: txt: | awk -F'[,: ]' '
   /^#/ || /#FFFFFF/ {next}
   !($2 in fb)       {fb[$2]=$1}
   END               {r=$2;for(i=0;i<=r;i++){if(i in fb)print i,fb[i]; else print i,"-1"}}'

-F[,: ]告诉awk用逗号,冒号或空格分隔行上的单词 - 这有助于我到达每行开头的行和列。带有/^#/的行会跳过ImageMagick文本输出第一行中的注释以及包含white#FFFFFF的所有行。

然后,我有一个由图像行索引的数组fb[],它保存每行上第一个黑色像素的列。每次我找到一行不在我的数组fb[]中的行时,我将其保存在数组中。

最后,在END{}内,我通过fb[]打印这些行中第一个黑色像素的所有行和索引。请注意,我输出-1代替任何未定义的元素(即那些没有非白色像素的元素) - 感谢@KurtPfeifle提示。