/// <summary> /// Convert the color to <b>RGB</b> color space. /// </summary> /// /// <returns>Returns <see cref="RGB"/> instance, which represents converted color value.</returns> /// public RGB ToRGB( ) { RGB rgb = new RGB( ); ToRGB( this, rgb ); return rgb; }
// Gather statistics for the specified image private unsafe void ProcessImage( UnmanagedImage image, byte* mask, int maskLineSize ) { // get image dimension int width = image.Width; int height = image.Height; pixels = pixelsWithoutBlack = 0; int[] s = new int[256]; int[] l = new int[256]; int[] swb = new int[256]; int[] lwb = new int[256]; RGB rgb = new RGB( ); HSL hsl = new HSL( ); int pixelSize = ( image.PixelFormat == PixelFormat.Format24bppRgb ) ? 3 : 4; int offset = image.Stride - width * pixelSize; int maskOffset = maskLineSize - width; // do the job byte * p = (byte*) image.ImageData.ToPointer( ); if ( mask == null ) { // for each line for ( int y = 0; y < height; y++ ) { // for each pixel for ( int x = 0; x < width; x++, p += pixelSize ) { rgb.Red = p[RGB.R]; rgb.Green = p[RGB.G]; rgb.Blue = p[RGB.B]; // convert to HSL color space BestCS.Imaging.HSL.FromRGB( rgb, hsl ); s[(int) ( hsl.Saturation * 255 )]++; l[(int) ( hsl.Luminance * 255 )]++; pixels++; if ( hsl.Luminance != 0.0 ) { swb[(int) ( hsl.Saturation * 255 )]++; lwb[(int) ( hsl.Luminance * 255 )]++; pixelsWithoutBlack++; } } p += offset; } } else { // for each line for ( int y = 0; y < height; y++ ) { // for each pixel for ( int x = 0; x < width; x++, p += pixelSize, mask++ ) { if ( *mask == 0 ) continue; rgb.Red = p[RGB.R]; rgb.Green = p[RGB.G]; rgb.Blue = p[RGB.B]; // convert to HSL color space BestCS.Imaging.HSL.FromRGB( rgb, hsl ); s[(int) ( hsl.Saturation * 255 )]++; l[(int) ( hsl.Luminance * 255 )]++; pixels++; if ( hsl.Luminance != 0.0 ) { swb[(int) ( hsl.Saturation * 255 )]++; lwb[(int) ( hsl.Luminance * 255 )]++; pixelsWithoutBlack++; } } p += offset; mask += maskOffset; } } // create histograms saturation = new ContinuousHistogram( s, new Range( 0, 1 ) ); luminance = new ContinuousHistogram( l, new Range( 0, 1 ) ); saturationWithoutBlack = new ContinuousHistogram( swb, new Range( 0, 1 ) ); luminanceWithoutBlack = new ContinuousHistogram( lwb, new Range( 0, 1 ) ); }
/// <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> /// /// <returns>Returns <see cref="YCbCr"/> instance, which represents converted color value.</returns> /// public static YCbCr FromRGB( RGB rgb ) { YCbCr ycbcr = new YCbCr( ); FromRGB( rgb, ycbcr ); return ycbcr; }
/// <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 float r = Math.Max( 0.0f, Math.Min( 1.0f, (float) ( ycbcr.Y + 0.0000 * ycbcr.Cb + 1.4022 * ycbcr.Cr ) ) ); float g = Math.Max( 0.0f, Math.Min( 1.0f, (float) ( ycbcr.Y - 0.3456 * ycbcr.Cb - 0.7145 * ycbcr.Cr ) ) ); float b = Math.Max( 0.0f, Math.Min( 1.0f, (float) ( 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 ); rgb.Alpha = 255; }
/// <summary> /// Convert from HSL to RGB color space. /// </summary> /// /// <param name="hsl">Source color in <b>HSL</b> color space.</param> /// <param name="rgb">Destination color in <b>RGB</b> color space.</param> /// public static void ToRGB( HSL hsl, RGB rgb ) { if ( hsl.Saturation == 0 ) { // gray values rgb.Red = rgb.Green = rgb.Blue = (byte) ( hsl.Luminance * 255 ); } else { float v1, v2; float hue = (float) hsl.Hue / 360; v2 = ( hsl.Luminance < 0.5 ) ? ( hsl.Luminance * ( 1 + hsl.Saturation ) ) : ( ( hsl.Luminance + hsl.Saturation ) - ( hsl.Luminance * hsl.Saturation ) ); v1 = 2 * hsl.Luminance - v2; rgb.Red = (byte) ( 255 * Hue_2_RGB( v1, v2, hue + ( 1.0f / 3 ) ) ); rgb.Green = (byte) ( 255 * Hue_2_RGB( v1, v2, hue ) ); rgb.Blue = (byte) ( 255 * Hue_2_RGB( v1, v2, hue - ( 1.0f / 3 ) ) ); } rgb.Alpha = 255; }
/// <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 ) { float r = (float) rgb.Red / 255; float g = (float) rgb.Green / 255; float b = (float) rgb.Blue / 255; ycbcr.Y = (float) ( 0.2989 * r + 0.5866 * g + 0.1145 * b ); ycbcr.Cb = (float) ( -0.1687 * r - 0.3313 * g + 0.5000 * b ); ycbcr.Cr = (float) ( 0.5000 * r - 0.4184 * g - 0.0816 * b ); }
/// <summary> /// Convert from RGB to HSL color space. /// </summary> /// /// <param name="rgb">Source color in <b>RGB</b> color space.</param> /// /// <returns>Returns <see cref="HSL"/> instance, which represents converted color value.</returns> /// public static HSL FromRGB( RGB rgb ) { HSL hsl = new HSL( ); FromRGB( rgb, hsl ); return hsl; }
/// <summary> /// Convert from RGB to HSL color space. /// </summary> /// /// <param name="rgb">Source color in <b>RGB</b> color space.</param> /// <param name="hsl">Destination color in <b>HSL</b> color space.</param> /// /// <remarks><para>See <a href="http://en.wikipedia.org/wiki/HSI_color_space#Conversion_from_RGB_to_HSL_or_HSV">HSL and HSV Wiki</a> /// for information about the algorithm to convert from RGB to HSL.</para></remarks> /// public static void FromRGB( RGB rgb, HSL hsl ) { float r = ( rgb.Red / 255.0f ); float g = ( rgb.Green / 255.0f ); float b = ( rgb.Blue / 255.0f ); float min = Math.Min( Math.Min( r, g ), b ); float max = Math.Max( Math.Max( r, g ), b ); float delta = max - min; // get luminance value hsl.Luminance = ( max + min ) / 2; if ( delta == 0 ) { // gray color hsl.Hue = 0; hsl.Saturation = 0.0f; } else { // get saturation value hsl.Saturation = ( hsl.Luminance <= 0.5 ) ? ( delta / ( max + min ) ) : ( delta / ( 2 - max - min ) ); // get hue value float hue; if ( r == max ) { hue = ( ( g - b ) / 6 ) / delta; } else if ( g == max ) { hue = ( 1.0f / 3 ) + ( ( b - r ) / 6 ) / delta; } else { hue = ( 2.0f / 3 ) + ( ( r - g ) / 6 ) / delta; } // correct hue if needed if ( hue < 0 ) hue += 1; if ( hue > 1 ) hue -= 1; hsl.Hue = (int) ( hue * 360 ); } }
// Gather statistics for the specified image private unsafe void ProcessImage( UnmanagedImage image, byte* mask, int maskLineSize ) { // get image dimension int width = image.Width; int height = image.Height; pixels = pixelsWithoutBlack = 0; int[] yhisto = new int[256]; int[] cbhisto = new int[256]; int[] crhisto = new int[256]; int[] yhistoWB = new int[256]; int[] cbhistoWB = new int[256]; int[] crhistoWB = new int[256]; RGB rgb = new RGB( ); YCbCr ycbcr = new YCbCr( ); int pixelSize = ( image.PixelFormat == PixelFormat.Format24bppRgb ) ? 3 : 4; int offset = image.Stride - width * pixelSize; int maskOffset = maskLineSize - width; // do the job byte * p = (byte*) image.ImageData.ToPointer( ); if ( mask == null ) { // for each line for ( int y = 0; y < height; y++ ) { // for each pixel for ( int x = 0; x < width; x++, p += pixelSize ) { rgb.Red = p[RGB.R]; rgb.Green = p[RGB.G]; rgb.Blue = p[RGB.B]; // convert to YCbCr color space BestCS.Imaging.YCbCr.FromRGB( rgb, ycbcr ); yhisto[(int) ( ycbcr.Y * 255 )]++; cbhisto[(int) ( ( ycbcr.Cb + 0.5 ) * 255 )]++; crhisto[(int) ( ( ycbcr.Cr + 0.5 ) * 255 )]++; pixels++; if ( ( ycbcr.Y != 0.0 ) || ( ycbcr.Cb != 0.0 ) || ( ycbcr.Cr != 0.0 ) ) { yhistoWB[(int) ( ycbcr.Y * 255 )]++; cbhistoWB[(int) ( ( ycbcr.Cb + 0.5 ) * 255 )]++; crhistoWB[(int) ( ( ycbcr.Cr + 0.5 ) * 255 )]++; pixelsWithoutBlack++; } } p += offset; } } else { // for each line for ( int y = 0; y < height; y++ ) { // for each pixel for ( int x = 0; x < width; x++, p += pixelSize, mask++ ) { if ( *mask == 0 ) continue; rgb.Red = p[RGB.R]; rgb.Green = p[RGB.G]; rgb.Blue = p[RGB.B]; // convert to YCbCr color space BestCS.Imaging.YCbCr.FromRGB( rgb, ycbcr ); yhisto[(int) ( ycbcr.Y * 255 )]++; cbhisto[(int) ( ( ycbcr.Cb + 0.5 ) * 255 )]++; crhisto[(int) ( ( ycbcr.Cr + 0.5 ) * 255 )]++; pixels++; if ( ( ycbcr.Y != 0.0 ) || ( ycbcr.Cb != 0.0 ) || ( ycbcr.Cr != 0.0 ) ) { yhistoWB[(int) ( ycbcr.Y * 255 )]++; cbhistoWB[(int) ( ( ycbcr.Cb + 0.5 ) * 255 )]++; crhistoWB[(int) ( ( ycbcr.Cr + 0.5 ) * 255 )]++; pixelsWithoutBlack++; } } p += offset; mask += maskOffset; } } // create histograms yHistogram = new ContinuousHistogram( yhisto, new Range( 0.0f, 1.0f ) ); cbHistogram = new ContinuousHistogram( cbhisto, new Range( -0.5f, 0.5f ) ); crHistogram = new ContinuousHistogram( crhisto, new Range( -0.5f, 0.5f ) ); yHistogramWithoutBlack = new ContinuousHistogram( yhistoWB, new Range( 0.0f, 1.0f ) ); cbHistogramWithoutBlack = new ContinuousHistogram( cbhistoWB, new Range( -0.5f, 0.5f ) ); crHistogramWithoutBlack = new ContinuousHistogram( crhistoWB, new Range( -0.5f, 0.5f ) ); }
/// <summary> /// Paint the controls. /// </summary> /// /// <param name="pe">Paint event arguments.</param> /// protected override void OnPaint( PaintEventArgs pe ) { Graphics g = pe.Graphics; Rectangle rc = this.ClientRectangle; Rectangle rcPie; Brush brush; RGB rgb = new RGB( ); HSL hsl = new HSL( ); // get pie rectangle rcPie = new Rectangle( 4, 4, System.Math.Min( rc.Right, rc.Bottom ) - 8, System.Math.Min( rc.Right, rc.Bottom ) - 8 ); // init HSL value hsl.Luminance = 0.5f; hsl.Saturation = 1.0f; if ( type == HuePickerType.Value ) { // draw HSL pie for ( int i = 0; i < 360; i++ ) { hsl.Hue = i; // convert from HSL to RGB BestCS.Imaging.HSL.ToRGB( hsl, rgb ); // create brush brush = new SolidBrush( rgb.Color ); // draw one hue value g.FillPie( brush, rcPie, -i, -1 ); brush.Dispose( ); } } else { // draw HSL pie for ( int i = 0; i < 360; i++ ) { if ( ( ( min < max ) && ( i >= min ) && ( i <= max ) ) || ( ( min > max ) && ( ( i >= min ) || ( i <= max ) ) ) ) { hsl.Hue = i; // convert from HSL to RGB BestCS.Imaging.HSL.ToRGB( hsl, rgb ); // create brush brush = new SolidBrush( rgb.Color ); } else { brush = new SolidBrush( Color.FromArgb( 128, 128, 128 ) ); } // draw one hue value g.FillPie( brush, rcPie, -i, -1 ); brush.Dispose( ); } } // double halfWidth = (double) rcPie.Width / 2; double angleRad = -min * System.Math.PI / 180; double angleCos = System.Math.Cos( angleRad ); double angleSin = System.Math.Sin( angleRad ); double x = halfWidth * angleCos; double y = halfWidth * angleSin; ptCenter.X = rcPie.Left + (int) ( halfWidth ); ptCenter.Y = rcPie.Top + (int) ( halfWidth ); ptMin.X = rcPie.Left + (int) ( halfWidth + x ); ptMin.Y = rcPie.Top + (int) ( halfWidth + y ); // draw MIN pointer g.FillEllipse( blackBrush, rcPie.Left + (int) ( halfWidth + x ) - 4, rcPie.Top + (int) ( halfWidth + y ) - 4, 8, 8 ); g.DrawLine( blackPen, ptCenter, ptMin ); // check picker type if ( type == HuePickerType.Range ) { angleRad = -max * System.Math.PI / 180; angleCos = System.Math.Cos( angleRad ); angleSin = System.Math.Sin( angleRad ); x = halfWidth * angleCos; y = halfWidth * angleSin; ptMax.X = rcPie.Left + (int) ( halfWidth + x ); ptMax.Y = rcPie.Top + (int) ( halfWidth + y ); // draw MAX pointer g.FillEllipse( whiteBrush, rcPie.Left + (int) ( halfWidth + x ) - 4, rcPie.Top + (int) ( halfWidth + y ) - 4, 8, 8 ); g.DrawLine( whitePen, ptCenter, ptMax ); } base.OnPaint( pe ); }
// Gather statistics for the specified image private unsafe void ProcessImage(UnmanagedImage image, byte *mask, int maskLineSize) { // get image dimension int width = image.Width; int height = image.Height; pixels = pixelsWithoutBlack = 0; int[] yhisto = new int[256]; int[] cbhisto = new int[256]; int[] crhisto = new int[256]; int[] yhistoWB = new int[256]; int[] cbhistoWB = new int[256]; int[] crhistoWB = new int[256]; RGB rgb = new RGB( ); YCbCr ycbcr = new YCbCr( ); int pixelSize = (image.PixelFormat == PixelFormat.Format24bppRgb) ? 3 : 4; int offset = image.Stride - width * pixelSize; int maskOffset = maskLineSize - width; // do the job byte *p = (byte *)image.ImageData.ToPointer( ); if (mask == null) { // for each line for (int y = 0; y < height; y++) { // for each pixel for (int x = 0; x < width; x++, p += pixelSize) { rgb.Red = p[RGB.R]; rgb.Green = p[RGB.G]; rgb.Blue = p[RGB.B]; // convert to YCbCr color space BestCS.Imaging.YCbCr.FromRGB(rgb, ycbcr); yhisto[(int)(ycbcr.Y * 255)]++; cbhisto[(int)((ycbcr.Cb + 0.5) * 255)]++; crhisto[(int)((ycbcr.Cr + 0.5) * 255)]++; pixels++; if ((ycbcr.Y != 0.0) || (ycbcr.Cb != 0.0) || (ycbcr.Cr != 0.0)) { yhistoWB[(int)(ycbcr.Y * 255)]++; cbhistoWB[(int)((ycbcr.Cb + 0.5) * 255)]++; crhistoWB[(int)((ycbcr.Cr + 0.5) * 255)]++; pixelsWithoutBlack++; } } p += offset; } } else { // for each line for (int y = 0; y < height; y++) { // for each pixel for (int x = 0; x < width; x++, p += pixelSize, mask++) { if (*mask == 0) { continue; } rgb.Red = p[RGB.R]; rgb.Green = p[RGB.G]; rgb.Blue = p[RGB.B]; // convert to YCbCr color space BestCS.Imaging.YCbCr.FromRGB(rgb, ycbcr); yhisto[(int)(ycbcr.Y * 255)]++; cbhisto[(int)((ycbcr.Cb + 0.5) * 255)]++; crhisto[(int)((ycbcr.Cr + 0.5) * 255)]++; pixels++; if ((ycbcr.Y != 0.0) || (ycbcr.Cb != 0.0) || (ycbcr.Cr != 0.0)) { yhistoWB[(int)(ycbcr.Y * 255)]++; cbhistoWB[(int)((ycbcr.Cb + 0.5) * 255)]++; crhistoWB[(int)((ycbcr.Cr + 0.5) * 255)]++; pixelsWithoutBlack++; } } p += offset; mask += maskOffset; } } // create histograms yHistogram = new ContinuousHistogram(yhisto, new Range(0.0f, 1.0f)); cbHistogram = new ContinuousHistogram(cbhisto, new Range(-0.5f, 0.5f)); crHistogram = new ContinuousHistogram(crhisto, new Range(-0.5f, 0.5f)); yHistogramWithoutBlack = new ContinuousHistogram(yhistoWB, new Range(0.0f, 1.0f)); cbHistogramWithoutBlack = new ContinuousHistogram(cbhistoWB, new Range(-0.5f, 0.5f)); crHistogramWithoutBlack = new ContinuousHistogram(crhistoWB, new Range(-0.5f, 0.5f)); }