Масштабирование изображения с помощью SRT до минимально возможного соотношения с помощью imagemagick - PullRequest
0 голосов
/ 16 апреля 2020

Это дополнительный вопрос к Обрезка и изменение размера изображения вокруг пользовательской точки фокусировки , где я получил полезные ответы о том, какие части команд использовать для imagemagick для достижения того, чего я хочу: Масштабировать изображение вниз, но вместо того, чтобы использовать предопределенную гравитацию (например, «Центр» или «Север»), я хочу использовать пользовательскую точку фокусировки на изображении, которая должна быть новым центром масштабированного изображения, чтобы обеспечить «важную точку» изображение всегда видно при кадрировании / изменении его размера.

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

То, что я сейчас делаю:

# Example image from https://unsplash.com/photos/p-I9wV811qk
source_image = 'input.jpg'

source_image_size = [3008, 2000]
target_image_size = [295, 195]

# Focus point position, in percentages.
focus_point = {
  x: 46.7087766,
  y: 24.2
}

# Calculate the focus point in px on the source image.
source_focus_point = [
  source_image_size[0] / 100.0 * focus_point[:x],
  source_image_size[1] / 100.0 * focus_point[:y]
]

# Calculate the distances to the focus point in percentage,
# from all four image sides, and use the smalles value.
smallest_percentage_distance = [
  focus_point[:x],
  (100.0 - focus_point[:x]),
  focus_point[:y],
  (100.0 - focus_point[:y])
].min

# Scale image to reach smallest percentage distance.
scale_factor = smallest_percentage_distance / 100.0

# Calculate the focus point on the target image for the transformation,
# which will be on the center of the new image.
target_focus_point = [
  target_image_size[0].to_f / 2.0,
  target_image_size[1].to_f / 2.0
]

# Define how many degrees the image should be rotated.
rotation_degrees = 0

command = [
  'convert',
  source_image,
  "-set option:distort:viewport #{target_image_size.join('x')}",
  "-distort SRT '#{source_focus_point.join(',')} #{scale_factor} #{rotation_degrees} #{target_focus_point.join(',')}'",
  'output2.jpg'
].join ' '

В результате получается следующая команда:

convert input.jpg -set option:distort:viewport 295x195 -distort SRT '1405.000000128,484.0 0.242 0 147.5,97.5' output.jpg

В моем понимании, второй аргумент SRT ImageMagick искажает (здесь, scale_factor) определяет, насколько в%, изображение должно быть уменьшено. Моя идея состояла в том, чтобы рассчитать расстояния всех сторон до точки фокусировки, взять наименьшее расстояние, преобразовать его в подходящий аргумент и использовать его для определения величины масштабирования.

Цель - масштабировать изображение как можно больше, чтобы гарантировать, что выходное изображение не обрезается слишком сильно, чтобы показать как можно больше исходного изображения. Мой вывод сейчас обрезается слишком сильно.

Я попытался визуализировать его для лучшего понимания: enter image description here

Исходное изображение можно найти здесь: https://unsplash.com/photos/p-I9wV811qk

Что я делаю не так? Как рассчитать значение для правильного масштабирования изображения, чтобы максимально увеличить видимое изображение?


Редактировать 1
В конце несколько вариантов изображение будет сгенерировано, имея другой формат rat ios. Рядом с указанным 295x195, другой будет 1440x560; Особенно в этом случае простая «обрезка под действием силы тяжести», скорее всего, обрезает среднюю или верхнюю часть изображения, таким образом, точка фокусировки гарантирует постоянную видимость жизненно важной части.


Отредактируйте 2 в ответ от fmw42
Код работает так далеко, что делает изменение размера и обрезку без использования SRT. К сожалению, результат гораздо дальше по сравнению с результатом, который у меня есть в настоящее время (но, возможно, я что-то сделал не так при адаптации скрипта).

То, что я сделал, было

  • с использованием изображение из моего вопроса
  • с заменой px и py на значения точек фокусировки из моего вопроса
  • с сохранением вычисления scale, но с использованием wd=295 и ht=195, как это желаемый целевой урожай

Полученный результат выглядит следующим образом: enter image description here

Ответы [ 2 ]

1 голос
/ 30 апреля 2020

