【问题标题】:Compare RGB colors in a pixel and change its original color to the closest one比较像素中的 RGB 颜色并将其原始颜色更改为最接近的颜色
【发布时间】:2013-04-12 06:44:21
【问题描述】:

我的作业需要帮助。基本上,这就是我想要做的:

  • 将图像加载到PictureBox
  • 计算每个像素中255(最大值)与R值的差值,以及255与G值的差值,以及B值的差值
  • 从上面的计算来看,绝对值最小的表示像素的颜色更接近那个颜色(例如:(255-R值)的绝对值最小,所以像素更接近那个颜色)
  • 将像素颜色更改为更接近的颜色(在上例中,表示将其更改为红色)
  • 在输出图片框中显示结果

结果,我将获得具有这三种原色的图像。

我写的代码是这样的:

    Bitmap img = new Bitmap(InputPictureBox.Image);
        byte R, G, B;
        Color pixelColor;
        for (int x = 0; x < img.Width; x++)
        {
            for (int y = 0; y < img.Height; y++)
            {
                pixelColor = img.GetPixel(x, y);
                R = (byte) Math.Abs(pixelColor.R - 255);
                G = (byte) Math.Abs(pixelColor.G - 255);
                B = (byte) Math.Abs(pixelColor.B - 255);

                if (R < G && R < B)
                {
                    pixelColor = Color.Red;
                }
                else if (G < R && G < B)
                {
                    pixelColor = Color.Green;
                }
                else if (B < R && B < G)
                {
                    pixelColor = Color.Blue;
                }
            }
        }
  OutputPictureBox.Image = img;

问题是彩色图像随后会反转。那么,我的代码有什么问题?我认为if 语句不起作用,但我不知道为什么。我错了吗?

还有一个与我上面的代码相关的问题,它是否可以通过简单地计算 R/G/B 值的差距来实现,或者它绝对必须通过使用欧几里得距离来完成?

如果您不介意,请告诉我如何解决这个问题,或者应该如何编写代码。我曾经读过一个非常相似的问题,但给出的答案仍然没有给我一个线索。

