jpegtran 擦除:彩色与灰度图像

问题描述 投票:0回答:1

考虑以下简单的 shell 脚本 (Debian/stable) 系统 (*)

% ./demo.sh
26b955f9e6987c2617c97a653f1fe3dd  mask_white_gray.jpg
4fe7eb3d04c54887c1b0c9c33f8526bf  mask_gray.jpg

查看生成的中间药物图像,我可以看到实际上存在差异。例如:

$ compare mask_white_gray.jpg  mask_gray.jpg -compose src diff.png
mask_灰色 mask_white_gray 差异
mask_gray mask_white_gray diff

我不明白为什么 jpegtran 会为彩色情况选择比灰度情况更大的区域。该文档简单地指出:

如果划像区域和划像区域之外的区域,当 调整到最近的 iMCU 边界 [...]

有人可以帮助我理解我所看到的吗?我的印象是,在这种情况下,iMCU 边界应该是相同的。


(*)

% cat demo.sh
#!/bin/sh
#set -x

convert -size 100x100 xc:white orig.ppm
cjpeg -outfile orig.jpg orig.ppm

jpegtran -copy none -outfile white.jpg orig.jpg
jpegtran -copy none -grayscale -outfile gray.jpg orig.jpg

jpegtran -wipe 50x50+0+0 -outfile mask_white.jpg white.jpg
jpegtran -wipe 50x50+0+0 -outfile mask_gray.jpg gray.jpg

jpegtran -grayscale -outfile mask_white_gray.jpg mask_white.jpg

md5sum mask_white_gray.jpg
md5sum mask_gray.jpg

% jpegtran -version
libjpeg-turbo version 2.1.5 (build 20230203)
jpeg libjpeg jpegtran
1个回答
0
投票

让我们仔细看看我们看到的输出:

  • mask_gray.jpg
    (从一开始就是灰度图像)显示一个 56x56 的灰色正方形。
  • mask_white.jpg
    (彩色)和
    mask_white_gray.jpg
    (彩色转灰度)均显示 64x64 灰色方块。

很明显,在任何这些情况下我们都没有得到 50x50 的正方形。

这是由 JPEG 的内部结构引起的,该结构基于 8x8 基本块。

jpegtran -wipe
命令在块级别而不是像素级别运行。这解释了为什么
mask_gray.jpg
有一个 56x56 的灰色正方形 (56 = 8 * 7)。

对于彩色图像,采样因子可以发挥作用:JPEG 允许 8x8 块表示原始图像中超过 8x8 的像素,具体取决于每个通道指定的子采样因子。要查看这些因素,我们可以使用

djpeg -verbose -fast white.jpg > /dev/null
:

Component 1: 2hx2v q=0
Component 2: 1hx1v q=1
Component 3: 1hx1v q=1

这里,2hx2v 表示第一个颜色通道使用 2x 子采样,这意味着每个 8x8 块代表一个 16x16 像素区域。在彩色图像上调用

jpegtran -wipe
时,我们会直观地创建大小为 16 块倍数的灰色方块,这解释了 64x64 的灰色方块。

将彩色图像转换为灰度图像时,jpegtran 无法重新生成 64x64 区域中擦除的数据,从而导致灰色矩形不改变大小。

如果您想确保在两种情况下获得相同的输出,您可以修改

cjpeg
命令以强制彩色图像使用 8x8 块:

cjpeg -sample 1x1 -outfile orig.jpg orig.ppm

这将确保两个图像都为您提供相同的 56x56 灰度块。


如果您想更深入地挖掘并仔细了解幕后发生的事情,jpegtran 的 do_wipe 函数只有 20 行并且非常可读。

© www.soinside.com 2019 - 2024. All rights reserved.