Calculating brightness of an image in grey scale (32bbparb) - c#

everyone. I was trying to calculate the brightness of a laser spot image, the image was originally in green colour as the laser is monochromatic in green colour. but the photo was then converted to grey scale image, using grey scale filter, I tried to define two for- loop to get the pixel value of the picture, but it seems I got something really unexpected, I have not much clue what's going on. I think I need someone to shed a light for me.
Situation: I have a black and white image, the algorithm below didn't give the brightest point i.e. the white spot, instead it points at some random position ( which is not black nor white).
EDIT:I use for loop to loop over the picture to find the pixel values.
for (int i = xstart; i < xend; i++)
{
for (int j = ystart; j < yend; j++)
{
Color pixelColor = myBitmap.GetPixel(i, j);
brightness = pixelColor.GetBrightness();
//brightness = 0.2126 * pixelColor.R + 0.7152 * pixelColor.G + 0.0722 * pixelColor.B;
//brightness = 0.333 * pixelColor.R + 0.333 * pixelColor.G + (1 - 0.333 * 2) * pixelColor.B;
brightness_array[k, 0] = i;
brightness_array[k, 1] = j;
brightness_array[k, 2] = brightness;
k++;
}
}
to find brightness all these algorithms gave a wrong position for the brightest point, i wonder it's because i had an extra alpha channel for transparency which affects the result.
double max_brightness = 0.0;
int positionX = 0;
int positionY = 0;
for (int m = 0; m < k; m++)
{
if (brightness_array[m, 2] > max_brightness)
{
positionX = Convert.ToInt32(brightness_array[m, 0]);
positionY = Convert.ToInt32(brightness_array[m, 1]);
max_brightness = brightness_array[m, 2];
}
}
The above code is how I found the maximum brightness, I scan the pixel one by one, and set the new max_brightness pixel as max_brightness , so that after you loop over the whole picture, you should get the max_brightness.

The code to work out the brightest point on the image is working fine. The problem is that the picture is displayed in a picture box which scales the image down and your mousemove code to determine where position of the cursor within the picturebox doesn't match the point on the raw image.

Related

How to recognize "green" in a particular image?

