Timelapse

Film accéléré oiseaux, ciel, ...

Introduction

raspberry

Le raspberry muni d'une caméra permet de prendre à intervalles réguliers des photos.
Grâce à la commande raspistill utilisée dans des scripts shell, on peut prendre des photos à intervalle régulier, puis les combiner en fin de journée dans une vidéo récapitulative.
Cela peut donner des séquences instructives ou esthétiques.

demarrage

Le raspberry en version autonome (batterie) doit être vérifié au démarrage, le script mailer.py permet d'envoyer un mail et connaître son adresse IP.
Ensuite, se connecter en ssh pour voir si la prise de photos a lieu.

mailer.py

# mailer.py : envoi d'un mail avec adresse IP du raspberry

# important : pour éviter une erreur d'authentification,
# https://myaccount.google.com/lesssecureapps
# source :
# https://iotdesignpro.com/projects/sending-smtp-email-using-raspberry-pi
import subprocess
import smtplib
import socket
from email.mime.text import MIMEText
import datetime

hostname1 = 'camera_ciel '

# Change to your own account information
# ===================================
# CHERCHER Script_mailer.py_credentials DANS COFFRE-FORT
# POUR REMPLIR CETTE SECTION
to              = 'ENVOYER_A'
gmail_user      = 'ENVOYEUR'
gmail_password  = 'ENVOYEUR_PASS'
smtpserver      = smtplib.SMTP('smtp.gmail.com', 587)
# ===================================

smtpserver.ehlo()
smtpserver.starttls()
smtpserver.ehlo
smtpserver.login(gmail_user, gmail_password)
today = datetime.date.today()
# Very Linux Specific
arg='ip route list'
p=subprocess.Popen(arg,shell=True,stdout=subprocess.PIPE)
data = p.communicate()
split_data = data[0].split()
ipaddr = split_data[split_data.index('src')+1]
my_ip = '%s' %  ipaddr

arg='df -h . | tail -1'
p=subprocess.Popen(arg,shell=True,stdout=subprocess.PIPE)
data = p.communicate()
split_data = data[0].split()
data2 = split_data[3]

arg='hostname'
p=subprocess.Popen(arg,shell=True,stdout=subprocess.PIPE)
data = p.communicate()

msg = MIMEText(my_ip + ', ' + data2 + ' libres')
print(msg)

msg['Subject'] = hostname1 + '- raspi %s' % today.strftime('%b %d %Y')
msg['From'] = gmail_user
msg['To'] = to
smtpserver.sendmail(gmail_user, [to], msg.as_string())
smtpserver.quit()
                        

Prise photos

raspistilltimelapse

Autoriser d'abord la camera du raspberry pi dans raspi-config, puis utiliser le script ci-dessous

raspistill_timelapse.sh
echo '-----------------------'
echo Pause de 30s
echo avant prise de photo toutes les 10s
echo pendant une heure
echo avant shutdown
echo '-----------------------'
sleep 30

compteftp=XXXXXXXX
passftp=YYYYYYYY
ftphost=FTPHOST

cd
mkdir PHOTOS
cd    PHOTOS
d=$(date +%H%M)
mkdir $d
cd $d
# raspistill -t 3600000 --timeout 1000 -tl 1000 -q 70 -n -w 1600 -h 900 -o img_%06d.jpg
# https://raspberrypi.stackexchange.com/questions/12321/getting-correctly-exposed-photos-and-the-right-shutter-speed-for-the-rpi-camera
# éviter surexposition (image trop claire) : --timeout 1000
# prendre des photos toutes les secondes pendant une heure : -t 3600000 -tl 1000
raspistill --timeout 1000 -tl 1000 -q 70 -n -w 1600 -h 900 -o img_%06d.jpg

# tl, --timelapse        : Timelapse mode. Takes a picture every ms. %d == frame number (Try: -o img_%04d.jpg)
                        

ciel

Autoriser d'abord la camera du raspberry pi dans raspi-config, puis utiliser le script ci-dessous

prendre_photo_toutes_mn.sh
echo '-----------------------'
echo Pause de 30s
echo avant prise de photo toutes les 10s
echo pendant une heure
echo avant shutdown
echo '-----------------------'
sleep 30

compteftp=XXXXXXXX
passftp=YYYYYYYY
ftphost=FTPHOST

