简体   繁体   中英

Compare RGB colors in a pixel and change its original color to the closest one

I need help for my assignment. Basically, this is what I want to do:

  • Load an image to a PictureBox
  • Calculate the difference between 255 (the maximum value) and the R value in each pixel, and the difference between 255 and G value, and also for B value
  • From the calculation above, the least absolute value will indicate that the pixel's color is closer to that color (ex: (255-R value) has the smallest absolute value, so the pixel is closer to that color)
  • Change the pixel color to the closer color (in example above, it means change it to Red)
  • Display the result in the output picturebox

As the result, I will obtain the image with those three primary colors.

I have written the code like this:

    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;

The problem is that the color image then turn to be inverted. So, what is wrong in my code? I assume that the if statements don't work, but I don't know why. Am I wrong?

One more question related to my code above, can it actually work by simply calculating the gap of R/G/B value like that OR it absolutely has to be done by using euclidean distance?

If you don't mind please show me how to fix this or maybe how the code should be written. I ever read a quite similar question, but the given answer still didn't give me a clue.

Your code actually works, although there is a bit of overthinking put into it.

Try this:

The code has been moved to the Update section at the bottom of the post

Result:

结果


I've removed the overthinking part.

  • There's no reason (at least from reading your question) why you need to invert the color component values;

    1. Simply doing R = pixelColor.R is enough;

    2. And through this you don't have to think of it as "which has the least amount of red", but rather, " if it has the most amount of red, it's red !"

  • As LightStriker pointed out : You are missing (it is nowhere in your code) the code to set new value back into the image;

    1. This is accomplished using img.SetPixel(x, y, pixelColor) .
  • I've added an else clause to match pixels where no single color component is greater than both others.

    1. For example, Yellow (255, 255, 0) would not be matched by your rules;

    2. Using the version in this answer, it gets replaced by a Black pixel.


Update: per the comments below asking for additional clarification. Here's how you would add more conditional statements:

// 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;

With this updated code, add all colors that should be picked randomly to the randomizedColors array. Use the lambda function, ColorRandomizer , to assist in choosing a color randomly; keep in mind that this function will randomly pick between the first element and the one specified.

Following is inverting all the colors.

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

You can use:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM