Пример #1
0
        private Bitmap DecompressPFrame(byte[] bs)
        {
            int index = 0;                         // sbytes index

            sbyte[] decoded = RunLengthDecode(bs); // data including paddings

            // read in vectors
            var vectors = new Vector[(int)Math.Ceiling((double)FrameHeight / N) * (int)Math.Ceiling((double)FrameWidth / N)];

            for (int i = 0; i < vectors.Length; ++i)
            {
                vectors[i].x = decoded[index++];
                vectors[i].y = decoded[index++];
            }

            // ycbcr differences
            var data = new sbyte[decoded.Length - index];

            Array.Copy(decoded, index, data, 0, data.Length);

            YCbCrSubSample diffs = SeparateYCbCrFromSbytes(FrameHeight, FrameWidth, data); // pframe diffs

            AddDifferencesToMemoryFrame(diffs, vectors);

            YCbCr[,] yCbCrs = UpSample(frameMemory);
            return(ColorChannel.CreateBitmapFromYCbCr(yCbCrs));
        }
Пример #2
0
        private byte[] CompressIframe(Bitmap bitmap)
        {
            YCbCr[,] yCbCrs = ColorChannel.ReadYCbCrs(bitmap);
            YCbCrSubSample yCbCrSubSamples = JPEG.SubSample(yCbCrs);

            //DCT subquantized
            // for each channel, run a sperate thread for DCT, quantized, zigzag sampling, and RLE
            var tasks = new Task[3];

            sbyte[,] yQuantized = null, cbQuantized = null, crQuantized = null;

            tasks[0] = Task.Factory.StartNew(() =>
            {
                yQuantized = DCTSubQuantized(yCbCrSubSamples.Y, LuminanceQuantizationTable);
            });
            tasks[1] = Task.Factory.StartNew(() =>
            {
                cbQuantized = DCTSubQuantized(yCbCrSubSamples.Cb, ChrominanceQuantizationTable);
            });
            tasks[2] = Task.Factory.StartNew(() =>
            {
                crQuantized = DCTSubQuantized(yCbCrSubSamples.Cr, ChrominanceQuantizationTable);
            });
            Task.WaitAll(tasks);

            // upquantized IDCT, store as frame memory
            int yHeight = yCbCrSubSamples.Y.GetLength(0), yWidth = yCbCrSubSamples.Y.GetLength(1), cHeight = yCbCrSubSamples.Cb.GetLength(0), cWidth = yCbCrSubSamples.Cb.GetLength(1);

            tasks[0] = Task.Factory.StartNew(() =>
            {
                frameMemory.Y = UpQuantizedIDCT(yHeight, yWidth, yQuantized, LuminanceQuantizationTable);
            });
            tasks[1] = Task.Factory.StartNew(() =>
            {
                frameMemory.Cb = UpQuantizedIDCT(cHeight, cWidth, cbQuantized, ChrominanceQuantizationTable);
            });
            tasks[2] = Task.Factory.StartNew(() =>
            {
                frameMemory.Cr = UpQuantizedIDCT(cHeight, cWidth, crQuantized, ChrominanceQuantizationTable);
            });

            // zigzag RLE
            sbyte[] yStream  = ZigZagTransform(yQuantized);
            sbyte[] cbStream = ZigZagTransform(cbQuantized);
            sbyte[] crStream = ZigZagTransform(crQuantized);

            // concatennate byte stream
            var data = new sbyte[yStream.Length + cbStream.Length + crStream.Length];

            yStream.CopyTo(data, 0);
            cbStream.CopyTo(data, yStream.Length);
            crStream.CopyTo(data, yStream.Length + cbStream.Length);

            Task.WaitAll(tasks);

            return(RunLengthEncode(data));
        }
Пример #3
0
        // duplicate cb cr channels to reproduce ycbcr pixels
        public static YCbCr[,] UpSample(YCbCrSubSample chans)
        {
            int h = chans.Y.GetLength(0), w = chans.Y.GetLength(1);

            YCbCr[,] yCbCrs = new YCbCr[h, w];

            for (int row = 0; row < h; ++row)
            {
                for (int col = 0; col < w; ++col)
                {
                    yCbCrs[row, col].Y = chans.Y[row, col];
                    // fill up the square with top left number
                    int subR = row >> 1, subC = col >> 1;
                    yCbCrs[row, col].Cb = chans.Cb[subR, subC];
                    yCbCrs[row, col].Cr = chans.Cr[subR, subC];
                }
            }
            return(yCbCrs);
        }
