Einführung

Manche Digitalkameras können Fotos in einem bestimmten Zeitintervall auslösen. Nach ein paar Stunden sammeln sich viele Fotos in einem Ordner an, welche man mit ffmpeg in ein Video umwandeln kann. Ich habe einige Zeit gebraucht, bis alles endlich funktioniert hat. Hier seht ihr, wie man das mit ffmpeg machen kann.

Schritt für Schritt

Ausgangslage

Als Ausgangslage habe ich viele Fotos in einem Verzeichnis:

$ ls
2011-07-08_13-59-58.jpg  2011-07-08_15-01-27.jpg  2011-07-08_16-02-57.jpg
2011-07-08_14-00-07.jpg  2011-07-08_15-01-38.jpg  2011-07-08_16-03-08.jpg
2011-07-08_14-00-17.jpg  2011-07-08_15-01-47.jpg  2011-07-08_16-03-17.jpg
[...]

In meinem Fall sind das 1104 Fotos:

$ ls *.jpg | wc -l
1104

Diese Fotos haben zusammen eine Grösse von 2.4 GB:

$ du -ch *.jpg
1.6M    2011-07-08_13-59-58.jpg
1.6M    2011-07-08_14-00-07.jpg
[...]
2.0M    2011-07-15_14-48-28.jpg
2.4G    insgesamt

Ich möchte von diesen Fotos ein HD-Video umwandeln. Die Fotos haben eine Auflösung von 2592 x 1944 Pixel:

$ jhead 2011-07-15_14-47-51.jpg | grep Resolution
Resolution   : 2592 x 1944

Fotos verkleinern

Da die Fotos zu gross sind, verkleinert man die Fotos auf zuerst auf 1080 Pixel in der Höhe:

for datei in *.jpg
do
  convert -resize x1080 -quality 50 "$datei" "small_$datei"
done

Fotos umbenennen

Damit ffmpeg die Fotos in ein Video umwandeln kann, müssen die Fotos im Format wie 0001.jpg vorliegen. Die führenden Nullen sind für ffmpeg wichtig. Die Fotos können mit convert (aus dem Paket imagemagick) konvertiert werden:

LENGTH=`ls | wc -l | wc -L`
NUMBER="1"
find *.jpg | while read foto
do
  mv $foto "`printf %0${LENGTH}d $NUMBER`".jpg
  NUMBER=$((NUMBER + 1))
done

Fotos in ein Video konvertieren

Jetzt kann man mit ffmpeg die Fotos in ein Video umwandeln:

ffmpeg -f image2 -i %0${LENGTH}d.jpg -r 25 -vcodec libx264 output.mpg

Fertig: Video abspielen

Das Video ist nach dem Konvertieren 28 MB gross:

$ du -h output.mpg
28M     output.mpg

Das Video kann jetz abgespielt werden

mplayer output.mpg

Automatisch mit einem Skript

Um diese Schritte zu vereinfachen, habe ich ein kleines Bash-Skript pic2vid geschrieben, welches all diese Schritte schön ausführt:

#!/usr/bin/env bash
########################################################################
#
# pic2vid
# Konvertiert mehrere Fotos zu einem Video (Zeitraffer)
#
# GNU General Public License
# 2012 by Emanuel Duss
#
########################################################################

########################################################################
# Variabeln
DIR="$1"
PICDIR="pic2vid"
SMALLDIR="$DIR/$PICDIR"
SIZE="x1080"
QUALITY="90"
OUTPUTFILE="output.mpg"
CODEC="libx264"
FRAMESPERSECOND="25"

########################################################################
# Funktionen
Printusage () {
  echo "Usage:
  $0 directory"
}

########################################################################
# Main
# Prüfe Fehler
if [ -z "$1" ]
then
  Printusage
  exit 1
fi
if [ ! -d "$DIR" ]
then
  echo "$DIR ist kein Verzeichnis"
  Printusage
  exit 1
fi
if [ -d "$SMALLDIR" ]
then
  echo "Verzeichnis für aufzubereitende Fotos bereits vorhanden."
else
  mkdir "$SMALLDIR"
fi
if [ ! -d "$SMALLDIR" ]
then
  echo "Kann $SMALLDIR nicht anlegen. Bitte Berechtigungen prüfen."
  exit 1
fi
cd $DIR

# Fotos verkleinern (nur, wenn noch nicht verkleinert)
TOTAL="`ls *.[Jj][Pp][Gg] | wc -l`"
COUNT="1"
for file in *.[Jj][Pp][Gg]
do
  if [ -f "${PICDIR}/$file" ]
  then
    echo "Überspringe $file, da bereits konvertiert (${PICDIR}/$file)"
  else
    echo "$file: Foto $COUNT von $TOTAL ($((100 * $COUNT / $TOTAL))%)"
    convert -resize $SIZE -quality $QUALITY "$file" "${PICDIR}/$file"
  fi
  ((COUNT++))
done

# Fotos umbenennen (in Form wie 0001.jpg bis 2342.jpg)
cd $PICDIR
LENGTH="`ls *.[Jj][Pp][Gg] | wc -l | wc -L`"
NUMBER="1"
for file in *.[Jj][Pp][Gg]
do
  NEWNAME="`printf %0${LENGTH}d $NUMBER`.jpg"
  if [ -f "$NEWNAME" ]
  then
    echo "Datei $file bereits umbenannt. OK."
  else
    # Symlink statt umbenennen, damit die Prüfung ob schon konvertiert auch funktioniert
    ln -s "$file" "`printf %0${LENGTH}d $NUMBER`".jpg
  fi
  ((NUMBER++))
done

# Bilder mit ffmpeg zu Video zusammenfügen
ffmpeg -f image2 -i %0${LENGTH}d.jpg -r $FRAMESPERSECOND -vcodec $CODEC ../$OUTPUTFILE
# EOF

Das Skript sagt einem, wie man es anwenden muss:

$ pic2vid
Usage:
  pic2vid directory

So erstelle ich z. B. im aktuellen Verzeichnis mit allen Bildern ein Video:

pic2vid .

Und schon hat man sein Zeitraffervideo.

Die aktuellste Version davon gibt es auf GitHub in meinem Scripts Repository: pic2vid.