【问题讨论】:

  • 使用托管 API 访问位图数据通常太慢了。考虑使用不安全的函数指针直接读取和操作位图数据。这是一篇我喜欢的好文章:bobpowell.net/lockingbits.htm
  • 我建议将 'Math.Abs​​(pixelColor.R - 255)' 替换为 '255 - pixelColor.R',因为您知道这始终是积极的。
  • @ByteBlast 啊,是的,谢谢你的评论。我已经阅读了一些关于不安全模式的参考资料,然后是 lockbits,但现在我想解决如何修复上面的代码
  • @JoeF 我曾尝试过“Math.Abs​​(pixelColor.R - 255)”和“255 - pixelColor.R”,但它们仍然会使颜色反转。怎么了? :(
  • 但是你没有在任何地方输入新的颜色......你没有用“pixelColor”做任何事情。我在任何地方都看不到“SetPixel”。

标签: c# colors pixel rgb


【解决方案1】:

您的代码确实有效,尽管其中有一些过度思考。

试试这个:

代码已移至帖子底部的更新部分

结果:


我已经删除了过度思考的部分。

  • 没有理由(至少从阅读您的问题来看)为什么需要反转颜色分量值;

    1. 只要做R = pixelColor.R就够了;

    2. 通过这一点,您不必将其视为“具有最少数量的 红色”,而是“如果它有大部分红色,它是红色!”

  • 作为LightStriker pointed out:您缺少(在您的代码中没有)将新值设置回图像的代码;

    1. 这是使用img.SetPixel(x, y, pixelColor) 完成的。
  • 我添加了一个else 子句来匹配没有单一颜色分量大于其他两个的像素。

    1. 例如,Yellow (255, 255, 0) 不会与您的规则匹配;

    2. 使用此答案中的版本,它会被Black 像素替换。


更新:comments below 要求进一步澄清。以下是添加更多条件语句的方法:

// NEW (start) --------------------------------------------------
Color[] randomizedColors = new Color[] { Color.Red, Color.Green, Color.Blue };
Random randomizer = new Random();
// NEW (end) --------------------------------------------------

Bitmap img = new Bitmap(InputPictureBox.Image);
byte R, G, B;
Color pixelColor;

// NEW (start) --------------------------------------------------
Func<int, Color> ColorRandomizer = (numberOfColors) =>
{
    if (numberOfColors > randomizedColors.Length)
    {
        numberOfColors = randomizedColors.Length;
    }
    return randomizedColors[randomizer.Next(numberOfColors)];
};
// NEW (end) --------------------------------------------------

for (int x = 0; x < img.Width; x++)
{
    for (int y = 0; y < img.Height; y++)
    {
        pixelColor = img.GetPixel(x, y);
        R = pixelColor.R;
        G = pixelColor.G;
        B = pixelColor.B;

        if (R > G && R > B)
        {
            pixelColor = Color.Red;
        }
        else if (G > R && G > B)
        {
            pixelColor = Color.Green;
        }
        else if (B > R && B > G)
        {
            pixelColor = Color.Blue;
        }
// NEW (start) --------------------------------------------------
        else if (pixelColor == Color.Yellow)
        {
            // 2 = Red or Green
            pixelColor = ColorRandomizer(2);
        }
        else if (pixelColor = Color.FromArgb(152, 152, 152))
        {
            // 3 = Red, Green, or Blue
            pixelColor = ColorRandomizer(3);
        }
        /* else if (pixelColor = Some_Other_Color)
        {
            // 3 = Red, Green, or Blue
            pixelColor = ColorRandomizer(3);
        } */
// NEW (end) --------------------------------------------------
        else
        {
            pixelColor = Color.Black;
        }
        img.SetPixel(x, y, pixelColor);
    }
}

OutputPictureBox.Image = img;

使用此更新后的代码,将应随机选取的所有颜色添加到 randomizedColors 数组中。使用 lambda 函数ColorRandomizer 来辅助随机选择颜色;请记住,此函数将在第一个元素和指定的元素之间随机选择。

【讨论】:

  • 对于迟到的附加问题抱歉:如果我不想使用黑色(例如,我有黄色 (255, 255, 0),我希望程序在红色和绿色),我可以使用与生成随机数时类似的方法吗?有没有办法在两种方法(例如:pixelColor = Color.Red 和 pixelColor = Color.Green 之间)甚至三种方法之间进行选择?
  • @feanifarida 绝对!这完全取决于他们的优先级。如果您希望它们优先,则在现有条件(if 语句)之前添加它们。另一方面,如果您希望它们在 之后被考虑,那么只需将它们添加到底部即可。
  • 我已经阅读了一些与随机方法相关的参考资料。其中一个给出了一个类似于这种形式的例子: state = Random.value
  • @feanifarida 如果我理解正确的话……当你遇到Yellow 时,你想随机选择RedGreen - 这就是你想要吗?
  • 是的,这就是我想要的。正如您在代码中所解释的那样,对于某些条件,例如 (255, 255, 0) 或 (152, 152, 152),如果我使用之前的规则,我当然无法定义它是红色/绿色/蓝色,这就是你建议使用黑色的原因。但是如果是 (255, 255, 0) 我希望程序在红色和绿色之间随机选择,而对于这个 (152, 152, 152) 它随机选择红色/绿色/蓝色怎么办?
【解决方案2】:

以下是反转所有颜色。

R = (byte) Math.Abs(pixelColor.R - 255);
G = (byte) Math.Abs(pixelColor.G - 255);
B = (byte) Math.Abs(pixelColor.B - 255);

你可以使用:

R = (byte) pixelColor.R;
G = (byte) pixelColor.G;
B = (byte) pixelColor.B;

【讨论】:

  • 如果您阅读 if 语句,您会发现这是错误的。
猜你喜欢
  • 2019-07-02
  • 1970-01-01
  • 2015-07-21
  • 1970-01-01
  • 2013-06-25
  • 1970-01-01
  • 2017-10-28
  • 2018-01-20
  • 1970-01-01
相关资源
最近更新 更多