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;
}
}
}