0

目前我正在为一个大学项目开发​​一个 jpeg 编码器。图像具有固定大小,编码器使用固定量化和 Huffman 表进行基线处理。首先,我的代码从 SDRAM 读取 32 位 RGBx 值,转换为 YCbCr 颜色空间,将每个通道归一化为 0 并写回。然后,它开始对 8x8 块进行 DCT,并将熵编码数据写入 SDRAM。此过程使用 C 完成,然后 Python 代码创建一个带有适当 JFIF 标记和熵编码数据的文件。最后,操作系统默认的 jpeg 解码器用于通过简单的双击来查看图像。

我的代码适用于 8x8、8x16 和 16x8 图像,但不适用于 16x16,也不适用于项目中使用的图像的实际大小。下面您可能会看到 16x16 示例。

16x16 输入图像16x16 输入

16x16 输出图像16x16 输出

但是,在 stackoverflow 上,它似乎与我的操作系统的默认解码器不同。下面是它在 macOS 预览应用程序上的样子。

在此处输入图像描述

我相信我的问题是由于 JFIF 中的标记或某种算法错误造成的。

如果有 jpeg 经验的人可以帮助我,我会很高兴。

亲切的问候

4

1 回答 1

1

我写了一个 jpeg 编解码器。它在https://github.com/MalcolmMcLean/babyxrc进行维护,但是尽管欢迎您查看甚至使用它,但这并不能真正回答您的问题。

JPEG 基于色度的 16x16 块和亮度的 8x8 块。因此,软件的初始版本在第一个 16x16 块之后崩溃也就不足为奇了。这只是一个例行的编程错误。如果您无法通过阅读 JEG 规范找到它,请启动编辑器并创建一个 32x32 平面图像。然后查看二进制文件,看看它与您的不同之处。

这是我的负载扫描,没有子采样

static int loadscanYuv111(JPEGHEADER *hdr, unsigned char *buff, FILE *fp)
{
  short lum[64];
  short Cb[64];
  short Cr[64];
  BITSTREAM *bs;
  int i;
  int ii;
  int iii;
  int iv;
  int diffdc = 0;
  int dcb = 0;
  int dcr = 0;
  int actableY;
  int actableCb;
  int actableCr;
  int dctableY;
  int dctableCb;
  int dctableCr;
  int count = 0;
  int target;
  int luminance;
  int red;
  int green;
  int blue;

  actableY = hdr->useac[0];
  actableCb = hdr->useac[1];
  actableCr = hdr->useac[2];
  dctableY = hdr->usedc[0];
  dctableCb = hdr->usedc[1];
  dctableCr = hdr->usedc[2];

  bs = bitstream(fp);

  for(i=0;i<hdr->height;i+=8)
    for(ii=0;ii<hdr->width;ii+=8)
    {
      if(hdr->dri && (count % hdr->dri) == 0 && count > 0 )
      {
        readmarker(bs);
        diffdc = 0;
        dcb = 0;
        dcr = 0;
      }

      getblock(lum, hdr->dctable[dctableY], hdr->actable[actableY], bs);
      lum[0] += diffdc;
      diffdc = lum[0];

      for(iv=0;iv<64;iv++)
        lum[iv] *= hdr->qttable[hdr->useq[0]][iv];
      unzigzag(lum);
      idct8x8(lum);

      getblock(Cb, hdr->dctable[dctableCb], hdr->actable[actableCb], bs);
      Cb[0] += dcb;
      dcb = Cb[0];

      for(iv=0;iv<64;iv++)
        Cb[iv] *= hdr->qttable[hdr->useq[1]][iv];
      unzigzag(Cb);
      idct8x8(Cb);

      getblock(Cr, hdr->dctable[dctableCr], hdr->actable[actableCr], bs);
      Cr[0] += dcr;
      dcr = Cr[0];

      for(iv=0;iv<64;iv++)
        Cr[iv] *= hdr->qttable[hdr->useq[2]][iv];
      unzigzag(Cr);
      idct8x8(Cr);

      for(iii=0;iii<8;iii++)
      {
        if( i + iii >= hdr->height)
          break;
        for(iv=0;iv<8;iv++)
        {
          if(ii + iv >= hdr->width)
            break;
          target = (i + iii) * hdr->width * 3 + (ii + iv) * 3;
          luminance = lum[iii*8+iv]/64 + 128;
          red = (int) (luminance + 1.402  * Cr[iii*8+iv]/64);
          green = (int) (luminance - 0.34414 * Cb[iii*8+iv]/64 - 0.71414 * Cr[iii*8+iv]/64);
          blue = (int) (luminance + 1.772  * Cb[iii*8+iv]/64);
          red = clamp(red, 0, 255);
          green = clamp(green, 0, 255);
          blue = clamp(blue, 0, 255);
          buff[target] = red;
          buff[target+1] = green;
          buff[target+2] = blue;
        }
      }

      count++;
    }

  killbitstream(bs);
  if(loadeoi(fp) == 0)
    return 0;

  return -1;
}

如您所见,数据是交错的。但是,如果您弄错了,它将创建正确尺寸的特殊图像,而不是比预期更小的图像。

于 2017-05-23T14:27:28.090 回答