Пример #4
0
        public static Bitmap Decompress(int height, int width, byte[] compressedData)
        {
            YCbCrSubSample yCbCrSubSamples = DecodeCompressedBytes(height, width, compressedData);

            // up sample
            YCbCr[,] yCbCrs = UpSample(yCbCrSubSamples);

            // change to RGB and write to bitmap
            int    h = yCbCrs.GetLength(0), w = yCbCrs.GetLength(1);
            Bitmap img = new Bitmap(w, h, System.Drawing.Imaging.PixelFormat.Format32bppArgb);

            for (int row = 0; row < h; ++row)
            {
                for (int col = 0; col < w; ++col)
                {
                    img.SetPixel(col, row, ColorChannel.YcbcrToRgb(yCbCrs[row, col]));
                }
            }
            return(img);
        }
Пример #5
0
        public static byte[] Compress(Bitmap image)
        {
            // 1. get YCbCr channels of the image
            YCbCr[,] yCbCrs = ColorChannel.ReadYCbCrs(image);

            // 2. sub sample
            YCbCrSubSample yCbCrSubSamples = SubSample(yCbCrs);

            // for each channel, run a sperate thread for DCT, quantized, zigzag sampling
            var tasks = new Task[3];

            sbyte[] yStream = null, cbStream = null, crStream = null;

            tasks[0] = Task.Factory.StartNew(() =>
            {
                //3,4. DCT sub quantized
                sbyte[,] s = DCTSubQuantized(yCbCrSubSamples.Y, LuminanceQuantizationTable);
                yStream    = ZigZagTransform(s);
            });
            tasks[1] = Task.Factory.StartNew(() =>
            {
                sbyte[,] s = DCTSubQuantized(yCbCrSubSamples.Cb, ChrominanceQuantizationTable);
                cbStream   = ZigZagTransform(s);
            });
            tasks[2] = Task.Factory.StartNew(() =>
            {
                sbyte[,] s = DCTSubQuantized(yCbCrSubSamples.Cr, ChrominanceQuantizationTable);
                crStream   = ZigZagTransform(s);
            });
            Task.WaitAll(tasks);

            // concatennate byte stream
            var data = new sbyte[yStream.Length + cbStream.Length + crStream.Length];

            yStream.CopyTo(data, 0);
            cbStream.CopyTo(data, yStream.Length);
            crStream.CopyTo(data, yStream.Length + cbStream.Length);

            return(RunLengthEncode(data));
        }
Пример #6
0
        private void AddDifferencesToMemoryFrame(YCbCrSubSample diffs, Vector[] vectors)
        {
            int vectorIndex = 0;

            int yHeight = FrameHeight - 1;
            int yWidth = FrameWidth - 1;
            int cHeight = yHeight >> 1, cWidth = yWidth >> 1; // cb cr

            for (int row = 0; row <= yHeight; row += N)
            {
                for (int col = 0; col <= yWidth; col += N)
                {
                    Vector v = vectors[vectorIndex++];

                    for (int Y = row, yBound = row + N; Y < yBound && Y <= yHeight; ++Y)
                    {
                        for (int X = col, xBound = col + N; X < xBound && X <= yWidth; ++X)
                        {
                            int ry = Math.Max(0, Math.Min(Y - v.y, yHeight));
                            int rx = Math.Max(0, Math.Min(X - v.x, yWidth));
                            diffs.Y[Y, X] += frameMemory.Y[ry, rx];
                        }
                    }

                    for (int Y = (row >> 1), yBound = Y + (N >> 1); Y < yBound && Y <= cHeight; ++Y)
                    {
                        for (int X = (col >> 1), xBound = X + (N >> 1); X < xBound && X <= cWidth; ++X)
                        {
                            int ry = Math.Max(0, Math.Min(Y - v.y, cHeight));
                            int rx = Math.Max(0, Math.Min(X - v.x, cWidth));
                            diffs.Cb[Y, X] += frameMemory.Cb[ry, rx];
                            diffs.Cr[Y, X] += frameMemory.Cr[ry, rx];
                        }
                    }
                }
            }

            frameMemory = diffs;
        }
