automatisch aus einem Panoramabild ein Panoramavideo

in Stapelverarbeitung erstellen

Panoramabilder, gerade wenn sie sehr viel breiter als hoch sind lassen sich auf Bildschirmen nur unbefriedigend darstellen. Dieser Vorschlag erstellt aus dem Bild ein Video, dass ein einfaches Drehbuchhat: Panoramabild in Totale, kurze Pause, Zoom in Nahe am linken Bildrand, Schwenk nach rechts bis zum Bildrand, kurze Pause, Ende.

Dies lässt sich sehr schön Automatisieren, es genügt dann ein Befehl, oder in eine GUI aeingebunden auch ein Mausklick um dieses Video zu erstellen. Das geht unter Linux mit Hilfe von ImageMagick, x264 und ein wenig Bash. Das Skript verwendet Multitasking mit wählbarer Anzahl der Tasks. Es benötigt einiges an Plattenplatz während der Erstellung. Das Ergebnis ist eine sehr effizient kodierte Videodatei, da die Differenz von Bild zu Bild jeweils nur wenig neue Bildinformation enthält und der meiste Teil des Bildes jeweils präzise aus einem horizontalen Verschiebevektor gebildet wird. Genau das kann die H.264 perfekt.

Hier ein Panoramabild Beispiel Panoramabild

Download<--Klicke hier für Video

download

