/// <summary> /// Convert from HSV to RGB color space. /// </summary> /// /// <param name="hsl">Source color in <b>HSV</b> color space.</param> /// <param name="rgb">Destination color in <b>RGB</b> color space.</param> /// public static void ToRGB(HSV hsv, RGB rgb) { double rr = 0.0, gg = 0.0, bb = 0.0; double hh, ss, vv; double SCALE = 255.0; double hSCALE = 256.0; double GETA = 2.0; double hGETA = 2.0; if (hsv.Hue == 6 * hGETA * (hSCALE)) { hsv.Hue = 0; } hh = (double)hsv.Hue / hGETA; ss = (double)hsv.Saturation / GETA; vv = (double)hsv.Value / GETA; switch ((int)(hh / hSCALE)) { case 0: rr = 1.0 * SCALE; gg = hh; bb = 0.0; break; case 1: rr = 2.0 * hSCALE - hh; gg = 1.0 * SCALE; bb = 0.0; break; case 2: rr = 0.0; gg = 1.0 * SCALE; bb = hh - 2.0 * hSCALE; break; case 3: rr = 0.0; gg = 4.0 * hSCALE - hh; bb = 1.0 * SCALE; break; case 4: rr = hh - 4.0 * hSCALE; gg = 0.0; bb = 1.0 * SCALE; break; case 5: rr = 1.0 * SCALE; gg = 0.0; bb = 6.0 * hSCALE - hh; break; } rr = (rr + (1.0 * SCALE - rr) * (1.0 * SCALE - ss) / (SCALE)) * vv / SCALE; gg = (gg + (1.0 * SCALE - gg) * (1.0 * SCALE - ss) / (SCALE)) * vv / SCALE; bb = (bb + (1.0 * SCALE - bb) * (1.0 * SCALE - ss) / (SCALE)) * vv / SCALE; if (rr < 0) { rgb.Red = 0; } else if (rr > 255) { rgb.Red = 255; } else { rgb.Red = (byte)rr; } if (gg < 0) { rgb.Green = 0; } else if (gg > 255) { rgb.Green = 255; } else { rgb.Green = (byte)gg; } if (bb < 0) { rgb.Blue = 0; } else if (bb > 255) { rgb.Blue = 255; } else { rgb.Blue = (byte)bb; } }
/// <summary> /// Selection based on pixel similarity in HSV color space /// </summary> public static unsafe Bitmap Similiar_HSV(Bitmap image, Rectangle rect, List <HSV> hsvs, int similarity) { Bitmap dest = (Bitmap)image.Clone(); if (hsvs.Count == 0) { return(dest); } BitmapData srcDat = image.LockBits(rect, ImageLockMode.ReadOnly, image.PixelFormat); BitmapData dstDat = dest.LockBits(rect, ImageLockMode.ReadWrite, dest.PixelFormat); int width = rect.Width; int height = rect.Height; int stride = srcDat.Stride; // get pixel size int pixelSize = (image.PixelFormat == PixelFormat.Format24bppRgb) ? 3 : 4; int offset = stride - width * pixelSize; // do the job byte *src = (byte *)srcDat.Scan0.ToPointer(); byte *dst = (byte *)dstDat.Scan0.ToPointer(); //H = 0 ~ 3066 //S = 0 ~ 511 //V = 0 ~ 511 const int HSV_num = 3067 + 512 + 512; int[] table_mix = new int[HSV_num]; for (int i = 0; i < HSV_num; i++) { table_mix[i] = -1; } int total_l; foreach (HSV hsv in hsvs) { total_l = hsv.Hue + hsv.Saturation + hsv.Value; for (int i = 0; i < similarity / 2; i++) { if ((total_l + i) < HSV_num) { table_mix[total_l + i] = 1; } if ((total_l - i) >= 0) { table_mix[total_l - i] = 1; } } } int koba; // for each row for (int y = 0; y < height; y++) { // for each pixel for (int x = 0; x < width; x++, src += pixelSize, dst += pixelSize) { HSV hsv = HSV.FromRGB(new RGB(src[RGB.R], src[RGB.G], src[RGB.B])); koba = hsv.Hue + hsv.Saturation + hsv.Value; if (table_mix[koba] == 1) { dst[RGB.R] = dst[RGB.G] = dst[RGB.B] = 0; } else { dst[RGB.R] = dst[RGB.G] = dst[RGB.B] = 255; } } src += offset; dst += offset; } image.UnlockBits(srcDat); dest.UnlockBits(dstDat); return(dest); }
/// <summary> /// Convert from RGB to HSV color space. /// </summary> /// /// <param name="rgb">Source color in <b>RGB</b> color space.</param> /// <param name="hsl">Destination color in <b>HSV</b> color space.</param> /// /// <remarks><para>See <a href="http://en.wikipedia.org/wiki/HSI_color_space#Conversion_from_RGB_to_HSV_or_HSV">HSV and HSV Wiki</a> /// for information about the algorithm to convert from RGB to HSV.</para></remarks> /// public static void FromRGB(RGB rgb, HSV hsv) { double rr, gg, bb; double hh, ss, vv; double cmax, cmin, cdes; double SCALE = 255.0; double hSCALE = 256.0; double GETA = 2.0; double hGETA = 2.0; rr = (double)rgb.Red; gg = (double)rgb.Green; bb = (double)rgb.Blue; cmax = gg; if (rr > cmax) { cmax = rr; } if (bb > cmax) { cmax = bb; } cmin = gg; if (rr < cmin) { cmin = rr; } if (bb < cmin) { cmin = bb; } cdes = cmax - cmin; vv = cmax; hh = 0.0; if (cdes != 0.0) { ss = cdes * SCALE / cmax; if (cmax == rr) { hh = (gg - bb) * SCALE / cdes; } if (cmax == gg) { hh = (bb - rr) * SCALE / cdes + 2.0 * hSCALE; } if (cmax == bb) { hh = (rr - gg) * SCALE / cdes + 4.0 * hSCALE; } } else if (cdes != 0.0) { ss = cdes * SCALE / cmax; hh = 0.0; } else { ss = 0.0; hh = 0.0; } if (hh < 0.0) { hh += 6.0 * hSCALE; } hsv.Hue = (int)(hh * hGETA); hsv.Saturation = (int)(ss * GETA); hsv.Value = (int)(vv * GETA); }
/// <summary> /// Stretch HSV histogram to create new image /// </summary> public static unsafe Bitmap HistogramStretchHSV(Bitmap image, Rectangle rect) { Bitmap dest = (Bitmap)image.Clone(); BitmapData srcDat = image.LockBits(rect, ImageLockMode.ReadOnly, image.PixelFormat); BitmapData dstDat = dest.LockBits(rect, ImageLockMode.ReadWrite, dest.PixelFormat); int width = rect.Width; int height = rect.Height; int stride = srcDat.Stride; // get pixel size int pixelSize = (image.PixelFormat == PixelFormat.Format24bppRgb) ? 3 : 4; int offset = stride - width * pixelSize; // do the job byte *src = (byte *)srcDat.Scan0.ToPointer(); byte *dst = (byte *)dstDat.Scan0.ToPointer(); int pix_num = width * height; //縦×横 int[] num_b = new int[512]; int min_per, max_per; int per1 = pix_num / 100; int per99 = pix_num / 100 * 99; int[] aryH = new int[pix_num]; int[] aryS = new int[pix_num]; int[] aryV = new int[pix_num]; int maxH, maxS, maxV; int minV; maxH = maxS = maxV = 0; minV = 255; int tmp_pix, last_pix; double ratio; int pos; int count_i = 0; int sum = 0; RGB rgb = new RGB(); HSV hsv = new HSV(); // RGB histograms // for each row for (int y = 0; y < height; y++) { // for each pixel for (int x = 0; x < width; x++, src += pixelSize) { rgb.Red = src[RGB.R]; rgb.Green = src[RGB.G]; rgb.Blue = src[RGB.B]; hsv = HSV.FromRGB(rgb); pos = y * width + x; aryH[pos] = hsv.Hue; aryS[pos] = hsv.Saturation; aryV[pos] = hsv.Value; if (hsv.Hue > maxH) { maxH = hsv.Hue; } if (hsv.Saturation > maxS) { maxS = hsv.Saturation; } if (hsv.Value > maxV) { maxV = hsv.Value; } if (hsv.Value < minV) { minV = hsv.Value; } } src += offset; } // histogram for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++, src += pixelSize) { num_b[aryV[y * width + x]]++; } } do { sum += num_b[count_i++]; } while (sum < per1); min_per = count_i - 1; do { sum += num_b[count_i++]; } while (sum < per99); max_per = count_i - 1; ratio = (double)(511.0 / (max_per - min_per)); // stretch histogram for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++, src += pixelSize) { pos = y * width + x; tmp_pix = aryV[pos]; if (tmp_pix <= min_per) { last_pix = 0; } else if (tmp_pix >= max_per) { last_pix = 511; } else { last_pix = (int)((tmp_pix - min_per) * ratio); } if (last_pix < 0) { aryV[pos] = 0; } else if (last_pix >= 511) { aryV[pos] = 511; } else { aryV[pos] = last_pix; } } } // for each row for (int y = 0; y < height; y++) { // for each pixel for (int x = 0; x < width; x++, src += pixelSize, dst += pixelSize) { pos = y * width + x; hsv.Hue = aryH[pos]; hsv.Saturation = aryS[pos]; hsv.Value = aryV[pos]; HSV.ToRGB(hsv, rgb); dst[RGB.R] = rgb.Red; dst[RGB.G] = rgb.Green; dst[RGB.B] = rgb.Blue; } src += offset; dst += offset; } image.UnlockBits(srcDat); dest.UnlockBits(dstDat); return(dest); }