Пример #7
0
 private Bitmap DecompressIFrame(byte[] bs)
 {
     frameMemory     = DecodeCompressedBytes(FrameHeight, FrameWidth, bs);
     YCbCr[,] yCbCrs = UpSample(frameMemory);
     return(ColorChannel.CreateBitmapFromYCbCr(yCbCrs));
 }
Пример #8
0
        private byte[] CompressPframe(Bitmap bitmap)
        {
            YCbCr[,] yCbCrs = ColorChannel.ReadYCbCrs(bitmap);
            YCbCrSubSample yCbCrSubSamples = JPEG.SubSample(yCbCrs);

            // motion vecotr estimate
            var            mv          = new MotionVector(15);
            EstimateResult vecotrDiffs = mv.Estimate(frameMemory, yCbCrSubSamples);

            // dct subquantized differences
            var tasks = new Task[3];

            sbyte[,] yQuantized = null, cbQuantized = null, crQuantized = null;

            tasks[0] = Task.Factory.StartNew(() =>
            {
                yQuantized = DCTSubQuantized(vecotrDiffs.YDiffs, LuminanceQuantizationTable);
            });
            tasks[1] = Task.Factory.StartNew(() =>
            {
                cbQuantized = DCTSubQuantized(vecotrDiffs.CbDiffs, ChrominanceQuantizationTable);
            });
            tasks[2] = Task.Factory.StartNew(() =>
            {
                crQuantized = DCTSubQuantized(vecotrDiffs.CrDiffs, ChrominanceQuantizationTable);
            });
            Task.WaitAll(tasks);

            //upquantized IDCT, add to frame memory
            int yHeight = yCbCrSubSamples.Y.GetLength(0), yWidth = yCbCrSubSamples.Y.GetLength(1), cHeight = yCbCrSubSamples.Cb.GetLength(0), cWidth = yCbCrSubSamples.Cb.GetLength(1);

            tasks[0] = Task.Factory.StartNew(() =>
            {
                yCbCrSubSamples.Y = UpQuantizedIDCT(yHeight, yWidth, yQuantized, LuminanceQuantizationTable);
            });
            tasks[1] = Task.Factory.StartNew(() =>
            {
                yCbCrSubSamples.Cb = UpQuantizedIDCT(cHeight, cWidth, cbQuantized, ChrominanceQuantizationTable);
            });
            tasks[2] = Task.Factory.StartNew(() =>
            {
                yCbCrSubSamples.Cr = UpQuantizedIDCT(cHeight, cWidth, crQuantized, ChrominanceQuantizationTable);
            });

            // zigzag RLE differences
            sbyte[] yStream  = ZigZagTransform(yQuantized);
            sbyte[] cbStream = ZigZagTransform(cbQuantized);
            sbyte[] crStream = ZigZagTransform(crQuantized);

            // concatennate byte stream
            var data = new sbyte[vecotrDiffs.Vectors.Length * 2 + yStream.Length + cbStream.Length + crStream.Length];

            for (int i = 0, j = 0; i < vecotrDiffs.Vectors.Length; ++i)
            {
                data[j++] = (sbyte)(vecotrDiffs.Vectors[i].x);
                data[j++] = (sbyte)(vecotrDiffs.Vectors[i].y);
            }

            yStream.CopyTo(data, vecotrDiffs.Vectors.Length * 2);
            cbStream.CopyTo(data, yStream.Length + vecotrDiffs.Vectors.Length * 2);
            crStream.CopyTo(data, yStream.Length + cbStream.Length + vecotrDiffs.Vectors.Length * 2);

            Task.WaitAll(tasks);
            AddDifferencesToMemoryFrame(yCbCrSubSamples, vecotrDiffs.Vectors); // update frame memory
            return(RunLengthEncode(data));
        }
