/// <summary> /// Converts a bitmap to a 2-bit grayscale array. /// </summary> /// <param name="bmp">Source bitmap</param> /// <param name="lum">Multiply luminosity</param> /// <param name="hue">Detected hue</param> /// <returns>Array with value for every pixel between 0 and 3</returns> public static byte[] ConvertToGray2(BitmapSource bmp, double lum, out double hue) { var frame = new byte[bmp.PixelWidth * bmp.PixelHeight]; var bytesPerPixel = (bmp.Format.BitsPerPixel + 7) / 8; var bytes = new byte[bytesPerPixel]; var rect = new Int32Rect(0, 0, 1, 1); double imageHue = 0; for (var y = 0; y < bmp.PixelHeight; y++) { rect.Y = y; for (var x = 0; x < bmp.PixelWidth; x++) { rect.X = x; bmp.CopyPixels(rect, bytes, bytesPerPixel, 0); // convert to HSL double h; double saturation; double luminosity; ColorUtil.RgbToHsl(bytes[2], bytes[1], bytes[0], out h, out saturation, out luminosity); frame[y * bmp.PixelWidth + x] = (byte)Math.Round(Math.Min(1, luminosity * lum) * 3d); if (luminosity > 0) { imageHue = h; } } } hue = imageHue; return(frame); }
/// <summary> /// Converts a bitmap to an RGB24 array. /// </summary> /// <param name="bmp">Source bitmap</param> /// <param name="buffer">Destination buffer. Will be filled with RGB values for each pixel between 0 and 255.</param> /// <param name="offset">Offset in destination array</param> /// <param name="lum">Multiply luminosity</param> public static void ConvertToRgb24(BitmapSource bmp, byte[] buffer, int offset = 0, double lum = 1) { var bytesPerPixel = (bmp.Format.BitsPerPixel + 7) / 8; var bytes = new byte[bytesPerPixel]; var rect = new Int32Rect(0, 0, 1, 1); var pos = offset; for (var y = 0; y < bmp.PixelHeight; y++) { for (var x = 0; x < bmp.PixelWidth; x++) { rect.X = x; rect.Y = y; bmp.CopyPixels(rect, bytes, bytesPerPixel, 0); if (Math.Abs(lum - 1) > 0.01) { double hue, saturation, luminosity; byte r, g, b; ColorUtil.RgbToHsl(bytes[2], bytes[1], bytes[0], out hue, out saturation, out luminosity); ColorUtil.HslToRgb(hue, saturation, luminosity * lum, out r, out g, out b); buffer[pos] = r; buffer[pos + 1] = g; buffer[pos + 2] = b; } else { buffer[pos] = bytes[2]; // r buffer[pos + 1] = bytes[1]; // g buffer[pos + 2] = bytes[0]; // b } pos += 3; } } }
/// <summary> /// Converts an RGB24 frame to a grayscale array. /// </summary> /// <param name="width">Width in pixels</param> /// <param name="height">Height in pixels</param> /// <param name="frameRgb24">RGB24 frame, top left to bottom right, three bytes per pixel with values between 0 and 255</param> /// <param name="numColors">Number of gray tones. 4 for 2 bit, 16 for 4 bit</param> /// <returns>Gray2 frame, top left to bottom right, one byte per pixel with values between 0 and 3</returns> public static byte[] ConvertToGray(int width, int height, byte[] frameRgb24, int numColors) { var frame = new byte[width * height]; var pos = 0; for (var y = 0; y < height; y++) { for (var x = 0; x < width * 3; x += 3) { var rgbPos = y * width * 3 + x; // convert to HSL double hue; double saturation; double luminosity; ColorUtil.RgbToHsl(frameRgb24[rgbPos], frameRgb24[rgbPos + 1], frameRgb24[rgbPos + 2], out hue, out saturation, out luminosity); frame[pos++] = (byte)Math.Round(luminosity * (numColors - 1)); } } return(frame); }
/// <summary> /// Converts a bitmap to an RGB24 array. /// </summary> /// <param name="bmp">Source bitmap</param> /// <param name="buffer">Destination buffer. Will be filled with RGB values for each pixel between 0 and 255.</param> /// <param name="offset">Offset in destination array</param> /// <param name="lum">Multiply luminosity</param> public static void ConvertToRgb24(BitmapSource bmp, byte[] buffer, int offset = 0, double lum = 1) { var stride = bmp.PixelWidth * (bmp.Format.BitsPerPixel / 8); var bytes = new byte[bmp.PixelHeight * stride]; bmp.CopyPixels(bytes, stride, 0); if (Math.Abs(lum - 1) > 0.01) { for (var i = 0; i < bytes.Length; i += 3) { double hue, saturation, luminosity; byte r, g, b; ColorUtil.RgbToHsl(bytes[i + 2], bytes[i + 1], bytes[i], out hue, out saturation, out luminosity); ColorUtil.HslToRgb(hue, saturation, luminosity * lum, out r, out g, out b); buffer[i] = r; buffer[i + 1] = g; buffer[i + 2] = b; } } else { unsafe { fixed(byte *pBuffer = buffer, pBytes = bytes) { byte *pB = pBuffer, pEnd = pBytes + bytes.Length; for (var pByte = pBytes; pByte < pEnd; pByte += 4, pB += 3) { *(pB) = *(pByte + 2); *(pB + 1) = *(pByte + 1); *(pB + 2) = *(pByte); } } } } }
/// <summary> /// Converts a bitmap to a 2-bit grayscale array by using the luminosity of the pixels and /// histogram stretching. /// </summary> /// <param name="bmp">Source bitmap</param> /// <param name="minLum">Min threshold for luminosity histogram stretching</param> /// <param name="maxLum">Max threshold for luminosity histogram stretching</param> /// <param name="hue">Detected hue</param> /// <returns>Array with value for every pixel between 0 and 3</returns> public static byte[] ConvertToGray2(BitmapSource bmp, double minLum, double maxLum, out double hue) { var frame = new byte[bmp.PixelWidth * bmp.PixelHeight]; var bytesPerPixel = (bmp.Format.BitsPerPixel + 7) / 8; var bytes = new byte[bytesPerPixel]; var rect = new Int32Rect(0, 0, 1, 1); double imageHue = 0; for (var y = 0; y < bmp.PixelHeight; y++) { rect.Y = y; for (var x = 0; x < bmp.PixelWidth; x++) { rect.X = x; bmp.CopyPixels(rect, bytes, bytesPerPixel, 0); // convert to HSL double h; double saturation; double luminosity; ColorUtil.RgbToHsl(bytes[2], bytes[1], bytes[0], out h, out saturation, out luminosity); var pixelBrightness = (luminosity - minLum) / (maxLum - minLum); byte frameVal = (byte)Math.Min(Math.Max(Math.Round(pixelBrightness * 3d), 0), 3); frame[y * bmp.PixelWidth + x] = frameVal; // Don't use very low luminosity values to calculate hue because they are less accurate. if (frameVal > 0) { imageHue = h; } } } hue = imageHue; return(frame); }