views:

423

answers:

5

Hi

How to identify black/dark image in C#. Is there any API to check the image visibility or darkness ratio? In my application, while copying images, I want to check each image and want to discard black images.

Any Idea how to achieve this?

+5  A: 

An idea to get the image darkness/brightness can be:

Bitmap bitmap = // the bitmap
var colors = new List<Color>();
for (int x = 0; x < bitmap.Size.Width; x++)
{
    for (int y = 0; y < bitmap.Size.Height; y++)
    {
        colors.Add(bitmap.GetPixel(x, y));
    }
}

float imageBrightness = colors.Average(color => color.GetBrightness());

Maybe consider dark images as ones with brightness less than 0.1 (or any other value relevant)

Elisha
Bitmap.GetPixel is super slow. DreamWalker's solution of using BitMap.LockBits and unsafe code will outperform this by a long way...
ParmesanCodice
As ParmesanCodice mentioned, I am now filtering slightly bigger images (640x480) and dark image filter makes it so slow.
ZHS
A: 

I'd start by iterating over all pixels in your image, computing the HSV color of each pixel, and then averaging the 'V' component (which represents the 'brightness' of the color).

Frerich Raabe
+4  A: 
// For fast access to pixels        
public static unsafe byte[] BitmapToByteArray(Bitmap bitmap) { 
    BitmapData bmd = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly,
                                     PixelFormat.Format32bppArgb);
    byte[] bytes = new byte[bmd.Height * bmd.Stride];
    byte* pnt = (byte*) bmd.Scan0;
    Marshal.Copy((IntPtr) pnt, bytes, 0, bmd.Height * bmd.Stride);
    bitmap.UnlockBits(bmd);
    return bytes;
}

public bool IsDark(Bitmap bitmap, byte tolerance, double darkProcent) {
    byte[] bytes = BitmapToByteArray(bitmap);
    int count = 0, all = bitmap.Width * bitmap.Height;
    for (int i = 0; i < bytes.Length; i += 4) {
        byte r = bytes[i + 2], g = bytes[i + 1], b = bytes[i];
        byte brightness = (byte) Math.Round((0.299 * r + 0.5876 * g + 0.114 * b));
        if (brightness <= tolerance)
            count++;
    }
    return (1d * count / all) <= darkProcent;
}

public void Run(Bitmap bitmap) { // Example of use
    // some code
    bool dark = IsDark(bitmap, 40, 0.9); 
    // some code
}
DreamWalker
+1, it may help some users to provide some explaining for the math on the brightness line.
sixlettervariables
+1  A: 

You can use the AForge.NJET framework which includes Image Processing support. For example, see the ImageStatisticsHSL Class. Choose a proper Saturation value, or use the Luminance histogram.

The class is used to accumulate statistical values about images, like histogram, mean, standard deviation, etc. for each HSL color channel.

The class accepts 24 and 32 bpp color images for processing.

Sample usage C#:

// gather statistics
ImageStatisticsHSL stat = new ImageStatisticsHSL( image );
// get saturation channel's histogram
ContinuousHistogram saturation = stat.Saturation;
// check mean value of saturation channel
if ( saturation.Mean > 0.5 )
{
    // do further processing
}
gimel
A: 

Thanks Elisha for the idea, I am doing it in this way:

Bitmap bitmap = new Bitmap("123712.jpg");
float brightness = 0;
for (int x = 0; x < bitmap.Size.Width; x++)
{
     for (int y = 0; y < bitmap.Size.Height; y++)
     {
          brightness += bitmap.GetPixel(x, y).GetBrightness();
     }
}

float average = brightness / (bitmap.Size.Width * bitmap.Size.Height);
ZHS
euhm, That last line is wrong? should be bitmap.Size.Width * bitmap.Size.Height
Stormenet
yeah, I was wrong! I didn't realize this. Thats why I was thinking that why the average is too big. Thank you for correction :)
ZHS