Reputation: 1627
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
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 int
s it gives you and the Color
s required by GetNearestOfBWR
. (FromArgb
and ToArgb
do this, I believe.)
Upvotes: 1
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
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:
Converted in RGB:
Converted in HLS (i.e., the RGB color is converted to HLS and the distance is calculated):
HSV:
CIELAB:
Upvotes: 5