Я использую библиотеку 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] установлено значение два, он просто захватывает два блока вместо одного.