cd
mkdir PHOTOS
cd    PHOTOS
d=$(date +%H%M)
mkdir $d
cd $d
while true; do
 heure=$(date +%H)
 if [ $heure -gt 4 ]; then
 if [ $heure -lt 22 ]; then
 image=$(date +%Y%m%d_%Hh%Mmn%Ss).jpg
 raspistill -q 70 -n -w 1600 -h 900 -o ${image}
 # -t 3600000 -tl 1000 : prendre photo toutes les mn pendant une heure
 # --timeout 1000 : éviter surexposition (temps ensoleillé)
 # METTRE LES DEUX LIGNES SUIVANTES SUR UNE SEULE
 lftp -e "open ftp://${compteftp}:${passftp}@${ftphost} ;
  cd www/temporaire/images/ciel_camera3-16gb ; put ${image} ; quit"
 rm ${image}
 fi
 fi
 sleep 10
done
                        

hauteur_bouchon

Autoriser d'abord la camera du raspberry pi dans raspi-config, puis utiliser le script ci-dessous

hauteur_bouchon.sh

# hauteur_bouchon.sh
# ajouter la ligne suivante à .profile :
# sh hauteur_bouchon.sh

# 20210502 : surveillance mini fuite arrivée eau froide dans WC

mkdir hauteur_bouchon
cd    hauteur_bouchon
echo 'Pause 1 mn avant lancement script ...'
sleep 1m

compteftp=XXXXXXXX
passftp=YYYYYYYY
ftphost=FTPHOST


while true; do
 image=$(date +%Y%m%d_%Hh%Mmn).jpg
 raspistill -q 70 -n -w 1600 -h 900 -o ${image}
 # METTRE DEUX LIGNES SUIVANTES SUR UNE SEULE
 lftp -e "open ftp://${compteftp}:${passftp}@${ftphost} ;
 cd www/temporaire/images/hauteur_bouchon ; put ${image} ; quit"
 rm ${image}
 sleep 15m
 n=$((n+1))
done
                        

Création timelapse

annoter_images.sh

L'annotation consiste à insérer un horodatage au bas de l'image.

annoter_images.sh
# $HOME/Images/www_temporaire/annoter_images.sh

# source : http://gangand.net/ff/formation/notes/system_partie_1.html
curdir=$(pwd)
liste_jpg=$(pwd)/liste_jpg.txt
ls -1 *jpg | sort > ${liste_jpg}
echo $(date) $(wc -l < ${liste_jpg}) images brutes dans $(pwd)
dir_annotee=$(pwd).annotee
mkdir ${dir_annotee} 2>>/dev/null
cd    ${dir_annotee}
echo $(date) $(ls -l | wc -l) images déjà annotées dans $(pwd)
cd ${curdir}

nouv_annotees=0
while read a; do
	if [ -f ${dir_annotee}/$a ]; then
		x=1
	else
		nouv_annotees=$((nouv_annotees+1))
		b=$(echo $a | sed 's/\.jpg//')
		convert $a -fill white \
		 -undercolor '#00000080' \
		 -gravity South \
		 -pointsize 70 \
		 -annotate +0+5 $b ${dir_annotee}/$a
	fi
done < ${liste_jpg}
echo $(date) ${nouv_annotees} nouvelles images annotées dans ${dir_annotee}
cd ${dir_annotee}
if [ ${nouv_annotees} -gt 0 ]; then
	echo $(date) $(ls -l | wc -l) images annotées dans ${dir_annotee}
fi
rm ${liste_jpg}

                        

move_ftp2local.sh

Avant de créer la video (le timelapse), il faut rapatrier les images en local.

move_ftp2local.sh

# move_ftp2local.sh

# lancer cette commande en infini avec
# while true; do move_ftp2local.sh; sleep 10m; echo $(date) Pause 10 mn; done

ftp_images=/run/user/1000/gvfs/ftp:host=A_COMPLETER_SELON_CHEMIN_MONTE_DANS_TERMINAL
   ftp_ciel=${ftp_images}/ciel_camera3-16gb

loc_images=/home/pi/Images/images_ciel_et_WC
   loc_ciel=${loc_images}/ciel_camera3-16gb

if [ "x$1" = "x" ]; then
    dossdest=$(date +%Y%m%d)
else
    dossdest=$1
