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:
convert '$image_path' -colorspace HSL -channel g -separate +channel -format '%[fx:mean]' info:
$imagick = new Imagick($image_path);
$imagick->setColorspace(imagick::COLORSPACE_HSL);
print_r($imagick->getImageChannelMean(imagick::CHANNEL_GREEN));
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.
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;
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
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With