Пример #9
0
        // estimate best match using 2d logorithmic search
        public EstimateResult Estimate(YCbCrSubSample reference, YCbCrSubSample target)
        {
            // image dimension
            int height = reference.Y.GetLength(0);
            int width  = reference.Y.GetLength(1);

            // number of 8*8 blocks to fill the y channel
            int h = (int)Math.Ceiling((double)height / N);
            int w = (int)Math.Ceiling((double)width / N);

            var result      = new EstimateResult {
            };
            int vectorIndex = 0;

            result.Vectors = new Vector[h * w];

            // y channel with paddings if origin image is not multiples of 8
            h           <<= 3;
            w           <<= 3;
            result.YDiffs = new double[h, w];

            // cb  cr
            h = (int)Math.Ceiling((double)reference.Cb.GetLength(0) / N) << 3;
            w = (int)Math.Ceiling((double)reference.Cb.GetLength(1) / N) << 3;
            result.CbDiffs = new double[h, w];
            result.CrDiffs = new double[h, w];

            // dec to prevent -1 calculation inside the loop
            --width; --height;
            // cb cr height and width
            int cHeight = height >> 1, cWidth = width >> 1;

            for (int row = 0; row <= height; row += N)
            {
                for (int col = 0; col <= width; col += N)
                {
                    // calculate the difference at the same pos first
                    var r8 = new double[N, N];
                    var t8 = new double[N, N];
                    // 8*8 block filling
                    for (int i = 0, Y = row; i < N; ++i)
                    {
                        for (int j = 0, X = col; j < N; ++j)
                        {
                            // use y channel to get vector
                            r8[i, j] = reference.Y[Y, X];
                            t8[i, j] = target.Y[Y, X];
                            if (X < width) // padding number use the boundary number
                            {
                                ++X;
                            }
                        }
                        if (Y < height)
                        {
                            ++Y;
                        }
                    }

                    Differences min = CalDifferences(r8, t8);
                    Vector      mv  = new Vector {
                        x = 0, y = 0
                    };

                    // 2d logorithmic search for new reference block (p92)
                    int  centerY = row, centerX = col;
                    int  offset = (int)Math.Ceiling(P / 2.0);
                    bool last   = false;

                    while (!last)
                    {
                        // find one of the nine specified macroblocks that yields minimum MAD, then update centerX, centerY, min Difference. vecotr.
                        for (int offY = centerY - offset; offY <= centerY + offset; offY += offset)
                        {
                            for (int offX = centerX - offset; offX <= centerX + offset; offX += offset)
                            {
                                if ((offX == centerX && offY == centerY) || offX < 0 || offY < 0 || offX > width || offY > height)
                                {
                                    continue;
                                }

                                // 8*8 block filling references block
                                for (int i = 0, Y = offY; i < N; ++i)
                                {
                                    for (int j = 0, X = offX; j < N; ++j)
                                    {
                                        r8[i, j] = reference.Y[Y, X];
                                        if (X < width) // padding number use the boundary number
                                        {
                                            ++X;
                                        }
                                    }
                                    if (Y < height)
                                    {
                                        ++Y;
                                    }
                                }
                                Differences d = CalDifferences(r8, t8);

                                // compare with min
                                if (d.AbsoluteDifference < min.AbsoluteDifference)
                                {
                                    min     = d;
                                    mv.x    = col - offX;
                                    mv.y    = row - offY;
                                    centerX = offX;
                                    centerY = offY;
                                }
                            }
                        }


                        if (offset == 1)
                        {
                            last = true;
                        }
                        offset = (int)Math.Ceiling(offset / 2.0);
                    }

                    // cb cr
                    for (int Y = row >> 1, YB = Y + (N >> 1); Y < YB && Y < cHeight; ++Y)
                    {
                        for (int X = col >> 1, XB = X + (N >> 1); X < XB && X < cWidth; ++X)
                        {
                            int ry = Math.Max(0, Math.Min(Y - mv.y, cHeight));
                            int rx = Math.Max(0, Math.Min(X - mv.x, cWidth));
                            result.CbDiffs[Y, X] = target.Cb[Y, X] - reference.Cb[ry, rx];
                            result.CrDiffs[Y, X] = target.Cr[Y, X] - reference.Cr[ry, rx];
                        }
                    }

                    // y
                    for (int _y = 0, Y = row; _y < N; ++_y, ++Y)
                    {
                        for (int _x = 0, X = col; _x < N; ++_x, ++X)
                        {
                            result.YDiffs[Y, X] = min.DifferenceBlock[_y, _x];
                        }
                    }
                    result.Vectors[vectorIndex++] = mv;
                }
            }

            return(result);
        }