Обнаружить, если изображение в оттенках серого или в цвете, используя Imagick


Я пытаюсь попытаться присвоить значение изображению на основе его "уровня насыщенности", чтобы увидеть, является ли изображение черно-белым или цветным. Я использую Imagick, и нашел то, что кажется идеальным кодом для командной строки, и пытаюсь воспроизвести его с помощью библиотеки PHP.

Я думаю, что понимаю концепцию:

  1. преобразование изображения в HSL.
  2. извлеките канал " g " (который является каналом S в HSL).
  3. вычислите среднее значение этого канал.


Код командной строки

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


Мой PHP код

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


Вывод

Мой PHP-код не выводит те же значения, что и код командной строки. Например, изображение в оттенках серого дает 0 для кода командной строки, но код PHP дает [mean] => 10845.392051182 [standardDeviation] => 7367.5888849872.

Аналогично, другое изображение в оттенках серого дает 0 против [mean] => 31380.528443457 [standardDeviation] => 19703.501101904.

Красочное изображение дает 0.565309 против [mean] => 33991.552881892 [standardDeviation] => 16254.018540044.


Просто не похоже, что существует какая-то закономерность между различными значениями. Я делаю что-то явно неправильное?

Спасибо.


Просто чтобы добавить, я также попробовал этот PHP-код

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

Но я получаю ошибку Unable to set format, когда пытаюсь установить формат. Я тоже пробовал setFormat('%[fx:mean] info:'), setFormat('%[mean]'), setFormat('%mean'), и т.д.



Обновление-исправлено!

Спасибо @danack за то, что выяснил, что мне нужно использовать transformImageColorspace(), а не setColorspace(). То рабочий код приведен ниже.

$imagick = new Imagick($image_path);
$imagick->transformImageColorspace(imagick::COLORSPACE_HSL);
$saturation_channel = $imagick->getImageChannelMean(imagick::CHANNEL_GREEN);
$saturation_level = $saturation_channel['mean']/65535;
3 5

3 ответа:

SetFormat не копирует параметр командной строки -format - тот, что в Imagick пытается установить формат изображения, который должен быть png, jpg и т. д. Один из них в командной строке задает формат для info - ближайшего соответствия, для которого в Imagick вызывается $imagick->identifyImage(true) и анализируются результаты этого.

Кроме того, вы просто вызываете неправильную функцию - это должно быть transformImageColorspace, а не setColorSpace. Если вы используете это, вы можете использовать статистику из getImageChannelMean.

Там существуют и другие способы проверки серости, которые могут быть более подходящими при определенных обстоятельствах. Первый-преобразовать клон изображения в оттенки серого, а затем сравнить его с исходным изображением:

$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";
}
Это, вероятно, было бы уместно, если бы у вашего изображения были области цвета, которые также были прозрачными - таким образом, они теоретически имеют цвет, но не заметно.

Или если вас интересует только формат изображения в оттенках серого:

$imageType = $imagick->getImageType();
if ($imageType === \Imagick::IMGTYPE_GRAYSCALE || 
    $imageType === Imagick::IMGTYPE_GRAYSCALEMATTE) {
     //This is grayscale
}

Я нашел командную строку здесь:

convert image.png -colorspace HSL -channel g -separate +channel -format "%[fx:mean]" info:
Он выводит число от 0 до 1, где ноль означает оттенки серого.

Если ваши изображения имеют оттенок. (из сканера в качестве примера)вы должны сделать автоматический цвет для них, прежде чем обнаруживать серую шкалу. Вы должны normalizeImage(imagick::CHANNEL_ALL) для всех отдельных каналов изображения. separateImageChannel()

Но

Введите описание изображения здесь