Перспектива искажения ImageMagick

Мое требование заключается в том, чтобы в перспективе преобразовать пользовательское изображение в предварительно отрендеренное фоновое изображение (которое фактически является изображением на кадр в видео).

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

#!/bin/bash
# @author: neurosys
# @Description: Perspective transforms and projects an alpha image
# onto a background image.

if [ $# -ne 11 ]
then
    echo 'Usage: ./map_image.sh background.jpg image.png output.jpg x1 y1 x2 y2 x3 y3 x4 y4';
    exit;
fi

BG=$1
IMAGE=$2
DEST=$3
TEMP='temp.png'

BG_SIZE_W=$(convert $BG -print "%w\n" /dev/null)
BG_SIZE_H=$(convert $BG -print "%h\n" /dev/null)

IMAGE_W=$(convert $IMAGE -print "%w\n" /dev/null)
IMAGE_H=$(convert $IMAGE -print "%h\n" /dev/null)

X1=$4
Y1=$5

X2=$6
Y2=$7

X3=$8
Y3=$9

X4=${10}
Y4=${11}

OFFSET=15

TRANSFORM="$OFFSET,$OFFSET, $X1,$Y1  $(($IMAGE_W+$OFFSET)),$OFFSET $X2,$Y2  $OFFSET, $(($IMAGE_H+$OFFSET)) $X3,$Y3   $(($IMAGE_W+$OFFSET)), $(($IMAGE_H+$OFFSET)) $X4,$Y4"

echo "Transform matrix: $TRANSFORM"

convert $IMAGE -background transparent -extent $BG_SIZE_W\x$BG_SIZE_H-$OFFSET-$OFFSET $TEMP
convert $TEMP -background transparent -distort Perspective "$TRANSFORM" $TEMP
convert $BG $TEMP -composite $DEST
rm -f $TEMP

Тем не менее, требуется около 4 секунд, чтобы получить желаемое изображение на моем компьютере следующим образом:

[neuro@neuro-linux ~]$ time ./map_image.sh bg.png Hp-lovecraft.jpg output.jpg 494 108 579 120 494 183 576 196 && nomacs output.jpg
Transform matrix: 15,15, 494,108  195,15 579,120  15, 267 494,183   195, 267 576,196

real   0m3.852s
user   0m3.437s
sys   0m0.037s
[neuro@neuro-linux ~]$

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

Изображения, использованные в приведенном выше примере,

  • Фон Изображение на заднем плане
  • Пользователь представил изображение Пользователь представил изображение
  • Выход Выход

Мне интересно, есть ли способ ускорить это так, чтобы я мог генерировать кадры для видео длиной в одну минуту (25 кадров в секунду * 60 секунд) в течение нескольких секунд?

На самом деле, в случае неудачи такого подхода, я могу прибегнуть к написанию специально для этого программы OpenGL, которая, я считаю, будет намного быстрее, если использовать аппаратное обеспечение.

Немного не по теме: фоновое изображение отображается в программном обеспечении для анимации (3ds Max). В случае, если я прибегаю к написанию рендерера opengl, я могу импортировать сетку и камеру из 3ds Max и сделать это для лучшей перспективы и освещения.

Благодарю.

Редактировать:

С помощью ребят на форуме ImageMagick узкое место оказалось в первом преобразовании -extent, которое было ненужным.

В итоге я объединил все команды в одну:

convert image.png -background transparent +distort Perspective "1,1, 494,108  201,1 579,120  1, 201 494,183   201, 201 576,196" -compose DstOver -composite bg.png out.png

Он запускается за 0,6 секунды, но прозрачность почему-то не работает, поэтому выходное изображение в итоге становится только искаженным изображением с черным фоном вокруг.

Редактировать:

Кто-то на форумах ImageMagick написал очень быстрый и чистый скрипт, который сократил его до 0,13 секунды.

Вот ссылка на тот случай, если это кому-нибудь понадобится: https://www.imagemagick.org/discourse-server/viewtopic.php?f=1&t=29495&p=132182

2 ответа

Попробуйте использовать формат MPC в качестве $TEMP вместо PNG. Кодирование MPC намного намного быстрее. Он предназначен для использования в качестве временного файла, для использования с ImageMagick.

MPC фактически создает два файла, *.mpc и *.cache, поэтому вам нужно удалить оба. В вашем сценарии установите TEMP=temp.mpc и TEMPCACHE=temp.cache, а затем в конце сценария rm $TEMP TEMPCACHE

Смотрите запись MPC на странице форматов ImageMagick.

Если я получу размеры изображения, используя вашу технику, это займет около 0,4 секунды для ширины и еще 0,4 секунды для высоты. Я имею в виду, как это:

BG_SIZE_W=$(convert $BG -print "%w\n" /dev/null)   # 0.48 sec
BG_SIZE_H=$(convert $BG -print "%h\n" /dev/null)   # 0.48 sec

Если вы получаете ширину и высоту за один раз, это займет 0,006 секунды на моей машине:

read BG_SIZE_W BG_SIZE_H < <(identify -ping -format "%w %h" bg.png)

Я все еще смотрю на остальную часть вашего кода.

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