Image::Magick (perlmagick) изменение размера, соотношение сторон и проблемы с качеством (отличаются от утилиты командной строки convert)

Я пытаюсь выполнить некоторые операции масштабирования изображений с помощью ImageMagick и perlmagick (Image::Magick). Все изображения, которые у меня есть в качестве источников, являются большими изображениями, и я хочу изменить их размеры до различных интервалов, либо по высоте, либо по ширине. Я хочу всегда сохранять пропорции.

Учитывая пример изображения с размерами 3840 пикселей × 2160 пикселей (3840x2160), я хочу создать следующие изображения с измененным размером:

    ?x1000
    ?x500
    ?x100
    1600x?
    1200x?
    800x?
    400x?

Я могу сделать это очень просто, используя утилиту командной строки convert со следующими командами (по порядку):

    convert input_filename.jpg -resize x1000 output_wx1000.jpg
    convert input_filename.jpg -resize x500  output_wx500.jpg
    convert input_filename.jpg -resize x100  output_wx100.jpg
    convert input_filename.jpg -resize 1600  output_1600xh.jpg
    convert input_filename.jpg -resize 1200  output_1200xh.jpg
    convert input_filename.jpg -resize 800   output_800xh.jpg
    convert input_filename.jpg -resize 400   output_400xh.jpg

Так как я пытаюсь выполнить эти операции массово в сочетании с другими операциями, я пытаюсь выполнить те же самые операции в perl, используя Image:: Magick. Я пробовал несколько разных методов со следующими результатами:

#METHOD 1
    my $image = Image::Magick->new();
    $image->Read($input_filename);
    $image->Resize(
        ($width  ? ('width'  => $width)  : ()),
        ($height ? ('height' => $height) : ()),
    );
    $image->Write(filename => $output_filename);

Это приводит к изображениям, которые не поддерживают соотношение сторон. Например, если указана высота 100, выходное изображение будет иметь оригинальную ширину на 100 (3840x100). Аналогичный эффект достигается при подаче ширины - высота сохраняется, а соотношение сторон - нет.

#METHOD 2
    my $image = Image::Magick->new();
    $image->Read($input_filename);
    die "Only one dimension can be supplied" if $width && $height;
    $image->Resize(geometry => $width) if $width;
    $image->Resize(geometry => "x$height") if $height;
    $image->Write(filename => $output_filename);

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

#METHOD 3
    `convert "$input_filename" -resize $width   "$output_filename"` if $width;
    `convert "$input_filename" -resize x$height "$output_filename"` if $height;

Это приводит к изображениям, которые все правильные, но разветвляются за пределы процесса perl, что приводит к проблемам эффективности.

Есть ли лучший способ в perl, чтобы эта операция изменения размера производила те же результаты, что и утилита преобразования командной строки?

Моя утилита командной строки сообщает о версии 6.7.9-10, а Image:: Magick сообщает о версии 6.79.

2 ответа

Ваш метод № 2 находится на правильном пути. Чтобы сохранить соотношение сторон, укажите ширину и высоту через geometry ключевое слово. Вашу процедуру можно сделать более общей, выполнив изменение размера за один вызов вместо двух:

$image->Resize(geometry => "${width}x${height}");

Это гарантирует, что Resize будет вызываться только один раз, даже если вы указали $ width и $ height. Просто убедитесь, что если какое-либо значение не указано, вы устанавливаете его в пустую строку. Если вы указали ширину и высоту для вашей процедуры в методе № 2, это могло быть причиной размытости, которую вы видели.

Другим возможным источником размытия является фильтр, используемый оператором изменения размера. Лучший фильтр для данной операции зависит как от цветовых характеристик изображения, так и от соотношения между исходными размерами и целевыми размерами. Я рекомендую ознакомиться с http://www.imagemagick.org/script/command-line-options.php для получения информации об этом. В PerlMagick вы можете указать фильтр для изменения размера для использования через filter ключевое слово.

Тем не менее, я не нашел особых проблем с размытостью изображений, которые я пробовал, поэтому, если проблема не исчезнет, ​​тестовое изображение будет наиболее полезным.

Возможно, я немного опоздал на эту вечеринку, но поскольку у меня была очень похожая цель - изменение размера изображения и поддержание баланса между качеством изображения и объемом дискового пространства, которое оно занимает, - я придумал следующий код. Я начал с кода OPs и следил за этой очень интересной статьей: https://www.smashingmagazine.com/2015/06/efficient-image-resizing-with-imagemagick/

Вот результат:

      sub optimize_image_size
{
my $imagePath = shift();
my $height = shift(); #720
my $width = shift(); #1080

 my $image = Image::Magick->new();
    $image->Read($imagePath);
    die "Only one dimension can be supplied" if $width && $height;
    $image->Thumbnail(geometry => "$width",filter=>'Triangle') if $width;
    $image->Thumbnail(geometry => "x$height",filter=>'Triangle') if $height;
    $image->Colorspace(colorspace=>'sRGB');
    $image->Posterize(levels=>136, dither=>'false');
    $image->UnsharpMask(radius=>0.25, sigma=>0.25, threshold=>0.065, gain=>8);
    $image->Write(filename => $imagePath
            , quality=>'82'
            , interlace=>'None'
    );

}

По крайней мере, для меня это дает очень удовлетворительное уменьшение размера (мои образцы изображений с 6 МБ были уменьшены до примерно 90 КБ), сохраняя при этом качество, аналогичное настройкам Photoshops "для Интернета", и, конечно, сохраняя соотношение сторон независимо от того, указываете ли вы ширину или высоту.

Слишком поздно для OP, но, возможно, это поможет другим людям.

Другие вопросы по тегам