protected override unsafe void ProcessFilter(UnmanagedImage image, Rectangle rect)
{
int pixelSize = Image.GetPixelFormatSize(image.PixelFormat) / 8;
int startX = rect.Left;
int startY = rect.Top;
int stopX = startX + rect.Width;
int stopY = startY + rect.Height;
int offset = image.Stride - rect.Width * pixelSize;
RGB rgb = new RGB();
YCbCr ycbcr = new YCbCr();
float ky = 0, by = 0;
float kcb = 0, bcb = 0;
float kcr = 0, bcr = 0;
// Y line parameters
if (inY.Max != inY.Min)
{
ky = (outY.Max - outY.Min) / (inY.Max - inY.Min);
by = outY.Min - ky * inY.Min;
}
// Cb line parameters
if (inCb.Max != inCb.Min)
{
kcb = (outCb.Max - outCb.Min) / (inCb.Max - inCb.Min);
bcb = outCb.Min - kcb * inCb.Min;
}
// Cr line parameters
if (inCr.Max != inCr.Min)
{
kcr = (outCr.Max - outCr.Min) / (inCr.Max - inCr.Min);
bcr = outCr.Min - kcr * inCr.Min;
}
// do the job
byte* ptr = (byte*)image.ImageData.ToPointer();
// allign pointer to the first pixel to process
ptr += (startY * image.Stride + startX * pixelSize);
// for each row
for (int y = startY; y < stopY; y++)
{
// for each pixel
for (int x = startX; x < stopX; x++, ptr += pixelSize)
{
rgb.Red = ptr[RGB.R];
rgb.Green = ptr[RGB.G];
rgb.Blue = ptr[RGB.B];
// convert to YCbCr
Accord.Imaging.YCbCr.FromRGB(rgb, ycbcr);
// correct Y
if (ycbcr.Y >= inY.Max)
ycbcr.Y = outY.Max;
else if (ycbcr.Y <= inY.Min)
ycbcr.Y = outY.Min;
else
ycbcr.Y = ky * ycbcr.Y + by;
// correct Cb
if (ycbcr.Cb >= inCb.Max)
ycbcr.Cb = outCb.Max;
else if (ycbcr.Cb <= inCb.Min)
ycbcr.Cb = outCb.Min;
else
ycbcr.Cb = kcb * ycbcr.Cb + bcb;
// correct Cr
if (ycbcr.Cr >= inCr.Max)
ycbcr.Cr = outCr.Max;
else if (ycbcr.Cr <= inCr.Min)
ycbcr.Cr = outCr.Min;
else
ycbcr.Cr = kcr * ycbcr.Cr + bcr;
// convert back to RGB
Accord.Imaging.YCbCr.ToRGB(ycbcr, rgb);
ptr[RGB.R] = rgb.Red;
ptr[RGB.G] = rgb.Green;
ptr[RGB.B] = rgb.Blue;
}
ptr += offset;
}
}
}