Transférer et géolocaliser mes photos : un petit script

En matière de classement des photos, comme dans bien d'autres domaines, j'ai le sentiment de ramer à contre courant. L'heure est à l'utilisation de logiciels graphiques sophistiqués, prenant en charge depuis l'insertion de la carte SD (ou la connexion de l'APN) jusqu'au téléversement sur l'album en ligne. Digikam fait, paraît-il, cela très bien, mais je le trouve trop lourd et d'un emploi mal aisé. Je fondais quelques espoir sur oqapy, malheureusement je ne le trouve plus sur les dépôts Archlinux, même pas dans AUR... J'aime assez gthumb mais il ne sait pas faire tout ça.

Bref, je continue à travailler à la mimine selon un processus bien établi :

  • Créer un répertoire au nom significatif tant du point de vue chronologique que géographique (aaaammjj_Localisation)
  • Y copier les fichiers JPG et les renommer selon un shéma analogue (aaaammjj_hhmmss_Localisation_NomOriginel.JPG)
  • Y copier le ou les éventuel(s) fichiers gpx associés et géolocaliser les images
  • Sélectionner, recadrer et éventuellement retoucher les meilleurs clichés avant de les transférer vers notre album Piwigo

Pour renommer les photos j'utilise exiv2 de la manière suivante :

exiv2 -r %Y%m%d_%H%M%S_Localisation_:basename: mv *.JPG

Pour géolocaliser j’utilise Gpscorrelate, que j'ai présenté ici, qui est malheureusement abandonné par son créateur mais a l'avantage de disposer à la fois d'une version graphique et d'une version en ligne de commande.

gpscorrelate -g monFichierTrace.gpx -z [valeur] *.JPG

La valeur à associer à l'option -z est le décalage du fuseau horaire, par exemple +1:00 pour l’heure normale d’Europe centrale (CET : Paris, Bruxelles, Genève…) et +2:00 pour l’heure d’été d’Europe centrale (CEST). Ceci dans la mesure ou l’horodatage des photos est faite en heure locale et celle du GPS en UTC, ce qui est en principe le cas. Il y a d'autres options possible, voir la  documentation.

Bon, ce n'est pas trop compliqué, mais il faut se souvenir des options, tout ça.... Pourquoi ne pas automatiser le processus dans un petit script ?

#! /bin/bash 

#######################
##     photoman      ##
## interface à exiv2 ##
## et à gpscorrelate ##
#######################


declare -i nbRep=0
declare -i nbPhotos=0
declare -A DateTab

# chemin du répertoire photo
photoRep="/media/NAS/Public/Photos/"
# chemin du GPS
GPS="/run/media/vincent/GARMIN/Garmin/GPX"

IFS=$'\\n'
shopt -s nullglob

# détection du GPS
if [ -d $GPS ]; then
    find $GPS -iname "*.gpx" > /tmp/tracesGPS
    if [ $(wc -l /tmp/tracesGPS | cut -d " " -f 1) != 0 ]; then        
        echo
        read -n 1 -s -p "un ou plusieurs fichiers gpx ont été trouvé dans le GPS. Les copier dans le(s) répertoire(s) photos [O/n] ? " copieTrace
        copieTrace="${copieTrace:=o}"
        case $copieTrace in
            o|O|y|Y ) Geolocalisation=true;;
            * ) Geolocalisation=false;;
        esac
    fi
else
    read -n 1 -s -p "Le GPS n'a pas été détecté : continuer quand même [o/N] ? " question
    question="${question:=n}"
    case $question in
            o|O|y|Y ) Geolocalisation=false ;;
            * ) exit;;
    esac
fi
echo

#traitement des photos
for fichier in *
do
    if [ ! -f $fichier ]; then continue; fi
    MimeType=$(file --mime-type $fichier)
    if [[ ${MimeType:(-10)} != "image/jpeg" ]]; then continue; fi
    datePhoto=$(exiv2 -g Exif.Photo.DateTimeOriginal $fichier | sed -r 's/^ *//;s/ {1,}/ /g'| cut -d " " -f 4 | sed 's/://g')
    repertoire=$photoRep${datePhoto:0:4}"/"
    if [ -z ${DateTab[$datePhoto]} ]; then 
        echo
        read -p "Veuillez indiquer une localisation correspondant à la journée du $datePhoto puis appuyez sur [Entrée] : " localisation
        echo
        DateTab[$datePhoto]="_"$(echo $localisation | sed 's/ /-/g')
        mkdir $repertoire$datePhoto${DateTab[$datePhoto]} 2> /dev/null
        ((nbRep++))
        # copier les fichiers gpx        
        if $Geolocalisation; then
            while read line  
                do   
                cp $line $repertoire$datePhoto${DateTab[$datePhoto]}
            done < /tmp/tracesGPS
        fi
    fi 
    fichierRenomme=$repertoire$datePhoto${DateTab[$datePhoto]}"/"$(echo $fichier | sed 's/ /-/g')
    cp $fichier $fichierRenomme
    ((nbPhotos++))
    exiv2 "-r%Y%m%d_%H%M%S"${DateTab[$datePhoto]}"_:basename:" mv $fichierRenomme
