ImageMagick:降低图像中所有像素的RGB值

3

具体来说,我想通过减少每个像素的RGB值100来处理给定图像。

例如,如果一个像素的R: 232,G: 40,B: 120,则希望新的RGB值为R: 132,G: 0,B: 20。

我尝试了在ImageMagick论坛上找到的解决方案:

convert input.jpg -channel R -evaluate subtract 25700 \
-channel G -evaluate subtract 25700 \
-channel B -evaluate subtract 25700 output.jpg

编辑:我使用25700的原因是因为显然需要将rgb值乘以257。100 * 257 = 25700。

虽然一开始似乎可以正常工作(明显变暗图片),但似乎某些像素不会改变,而且对于我正在进行的操作非常重要(我正在修剪所得图像,试图修剪具有0像素值的边框)。

一个常见的问题是,最终会得到一个RGB值为3,0,0的像素,但我想让该像素的RGB值为0,并增加我减去的常量,但似乎不起作用。

有什么建议吗?谢谢!

2个回答

4
坦白地说,我不太理解你的命令行中数值为25700的价值。然而,我向您建议使用更强大的-fx运算符的不同命令行。这看起来有点复杂,但希望更易于理解... 但首先,我看到您的描述,想要从每个当前的R、G和B颜色值中减去一个固定的数值120。因此,这是一个灰像素颜色...正如您在ImageMagick的内置颜色列表中可以查找到的那样,它的名称是gray47:
convert -list color | grep '(120,120,120)'
  gray47                srgb(120,120,120)                             X11 XPM 
  grey47                srgb(120,120,120)                             SVG X11 

这使我想到了以下命令:
   convert \
       input.jpg \
      -channel red   -fx 'r - gray47' \
      -channel green -fx 'g - gray47' \
      -channel blue  -fx 'b - gray47' \
       output.jpg

这种编写命令的方式可能会让您了解到一些容易推导出的修改,以备将来需要使用...
要立即预览结果弹出窗口(而不是将其写入文件),您还可以使用 -show: 作为输出,就像这样:
   convert \
       input.jpg \
      -channel red   -fx 'r - gray47' \
      -channel green -fx 'g - gray47' \
      -channel blue  -fx 'b - gray47' \
      -show:

更新

如果您想检查每个像素的真实差异,您可以让ImageMagick打印出每个像素的颜色值:

convert  input.jpg   input.txt
convert  output.jpg  output.txt

.txt文件的格式相当容易理解,一旦你知道第一列给出像素从零开始的坐标:123,456: 意味着:第124列(!),第457行。

现在,即使是在自动化、脚本版本中,你也可以尽情比较这两个.txt文件,而不需要求助于Gimp。 :-)

甚至可以使用input.txt,并对每个像素值应用Perl、Ruby、Python或Shellscript,将其从每个通道分别减去120,将其保存为output2.txt,然后将其转换回JPEG:

convert  output2.txt  output2.jpg

然后查找两个输出图像之间的像素差异:
compare  output.jpg  output2.jpg  delta.jpg
compare  output.jpg  output2.jpg  view:

一架全白的飞机意味着“没有差异”,任何红色像素都会暗示某种变化。现在,如果这个答案不能为我赢得一张赞,那么我不知道什么能赢得了… :-)

1
嗨Kurt - 我很感激你详细的回答。然而,虽然这似乎在第一眼看起来有效,但它似乎有与我的示例相同的问题 - 虽然图像整体变暗了,但由于某种原因,它似乎缺乏精度 - 即许多像素的RGB值不会准确地降低。如果您尝试查看随机像素值(使用Gimp或其他工具),然后运行此命令后再查看相同的像素值,它可能会减少,但不完全准确。您知道为什么会发生这种情况以及如何解决吗?谢谢! - Ken
2
@Ken:如果你在用一个 Q16(或 Q8)构建的 ImageMagick 安装(QuantumRange),处理一张 8位(或 16位)深度的图像时可能会发生舍入误差。 - Kurt Pfeifle
1
非常感谢 Kurt!我还有一个小问题,我保证会给你点赞/采纳答案 :) (不管怎样,我已经打算这么做了,别担心)。有没有什么简单的方法可以在不编写自己的解析器的情况下轻松地对txt文件进行这些更改?此外,这是减去某个像素的grey39后出现差异的示例:原始值:155,117: ( 1, 0, 0) #010000 rgb(1,0,0) 减法后:155,117: ( 0, 2, 1) #000201 rgb(0,2,1) 为什么一些值会增加? - Ken

1

Ken,不需要编写一个大的解析器。只需使用几个 shell 命令即可轻松完成。先进行测试,然后将它们放入 Shell 或批处理脚本中。类似这样(作为 Bash 脚本):

#!/bin/bash
echo "注意:这个脚本可能需要很长时间才能完成..." echo "(此脚本用于将带有 Alpha 通道的 PNG 文件转换为其他类型的图像,您需要稍微修改它。)" echo echo "此脚本接受一个 8 位 RGBA 输入图像并创建一个较暗的输出图像。" echo "其方法是:从每个颜色通道的数值中减去 100 的值。" echo
input="${1}"
_im_header=$(identify -format "%W,%H" "${input}")
echo "# ImageMagick 像素枚举: ${_im_header},255,rgba" > input-minus-120.txt
convert "${input}" input.txt
cat input.txt \ | \ sed 's#) .*$#)#; s# ##g; s#:#: #; s#(# #; s#)##; s#,# #g; s# #,#' \ | \ while read coord red green blue alpha; do echo -n "${coord}"; echo -n " ("; echo -n " $(($red - 100)),"; echo -n " $(($green - 100)),"; echo -n " $(($blue - 100)),"; echo -n " $(($alpha))"; echo -n " ) "; echo; done \ | sed 's#-[0-9]*#0#g' \ >> input-minus-120.txt
convert input-minus-120.txt output-minus-120.jpg

这个脚本在 MacBook Pro 上运行需要 153 秒,处理一个大小为 750 kByte 的 1080x889 像素 PNG 文件。

生成的 input.txt 文件有 960120 行(PNG 中像素的数量)。

因此,这个暴力破解 shell 脚本的性能约为每秒 6275 个像素。


再次感谢 - 不幸的是,这肯定需要太长时间才能实现。你知道为什么一些值会增加吗(根据我的评论结尾)? - Ken
1
@Ken:脚本已更新--我还在答案末尾添加了一些基准数值...另外,我现在才看到你想要减去100而不是120。 - Kurt Pfeifle
1
@Ken:我并没有说这种方法很高效 :-) 我设计它是为了帮助你调试真正的命令。它给你一个参考,可以用来评估真实命令中有多少像素不显示预期值,偏差有多大,并查看是否存在这种偏差的“模式”...还可以看看重复运行真实命令是否会产生不同的结果。 - Kurt Pfeifle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接