/// <summary> /// Convert from RGB to YCbCr color space (Rec 601-1 specification). /// </summary> /// /// <param name="rgb">Source color in <b>RGB</b> color space.</param> /// <param name="ycbcr">Destination color in <b>YCbCr</b> color space.</param> /// public static void FromRGB(RGB rgb, YCbCr ycbcr) { double r = (double)rgb.Red / 255; double g = (double)rgb.Green / 255; double b = (double)rgb.Blue / 255; ycbcr.Y = 0.2989 * r + 0.5866 * g + 0.1145 * b; ycbcr.Cb = -0.1687 * r - 0.3313 * g + 0.5000 * b; ycbcr.Cr = 0.5000 * r - 0.4184 * g - 0.0816 * b; }
/// <summary> /// Convert from YCbCr to RGB color space. /// </summary> /// /// <param name="ycbcr">Source color in <b>YCbCr</b> color space.</param> /// <param name="rgb">Destination color in <b>RGB</b> color spacs.</param> /// public static void ToRGB(YCbCr ycbcr, RGB rgb) { // don't warry about zeros. compiler will remove them double r = Math.Max(0.0, Math.Min(1.0, ycbcr.Y + 0.0000 * ycbcr.Cb + 1.4022 * ycbcr.Cr)); double g = Math.Max(0.0, Math.Min(1.0, ycbcr.Y - 0.3456 * ycbcr.Cb - 0.7145 * ycbcr.Cr)); double b = Math.Max(0.0, Math.Min(1.0, ycbcr.Y + 1.7710 * ycbcr.Cb + 0.0000 * ycbcr.Cr)); rgb.Red = (byte)(r * 255); rgb.Green = (byte)(g * 255); rgb.Blue = (byte)(b * 255); }
/// <summary> /// Color filtering in YCbCr color space. /// </summary> public static unsafe Bitmap YCbCrFilter(Bitmap image, Rectangle rect, DoubleRange Y, DoubleRange Cb, DoubleRange Cr) { Bitmap dest = new Bitmap(image.Width, image.Height, PixelFormat.Format8bppIndexed); BitmapData source = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadWrite, image.PixelFormat); BitmapData destination = dest.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadWrite, dest.PixelFormat); int startX = rect.Left; int startY = rect.Top; int stopX = rect.Right; int stopY = rect.Bottom; // get pixel size int pixelSize = (image.PixelFormat == PixelFormat.Format24bppRgb) ? 3 : 4; int srcOffset = source.Stride - rect.Width * pixelSize; int dstOffset = destination.Stride - rect.Width; RGB rgb = new RGB(); YCbCr ycbcr = new YCbCr(); // do the job byte *src = (byte *)source.Scan0 + startY * source.Stride + startX * pixelSize; byte *dst = (byte *)destination.Scan0 + startY * destination.Stride + startX; // for each row for (int y = startY; y < stopY; y++) { // for each pixel for (int x = startX; x < stopX; x++, src += pixelSize, dst++) { rgb.Red = src[RGB.R]; rgb.Green = src[RGB.G]; rgb.Blue = src[RGB.B]; // convert to YCbCr ycbcr = YCbCr.FromRGB(rgb); // check YCbCr values if (Y.IsInside(ycbcr.Y) & Cb.IsInside(ycbcr.Cb) && Cr.IsInside(ycbcr.Cr)) { *dst = 0; } else { *dst = 255; } } src += srcOffset; dst += dstOffset; } int width = image.Width; int height = image.Height; int stride = destination.Stride; // remove upper part for (int y = 0; y < startY; y++) { dst = (byte *)destination.Scan0.ToPointer() + y * stride; SystemTools.SetUnmanagedMemory(dst, 255, stride); } // remove lower part for (int y = stopY; y < height; y++) { dst = (byte *)destination.Scan0.ToPointer() + y * stride; SystemTools.SetUnmanagedMemory(dst, 255, stride); } for (int y = startY; y < stopY; y++) { // remove left part dst = (byte *)destination.Scan0.ToPointer() + y * stride; SystemTools.SetUnmanagedMemory(dst, 255, startX); // remove right part dst += stopX; SystemTools.SetUnmanagedMemory(dst, 255, stride - stopX); } image.UnlockBits(source); dest.UnlockBits(destination); return(dest); }