done

#Bilan
if [ $nbPhotos -eq 0 ]; then 
    echo
    echo "Il n'y a aucune photo à transférer dans ce répertoire"
    echo "+++++++++++++++++++++++++++++++++++++++++++++++++++++"
    echo
    exit
fi
echo "$nbPhotos photos ont été transférées dans $nbRep répertoire(s)."
printf '\\033[7m'
read -n 1 -s -p "===> Supprimer toutes les photos dans le répertoire d'origine [o/N] ? " question
question="${question:=n}"
printf '\\033[0m'echo
case $question in
        o|O|y|Y ) rm -rf *.[jJ][pP][gG] ;;
        * ) : ;;
esac

#Géolocalisation
if ! $Geolocalisation; then exit; fi
read -n 1 -s -p "Géolocaliser les photos transférées [O/n] ? " question
question="${question:=o}"
case $question in
        o|O|y|Y ) : ;;
        * ) exit;;
esac
for i in "$"
    do 
    cd $photoRep${i:0:4}"/"$i${DateTab[$i]}
    for f in "*.[gG][pP][xX]"
        do
        gpxFileDate=$(xml_grep 'trkpt' $f --nb_results 1 | xml_grep 'time' --text_only)
        UTCHour=$(date -d $(echo $gpxFileDate | sed "s/T/ /g" | sed "s/Z//g") +%k | sed "s/ //g")
        LocalHour=$(date -d $gpxFileDate +%k)
        TimeZone=$(( $LocalHour  - $UTCHour ))
        gpscorrelate -g $f -z $TimeZone *.[jJ][pP][gG]
    done
done

Quelques explications :

Les premières lignes servent de fichier ini : emplacement du répertoire photo et point de montage du GPS

Ensuite je détecte si le GPS est connecté et je vérifie (find -iname *.gpx) et s'il y a une (ou plusieurs) traces. On y reviendra plus tard

Puis pour chaque fichier du répertoire en cours
  • je teste s'il est de type image jpg,
  • j'extrais la date de prise de vue grace à exiv2
  • s'il n'existe pas je crée un répertoire correspondant à cette date (localisation demandée), j'y copie les éventuelles traces du GPS et j'incrémente un compteur (les noms des répertoires sont stockés dans un tableau associatif date => _localisation )
  • J'y copie le fichier photo, le renomme (aaaammjj_hhmmss_localisation_nomOririnel.JPG) et incrémenter un compteur
Une fois le transfert terminé je vide éventuellement le répertoire d'origine et je commence la géolocalisation proprement dite. Une seule difficulté, déterminer automatiquement la zone horaire qui s'applique ce jour (en supposant que l'APN est correctement réglé à l'heure locale).

Les trace gpx sont des fichiers XML. On peut évidement les exploiter à la hussarde à grand coup de sed ou de awk, mais un bon parseur vous facilitera la tache. J'utilise ici xml_grep fourni par le paquet perl-xml-twig (Archlinux) ou xml-twig-tools (Debian/Ubuntu). Il me permet ici d'extraire l'horodatage (UTC) du premier trackpoint, que j'exprime en heure locale pour calculer la différence.

J'appelle enfin gpscorrelate pour chaque fichier gpx, avec le décalage horaire calculé, et je l'applique à toutes les photos. En principe une photo n'est concernée que par une seule trace mais s'il arrivait que le fichier JPG contienne déjà des données exif gps elles ne seraient pas écrasées et un message d'erreur serait affiché.

Naturellement ce script ne répond précisément qu'à mes besoins personnels et probablement pas aux vôtres mais il démontre, je l'espère, qu'il n'est pas si difficile de réaliser soi-même l'application correspondant à ses desiderata.
Vus : 1053
Publié par Vincent Gay : 38