Trying to find a solution for how to recognize if there is a "green" color on particular screenshot (image below).
The problem is that when using a plain RGB Bitmap, it doesn't work as I would like to because the image is taken from a screenshot of a webpage and it's kind of blurry, so many pixels doesn't look like "green".
I need somehow to understand how to define whether there is "green" color on a particular screenshot
I need somehow to know whether there is green color
Iterate all pixels and search for the desired color
Color c = Color.Green; //or the color you want to search
Bitmap bmp = new Bitmap(Image.FromFile(#"c:\file.bmp"));
bool containsgreen = false;
for (int w = 0; w < bmp.Width; w++)
for (int h = 0; h < bmp.Height; h++)
if (bmp.GetPixel(w, h) == c)
containsgreen = true;
If you're looking for a color range or similar colors, you could also calculate the color distance to add tolerance
public static double GetColourDistance(Color e1, Color e2)
{
return Math.Sqrt((e1.R - e2.R) * (e1.R - e2.R) + (e1.G - e2.G) * (e1.G - e2.G) + (e1.B - e2.B) * (e1.B - e2.B));
}
I am going to assume from your question, that when you say green, you don't mean that any pixel will have some positive value for the G component of the RGB color, but that you mean it looks visually green to a human.
If that is the case, I suggest a modification to #fubo's code that calculates "visually green". That would be when the G component is greater than the other components.
Now, this will return true for some sketchy greens, e.g. a green that is very, very dark or very, very light. If you want to filter those out, use a tolerance value of your choosing.
Here's the code:
bool HasGreen(int tolerance)
{
using (var bmp = new Bitmap(Image.FromFile(#"c:\file.bmp")))
{
for (int w = 0; w < bmp.Width; w++)
for (int h = 0; w < bmp.Height; h++)
if (IsGreenPixel(bmp.GetPixel(w, h), tolerance))
return true;
}
return false;
}
bool IsGreenPixel(Color color, int tolerance)
=> color.G > color.R + tolerance && color.G > color.B + tolerance;
If you're looking for "what is the main green color in the green colors", you could modify this algorithm further by doing counts of colors and dropping them into buckets (i.e. a histogram).

Issue with Kinect V2 Coordinate Mapper

I'm currently undertaking a university project that involves object detection and recognition with a Kinect. Now I'm using the MapDethFrameToColorSpace method for coordinating the depth to rgb. I believe the issue is to with this loop here
for (int i = 0; i < _depthData.Length; ++i)
{
ColorSpacePoint newpoint = cPoints[i];
if (!float.IsNegativeInfinity(newpoint.X) && !float.IsNegativeInfinity(newpoint.Y))
int colorX = (int)Math.Floor(newpoint.X + 0.5);
int colorY = (int)Math.Floor(newpoint.Y + 0.5);
if ((colorX >= 0) && (colorX < colorFrameDescription.Width) && (colorY >= 0) && (colorY < colorFrameDescription.Height))
{
int j = ((colorFrameDescription.Width * colorY) + colorX) * bytesPerPixel;
int newdepthpixel = i * 4;
displaypixel[newdepthpixel] = colorpixels[(j)]; //B
displaypixel[newdepthpixel + 1] = colorpixels[(j + 1)]; //G
displaypixel[newdepthpixel + 2] = colorpixels[(j + 1)]; //R
displaypixel[newdepthpixel + 3] = 255; //A*/
}
It appears that the indexing is not correct or there are pixels/depth values missing because the output appears to be multiples of the same image but small and with a limited x index.
http://postimg.org/image/tecnvp1nx/
Let me guess: Your output image (displaypixel) is 1920x1080 pixels big? (Though from the link you posted, it seems to be 1829×948?)
That's your problem. MapDethFrameToColorSpace returns the corresponding position in the color image for each depth pixels. That means, you get 512x424 values. Putting those into a 1920x1080 image means only about 10% of the image is filled, and the part that's filled will be jumbled.
If you make your output image 512x424 pixels big instead, it should give you an image like the second on in this article.
Or you could keep your output image at 1920x1080, but instead of putting one pixel after the other, you'd also calculate the position where to put the pixel. So instead doing
int newdepthpixel = i * 4;
you'd need to do
int newdepthpixel = ((colorFrameDescription.Width * colorY) + colorX) * 4;
That would give you a 1920x1080 image, but with only 512x424 pixels filled, with lots of space in between.

Color resemblance for motion detection

Given 2 consecutive frames, how can I search for pixels that changed?
I tried the following:
if (old != null)
{
for (int i = 0; i < b.Width; i++)
{
for (int j = 0; j < b.Height; j++)
{
if (!b.GetPixel(i, j).Equals(old.GetPixel(i, j)))
s.SetPixel(i, j, b.GetPixel(i, j));
else
s.SetPixel(i, j, Color.White);
}
}
}
Where "old" is the previous frame and "s" is the new frame. The code basically paints the pixels that didn't change in white.
But since the webcam produces a very low quality frame almost all of the pixels change.
How can I eliminate the pixels that didn't change "greatly"?
A very basic approach is to convert your Color pixel to an 0 - 255 based grey value.
So you can compare your pixels as an integer and make some delta error difference.
Consider this method which convert a color to a integer grayscale value
private static int GreyScaleRange(Color originalColor)
{
return (int)((originalColor.R * .3) + (originalColor.G * .59)
+ (originalColor.B * .11));
}
So instead of doing equal function, you should do
int deltadifference = 5 ;
if (Math.abs((GreyScaleRange(b.GetPixel(i, j)) - (GreyScaleRange(old.GetPixel(i, j)) > deltadifference)
s.SetPixel(i, j, b.GetPixel(i, j));
else
s.SetPixel(i, j, Color.White);

Count black pixels using red value

I'm using the following code on an image who has only black/white values so that if a color is black it should be counted but somehow the following if statement doesn't work. Is it written correctly or Im just using a good logic here
for (int y = 0; y < image.Height; y++)
{
Color pixel = image.GetPixel(x, y);
if(pixel.R > 0)
{
//some code here
}
}
Assuming no transparency, try
if(pixel == Color.Black)
....
(pixel.R>0 just checks color's Red component. It is 0 for Black.)
For barcodes, it might be better to use some thresholds to differentiate colors, e.g.:
int threshold = (255 + 255 + 255) / 2;
if (pixel.R + pixel.G + pixel.B < threshold)
....

How to select by color range?

In my application I have loaded a picture and I want to be able to detect similar colors. So if I select a color I want the application to be able to find all pixels with that same (or almost the same) color. This is what I wrote for a detection system that looks in a vertical direction between the point of the mouse click and the end of the bitmap.
for (int y = mouseY; y < m_bitmap.Height; y++)
{
Color pixel = m_bitmap.GetPixel(mouseX, y);
//check if there is another color
if ((pixel.R > curcolor.R + treshold || pixel.R < curcolor.R - treshold) ||
(pixel.G > curcolor.G + treshold || pixel.G < curcolor.G - treshold) ||
(pixel.B > curcolor.B + treshold || pixel.B < curcolor.B - treshold))
{ //YESSSSS!
if ((y - ytop > minheight)&&(curcolor != Color.White)) //no white, at least 15px height
{
colorlayers.Add(new ColorLayer(curcolor, y - 1, ytop));
}
curcolor = pixel;
ytop = y;
}
}
Would this be the best way? Somehow it looks like it doesn't work too good with yellowish colors.
RGB is a 3D space.
A color far away threshold in all directions is not so similar to original one (and what is similar according to numbers may not be so similar to human beings eyes).
I would make a check using HSL (for example) where hue value as a finite 1D range, just for example:
for (int y = mouseY; y < m_bitmap.Height; y++)
{
Color pixel = m_bitmap.GetPixel(mouseX, y);
if (Math.Abs(color.GetHue() - curcolor.GetHue()) <= threshold)
{
// ...
}
}
Moreover please note that using bitmaps in this way (GetPixel() is terribly slow, take a look to this post to see a - much - faster alternative).
It might be interesting to look at how the magic wand tool in Paint.NET works.
This is how they compare 2 colors:
private static bool CheckColor(ColorBgra a, ColorBgra b, int tolerance)
{
int sum = 0;
int diff;
diff = a.R - b.R;
sum += (1 + diff * diff) * a.A / 256;
diff = a.G - b.G;
sum += (1 + diff * diff) * a.A / 256;
diff = a.B - b.B;
sum += (1 + diff * diff) * a.A / 256;
diff = a.A - b.A;
sum += diff * diff;
return (sum <= tolerance * tolerance * 4);
}
Source
The reason why yellow colors give a problem might be that RGB is not a perceptually uniform colorspace. This means that, given a distance between two points/colors in the colorspace, the perception of this color distance/difference will in general not be the same.
That said, you might want to use another color space, like HSL as suggested by Adriano, or perhaps Lab.
If you want to stick to RGB, I would suggest to calculate the euclidian distance, like this (I think it's simpler):
float distance = Math.sqrt((pixel.R-curcolor.R)^2 + (pixel.G-curcolor.G)^2 + (pixel.B-curcolor.B)^2);
if(distance < threshold)
{
// Do what you have to.
}

Categories

Resources