如何在不影响图像纹理的情况下替换图像某些部分的颜色?
您可以在此截图中看到结果的良好示例。
来源: https://www.leadtools.com/sdk/image-processing/functions/function.asp?id=158
如何在不影响图像纹理的情况下替换图像某些部分的颜色?
您可以在此截图中看到结果的良好示例。
来源: https://www.leadtools.com/sdk/image-processing/functions/function.asp?id=158
使用重新映射表是一种高效地替换颜色的方法。在下面的示例中,图像被绘制在图片框内。在绘画事件中,将颜色Color.Black更改为Color.Blue:
private void pictureBox_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
using (Bitmap bmp = new Bitmap("myImage.png"))
{
// Set the image attribute's color mappings
ColorMap[] colorMap = new ColorMap[1];
colorMap[0] = new ColorMap();
colorMap[0].OldColor = Color.Black;
colorMap[0].NewColor = Color.Blue;
ImageAttributes attr = new ImageAttributes();
attr.SetRemapTable(colorMap);
// Draw using the color map
Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);
g.DrawImage(bmp, rect, 0, 0, rect.Width, rect.Height, GraphicsUnit.Pixel, attr);
}
}
更多信息:http://msdn.microsoft.com/en-us/library/4b4dc1kz%28v=vs.110%29.aspx
在进行研究后,我发现没有一种高效/顺畅的方法来做到这一点,所以我自己动手实现了它。代码可以大量优化,但它能够完成任务,虽然不够高效,但更加顺畅,并允许您设置容差。
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;
}
尝试这个:
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);
}
}
GetPixel
非常慢,请参见:https://dev59.com/H1LTa4cB1Zd3GeqPWw1- - Andrew Bullock
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
替换它主要参考了C#.NET中如何更改像素颜色的答案,作者为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;
}