C# 量化dct不产生0的运行

C# 量化dct不产生0的运行,c#,jpeg,signal-processing,image-compression,dct,C#,Jpeg,Signal Processing,Image Compression,Dct,为了快速参考,这里有一个github 我正在尝试实现一个简单的JPEG压缩。 我将提供一些更值得注意的方法 问题是我没有看到任何值得注意的0运行,因此我的RLE编码对压缩图像没有任何作用 代码: RGB到YCbCr的转换: private static Ycbcr AlternativeRgbtoYCbCr ( Rgb rgb ) { var y = 16f + (65.481f*rgb.R + 128.553f*rgb.G + 24.966f*rgb.B); var cr =

为了快速参考,这里有一个github

我正在尝试实现一个简单的JPEG压缩。 我将提供一些更值得注意的方法

问题是我没有看到任何值得注意的0运行,因此我的RLE编码对压缩图像没有任何作用

代码:

RGB到YCbCr的转换:

private static Ycbcr AlternativeRgbtoYCbCr ( Rgb rgb ) {
    var y = 16f + (65.481f*rgb.R + 128.553f*rgb.G + 24.966f*rgb.B);
    var cr = 128f + (-37.797f * rgb.R - 74.203f * rgb.G + 112.0f * rgb.B);
    var cb = 128f + (112.0f*rgb.R - 93.786f*rgb.G - 18.214f*rgb.B);

    return new Ycbcr(y, cb, cr);
}
拆分为颜色空间:

/// <summary>
///     Loops through all the pixels and converts them to ycbcr
/// </summary>
public void SplitBytesIntoColorSpaces() {
    if (_imageIsSplit) return;
    for (var x = 0; x < LeftImageBitmap.Width; x++) {
        //var innerlist = new List<Ycbcr>();
        var innerY = new List<float>();
        var innerCr = new List<float>();
        var innerCb = new List<float>();
        for (var y = 0; y < LeftImageBitmap.Height; y++) {
            var color = ToRgb(LeftImageBitmap.GetPixel(x, y));
            //innerlist.Add(RgbtoYCbCr(color));
            innerY.Add(AlternativeRgbtoYCbCr(color).Y);
            innerCr.Add(AlternativeRgbtoYCbCr(color).Cr);
            innerCb.Add(AlternativeRgbtoYCbCr(color).Cb);
        }
        //ChromeList.Add(innerlist);
        LumList.Add(innerY);
        CrList.Add(innerCb);
        CbList.Add(innerCr);
    }
    _imageIsSplit = true;
}
编辑2:

量化方法:

public void QuantizeLuminance(ref double[,] data) {
    for (var i = 0; i < 8; i++) {
        for (var j = 0; j < 8; j++) {
            data[i, j] /= LuminanceQuantizationMatrix[i, j];

        }
    }
}
public void QuantizeLuminance(参考双[,]数据){
对于(变量i=0;i<8;i++){
对于(var j=0;j<8;j++){
数据[i,j]/=亮度量化矩阵[i,j];
}
}
}

