If the part that needs to be colored is unique in the original in terms of hue (and you could make it unique by changing it in the source image through Photoshop or something), this should do the trick. It works by locking an input bitmap (so each pixel can be manipulated) and then converting each pixel to HSB so that hue (the "color") of the pixel can be adjusted if it falls within a certain range of hues. This will have a nice effect because gradients such as shadow and slight variances will also be colorized correctly.
Colorizing code:
Bitmap bmp = ...
byte minHue = 0;
byte maxHue = 10;
byte newHue = 128;
...
BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height),
ImageLockMode.ReadWrite, bmp.PixelFormat);
IntPtr ptr = bmpData.Scan0;
int bytes = bmpData.Stride * bmpData.Height;
byte[] rgbValues = new byte[bytes];
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);
for (int c = 0; c < rgbValues.Length; c += 4)
{
HSBColor hsb = new HSBColor(Color.FromArgb(
rgbValues[c + 3], rgbValues[c + 2],
rgbValues[c + 1], rgbValues[c]));
if(hsb.H > minHue && hsb.H < maxHue)
{
hsb.H = Convert.ToByte(newHue);
}
Color color = hsb.ToRGB();
rgbValues[c] = color.B;
rgbValues[c + 1] = color.G;
rgbValues[c + 2] = color.R;
rgbValues[c + 3] = color.A;
}
System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);
bmp.UnlockBits(bmpData);
HSBColor.cs (from ZedGraph):
/// <summary>
/// Hue-Saturation-Brightness Color class to store a color value, and to manage conversions
/// to and from RGB colors in the <see cref="Color" /> struct.
/// </summary>
/// <remarks>
/// This class is based on code from http://www.cs.rit.edu/~ncs/color/ by Eugene Vishnevsky.
/// This struct stores the hue, saturation, brightness, and alpha values internally as
/// <see cref="byte" /> values from 0 to 255. The hue represents a fraction of the 360 degrees
/// of color space available. The saturation is the color intensity, where 0 represents gray scale
/// and 255 is the most colored. For the brightness, 0 represents black and 255
/// represents white.
/// </remarks>
[Serializable]
public struct HSBColor
{
/// <summary>
/// The color hue value, ranging from 0 to 255.
/// </summary>
/// <remarks>
/// This property is actually a rescaling of the 360 degrees on the color wheel to 255
/// possible values. Therefore, every 42.5 units is a new sector, with the following
/// convention: red=0, yellow=42.5, green=85, cyan=127.5, blue=170, magenta=212.5
/// </remarks>
public byte H;
/// <summary>
/// The color saturation (intensity) value, ranging from 0 (gray scale) to 255 (most colored).
/// </summary>
public byte S;
/// <summary>
/// The brightness value, ranging from 0 (black) to 255 (white).
/// </summary>
public byte B;
/// <summary>
/// The alpha value (opacity), ranging from 0 (transparent) to 255 (opaque).
/// </summary>
public byte A;
/// <summary>
/// Constructor to load an <see cref="HSBColor" /> struct from hue, saturation and
/// brightness values
/// </summary>
/// <param name="h">The color hue value, ranging from 0 to 255</param>
/// <param name="s">The color saturation (intensity) value, ranging from 0 (gray scale)
/// to 255 (most colored)</param>
/// <param name="b">The brightness value, ranging from 0 (black) to 255 (white)</param>
public HSBColor(int h, int s, int b)
{
this.H = (byte)h;
this.S = (byte)s;
this.B = (byte)b;
this.A = 255;
}
/// <summary>
/// Constructor to load an <see cref="HSBColor" /> struct from hue, saturation,
/// brightness, and alpha values
/// </summary>
/// <param name="h">The color hue value, ranging from 0 to 255</param>
/// <param name="s">The color saturation (intensity) value, ranging from 0 (gray scale)
/// to 255 (most colored)</param>
/// <param name="b">The brightness value, ranging from 0 (black) to 255 (white)</param>
/// <param name="a">The alpha value (opacity), ranging from 0 (transparent) to
/// 255 (opaque)</param>
public HSBColor(int a, int h, int s, int b)
: this(h, s, b)
{
this.A = (byte)a;
}
/// <summary>
/// Constructor to load an <see cref="HSBColor" /> struct from a system
/// <see cref="Color" /> struct.
/// </summary>
/// <param name="color">An rgb <see cref="Color" /> struct containing the equivalent
/// color you want to generate</param>
public HSBColor(Color color)
{
this = FromRGB(color);
}
/// <summary>
/// Implicit conversion operator to convert directly from an <see cref="HSBColor" /> to
/// a <see cref="Color" /> struct.
/// </summary>
/// <param name="hsbColor">The <see cref="HSBColor" /> struct to be converted</param>
/// <returns>An equivalent <see cref="Color" /> struct that can be used in the GDI+
/// graphics library</returns>
public static implicit operator Color(HSBColor hsbColor)
{
return ToRGB(hsbColor);
}
/// <summary>
/// Convert an <see cref="HSBColor" /> value to an equivalent <see cref="Color" /> value.
/// </summary>
/// <remarks>
/// This method is based on code from http://www.cs.rit.edu/~ncs/color/ by Eugene Vishnevsky.
/// </remarks>
/// <param name="hsbColor">The <see cref="HSBColor" /> struct to be converted</param>
/// <returns>An equivalent <see cref="Color" /> struct, compatible with the GDI+ library</returns>
public static Color ToRGB(HSBColor hsbColor)
{
Color rgbColor = Color.Black;
// Determine which sector of the color wheel contains this hue
// hsbColor.H ranges from 0 to 255, and there are 6 sectors, so 42.5 per sector
int sector = (int)Math.Floor((double)hsbColor.H / 42.5);
// Calculate where the hue lies within the sector for interpolation purpose
double fraction = (double)hsbColor.H / 42.5 - (double)sector;
double sFrac = (double)hsbColor.S / 255.0;
byte p = (byte)(((double)hsbColor.B * (1.0 - sFrac)) + 0.5);
byte q = (byte)(((double)hsbColor.B * (1.0 - sFrac * fraction)) + 0.5);
byte t = (byte)(((double)hsbColor.B * (1.0 - sFrac * (1.0 - fraction))) + 0.5);
switch (sector)
{
case 0: // red - yellow
rgbColor = Color.FromArgb(hsbColor.A, hsbColor.B, t, p);
break;
case 1: // yellow - green
rgbColor = Color.FromArgb(hsbColor.A, q, hsbColor.B, p);
break;
case 2: // green - cyan
rgbColor = Color.FromArgb(hsbColor.A, p, hsbColor.B, t);
break;
case 3: // cyan - blue
rgbColor = Color.FromArgb(hsbColor.A, p, q, hsbColor.B);
break;
case 4: // blue - magenta
rgbColor = Color.FromArgb(hsbColor.A, t, p, hsbColor.B);
break;
case 5:
default: // magenta - red
rgbColor = Color.FromArgb(hsbColor.A, hsbColor.B, p, q);
break;
}
return rgbColor;
}
/// <summary>
/// Convert this <see cref="HSBColor" /> value to an equivalent <see cref="Color" /> value.
/// </summary>
/// <remarks>
/// This method is based on code from http://www.cs.rit.edu/~ncs/color/ by Eugene Vishnevsky.
/// </remarks>
/// <returns>An equivalent <see cref="Color" /> struct, compatible with the GDI+ library</returns>
public Color ToRGB()
{
return ToRGB(this);
}
/// <summary>
/// Convert a <see cref="Color" /> value to an equivalent <see cref="HSBColor" /> value.
/// </summary>
/// <remarks>
/// This method is based on code from http://www.cs.rit.edu/~ncs/color/ by Eugene Vishnevsky.
/// </remarks>
/// <returns>An equivalent <see cref="HSBColor" /> struct</returns>
public HSBColor FromRGB()
{
return FromRGB(this);
}
/// <summary>
/// Convert a <see cref="Color" /> value to an equivalent <see cref="HSBColor" /> value.
/// </summary>
/// <remarks>
/// This method is based on code from http://www.cs.rit.edu/~ncs/color/ by Eugene Vishnevsky.
/// </remarks>
/// <param name="rgbColor">The <see cref="Color" /> struct to be converted</param>
/// <returns>An equivalent <see cref="HSBColor" /> struct</returns>
public static HSBColor FromRGB(Color rgbColor)
{
double r = (double)rgbColor.R / 255.0;
double g = (double)rgbColor.G / 255.0;
double b = (double)rgbColor.B / 255.0;
double min = Math.Min(Math.Min(r, g), b);
double max = Math.Max(Math.Max(r, g), b);
HSBColor hsbColor = new HSBColor(rgbColor.A, 0, 0, 0);
hsbColor.B = (byte)(max * 255.0 + 0.5);
double delta = max - min;
if (max != 0.0)
{
hsbColor.S = (byte)(delta / max * 255.0 + 0.5);
}
else
{
hsbColor.S = 0;
hsbColor.H = 0;
return hsbColor;
}
double h;
if (r == max)
h = (g - b) / delta; // between yellow & magenta
else if (g == max)
h = 2 + (b - r) / delta; // between cyan & yellow
else
h = 4 + (r - g) / delta; // between magenta & cyan
hsbColor.H = (byte)(h * 42.5);
if (hsbColor.H < 0)
hsbColor.H += 255;
return hsbColor;
}
}