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

pjr*_*die 2 imagemagick

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

在此输入图像描述

我希望输出如下:

0
1
0
Run Code Online (Sandbox Code Playgroud)

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

Kur*_*fle 5

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

1.基础知识

考虑一下:你可以告诉ImageMagick将任何图像转换为文本表示,它保存每个像素的确切颜色信息.例:

convert wizard: textwizard.txt
Run Code Online (Sandbox Code Playgroud)

                  (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
Run Code Online (Sandbox Code Playgroud)

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

# ImageMagick pixel enumeration: 480,640,255,srgb
Run Code Online (Sandbox Code Playgroud)

它的意思是:

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

其他行包括4列:

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

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

convert textwizard.txt wizard.jpg
Run Code Online (Sandbox Code Playgroud)

2.选择特定行

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

image.png[WIDTHxHEIGHT+X_OFFSET+Y_OFFSET]
Run Code Online (Sandbox Code Playgroud)

因此,要仅选择特定行,您可以设置HEIGHT1.要完全获得任何行,请设置X-OFFSET0.要获取特定行,请相应地进行设置 Y-OFFSET.

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

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
Run Code Online (Sandbox Code Playgroud)

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

convert wizard:[480x1+0+47] txt:-
Run Code Online (Sandbox Code Playgroud)

3.将它们拼接在一起

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

  1. 循环遍历图像的所有像素行.
  2. 将每个像素的颜色值输出为文本.
  3. 查找第一个非白色像素并保留其位置信息.

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
Run Code Online (Sandbox Code Playgroud)

-v white意志去选择哪一个包含字符串的所有行white.该-m 1参数将返回最多1个匹配(即第一个匹配).

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