通过修改AC系数将jpeg块着色为黑色

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

我正在尝试通过操纵 libjpeg 上的各个 DCT 系数值,将 DCT 空间上的 JPEG 图像区域着色为黑色。

我知道 DC 系数指定了色调。因此,忽略上/下采样问题,应该能够通过将所有 AC 系数归零并操纵 DC 系数来对整个块进行着色。但是,我无法弄清楚值的范围是多少。

例如,要将左上角的块着色为中点灰色,可以:

int row = 0;
int col = 0;

jvirt_barray_ptr *src_coef_arrays = jpeg_read_coefficients(&src.info);
for (int ci = 0; ci < src.info.num_components; ci++) {

    JBLOCKARRAY buffer = src.info.mem->access_virt_barray(
        (j_common_ptr)&src.info,
        src_coef_arrays[ci],
        row,
        comp_info.v_samp_factor,
        TRUE
    );
    for (int k = 0; k < DCTSIZE2; k++)
        blk_buf[0][col][k] = 0;
}

代替中点灰色,假设 YCbCr,可以通过仅更改亮度分量的 DC 系数来变暗/变亮:

  if (ci == 0)  // luma component
      blk_buf[0][col][0] = -50;  // tweak DC coeff of luma component
  else
      blk_buf[0][col][0] = 0;    // zero DC coeff of chroma components
  for (int k = 1; k < DCTSIZE2; k++)
      blk_buf[0][col][k] = 0;    // zero all AC coeffs

但是,我还没有弄清楚如何从特定的YCbCr值到DC值,即黑色的DC值是多少?如何从任意颜色转换为 DC 值?

jpeg libjpeg libjpeg-turbo
1个回答
0
投票

在 libjpeg 中操作“原始”DCT 系数有两个关键点:

  1. 返回的系数已经/仍在量化
  2. 系数放大了8倍

jdct.h
(libjpeg 的内部头文件)中提到了 8 的因子:

/*
 [...]
 * The DCT inputs are expected to be signed (range +-CENTERJSAMPLE).
 * The DCT outputs are returned scaled up by a factor of 8; they therefore
 * have a range of +-8K for 8-bit data, +-128K for 12-bit data.  This
 [...]
 */

因此,查找给定颜色所需的 DC 值的过程是:

  1. 将所需颜色转换为输出 jpeg 颜色空间(通常为 YCbCR)。检查

    info.jpeg_color_space
    。有效的 jpeg 颜色空间是:

    • JCS_YCbCr
    • JCS_GRAYSCALE
    • JCS_RGB
    • JCS_CMYK
    • JCS_YCCK
  2. 将值转换为

    -CENTERJSAMPLE : (CENTERJSAMPLE-1)
    范围乘以8。假设您想要黑色,JPEG颜色空间是YCbCR,因为黑色是
    YCbCr(-128, 0, 0)
    (假设YCbCr表示法取-128到127之间的值),那么:

    int DC_black_Y = -CENTERJSAMPLE *8;
    int DC_black_Cb = 0;
    int DC_black_Cr = 0;
    
  3. 将该值除以该图像分量的量化器矩阵的第一个元素(DC 值的量化器值)。您可以通过以下方式获取每个组件使用的量化器值:

    for (int ci = 0; ci < info.num_components; ci++) {
      const int quant_tbl_no = info.comp_info[ci].quant_tbl_no;
      const UINT16 dc_quant = info.quant_tbl_ptrs[quant_tbl_no]->quantval[0];
      [...]
    
  4. 将值远离零舍入(如果为正则取整,如果为负则取下限)

    // Round towards closest infinity (away from zero)
    // assuming dc_value and dc_quant are integers
    if (dc_value < 0)
      dc_value = (dc_value - dc_quant +1) / dc_quant;
    else if (dc_value > 0)
      dc_value = (dc_value + dc_quant -1) / dc_quant;
    // else do nothing, it's zero
    
© www.soinside.com 2019 - 2024. All rights reserved.