0

私は、Silverlight プロジェクトでFJCoreライブラリを使用して、リアルタイムの画像処理を支援してきました。ライブラリから圧縮とパフォーマンスを少し高める方法を見つけようとしています。現在、私が理解しているように、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 };

少なくとも、これは他の同様のライブラリがこれらの値を使用する方法です (たとえば、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] が 2 に設定されている場合、1 つではなく 2 つのブロックを取得しているだけです。

4

1 に答える 1

0

私はそれを考え出した。サンプリング係数を設定することで、ラスターコンポーネント自体をサブサンプリングするようにライブラリに指示していると思いました。サンプリング係数を設定すると、実際には、提供しているラスターコンポーネントの相対的なサイズをライブラリに通知していることがわかります。つまり、圧縮のために画像を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);
    }

これを最適化する追加の方法があるかもしれませんが、今のところは機能しています。

于 2010-03-10T08:18:44.407 に答える