VsampFactor и HsampFactor в библиотеке FJCore

Я использовал библиотеку FJCore в проекте Silverlight, чтобы помочь с некоторой обработкой изображений в реальном времени. , и я пытаюсь понять, как добиться от библиотеки немного большего сжатия и производительности. Теперь, насколько я понимаю, стандарт JPEG позволяет вам указать коэффициент подвыборки цветности (см. http://en.wikipedia.org/wiki/Chroma_subsampling и http://en.wikipedia.org/wiki/Jpeg); и кажется, что это должно быть реализовано в библиотеке FJCore с использованием массивов HsampFactor и VsampFactor:

    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 };

По крайней мере, так эти значения используются в других подобных библиотеках (например, см. Пример кода здесь для libjpeg).

Однако ни приведенные выше значения {2, 1, 1}, ни любой другой набор значений, который я пробовал, кроме {1, 1, 1}, не дает четкого изображения. Глядя на код, не кажется, что он так написан. Но хоть убей, я не могу понять, что на самом деле пытается делать код FJCore. Похоже, что он просто использует коэффициенты выборки для повторения операций, которые уже были выполнены, то есть, если бы я не знал лучше, я бы сказал, что это ошибка. Но это довольно устоявшаяся библиотека, основанная на довольно хорошо известном 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] установлено значение два, он просто захватывает два блока вместо одного.


person Ken Smith    schedule 06.03.2010    source источник


Ответы (1)


Я понял. Я думал, что, задавая коэффициенты выборки, вы говорите библиотеке, что нужно сделать субдискретизацию растровых компонентов. Оказывается, когда вы устанавливаете коэффициенты выборки, вы фактически сообщаете библиотеке относительный размер предоставляемых вами растровых компонентов. Другими словами, вам необходимо самостоятельно выполнить субдискретизацию цветности изображения, прежде чем отправлять его в библиотеку 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);
    }

Могут быть дополнительные способы оптимизировать это, но пока они работают.

person Ken Smith    schedule 10.03.2010
comment
Какова производительность FJCore по сравнению со встроенным кодировщиком jpeg, используемым GDI +? Мне нужно сохранить субдискретизацию 4: 4: 4, чтобы обеспечить повышенное сжатие без потери деталей (текст рядом с изображениями). Мне было интересно, поможет ли FJCore ... - person Oskar Austegard; 15.07.2010
comment
На самом деле я не тестировал эти два бок о бок: я использовал FJCore не потому, что он был быстрее или гибче, а потому, что мне нужно было использовать его с Silverlight для сжатия видео в формате jpeg. Мне было бы интересно услышать ваши результаты. - person Ken Smith; 20.07.2010