Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detect if image is grayscale or color using Imagick

I'm attempting to try and assign a value to an image based on its 'saturation level', to see if the image is black and white or color. I'm using Imagick, and have found what seems to be the perfect code for the command line and am trying to replicate it using the PHP library.

I think I understand the concept:

  1. Convert image to HSL.
  2. Extract the 'g' channel (which is the S channel in HSL).
  3. Calculate the mean of this channel.


Command line code

convert '$image_path' -colorspace HSL -channel g -separate +channel -format '%[fx:mean]' info:


My PHP code

$imagick = new Imagick($image_path);
$imagick->setColorspace(imagick::COLORSPACE_HSL);
print_r($imagick->getImageChannelMean(imagick::CHANNEL_GREEN));


Output

My PHP code isn't outputting the same sort of values as the command line code, though. For example, a grayscale image gives 0 for the command line code, but the PHP code gives [mean] => 10845.392051182 [standardDeviation] => 7367.5888849872.

Similarly, another grayscale image gives 0 vs. [mean] => 31380.528443457 [standardDeviation] => 19703.501101904.

A colorful image gives 0.565309 vs. [mean] => 33991.552881892 [standardDeviation] => 16254.018540044.


There just doesn't seem to be any kind of pattern between the different values. Am I doing something obviously wrong?

Thanks.


Just to add, I've also tried this PHP code

$imagick = new Imagick($image_path);
$imagick->setColorspace(imagick::COLORSPACE_HSL);
$imagick->separateImageChannel(imagick::CHANNEL_GREEN);
$imagick->setFormat('%[fx:mean]');

But I get an Unable to set format error when I try and set the format. I've also tried setFormat('%[fx:mean] info:'), setFormat('%[mean]'), setFormat('%mean'), etc.



Update — FIXED!

Thanks to @danack for figuring out I needed to use transformImageColorspace() and not setColorspace(). The working code is below.

$imagick = new Imagick($image_path);
$imagick->transformImageColorspace(imagick::COLORSPACE_HSL);
$saturation_channel = $imagick->getImageChannelMean(imagick::CHANNEL_GREEN);
$saturation_level = $saturation_channel['mean']/65535;
like image 448
dvyio Avatar asked May 28 '14 22:05

dvyio


2 Answers

setFormat doesn't replicate the command line option -format - the one in Imagick tries to set the image format, which should be png, jpg etc. The one in the command line is setting the format for info - the closest match for which in Imagick is calling $imagick->identifyImage(true) and parsing the results of that.

Also you're just calling the wrong function - it should be transformImageColorspace not setColorSpace. If you use that you can use the statistics from getImageChannelMean.

There are other ways to test for greyness which may be more appropriate under certain circumstances. The first is to convert the a clone of the image to grayscale, and then compare it to the original image:

$imagick = new Imagick($image_path);
$imagickGrey = clone $imagick;
$imagickGrey->setimagetype(\Imagick::IMGTYPE_GRAYSCALE);

$differenceInfo = $imagick->compareimages($imagickGrey, \Imagick::METRIC_MEANABSOLUTEERROR);

if ($differenceInfo['mean'] <= 0.0000001) {
    echo "Grey enough";
}

That would probably be appropriate if you image had areas of color that were also transparent - so they theoretically have color, but not visibly.

Or if you only care about whether the image is of a grayscale format:

$imageType = $imagick->getImageType();
if ($imageType === \Imagick::IMGTYPE_GRAYSCALE || 
    $imageType === Imagick::IMGTYPE_GRAYSCALEMATTE) {
     //This is grayscale
}
like image 152
Danack Avatar answered Sep 30 '22 14:09

Danack


I found a command line here:

convert image.png -colorspace HSL -channel g -separate +channel -format "%[fx:mean]" info:

It prints a number between 0 and 1, where zero means grayscale.

like image 39
Tor Klingberg Avatar answered Sep 30 '22 15:09

Tor Klingberg