2

I'm working in php, and going through each image pixel-by-pixel to get an average brightness for each image is going to be way to cpu intensive...

I've looked through both GD and imagemagick docs, but haven't found a way to return the average brightness of an image... Can this be done quickly either in these libraries, or in another package easily accessible by php?

fmw42
  • 46,825
  • 10
  • 62
  • 80
Eric
  • 2,900
  • 2
  • 19
  • 20

5 Answers5

4

Here is an interesting post using ImageMagick for computing the average graylevel of an image. This post also discusses Mark Ransom's technique of size reduction to 1x1 using ImageMagick.

mevatron
  • 13,911
  • 4
  • 55
  • 72
  • 1
    Too bad it doesn't discuss the benefits or drawbacks of the 1x1 technique. I imagine there are libraries that don't use an appropriate sampling method for the resize and would produce an inaccurate result. P.S. your answer would be stronger if it summarized the link. Links die after all. – Mark Ransom Jan 05 '12 at 22:12
3

In Imagemagick command line, you can convert to HSI or LAB and get the brightness (Intensity or Luminosity) from the average of the I or L channel. Any of these methods should work. Note that -scale 1x1 does a simple average of the whole image/channel and saves that value in 1 pixel result. -scale is very fast. It is not like -resize, which uses a specific filter function. Alternately, you can just compute the mean of the image without writing to 1 pixel.

convert image -colorspace HSI -channel b -separate +channel -scale 1x1 -format "%[fx:100*u]\n" info:

convert image -colorspace LAB -channel r -separate +channel -scale 1x1 -format "%[fx:100*u]\n" info:

convert image -colorspace HSI -channel b -separate +channel -format "%[fx:100*u.mean]\n" info:

convert image -colorspace LAB -channel r -separate +channel -format "%[fx:100*u.mean]\n" info:

convert image -colorspace HSI -channel b -separate +channel -format "%[mean]\n" info:

convert image -colorspace LAB -channel r -separate +channel -format "%[mean]\n" info:


The result will be between 0 and 100% with 0 being black and 100 white for all but the last two, where fx range is between 0 and 1. Thus the 100 factor to get percent. For the last two commands, the values will be between 0-255 for Q8 install and 0-65535 for Q16 install.

Note that channels are labeled in order as if they were r,g,b. But for modern versions of Imagemagick, you can use 0,1,2.

Alternately, you can get the pixel color for the channel which will be some gray value:

convert image -colorspace HSI -channel b -separate +channel -scale 1x1 -format "%[pixel:u.p{0,0}]\n" info:

convert image -colorspace LAB -channel r -separate +channel -scale 1x1 -format "%[pixel:u.p{0,0}]\n" info:


Sorry I do not know Imagick, but see

http://us3.php.net/manual/en/imagick.scaleimage.php

http://us3.php.net/manual/en/imagick.getimagepixelcolor.php

http://us3.php.net/manual/en/imagick.transformimagecolorspace.php

http://us3.php.net/manual/en/imagick.getimagechannelstatistics.php

or possibly

http://us3.php.net/manual/en/imagick.getimageproperty.php

Perhaps an Imagick expert would be kind enough to convert one of these commands from command line to Imagick code.

fmw42
  • 46,825
  • 10
  • 62
  • 80
1

Sample? Just pick 10% of random pixels instead of 100%... Error rate will rise obviously but 10% of the pixels seems fine to me, in most cases it should yield great results!

Mathieu Dumoulin
  • 12,126
  • 7
  • 43
  • 71
0

Cache the values if using them more then once, because this is not a fast solution. I tried first to resize the image to 1x1 pixel with imagick, but the results were not good. Best results I got without imagick resize, but its very slow with big images. The example resizes to 1000x1000 pixels. Keep in mind this example does not cover images with alpha channel.

function getImageBrightness( $path )
{
    $width  = 1000;
    $height = 1000;

    try
    {
        $imagick = new imagick( $path );
        $imagick->resizeImage( $width, $height );

        $_brightness = 0;

        for( $i=0; $i < $width; $i++ )
            for( $j=0; $j < $height; $j++ )
                if( $pixel = $imagick->getImagePixelColor($i, $j) )
                    if( $colors = $pixel->getColor() AND isset($colors['r']) )
                    {
                        $brightness = ($colors['r'] + $colors['g'] + $colors['b']) / (3* 255);

                        $_brightness = $brightness + $_brightness;
                    }

        $_brightness = $_brightness / ( $height * $width );

        return $_brightness; // from 0 (black) to 1 (white)

    } catch( ImagickException $e )
    {}

    return 0.5;  // default
}
Torben
  • 479
  • 6
  • 16
0

Imagick has a histogram feature to return colors by count. You can more quickly average the same information without processing pixel-by-pixel.

Performance will be dependent on the number of colors in the image/histogram (e.g. a single color image will be extremely fast).

<?php

$image = new Imagick('image.jpg');
$pixels = $image->getImageHistogram();  // Generate histogram of colors

$sumbright = 0;  // sum of brightness values
$cntbright = 0;  // count of pixels

foreach($pixels as $p){
  $color = $p->getColor();  // Get rbg pixel color
  $cnt = $p->getColorCount();  // Get number of pixels with above color

  $sumbright += (($color['r'] + $color['g'] + $color['b']) / (3*255)) * $cnt;  // Calculate 0.0 - 1.0 value of brightness (0=rgb[0] 1=rgb[255])

  $cntbright += $cnt;
}

$avgbright = $sumbright / $cntbright;  // Average 0-1 brightness of all pixels in the histogram

?>
CPG
  • 111
  • 1
  • 5