PHP Imagick - преобразовать изображение в оттенки серого (очень плохой результат)

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

Одним из процессов является преобразование изображений в оттенки серого. Все шло нормально (локально в Windows 7, Imagick 2.2.1-dev 6.5.8-7 Q16), пока я не загрузил скрипт на свой сервер веб-хостинга (Linux, Imagick 3.0.1, 6.2.8, 20.10.2010, В16).

Я пытался изменить качество, но это ничего не улучшило.

$img->setImageCompression(imagick::COMPRESSION_JPEG); 
$img->setImageCompressionQuality(100);

Вот результаты GD, Imagick и Photoshop введите здесь описание изображения

Я считаю, что что-то не так с версией 3.0.1. Может ли кто-нибудь подтвердить это?

Q1: Есть ли альтернативный способ преобразовать изображение в оттенки серого с помощью Imagick?

Q2: Можно ли преобразовать ресурс GD в Imagick? Поэтому я могу использовать imagefilter($img, IMG_FILTER_GRAYSCALE);, чтобы получить правильный результат, а затем вывести его с помощью Imagick.

ps: для Q2 вы можете предложить мне просто использовать GD для обработки изображения. Но проблема в том, что imagejpeg() не может сохранять изображения с сохраненным разрешением. и именно поэтому я переключился на Imagick.


person user1643156    schedule 25.11.2012    source источник
comment
какой код вы используете для преобразования в оттенки серого с помощью Imagick? Используете ли вы $image-›setColorspace(imagick::COLORSPACE_GRAY); Взгляните и на это stackoverflow.com/questions/4539307/   -  person Jeremy C    schedule 25.11.2012
comment
это $img->modulateImage(100, 0, 100);, где параметры (brightness, saturation, hue). Я считаю, что это правильная функция, и она действительно отлично работает с версией 2.2.1.   -  person user1643156    schedule 25.11.2012
comment
Тот факт, что он работает в конкретной версии, не означает, что это правильная функция для использования. Использование того, что упоминает Джереми, гарантирует, что ваше изображение на самом деле в оттенках серого, даже в формате файла JPEG. Вместо этого вы делаете просто фильтр. Изменить: 3 из пяти результатов поиска в Google предлагают подход Джереми.   -  person Christian    schedule 25.11.2012
comment
Похоже, это доступно только с версии 6.5.7, а версия на вашем сервере может быть старше. modulateImage должен работать, но, видимо, не так хорошо, как мог бы. php.net/manual/en/imagick.setcolorspace.php   -  person Jeremy C    schedule 25.11.2012
comment
@ Кристиан, давай, ты читал инструкцию? modulateImage является действительно функцией изменения яркости, насыщенности и оттенка. почему это не та функция, которую нужно использовать? версия 2.2.1 дает почти такой же результат, как и в Photoshop. и результат из 3.0.1 явно неверен.   -  person user1643156    schedule 25.11.2012
comment
@ user1643156 modulateImage() делает намного больше, чем вам нужно, что делает его более подверженным проблемам (как вы только что видели). Способ цветового пространства гораздо более надежен, поскольку вы говорите imagick специально переключаться на оттенки серого, а не просто применять случайный цветовой фильтр (я имею в виду, знает ли imagick, что ваш конечный результат должен быть в оттенках серого?).   -  person Christian    schedule 25.11.2012


Ответы (4)


Это мой предпочтительный способ сделать черно-белую фотографию в php/imagick: $im = $im->fxImage('intensity');

Это применяет функцию к изображению, где интенсивность равна 0.299*red+0.587*green+0.114*blue.

Эта формула основана на том, насколько наши глаза более чувствительны к разным цветам, и поэтому разница между этим и «плоским» изображением в градациях серого действительно равна ночи и дню.

Подробнее здесь:

person Codemonkey    schedule 03.12.2015

function ImagickToGD($imagick){
    $tmpfile = tmpfile();
    $imagick->writeImage($tmpfile);
    return imagecreatefromstring(file_get_contents($tmpfile));
}

Обратите внимание, что эта функция не выполняет никакой очистки (кроме временного файла, который PHP очищает автоматически).

Так, например, ваш код должен выглядеть так:

$img = new Imagick();
// ...
$gd = ImagickToGD($img);
unset($img); // destroy imagick
imagefilter($gd, IMG_FILTER_GRAYSCALE);
imagejpeg($gd, $target_name, 100);
imagedestroy($gd);

Кроме того, я не понял часть о «сохранении разрешения». В этих операциях нет ничего, относящегося к разрешению. Я так понимаю, вы имели в виду сжатие? Если вам нужно полное качество (т. е. без сжатия), просто используйте значение сжатия 100 (как я сделал).

Это приводит к сохранению существующего качества, поскольку открытие изображения с качеством 70% и сохранение его обратно с качеством 70% фактически снижает конечное качество на 49% (70% от 70%).


