/// <summary> /// Convert RGB colorspace to HSI colorspace. /// </summary> public static VectorHsi RGB2HSI(VectorRgb rgb) { VectorHsi hsi = new VectorHsi(); //method from CxImageLib. ximadsp.cpp file. byte H, S, I; UInt16 Rdelta, Gdelta, Bdelta; //get R, G, and B in 8-bit byte R = rgb.R; byte G = rgb.G; byte B = rgb.B; byte cMax = Math.Max(Math.Max(R, G), B);// calculate lightness (intensity) byte cMin = Math.Min(Math.Min(R, G), B); I = (byte)((((cMax + cMin) * HSIMAX) + RGBMAX) / (2 * RGBMAX)); if (cMax == cMin){ // r=g=b --> achromatic case S = 0; // saturation H = HSIUNDEFINED; // hue } else { // chromatic case if (I <= (HSIMAX / 2)) // saturation S = (byte)((((cMax - cMin) * HSIMAX) + ((cMax + cMin) / 2)) / (cMax + cMin)); else S = (byte)((((cMax - cMin) * HSIMAX) + ((2 * RGBMAX - cMax - cMin) / 2)) / (2 * RGBMAX - cMax - cMin)); // hue Rdelta = (UInt16)((((cMax - R) * (HSIMAX / 6)) + ((cMax - cMin) / 2)) / (cMax - cMin)); Gdelta = (UInt16)((((cMax - G) * (HSIMAX / 6)) + ((cMax - cMin) / 2)) / (cMax - cMin)); Bdelta = (UInt16)((((cMax - B) * (HSIMAX / 6)) + ((cMax - cMin) / 2)) / (cMax - cMin)); if (R == cMax) H = (byte)(Bdelta - Gdelta); else if (G == cMax) H = (byte)((HSIMAX / 3) + Rdelta - Bdelta); else // B == cMax H = (byte)(((2 * HSIMAX) / 3) + Gdelta - Rdelta); //if (H < 0) H += HSIMAX; //always false if (H > HSIMAX) H -= HSIMAX; } hsi.H = (float)(H / 255.0f); hsi.S = (float)(S / 255.0f); hsi.I = (float)(I / 255.0f); return hsi; }
/// <summary> /// show in TextBoxes HSI and RGB components /// </summary> /// <param name="color">color of pixel</param> /// <param name="boxes">6 TextBoxes</param> public static void ShowPixelComponents(Color color, params TextBox[] boxes) { VectorHsi hsi = new VectorHsi(color); int h = (int)(hsi.H * 255f); int s = (int)(hsi.S * 255f); int i = (int)(hsi.I * 255f); if (boxes.Length == 6) { boxes[0].Text = Convert.ToString(h); boxes[1].Text = Convert.ToString(s); boxes[2].Text = Convert.ToString(i); boxes[3].Text = Convert.ToString(color.R); boxes[4].Text = Convert.ToString(color.G); boxes[5].Text = Convert.ToString(color.B); } }
/// <summary> /// Convert HSI colorspace to RGB colorspace. /// </summary> public static VectorRgb HSI2RGB(VectorHsi hsi) { float h = hsi.H; float s = hsi.S; float i = hsi.I; //method from CxImageLib. ximadsp.cpp file. float m1, m2; byte R, G, B; h = (float)h * 360.0f; if (i <= 0.5) m2 = i * (1 + s); else m2 = i + s - i * s; m1 = 2 * i - m2; if (s == 0) { R = G = B = (byte)(i * 255.0f); } else { R = (byte)(HueToRGB(m1, m2, h + 120) * 255.0f); G = (byte)(HueToRGB(m1, m2, h) * 255.0f); B = (byte)(HueToRGB(m1, m2, h - 120) * 255.0f); } return new VectorRgb(R, G, B); }
/// <summary> /// Convert HSI colorspace to Color struct. /// </summary> public static Color HSI2COLOR(VectorHsi hsi) { float h = hsi.H; float s = hsi.S; float i = hsi.I; float m1, m2; byte R, G, B; h = (float)h * 360.0f; if (i <= 0.5) m2 = i * (1 + s); else m2 = i + s - i * s; m1 = 2 * i - m2; if (s == 0) { R = G = B = (byte)(i * 255.0f); } else { R = (byte)(HueToRGB(m1, m2, h + 120) * 255.0f); G = (byte)(HueToRGB(m1, m2, h) * 255.0f); B = (byte)(HueToRGB(m1, m2, h - 120) * 255.0f); } return Color.FromArgb(R, G, B); }
/// <summary> /// Copy Constructor /// </summary> /// <param name="vec">Vector HSI</param> public VectorHsi(VectorHsi vec) { this.h = vec.h; this.s = vec.s; this.i = vec.i; }
/// <summary> /// Clamp /// </summary> public static VectorHsi Clamp(VectorHsi source, float min, float max) { VectorHsi result = source; if (result.h < min) result.h = min; if (result.h > max) result.h = max; if (result.s < min) result.s = min; if (result.s > max) result.s = max; if (result.i < min) result.i = min; if (result.i > max) result.i = max; return result; }
/// <summary> /// Constructor - transformation HSI to RGB /// </summary> /// <param name="vec">Vector HSI</param> public VectorRgb(VectorHsi vec) { System.Drawing.Color cl = ColorspaceHelper.HSI2COLOR(vec); this.r = cl.R; this.g = cl.G; this.b = cl.B; }
/// <summary> /// Filter processing. /// </summary> /// <param name="rOriginal">Original raster.</param> /// <returns>Raster.</returns> public override Raster ProcessWithoutWorker(Raster rOriginal) { int width = rOriginal.Width; int height = rOriginal.Height; Raster raster = new Raster(width, height); VectorHsi hsi; float fIntensity = (float)this.intensity / 255f; float fSaturation = (float)this.saturation / 255f; float fHue = (float)this.hue / 255f; for (int j = 0; j < height; j++) { for (int i = 0; i < width; i++) { hsi = new VectorHsi(rOriginal[i, j]); hsi.ChangeSaturation(fSaturation); hsi.ChangeIntensity(fIntensity); hsi.ChangeHue(fHue); hsi = VectorHsi.Clamp(hsi, 0f, 1f); raster[i, j] = hsi.ToVectorRGB(); } } return raster; }
/// <summary> /// Filter processing, with BackgroundWorker. /// </summary> /// <param name="rOriginal">Original raster.</param> /// <param name="worker">BackgroundWorker.</param> /// <returns>Raster.</returns> public override Raster ProcessRaster(Raster rOriginal, System.ComponentModel.BackgroundWorker worker) { worker.WorkerReportsProgress = true; int width = rOriginal.Width; int height = rOriginal.Height; Raster raster = new Raster(width, height); VectorHsi hsi; float fIntensity = (float)this.intensity / 255f; float fSaturation = (float)this.saturation / 255f; float fHue = (float)this.hue / 255f; DateTime startTime = DateTime.Now; for (int j = 0; j < height; j++) { for (int i = 0; i < width; i++) { hsi = new VectorHsi(rOriginal[i, j]); hsi.ChangeSaturation(fSaturation); hsi.ChangeIntensity(fIntensity); hsi.ChangeHue(fHue); hsi = VectorHsi.Clamp(hsi, 0.0f, 1.0f); raster[i, j] = hsi.ToVectorRGB(); } worker.ReportProgress((int)(100f * j / height), DateTime.Now - startTime); } return raster; }