How can I replace a color for some parts of an image without affecting its texture?
You can see good example of the result in this screenshot
Source: https://www.leadtools.com/sdk/image-processing/functions/function.asp?id=158
How can I replace a color for some parts of an image without affecting its texture?
You can see good example of the result in this screenshot
Source: https://www.leadtools.com/sdk/image-processing/functions/function.asp?id=158
Upon doing research i found no efficient/smoothe way of doing this, so i dont it myself, the code could be cleaned up ALOT but it gets the job done, its not efficient but it is smoother and allows you to set a tolerance.
public static Image ColorReplace(this Image inputImage, int tolerance, Color oldColor, Color NewColor)
{
Bitmap outputImage = new Bitmap(inputImage.Width, inputImage.Height);
Graphics G = Graphics.FromImage(outputImage);
G.DrawImage(inputImage, 0, 0);
for (Int32 y = 0; y < outputImage.Height; y++)
for (Int32 x = 0; x < outputImage.Width; x++)
{
Color PixelColor = outputImage.GetPixel(x, y);
if (PixelColor.R > oldColor.R - tolerance && PixelColor.R < oldColor.R + tolerance && PixelColor.G > oldColor.G - tolerance && PixelColor.G < oldColor.G + tolerance && PixelColor.B > oldColor.B - tolerance && PixelColor.B < oldColor.B + tolerance)
{
int RColorDiff = oldColor.R - PixelColor.R;
int GColorDiff = oldColor.G - PixelColor.G;
int BColorDiff = oldColor.B - PixelColor.B;
if (PixelColor.R > oldColor.R) RColorDiff = NewColor.R + RColorDiff;
else RColorDiff = NewColor.R - RColorDiff;
if (RColorDiff > 255) RColorDiff = 255;
if (RColorDiff < 0) RColorDiff = 0;
if (PixelColor.G > oldColor.G) GColorDiff = NewColor.G + GColorDiff;
else GColorDiff = NewColor.G - GColorDiff;
if (GColorDiff > 255) GColorDiff = 255;
if (GColorDiff < 0) GColorDiff = 0;
if (PixelColor.B > oldColor.B) BColorDiff = NewColor.B + BColorDiff;
else BColorDiff = NewColor.B - BColorDiff;
if (BColorDiff > 255) BColorDiff = 255;
if (BColorDiff < 0) BColorDiff = 0;
outputImage.SetPixel(x, y, Color.FromArgb(RColorDiff, GColorDiff, BColorDiff));
}
}
return outputImage;
}
try this:
Color color = Color.Black; //Your desired colour
byte r = color.R; //For Red colour
Bitmap bmp = new Bitmap(this.BackgroundImage);
for (int x = 0; x < bmp.Width; x++)
{
for (int y = 0; y < bmp.Height; y++)
{
Color gotColor = bmp.GetPixel(x, y);
gotColor = Color.FromArgb(r, gotColor.G, gotColor.B);
bmp.SetPixel(x, y, gotColor);
}
}
Try to read out al the pixels and stuff them in an 3 array's (rgb) there you can set in a alogrithm to replace your colors.
Found the way to do it. This requires RGB<->HSL conversions (I used this class by Rich Newman for HSLColor:
using System; using System.Collections.Generic; using System.Text; using System.Drawing; namespace ColorDemo { public class HSLColor { // Private data members below are on scale 0-1 // They are scaled for use externally based on scale private double hue = 1.0; private double saturation = 1.0; private double luminosity = 1.0; private const double scale = 240.0; public double Hue { get { return hue * scale; } set { hue = CheckRange(value / scale); } } public double Saturation { get { return saturation * scale; } set { saturation = CheckRange(value / scale); } } public double Luminosity { get { return luminosity * scale; } set { luminosity = CheckRange(value / scale); } } private double CheckRange(double value) { if (value < 0.0) value = 0.0; else if (value > 1.0) value = 1.0; return value; } public override string ToString() { return String.Format("H: {0:#0.##} S: {1:#0.##} L: {2:#0.##}", Hue, Saturation, Luminosity); } public string ToRGBString() { Color color = (Color)this; return String.Format("R: {0:#0.##} G: {1:#0.##} B: {2:#0.##}", color.R, color.G, color.B); } #region Casts to/from System.Drawing.Color public static implicit operator Color(HSLColor hslColor) { double r = 0, g = 0, b = 0; if (hslColor.luminosity != 0) { if (hslColor.saturation == 0) r = g = b = hslColor.luminosity; else { double temp2 = GetTemp2(hslColor); double temp1 = 2.0 * hslColor.luminosity - temp2; r = GetColorComponent(temp1, temp2, hslColor.hue + 1.0 / 3.0); g = GetColorComponent(temp1, temp2, hslColor.hue); b = GetColorComponent(temp1, temp2, hslColor.hue - 1.0 / 3.0); } } return Color.FromArgb((int)(255 * r), (int)(255 * g), (int)(255 * b)); } private static double GetColorComponent(double temp1, double temp2, double temp3) { temp3 = MoveIntoRange(temp3); if (temp3 < 1.0 / 6.0) return temp1 + (temp2 - temp1) * 6.0 * temp3; else if (temp3 < 0.5) return temp2; else if (temp3 < 2.0 / 3.0) return temp1 + ((temp2 - temp1) * ((2.0 / 3.0) - temp3) * 6.0); else return temp1; } private static double MoveIntoRange(double temp3) { if (temp3 < 0.0) temp3 += 1.0; else if (temp3 > 1.0) temp3 -= 1.0; return temp3; } private static double GetTemp2(HSLColor hslColor) { double temp2; if (hslColor.luminosity < 0.5) //<=?? temp2 = hslColor.luminosity * (1.0 + hslColor.saturation); else temp2 = hslColor.luminosity + hslColor.saturation - (hslColor.luminosity * hslColor.saturation); return temp2; } public static implicit operator HSLColor(Color color) { HSLColor hslColor = new HSLColor(); hslColor.hue = color.GetHue() / 360.0; // we store hue as 0-1 as opposed to 0-360 hslColor.luminosity = color.GetBrightness(); hslColor.saturation = color.GetSaturation(); return hslColor; } #endregion public void SetRGB(int red, int green, int blue) { HSLColor hslColor = (HSLColor)Color.FromArgb(red, green, blue); this.hue = hslColor.hue; this.saturation = hslColor.saturation; this.luminosity = hslColor.luminosity; } public HSLColor() { } public HSLColor(Color color) { SetRGB(color.R, color.G, color.B); } public HSLColor(int red, int green, int blue) { SetRGB(red, green, blue); } public HSLColor(double hue, double saturation, double luminosity) { this.Hue = hue; this.Saturation = saturation; this.Luminosity = luminosity; } } }
(pixelHsl / refHsl) * targetHsl
Taken largely from this answer to How to Change Pixel Color of an Image in C#.NET by DareDevil:
public Bitmap ChangeColor(Bitmap scrBitmap,Color newColor)
{
Color actualColor;
Bitmap newBitmap = new Bitmap(scrBitmap.Width, scrBitmap.Height);
for (int i = 0; i < scrBitmap.Width; i++)
{
for (int j = 0; j < scrBitmap.Height; j++)
{
actualColor = scrBitmap.GetPixel(i, j);
if (actualColor.A > 150)
newBitmap.SetPixel(i, j, newColor);
else
newBitmap.SetPixel(i, j, actualColor);
}
}
return newBitmap;
}