Определите, является ли изображение в градациях серого или цветным, используя 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;

person dvyio    schedule 28.05.2014    source источник
comment
Не могли бы вы пояснить, что вы подразумеваете под моей версией PHP, которая не выводит такие же значения, как версия для командной строки? Вы используете две отдельные версии PHP?   -  person Mr. Llama    schedule 29.05.2014
comment
Извините — я думаю, что это плохая формулировка с моей стороны! Я отредактирую это. Это одна и та же версия PHP, я просто имею в виду две версии кода, то есть код командной строки и код PHP.   -  person dvyio    schedule 29.05.2014
comment
@danack i.stack.imgur.com/Jsku5.jpg   -  person Alexufo    schedule 31.07.2015


Ответы (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
}
person Danack    schedule 29.05.2014
comment
Спасибо! Мне нравится это решение как способ определить, является ли изображение в градациях серого, но мне просто интересно, знаете ли вы, почему $imagick->setColorspace(imagick::COLORSPACE_HSL); не работает? В идеале (что немного отличается от моего первоначального вопроса) мне нужно значение от 0,0 до 1,0 на основе средней насыщенности изображения. Я увеличил насыщенность изображения до максимума в Photoshop, и сценарий командной строки дал 0,995 (достаточно близко к 1,0), но приведенный выше сценарий дал 0,22 — что представляет собой 0,22? Кажется, это самое большое количество, выпущенное до сих пор. - person dvyio; 29.05.2014
comment
Просто чтобы уточнить, вместо того, чтобы просто классифицировать изображение как в градациях серого или нет, в идеале я хотел бы иметь возможность выбирать изображение на основе насколько оно красочно. Ваш код делает это, хотя результаты немного отличаются от расчета средней насыщенности. Если это невозможно, я могу разделить выходное значение из вашего кода на 0,25, чтобы получить значение, нормализованное до 1,0, но мне любопытно. Я очень ценю вашу помощь! - person dvyio; 29.05.2014
comment
просто интересно, знаете ли вы, почему $imagick-›setColorspace(imagick::COLORSPACE_HSL); не работает? Похоже, что это глючило. Это технический термин. setColorSpace, кажется, не оказывает никакого влияния на изображение - я попытаюсь разобраться в этом, поскольку я должен знать, что он делает. - person Danack; 30.05.2014
comment
В идеале я хотел бы иметь возможность выбирать изображение в зависимости от того, насколько оно красочное. Это другой вопрос. Вероятно, вы можете сделать это сейчас, не используя сломанную функцию setColorspace, i) разделив ее на каналы rgb, ii) вызвав сравнение изображений между r + g и g + b с METRIC_MEANSQUAREERROR в качестве суммирующего члена. - person Danack; 30.05.2014
comment
Спасибо, @danack! Если вам удастся выяснить, что происходит с setColorspace, будет полезно узнать. Но вы здорово помогли! - person dvyio; 30.05.2014
comment
@Davey Простые ошибки всегда лучше .... transformImageColorspace not setImageColorSpace - person Danack; 31.05.2014
comment
Идеально! Спасибо, @danack! - person dvyio; 05.06.2014
comment
@Danack, сэр, я попробовал ваш код, но он показывает Undefined index: означает, что когда я проверяю возвращаемый массив, он имеет только числовой массив, например: Array ([0] => Imagick Object () [1] => 0 ), так что, я должен подать в суд 1? заранее спасибо - person Zakir_SZH; 01.11.2016
comment
@Zakir_SZH задайте отдельный вопрос и включите версию Imagick. - person Danack; 01.11.2016
comment
@Danack, спасибо за ваш ответ, сэр, пожалуйста, посмотрите на вопрос ниже, ваша помощь очень ценится :) stackoverflow.com/questions/40415910/ - person Zakir_SZH; 04.11.2016

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

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

Он печатает число от 0 до 1, где ноль означает оттенки серого.

person Tor Klingberg    schedule 28.07.2015
comment
Спасибо, это работает очень хорошо! ++ convert ../image_bw.jpg -colorspace HSL -channel g -separate +channel -format '%[fx:mean]' info: + VALUE_RAW=0.0348832 ++ convert ../image_col.jpg -colorspace HSL -channel g -separate +channel -format '%[fx:mean]' информация: + VALUE_RAW=0.435082 Теперь я использую, что если значение ‹ 0.1, изображение в градациях серого. Если это 0,1-1, это цвет. - person Konstigt; 08.12.2018

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

Но

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

person Alexufo    schedule 21.10.2014