我认为此时您应该查看一些可用的源代码,看看如何纠正代码中的许多错误。RLE编码仅用于0的运行,这不是进行大量压缩的地方。DCT值用哈夫曼(可变长度代码)压缩,其中包括0的编码运行。你没有显示你的量化函数,所以我们无法判断它是否正确工作。即使这段代码能够正常工作,也会非常缓慢。这只是一个思考练习吗?这是JPEG的早期版本,我们被告知只使用表格。表的代码只是将[0到7][0到7]处的值与dct返回值除以表中相同索引处的值。您的dct系数是什么样子的?哇,您发布了除了量化之外的所有内容,这可能就是问题所在。我猜你在除以量化系数后没有正确地向零舍入。我应该提供什么更新@用户3344003
/// <summary>
///     Steps through a 2d array 8 pixels at a time.
///     When x reaches the end, x is set to 0 and y
///     is incremented by 8.
/// </summary>
/// <param name="x">ref position to the loop's x</param>
/// <param name="y">ref position to the loop's y</param>
/// <param name="xl">maximum x position</param>
/// <param name="yl">maximum y position</param>
private static void Step(ref int x, ref int y, int xl, int yl) {
    if (x + 8 < xl) {
        x += 8;
    }
    else if (x + 8 >= xl) {
        x = 0;
        y += 8;
    }
}
//DCT function that creates a task and runs dct on it
public double[,] Go(double[,] d) {
    _data = d;
    var task = Task<double[,]>.Factory.StartNew(() => {
        var output = new double[8, 8];
        for (var x = 0; x < _data.GetLength(0); x++)
            for (var y = 0; y < _data.GetLength(1); y++) {
                output[x, y] = GetValueForward(x, y);
            }
        return output;
    });
    return task.Result;
}
//gets a singular value for dct
private double GetValueForward(int u, int v) {
    double freq = 0;
    for (var i = 0; i < 8; i++) {
        for (var j = 0; j < 8; j++) {
            freq +=
                Math.Cos((2*i + 1)*u*Pi/16)*
                Math.Cos((2*j + 1)*v*Pi/16)*
                _data[i, j];
        }
    }

    freq *= 2*C(u)*C(v)/Math.Sqrt(8*8);
    return freq;
}
/// <summary>
///     DctImageProcessor's main method.
///     This method will run on 8x8 chunks
///     and process them into double arrays by channel.
/// </summary>
public void Process() {
    //get data manager's ycbcr chromelist
    _luminanceDatalist = Manager.LumList;
    _crDatalist = Manager.CrList;
    _cbDatalist = Manager.CbList;
    _lumOutList = new List<double[,]>();
    _cbOutList = new List<double[,]>();
    _crOutList = new List<double[,]>();
    var lumx = _luminanceDatalist[0].Count;
    var lumy = _luminanceDatalist.Count;

    var channelx = _crDatalist[0].Count;
    var channely = _crDatalist.Count;

    //SetArray(_luminanceDatalist);

    //dct
    var dct = new Dct();

    //quantizer
    var q = new Quantizer();

    //loop and Step() + store values into _lumOutList
    for (int i = 0, j = 0; i < lumx && j < lumy; Step(ref i, ref j, lumx, lumy)) {
        var lumarr = ForDctLum(i, j);
        var lumdct = dct.Go(lumarr);
        q.QuantizeLuminance(ref lumdct);
        _lumOutList.Add(lumdct);
    }

    for ( int i = 0, j = 0; i < channelx && j < channely; Step(ref i, ref j, channelx, channely) ) {
        var crArr = ForDctCr(i, j);
        var cbArr = ForDctCb(i, j);
        var crdct = dct.Go(crArr);
        var cbdct = dct.Go(cbArr);

        q.QuantizeChrominance(ref crdct);
        q.QuantizeChrominance(ref cbdct);

        _crOutList.Add(crdct);
        _cbOutList.Add(cbdct);
    }

    //rle
    var rleOutputs = _lumOutList.Select(Rle.ZigZag).ToList();
    rleOutputs.AddRange(_crOutList.Select(Rle.ZigZag));
    rleOutputs.AddRange(_cbOutList.Select(Rle.ZigZag));

    var encoded = Rle.Encode(rleOutputs);

    File.WriteAllBytes("./output.dct", encoded);
}
public static byte[] ZigZag(double[,] input) {
    var result = new double[8, 8];
    var output = new byte[64];
    int i = 0, j = 0;
    var d = -1; // -1 for top-right move, +1 for bottom-left move
    int start = 0, end = 8*8 - 1;
    do {
        output[start++] = (byte) input[i, j];
        output[end--] = (byte) input[8 - i - 1, 8 - j - 1];
        i += d;
        j -= d;

        if (i < 0) {
            i++;
            d = -d; // top reached, reverse
        }
        else if (j < 0) {
            j++;
            d = -d; // left reached, reverse
        }
    } while (start < end);
    if (start == end)
        result[i, j] = start;
    return output;
}
public static byte[] Encode(List<byte[]> list) {
    var ret = new List<byte>();
    var prev = list[0][0];
    byte count = 0;
    const byte delim = 255;

    foreach (var val in list.SelectMany(arr => arr)) {
        if (val != prev) {
            if (count > 1) {
                ret.Add(delim);
                ret.Add(count);
                ret.Add(prev);
            }
            else {
                ret.Add(prev);
            }
            prev = val;
            count = 1;
        }
        else {
            count ++;
            prev = val;
        }
    }
    return ret.ToArray();
}
private double[,] ChrominanceQuantizationMatrix { get; } = new double[8, 8] {
    {17, 18, 24, 47, 99, 99, 99, 99},
    {18, 21, 26, 66, 99, 99, 99, 99},
    {24, 26, 56, 99, 99, 99, 99, 99},
    {47, 66, 99, 99, 99, 99, 99, 99},
    {99, 99, 99, 99, 99, 99, 99, 99},
    {99, 99, 99, 99, 99, 99, 99, 99},
    {99, 99, 99, 99, 99, 99, 99, 99},
    {99, 99, 99, 99, 99, 99, 99, 99}
};

private double[,] LuminanceQuantizationMatrix { get; } = new double[8, 8] {
    {16, 11, 10, 16, 24, 40, 51, 61},
    {12, 12, 14, 19, 26, 58, 60, 55},
    {14, 13, 16, 24, 40, 57, 69, 56},
    {14, 17, 22, 29, 51, 87, 80, 62},
    {18, 22, 37, 56, 68, 109, 103, 77},
    {24, 35, 55, 64, 81, 104, 113, 92},
    {49, 64, 78, 87, 103, 121, 120, 101},
    {72, 92, 95, 98, 112, 100, 103, 99}
};
public void QuantizeLuminance(ref double[,] data) {
    for (var i = 0; i < 8; i++) {
        for (var j = 0; j < 8; j++) {
            data[i, j] /= LuminanceQuantizationMatrix[i, j];

        }
    }
}