snakealpha
11/9/2017 - 9:13 AM

encode and decode from bgra to ycocg color space.

encode and decode from bgra to ycocg color space.

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;
using Emgu.CV.Util;

namespace YCoCg
{
    class YCoCgProgram
    {
        static void Main(string[] args)
        {
            string filePath = args[0];

            Mat sourceData = new Mat(filePath, ImreadModes.Unchanged);
            CvInvoke.Imshow("Source Image", sourceData);

            Mat convertedMat = new Mat(sourceData.Height, sourceData.Width, DepthType.Cv8S, 3);
            for (int i = 0; i < sourceData.Rows; i++)
            {
                for (int j = 0; j < sourceData.Cols; j++)
                {
                    var v = sourceData.Col(j).Row(i);
                    var pixel = v.GetData();

                    var tarV = convertedMat.Col(j).Row(i);
                    var tarPixel = tarV.GetData();

                    var r = pixel[2];
                    var g = pixel[1];
                    var b = pixel[0];
                    var a = pixel[3];

                    var yChannel = (g /2) + (r + b) /4;
                    var coChannel = (sbyte)((r - b) /2);
                    var cgChannel = (sbyte)((g - (r + b) /2) /2);

                    tarPixel[0] = (byte)yChannel;

                    // 压缩色度分量 4:2:2 像素自取单通道
                    if ((j % 2 == 0 && i % 2 == 0) || (j % 2 == 1 && i % 2 == 1))
                    {
                        tarPixel[1] = (byte)coChannel;
                    }
                    else
                    {
                        tarPixel[1] = (byte)cgChannel;
                    }

                    // 使用空余通道记录alpha值
                    tarPixel[2] = pixel[3];

                    tarV.SetTo(tarPixel);
                }
            }

            // Remerge 4:2:2
            Mat recoveredMat = new Mat(sourceData.Height, sourceData.Width, DepthType.Cv8U, 3);
            for (int i = 0; i < convertedMat.Rows; i++)
            {
                for (int j = 0; j < convertedMat.Cols; j++)
                {
                    var tarV = recoveredMat.Col(j).Row(i);
                    var tarPixel = tarV.GetData();

                    var yChannel = convertedMat.Col(j).Row(i).GetData()[0];
                    sbyte coChannel = 0;
                    sbyte cgChannel = 0;

                    // 压缩色度分量 4:2:2 相邻2像素交互获取                    
                    coChannel = (sbyte)convertedMat.Col((int)(j & 0xfffffffe) + i % 2).Row(i).GetData()[1];
                    cgChannel = (sbyte)convertedMat.Col((int)(j & 0xfffffffe) + (1 - i % 2)).Row(i).GetData()[1];

                    var rChannel = yChannel + coChannel - cgChannel;
                    var bChannel = yChannel - coChannel - cgChannel;
                    var gChannel = yChannel + cgChannel;


                    tarPixel[2] = FormatIntToByte(rChannel);
                    tarPixel[1] = FormatIntToByte(gChannel);
                    tarPixel[0] = FormatIntToByte(bChannel);

                    tarV.SetTo(tarPixel);
                }
            }
            CvInvoke.Imshow("Recovered Image 4:2:2", recoveredMat);

            CvInvoke.WaitKey(0);
        }

        private static byte FormatIntToByte(int value)
        {
            if (value < 0) return 0;
            if (value > 255) return 255;
            return (byte)value;
        }
    }
}