我有一个图像,我可以使用Martix读取所有像素的颜色...如何更改任何像素的RGB如果我想将其转换为最接近的颜色(黑色,红色或白色)
我在Matrix中读取图像的代码是:
string sourceimg = @"D:\ProductionTools\Taskes\Image Processing\Test\001.jpg";
//...
Bitmap imageoriginal = new Bitmap(sourceimg);
int height = imageoriginal.Height;
int width = imageoriginal.Width;
Color[][] colormatrix = new Color[width][];
for (int i = 0; i < width; i++) {
colormatrix[i] = new Color[height];
for (int j = 0; j < height; j++) {
colormatrix[i][j] = new Color();
colormatrix[i][j] = imageoriginal.GetPixel(i, j);
}
}
答案 0 :(得分:5)
正如你的评论所指出的,问题是关于色距,这不是一件小事。它还涉及您使用的颜色空间,因此我将在此向您展示RGB,HSV,HLS和CIELAB中的示例。另外,要计算距离,您需要一个公式。为简单起见,让我们粘贴到欧氏距离,如
然后,为了简单地回答您的问题,您可以计算从当前颜色q
到您拥有的三个目标pi
(黑色,红色和白色)的距离。最小距离表示您替换的颜色。如果是平局,我保持最早的颜色给出最小距离。
现在,颜色空间在此任务中也非常重要,因为它确定了欧氏距离的含义。这是一个示例图像:
以RGB格式转换:
在HLS中转换(即RGB颜色转换为HLS并计算距离):
HSV:
CIELAB:
答案 1 :(得分:1)
正如已经指出的,这个问题最难的部分是知道给定的颜色是否“更接近”黑色,白色或红色。我把一些可能适合你的东西扔到了一起:
Color GetNearestOfBWR(Color c)
{
float redness = Math.Abs(180 - c.GetHue()) / 180;
float brightness = c.GetBrightness();
float saturation = c.GetSaturation();
你现在有三个值,每个值介于0和1之间,其中从0增加到1表示你越来越接近红色(粗略地说:更多红色/更少绿色和蓝色,更多颜色/更少黑色,更多颜色/更少灰色)。
你现在必须决定一个颜色在什么时候构成“红色”,老实说这是一个判断。你可以简单地拥有
double brightColourfulRedness = Math.Sqrt(
redness*redness + brightness*brightness + saturation*saturation);
if (brightColourfulRedness > 1)
return Color.FromArgb(255, 0, 0); // red;
(简单的欧几里德范数)但您可能希望比另一个更强烈地加权特定属性 - 或者只是修改1
阈值。
然后你必须决定什么映射到黑色或白色;这可能就像
一样简单 if (brightness > 0.5)
return Color.FromArgb(255, 255, 255); // white
return Color.FromArgb(0, 0, 0); // black
}
大!因此,现在您可以根据品味将颜色映射为红色,白色或黑色。剩下的就是将它应用于位图中的每个像素。如果您很乐意覆盖从文件中加载的Bitmap
,则不需要该数组;你可以这样做:
int height = imageoriginal.Height;
int width = imageoriginal.Width;
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
Color origC = imageoriginal.GetPixel(i, j);
Color newC = GetNearestOfBWR(origC);
imageoriginal.SetPixel(i, j, newC);
}
}
这可能非常慢,因此您也可以使用DmitryG的LockBits
代码,但您需要在它提供的int
和您需要的Color
之间进行转换。 GetNearestOfBWR
。 (FromArgb
和ToArgb
这样做,我相信。)