function GDToImagickTo($gd){
    $tmpfile = tmpfile();
    imagepng($tmpfile); // Png is our best image deal:
                        // lossless compression, transparency etc..
    $imagick = new Imagick()
    $imagick->readImage($tmpfile);
    return $imagick;
}
person Christian    schedule 25.11.2012
comment
извините, я на самом деле имел в виду GDToImagick.... поэтому я могу использовать оттенки серого с помощью gd -> gd2imagick() ->, а затем выводить изображение с помощью imagick. - person user1643156; 25.11.2012
comment
нет, я имел в виду разрешение. 72 dpi, 150 dpi, 300 dpi... хотя обычно они не имеют значения для файлов jpeg. Я делаю здесь то, что позволяю клиентам загружать отсканированные изображения (150 dpi или 300 dpi), и они выбирают водяные знаки для комбинирования. а затем они загружают файл и распечатывают их. если вы нажмете Print Preview в Photoshop, вы увидите, что изображение становится намного меньше, потому что GD imagejpeg() выводит изображения только с разрешением 72 dpi, в отличие от imagick, вы можете сохранить dpi (150 или 300). - person user1643156; 25.11.2012
comment
Я обновил ответ с помощью функции, которую вы хотели. Что касается вопроса DPI; его можно изменить со стороны клиента (в отличие от сжатия, которое фактически уничтожает образ). Кроме того, я видел пару скриптов для изменения DPI. Вы всегда можете imagejpg(); $imagick->readImage(); $imagick->setImageResolution(); $imagick->writeImage(); (если коротко) - person Christian; 25.11.2012
comment
... imagepng(), imagejpeg()... это одно и то же. пока эти функции используются. разрешение изображения будет уменьшено до 72 dpi, но на мониторе оно все равно будет отображаться четко. но когда вы распечатываете их на принтере. это только половина размера (72 из 150) исходного изображения. и вы не можете ожидать, что клиенты будут знать редактирование изображений, без сценариев или фотошопа, по крайней мере, не мои клиенты. они сканируют, загружают, комбинируют, скачивают, печатают... - person user1643156; 25.11.2012
comment
Ложь! Разрешение только сообщает принтеру, как печатать изображение; данные изображения не изменяются. Например, возьмите сканер и отсканируйте одно и то же изображение дважды, но с разным разрешением; как вы увидите, оба являются разными изображениями, поскольку растровое изображение содержит пиксели, а разрешение говорит только о том, насколько большими пиксели должны выглядеть на бумаге. Таким образом, изображение высокой плотности — это просто увеличенное изображение (т. е. фактическое изображение должно измениться). Это не относится к вашему изображению, где ввод точно такой же, как и вывод. - person Christian; 25.11.2012
comment
В заключение, разрешение JPEG — это просто метаданные. Это не влияет на фактическое изображение. Изображение с более высоким разрешением должно быть больше (в пикселях). Когда вы меняете метаданные разрешения, изображение остается прежним. Если вы не измените метаданные, изображение все равно останется прежним. Для получения дополнительной информации, пожалуйста, прочитайте это (есть много других ). - person Christian; 25.11.2012
comment
@user1643156 См. также: en.wikipedia.org/wiki/ - person Christian; 26.11.2012
comment
Спасибо за информацию Кристиан. Но проблема с GD заключается в том, что imagejpeg изменяет dpi на 72, хотя размер в пикселях может оставаться прежним, фактический размер (он же размер печати -> см) также изменяется. это похоже на создание в Photoshop: вы берете изображение с разрешением 300 dpi, меняете dpi на 72, вы заметите, что px уменьшится, вы возвращаете px к исходному размеру, фактический размер (см) также меняется (становится намного больше), и вы не можете этого избежать. Но этого не происходит с Imagick. - person user1643156; 26.11.2012
comment
@user1643156 user1643156 Вы смешиваете вещи. Photoshop ведет себя таким образом, потому что фактически изменяет изображение при изменении DPI. С другой стороны, JPEG DPI — это просто метаданные. На самом деле, чаще всего тогда нет, в первую очередь не будет набора метаданных DPI (как объясняется в ссылке). В любом случае, просто используйте хак DPI, о котором я упоминал выше. В качестве альтернативы вы можете использовать функциональность PHP exif. - person Christian; 26.11.2012

Посетите этот веб-сайт и ознакомьтесь с изображениями операторов Magick, найденными здесь www.rubblewebs.co.uk/imagemagick/.

Также посетите www.fmwconcepts.com/imagemagick/, здесь вы найдете несколько примеров...

person raduns    schedule 25.11.2012
comment
ImageMagick и Imagick в данном случае совершенно разные вещи. Я говорю о программировании, а не о настольных приложениях... - person user1643156; 25.11.2012

Вы можете использовать класс изображения по своему усмотрению, а затем использовать метод readImageBlob, чтобы отправить его в imagick http://www.php.net/manual/en/imagick.readimageblob.php

person Thiago Mata    schedule 16.04.2014