代码之家  ›  专栏  ›  技术社区  ›  Ken Smith

fjcore库中的vsampfactor和hsampfactor

  •  0
  • Ken Smith  · 技术社区  · 15 年前

    我一直在使用 FJCore 一个Silverlight项目中的库来帮助进行一些实时的图像处理,我正在尝试找出如何从库中获得更多的压缩和性能。现在,据我了解,jpeg标准允许您指定色度次采样率(请参见 http://en.wikipedia.org/wiki/Chroma_subsampling http://en.wikipedia.org/wiki/Jpeg ) 出现 这应该使用hsampfactor和vsampfactor数组在fjcore库中实现:

        public static readonly byte[] HsampFactor = { 1, 1, 1 };
        public static readonly byte[] VsampFactor = { 1, 1, 1 };
    

    然而,我很难弄清楚如何使用它们。在我看来,当前值应该表示4:4:4次采样(例如,完全没有次采样),如果我想得到4:1:1次采样,正确的值应该是这样的:

        public static readonly byte[] HsampFactor = { 2, 1, 1 };
        public static readonly byte[] VsampFactor = { 2, 1, 1 };
    

    至少,这是其他类似库使用这些值的方式(例如,请参见示例代码 here 对于LBJPEG)。

    但是,上述2、1、1的值以及我尝试过的任何其他值集,除了1、1、1都不会产生清晰的图像。在查看代码时,它看起来也不像是这样写的。但在我的生活中,我不知道fjcore代码实际上是什么 尝试 去做。似乎它只是使用样本因子来重复已经完成的操作——也就是说,如果我不知道更好的话,我会说这是一个bug。但这是一个完全建立的库,基于一些相当成熟的Java代码,所以如果是这样的话,我会感到惊讶。

    对于如何使用这些值获得4:2:2或4:1:1色度子采样,有人有什么建议吗?

    值得一提的是,这是 JpegEncoder 班级:

    for (comp = 0; comp < _input.Image.ComponentCount; comp++)
    {
        Width = _input.BlockWidth[comp];
        Height = _input.BlockHeight[comp];
    
        inputArray = _input.Image.Raster[comp];
    
        for (i = 0; i < _input.VsampFactor[comp]; i++)
        {
            for (j = 0; j < _input.HsampFactor[comp]; j++)
            {
                xblockoffset = j * 8;
                yblockoffset = i * 8;
                for (a = 0; a < 8; a++)
                {
                    // set Y value.  check bounds
                    int y = ypos + yblockoffset + a; if (y >= _height) break;
    
                    for (b = 0; b < 8; b++)
                    {
                        int x = xpos + xblockoffset + b; if (x >= _width) break;
                        dctArray1[a, b] = inputArray[x, y];
                    }
                }
                dctArray2 = _dct.FastFDCT(dctArray1);
                dctArray3 = _dct.QuantizeBlock(dctArray2, FrameDefaults.QtableNumber[comp]);
                _huf.HuffmanBlockEncoder(buffer, dctArray3, lastDCvalue[comp], FrameDefaults.DCtableNumber[comp], FrameDefaults.ACtableNumber[comp]);
                lastDCvalue[comp] = dctArray3[0];
            }
        }
    }
    

    注意,在I&J循环中,它们不控制任何类型的像素跳跃:如果hsampfactor[0]设置为2,则它只捕获两个块而不是一个块。

    1 回复  |  直到 15 年前
        1
  •  0
  •   Ken Smith    15 年前

    我知道了。我认为通过设置采样因子,可以告诉库对光栅组件本身进行次采样。结果发现,当您设置采样因子时,实际上是在告诉库您所提供的光栅组件的相对大小。换句话说,在将图像提交到FJCore库进行压缩之前,您需要自己对图像进行色度子采样。这就是它要找的东西:

        private byte[][,] GetSubsampledRaster()
        {
            byte[][,] raster = new byte[3][,];
            raster[Y] = new byte[width / hSampleFactor[Y], height / vSampleFactor[Y]];
            raster[Cb] = new byte[width / hSampleFactor[Cb], height / vSampleFactor[Cb]];
            raster[Cr] = new byte[width / hSampleFactor[Cr], height / vSampleFactor[Cr]];
    
            int rgbaPos = 0;
            for (short y = 0; y < height; y++)
            {
                int Yy = y / vSampleFactor[Y];
                int Cby = y / vSampleFactor[Cb];
                int Cry = y / vSampleFactor[Cr];
                int Yx = 0, Cbx = 0, Crx = 0;
                for (short x = 0; x < width; x++)
                {
                    // Convert to YCbCr colorspace.
                    byte b = RgbaSample[rgbaPos++];
                    byte g = RgbaSample[rgbaPos++];
                    byte r = RgbaSample[rgbaPos++];
                    YCbCr.fromRGB(ref r, ref g, ref b);
    
                    // Only include the byte in question in the raster if it matches the appropriate sampling factor.
                    if (IncludeInSample(Y, x, y))
                    {
                        raster[Y][Yx++, Yy] = r;
                    }
                    if (IncludeInSample(Cb, x, y))
                    {
                        raster[Cb][Cbx++, Cby] = g;
                    }
                    if (IncludeInSample(Cr, x, y))
                    {
                        raster[Cr][Crx++, Cry] = b;
                    }
    
                    // For YCbCr, we ignore the Alpha byte of the RGBA byte structure, so advance beyond it.
                    rgbaPos++;
                }
            }
            return raster;
        }
    
        static private bool IncludeInSample(int slice, short x, short y)
        {
            // Hopefully this gets inlined . . . 
            return ((x % hSampleFactor[slice]) == 0) && ((y % vSampleFactor[slice]) == 0);
        }
    

    可能还有其他的方法来优化它,但目前它正在工作。