Если ваша центральная точка находится слишком близко к стороне изображения, она может не поддерживать ни один из этих размеров, либо аспектную крысу ios. Что вы хотите сделать в этих случаях? Должно ли изображение быть меньше ваших желаемых размеров или дополнено черным или прозрачным? Или следует сохранить желаемый размер, а нужный центр не должен быть в центре?

Вот решение ImageMagick, если я теперь понимаю, что вы хотите, чтобы обрезать желаемые размеры и аспекты. Если центр расположен слишком близко к одной стороне, выходной размер будет по-прежнему соответствовать желаемому, но нужная точка не будет находиться в центре. Я пометил нужную точку относительно координат на входе маленьким красным кружком.

Еще раз синтаксис Unix.

Ввод:

enter image description here

Желаемая точка на 200 200:

cd
cd desktop
infile="barn.jpg"
inname=`convert "$infile" -format "%t" info:`
# get image dimensions and aspect ratio
WxH=`convert "$infile" -format "%wx%h" info:`
ww=`echo "$WxH" | cut -dx -f1`
hh=`echo "$WxH" | cut -dx -f2`

# define centering point
px=50
py=50

# define crop size
wd=295
ht=195

# check if enough space on each side
left=`convert xc: -format "%[fx:round($px-$wd/2)]" info:`
left=`convert xc: -format "%[fx:$left<0?0:$left]" info:`
right=`convert xc: -format "%[fx:$left+$wd-1]" info:`
right=`convert xc: -format "%[fx:$right>$ww-1?$ww-1:$right]" info:`
top=`convert xc: -format "%[fx:round($py-$ht/2)]" info:`
top=`convert xc: -format "%[fx:$top<0?0:$top]" info:`
bottom=`convert xc: -format "%[fx:$top+$ht-1]" info:`
bottom=`convert xc: -format "%[fx:$bottom>$hh-1?$hh-1:$bottom]" info:`

# compute crop values
xoff=$left
yoff=$top
width=`convert xc: -format "%[fx:round($right-$left+1)]" info:`
height=`convert xc: -format "%[fx:round($bottom-$top+1)]" info:`
echo "$left; $right; $top; $bottom;"
echo "$xoff; $yoff; $width; $height"

# crop and resize the image to original dimensions
convert "$infile" -fill red -draw "translate $px,$py circle 0,0 0,2" -alpha off \
-crop ${width}x${height}+${xoff}+${yoff} +repage ${inname}_${px}_${py}.jpg


enter image description here

Желаемая точка на 50, 50:

enter image description here

1 голос
/ 16 апреля 2020

Вот как мне это сделать в Imagemagick (Unix синтаксис)

Ввод:

enter image description here

# get image dimensions and aspect ratio
WxH=`convert barn.jpg -format "%wx%h" info:`
ww=`echo "$WxH" | cut -dx -f1`
hh=`echo "$WxH" | cut -dx -f2`
aspect=`convert xc: -format "%[fx:$ww/$hh]" info:`

# define centering point
px=200
py=200

# compute distances to each side of the image
dleft=$px
dright=$((ww-px-1))
dtop=$py
dbottom=$((hh-py-1))

# find the minimum distance and to which side
dminx=`convert xc: -format "%[fx:round(min($dleft,$dright))]" info:`
dminy=`convert xc: -format "%[fx:round(min($dtop,$dbottom))]" info:`
dmin=`convert xc: -format "%[fx:round(min($dminx,$dminy))]" info:`

# compute crop width, height and scale percent
if [ $dmin -eq $dminx ]; then
wd=$((2*dminx))
ht=`convert xc: -format "%[fx:round($wd/$aspect)]" info:`
scale=`convert xc: -format "%[fx:100*$ww/$wd]" info:`
else
ht=$((2*dminy))
wd=`convert xc: -format "%[fx:round($ht*$aspect)]" info:`
scale=`convert xc: -format "%[fx:100*$hh/$ht]" info:`
fi

# compute x and y offsets to the top left corner of crop region
xoff=`convert xc: -format "%[fx:round($px-$wd/2)]" info:`
yoff=`convert xc: -format "%[fx:round($py-$ht/2)]" info:`

# crop and resize the image to original dimensions
convert barn.jpg -crop ${wd}x${ht}+${xoff}+${yoff} +repage -resize $scale% barn_result.jpg


Результат:

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...