3

我有一个图像,我可以使用 Martix 读取它的所有像素颜色...如何更改任何像素的 RGB 如果我想将其转换为最接近的颜色(黑色、红色或白色)

我在矩阵中读取图像的代码是:

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);
    }
}  
4

2 回答 2

5

正如您在评论中指出的那样,问题是关于颜色距离,这不是一件小事。它还与您使用的色彩空间有关,因此在这里我将向您展示 RGB、HSV、HLS 和 CIELAB 的示例。此外,要计算距离,您需要一个公式。为简单起见,让我们坚持欧几里德距离,如在此处输入图像描述

然后为了简单地回答您的问题,您计算从当前颜色q到您拥有的三个目标pi(黑色、红色和白色)的距离。最小距离表示您替换的颜色。在领带的情况下,我保留给出最小距离的最早颜色。

现在,色彩空间在这项任务中也非常重要,因为它确定了欧几里德距离的含义。这是一个示例图像:

在此处输入图像描述

转换为 RGB:

在此处输入图像描述

在 HLS 中转换(即 RGB 颜色转换为 HLS 并计算距离):

在此处输入图像描述

单纯疱疹病毒:

在此处输入图像描述

CIELAB:

在此处输入图像描述

于 2013-01-09T14:55:54.563 回答
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它提供给您的Colors和GetNearestOfBWR. (FromArgb并且ToArgb这样做,我相信。)

于 2013-01-09T14:46:02.343 回答