Mohamed Kamal
Mohamed Kamal

Reputation: 1627

How To Replace Pixel color with other color in Image?

I have an Image and I can Read all it's Pixels colors using Martix ... How can I change The RGB for any Pixel If I want to convert it to the nearest color from (Black , Red or white)

My Code to Read the Image in Matrix is :

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

Upvotes: 3

Views: 2649

Answers (2)

Rawling
Rawling

Reputation: 50104

As has been pointed out, the hardest part of this problem is knowing whether a given color is "closer" to black, white or red. I've thrown something together that might work for you:

Color GetNearestOfBWR(Color c)
{
     float redness = Math.Abs(180 - c.GetHue()) / 180;
     float brightness = c.GetBrightness();
     float saturation = c.GetSaturation();

You now have three values, each between 0 and 1, where increasing from 0 to 1 means you are getting closer to red (roughly speaking: more red/less green&blue, more color/less black, more color/less grey).

You now have to decide at what point a color constitutes "red" and honestly that's a judgment call. You could simply have

     double brightColourfulRedness = Math.Sqrt(
         redness*redness + brightness*brightness + saturation*saturation);
     if (brightColourfulRedness > 1)
         return Color.FromArgb(255, 0, 0); // red;

(simple Euclidean norm) but you might want to weight a particular property more strongly than another - or simply modify the 1 threshold.

Then you have to decide what maps to black or to white; this could be as simple as

    if (brightness > 0.5)
        return Color.FromArgb(255, 255, 255); // white
    return Color.FromArgb(0, 0, 0); // black
}

Great! So now you have a function to map a color to red, white or black, according to taste. All that remains is to apply it to each pixel in your bitmap. If you're happy overwriting the Bitmap you loaded from your file, you don't need the array; you can just do:

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

This can be quite slow, so you could alternatively use DmitryG's LockBits code, but you'd need to convert between the ints it gives you and the Colors required by GetNearestOfBWR. (FromArgb and ToArgb do this, I believe.)

Upvotes: 1

mmgp
mmgp

Reputation: 19221

As pointed out in your comments, the question is about color distance, which is not a trivial matter. It also relates to which colorspace you use, so here I will show you examples in RGB, HSV, HLS, and CIELAB. Also, to calculate distance you need a formula. For simplicity, let's sticky to the euclidean distance, as in enter image description here

Then to trivially answer your question, you calculate the distance from the current color q to the three targets pi you have (black, red, and white). The smallest distance indicates the color you replace with. In case of tie, I keep the earliest color that gave the minimum distance.

Now, the colorspace is also very important in this task since it establishes the meaning for the euclidean distance. Here is a sample image:

enter image description here

Converted in RGB:

enter image description here

Converted in HLS (i.e., the RGB color is converted to HLS and the distance is calculated):

enter image description here

HSV:

enter image description here

CIELAB:

enter image description here

Upvotes: 5

Related Questions