C# 量化dct不产生0的运行
为了快速参考,这里有一个github 我正在尝试实现一个简单的JPEG压缩。 我将提供一些更值得注意的方法 问题是我没有看到任何值得注意的0运行,因此我的RLE编码对压缩图像没有任何作用 代码: RGB到YCbCr的转换: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 =
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];
}
}
}