fi
echo "$(date) Espace restant local : $(df -h ~)"
echo "$(date) Dossier destination : $dossdest"
echo "$(date) Appuyer sur o pour confirmer"
read reponse

if [ "x$reponse" = "xo" ]; then
    echo "$(date) C'est parti"
else
    echo "$(date) Opération abandonnée"
    exit
fi

if [ -d ${ftp_images} ]; then
    if [ -d ${ftp_ciel} ]; then
        mkdir ${loc_ciel}/$dossdest 2>/dev/null
        if [ -d ${loc_ciel} ]; then
            echo "$(date) $(ls -1 ${ftp_ciel}/*jpg | wc -l) jpg à déplacer [fuite WC]"
            mv ${ftp_ciel}/*jpg ${loc_ciel}/$dossdest
            cd ${loc_ciel}/$dossdest
            echo "$(date) annoter_images.sh dans ${loc_ciel}/$dossdest"
            annoter_images.sh
        fi
    fi
fi

echo "$(date) fin des opérations"
                        

images2video.sh

On peut maintenant créer la ou les videos avec ffmpeg.
Faire attention au temps nécessaire et à la taille des fichiers créés.

images2video.sh

# $HOME/Images/www_temporaire/images2video.sh

# source : http://gangand.net/ff/formation/notes/system_partie_1.html

# création d'une vidéo serie_HH_MM_SS.avi
# depuis les images du dossier courant
# le fichier .mkv est volumineux
# car il utilise les images telles quelles

# utile suite à la capture d'images par motion
# sur Raspberry Pi (oiseaux venant boire)
basenom=$(basename $(pwd))
tmpdir=/tmp/video_ffmpeg
workdir=${tmpdir}/${basenom}
mkdir ${tmpdir} 2>/dev/null
mkdir ${workdir} 2>/dev/null
ls -1 *jpg | sort > ${workdir}/liste_jpg.txt

# 1. copier les images (annotées par annoter_images.sh)
echo "$(date) 1. copie jpg dans ${workdir}"
cp *jpg ${workdir}

# 2. renommer les images
echo $(date) 2. renommer images en serie-...
cd ${workdir}
nbimages=0
n=10000
while read jpg; do
    mv $jpg serie-$n.jpg
    n=$((n+1))
    nbimages=$((nbimages+1))
done < ${workdir}/liste_jpg.txt
echo "$(date)    renommé ${nbimages} images"

# 3. créer une vidéo
#~ echo "$(date) 3. ffmpeg -f image2 -i serie-1%04d.jpg -r 12 ${basenom}_2592x1942.avi"
#~ ffmpeg -f image2 -i serie-1%04d.jpg -s 1296x971 -r 12 ${basenom}_1296x971.avi > /dev/null 2>&1

# qualité basse
# echo "$(date) ffmpeg -f image2 -i serie-1%04d.jpg -s 1300x970 -r 12 ${basenom}_1300x970.avi"
# ffmpeg -f image2 -i serie-1%04d.jpg -s 1300x970 -r 12 ${basenom}_1300x970.avi > /dev/null 2>&1

# https://video.stackexchange.com/questions/7903/how-to-losslessly-encode-a-jpg-image-sequence-to-a-video-in-ffmpeg
# https://hamelot.io/visualization/using-ffmpeg-to-convert-a-set-of-images-into-a-video/

# qualité basse
# echo "$(date) ffmpeg -f image2 -i serie-1%04d.jpg -r 12 ${basenom}_2592x1942.avi"
#               ffmpeg -f image2 -i serie-1%04d.jpg -r 12 ${basenom}_2592x1942.avi > /dev/null 2>&1

# qualité moyenne
# echo "$(date) 4. ffmpeg -f image2 -i serie-1%04d.jpg -b:v 1M -r 12 ${basenom}_1M_2592x1942.avi"
#               ffmpeg -f image2 -i serie-1%04d.jpg -b:v 1M -r 12 ${basenom}_1M_2592x1942.avi > /dev/null 2>&1

# bonne qualité
echo "$(date) ffmpeg -r 24 -f image2 -s 1300x900 -i serie-1%04d.jpg -vcodec libx264 -crf 25 -pix_fmt yuv420p ${basenom}.mp4"
              ffmpeg -r 24 -f image2 -s 1300x900 -i serie-1%04d.jpg -vcodec libx264 -crf 25  -pix_fmt yuv420p ${basenom}.mp4 > /dev/null 2>&1

# ne fonctionne pas
# echo "$(date) ffmpeg -r 24 -f image2 -s 1300x900 -i serie-1%04d.jpg -vcodec libx264 -crf 25  -pix_fmt yuv420p -vpre hq ${basenom}_vpre_hq.mp4"
#               ffmpeg -r 24 -f image2 -s 1300x900 -i serie-1%04d.jpg -vcodec libx264 -crf 25  -pix_fmt yuv420p -vpre hq ${basenom}_vpre_hq.mp4 > /dev/null 2>&1
# echo "$(date) ls -1 \*jpg \| xargs -i convert {} -resize 50% {}"
# ls -1 *jpg | xargs -i convert {} -resize 50% {}

# lecture difficile
echo "$(date) ffmpeg -framerate 30 -i serie-1%04d.jpg -codec copy -s 1300x970 -r 12 ${basenom}_codec_copy.mkv"
              ffmpeg -framerate 30 -i serie-1%04d.jpg -codec copy -s 1300x970 -r 12 ${basenom}_codec_copy.mkv > /dev/null 2>&1
# réduction de la taille du fichier mkv de 66% environ (655 Mo vers 185 Mo)
echo "$(date) ffmpeg -i ${basenom}_codec_copy.mkv  -vcodec libx264 -crf 25 ${basenom}_libx264_crf25.mp4"
              ffmpeg -i ${basenom}_codec_copy.mkv  -vcodec libx264 -crf 25 ${basenom}_libx264_crf25.mp4 > /dev/null 2>&1

# essayer mencoder pour ne pas avoir à copier/renommer les fichier
# créer une vidéo depuis une série d'images
# http://electron.mit.edu/~gsteele/ffmpeg/
mencoder "mf://*.jpg" -mf fps=24 -o ${basenom}_mencoder_b3000.avi -ovc lavc -lavcopts vcodec=msmpeg4v2:vbitrate=3000

mv *avi ..
mv *mkv ..
mv *mp4 ..

# 4. nettoyer
echo "$(date) 4. nettoyage"
rm ${workdir}/liste_jpg.txt
#~ rm -rf ${workdir}/*jpg

# 5. annoncer résultat
echo "$(date) 5. fichier .avi créé dans ${tmpdir}"
echo "$(date) 6. lancer niv pour ouvrir le dossier ${workdir}"
echo "$(date) ----- attention -----"
echo "$(date) grandes dimensions, risque d'image noire sur petits écrans"
echo "$(date) lire les fichiers réduits (1300x970)"
echo nemo ${tmpdir} > /home/pi/Images/images_ciel_et_WC/scripts/niv
chmod +x /home/pi/Images/images_ciel_et_WC/scripts/niv
                        

Raspistill

raspistill_exemples

raspistill est la commande natiuve de prise de photos du raspberry équipé d'une webcam

Documentation fournie

Prendre des photos d'affilée avec deux secondes entre chaque, pendant 30 secondes, soit 15 photos, en annotant avec l'heure, en augmentant la luminosité et le contraste :
raspistill -t 30000 -tl 2000 -o image%04d.jpg -br 40 -co 60 -q 70 -n -w 1280 -h 720 -a 4 -ae 32

Tout-en-un

reflexion

Le but du tout-en-un, un projet dans le projet, est de donner une boîte à un utilisateur, lui dire de brancher l'appareil sur le courant devant le ciel ou le paysage à filmer.
Il n'a rien d'autre à faire.
Le plus simple consisterait à se baser sur l'heure, en prenant les images pendant la période de jour, puis générer et compresser la vidéo la nuit. Au lever du jour suivant, on reprend le même cycle.

PROBLÈME de taille : le raspberry n'a pas de pile RTC (real-time clock), donc il ne sait pas quelle heure il est quand il démarre. C'est grâce au réseau et au protocole NTP qu'il va chercher l'heure qu'il est.

Donc il me faut trouver une solution SIMPLE pour automatiser le processus.
Idée : demander à l'utilisateur à quelle heure il va brancher l'appareil, puis fixer l'heure au démarrage avec la commande date.
Voir Linux - Changer date et heure en ligne de commande Par exemple pour changer la date au 1er septembre 2017 à 09h37 : date 0901093717