#!/bin/bash # © 2016 Joachim Schwender # Wandelt ein Panorama-Bild (viel breiter als hoch) in ein Video-Schwenk von links nach rechts. # Mit vielen Kameras kann man Panoramafolgen aufnehmen, die aus einzelnen Bildern bestehen und # mit Hugin (oder notfalls auch Gimp) aneinander gesetzt werden können. Daraus entsteht dann ein Panoramabild. # Dieses wird auf jedem Monitor nur als schmaler Streifen dargestellt. # Der Film hiervon ist einfach besser zu betrachten. # # Benötigt: ImageMagick, jpeginfo, mjpeg tools # WARNUNG: benötigt viel Plattenplatz im Temporären Verzeichnis, ca 1,3Mb pro Bild )!!!!!! # # ungefähre Anzahl der Bilder (Schritte nach links), der endgültige Wert wird so berechnet, # dass die Rundungsfehler minimal sind STEPS=700 # Anzahl der Schritte für den Schwenk ZoomSchrittweite=56 # Schrittweite beim zoomen VidBreite=1280 # Grösse des Video X und Y (sollte nicht verändert werden) VidHoehe=720 MAXTHREADS=4 # myexit() { echo "${1}"; exit; } fnullen() { printf "%04i" $1; } log() { case "$2" in ("1") echo -e -n "$1" # log auf konsole ;; ("2") echo -e "$1" >>$LOG # log in Datei ;; ("3") echo -e -n "$1" # log auf konsole echo -e "$1" >>$LOG # log in Datei ;; esac } TMPDIR=/tmp/video$$ LOG=${TMPDIR}/log mkdir ${TMPDIR} QDIR=$(pwd) [ -z ${1} ] && myexit "Bitte Quelldatei angeben und optional die Anzahl der Frames!" # die Quelldatei muss angegeben werden [ -z ${2} ] || STEPS=${2} # Als optionaler Parameter kann die Anzahl der Schritte angegeben werden SRC=${1} FNAME=$(basename ${SRC} ".jpg") TMP=${TMPDIR}/tempimage.ppm # Pan-bild analysieren. PanBildBreite=$(jpeginfo ${SRC}|cut -d "x" -f1|cut -d " " -f2) PanBildHoehe=$(jpeginfo ${SRC}|cut -d "x" -f2|cut -d " " -f2) # Framebreite aus der Höhe berechnen, angenommen ist ein Seitenverhältnis von 16/9 FrameBreite=$(echo "scale=0; ( ${PanBildHoehe} * 16 ) / 9" | bc) #""" # LEN=$(expr ${PanBildBreite} - ${FrameBreite}) INCREMENT=$(expr ${LEN} / ${STEPS}) # Der Wert ist abgerundet, also entsteht ein Rundungsfehler STEPS=$(expr ${LEN} / ${INCREMENT}) # dies korrigiert den Rudungsfehler log "Quellbild: PanBildHoehe: ${PanBildHoehe} PanBildBreite: ${PanBildBreite}, \ -- Ziel: Breite: ${FrameBreite} Schritte: ${STEPS}, Schrittweite: ${INCREMENT}\n" 3 log "Video: $VidBreite x $VidHoehe mit $MAXTHREADS Threads\n" 3 #--------------------------------------- # Zoombeginn i=0 X1=${VidBreite} BB=1000 Y1=10 while [ 1 ] do Y1=$(echo "scale=0;( ${PanBildHoehe} * ${X1} ) / ${PanBildBreite}" | bc) #" [ ${Y1} -lt ${VidHoehe} ] ||break BB=$(echo "scale=0;( ${VidHoehe} - ${Y1} ) / 2 + 1" |bc) #" XX=$(fnullen ${i}) ZA=$(expr $Y1 + $BB + $BB) log "\rZoomstatus: ${X1}x${Y1} Rand: ${VidBreite}x${VidHoehe}+${BB} Index: ${i} $ZA " 3 convert -resize ${X1}x${Y1} -border ${BB} -bordercolor black \ -crop ${VidBreite}x${VidHoehe}+${BB} ${SRC} ${TMPDIR}/a_$XX.ppm echo "${i}">${TMPDIR}/index # für While-schleifen-Beendung den letzten Index merken! i=$(expr ${i} + 1) X1=$(expr ${X1} + ${ZoomSchrittweite}) done log "\nZoom fertig." 3 # ich weiss nicht wie das besser geht den Wert aus der while schleife zu retten? i=$(cat ${TMPDIR}/index) log "nächster Index ${i}" 3 #--------------------------------------- convppm() { convert -crop ${FrameBreite}x${PanBildHoehe}+${1}+0 ${2} -comment "Frame $3" \ -resize ${VidBreite}x${VidHoehe}^ ${TMPDIR}/a_$3.ppm } # kleine Pause nach Zoom mit still stehendem Bild X1=$i XX=$(fnullen ${i}) convppm 0 ${SRC} ${XX} i=$(expr ${i} + 1) X2=$(expr ${i} + 25) for (( n=$i;n<$X2; n=$(expr $n + 1) )) do TT=$(fnullen ${n}) SS=$(fnullen $i) # 25 Kopien der gleichen Datei ergeben 1 s Standbild cp ${TMPDIR}/a_$XX.ppm ${TMPDIR}/a_$TT.ppm done # i=$X2 # index nachführen log "\nPause fertig, index: $X2" 3 #--------------------------------------- XPOS=0 while [ ${XPOS} -lt ${LEN} ] ; do for (( Thread=1;Thread<${MAXTHREADS}; Thread=$(expr $Thread + 1) )) do # Parallelverarbeitung von Bildern if [ ${XPOS} -lt ${LEN} ] then XX=$(fnullen ${i}) convppm ${XPOS} ${SRC} ${XX} & echo "${XX}">${TMPDIR}/index # für While-schleifen-Beendung den letzten Index merken! XPOS=$(expr ${XPOS} + ${INCREMENT}) i=$(expr ${i} + 1) fi done wait log "\rPanstatus: Bild ${XX} / ${STEPS}, X-Pos.: ${XPOS} / ${LEN} " 3 done log "\nPan fertig.\n" 3 cd ${TMPDIR} # letzten index lesen XX=$(cat index) log "${XX} Bilder generiert.\n" 3 # jetzt wandeln wir die einzelbilder in einen Videostrom # Ein kleiner Vor- und Abspann wird mit dieser Aufzählung erzeugt, das Bild läuft nicht sofort los, # und bleibt am Ende etwas stehen. FIFO=$TMPDIR/fifo$$ mkfifo $FIFO # x264 kann nicht von StdIn lesen also muss eine Fifo Datei her cat a_0000.ppm a_0000.ppm a_0000.ppm a_0000.ppm a_0000.ppm \ a_0000.ppm a_0000.ppm a_0000.ppm a_0000.ppm a_0000.ppm \ a_0000.ppm a_0000.ppm a_0000.ppm a_0000.ppm a_0000.ppm \ a_0000.ppm a_0000.ppm a_0000.ppm a_0000.ppm a_0000.ppm \ a_0000.ppm a_0000.ppm a_0000.ppm a_0000.ppm a_0000.ppm \ a_0000.ppm a_0000.ppm a_0000.ppm a_0000.ppm a_0000.ppm \ a_0000.ppm a_0000.ppm a_0000.ppm a_0000.ppm a_0000.ppm \ a_0000.ppm a_0000.ppm a_0000.ppm a_0000.ppm a_0000.ppm a_0000.ppm \ a_*.ppm\ a_${XX}.ppm a_${XX}.ppm a_${XX}.ppm a_${XX}.ppm a_${XX}.ppm \ a_${XX}.ppm a_${XX}.ppm a_${XX}.ppm a_${XX}.ppm a_${XX}.ppm \ a_${XX}.ppm a_${XX}.ppm a_${XX}.ppm a_${XX}.ppm a_${XX}.ppm \ a_${XX}.ppm a_${XX}.ppm a_${XX}.ppm a_${XX}.ppm a_${XX}.ppm \ a_${XX}.ppm a_${XX}.ppm a_${XX}.ppm a_${XX}.ppm a_${XX}.ppm \ a_${XX}.ppm a_${XX}.ppm a_${XX}.ppm a_${XX}.ppm a_${XX}.ppm \ a_${XX}.ppm a_${XX}.ppm a_${XX}.ppm a_${XX}.ppm a_${XX}.ppm \ a_${XX}.ppm a_${XX}.ppm a_${XX}.ppm a_${XX}.ppm a_${XX}.ppm \ |ppmtoy4m -S 420mpeg2 -v 0 -F 16:9 > $FIFO & x264 --sar 1:1 --fps 25 --trellis 2 --merange 24 -o ${QDIR}/${FNAME}.mkv $FIFO rm $FIFO cd ${QDIR} touch -r "${SRC}" "${FNAME}.mkv" log "fertig. Temporäres Verzeichnis ${TMPDIR} ggf. manuell löschen!\n" 3