2020-04-15


Zeitraffer Aufnahmen mit dem Banana PI


Ich wollte dieses Jahr eine längere Zeitraffer-Aufnahme aus meinem Küchenfenster machen, um nach ca. 1 1/2 Monaten den Blattwuchs der Bäume auf Video zu haben (sehr spannend Ich weiß).

Komponenten

Was braucht man denn dafür alles:

  • Einen Rechner

Ich habe meinen altbewährten Bananapi benutzt, da er eh immer an ist, und nur sehr wenig Strom zieht. Als Speicherplatz habe ich eine externe SSD verwendet.

  • Eine Webcam

Logitech C920, einfach weil Ich sie als einzige Webcam besitze.

  • Die passende Software
    • Linux als OS
    • fswebcam als Capture Software (gibts im Debian Repo)
    • cron um automatisiert ein Script aufzurufen, um periodisch Bilder zu machen

Setup

Der Aufbau ging super einfach von statten, die Webcam einfach per USB an den PI, selbiges mit der SSD. Dateisystem mounten, kleines Script schreiben, welches fswebcam parametrisiert startet, und dieses mit cron starten.

Ergebnis:

ja mist

Mit den automatischen Settings der Cam lässt sich über einen längeren Zeitraum also nicht arbeiten.

Zum Glück implementiert fswebcam jedoch eine Schnittstelle, mit der sich die Belichtungszeit, der Autofokus und ähnliches einstellen lassen können.

Dies ist auch wichtig, da die Kamera sich sehr schnell von Wolken, der Dämmerung und ähnliches aus dem Tritt bringen lässt. Mit den richtigen Settings lassen sich auf jeden Fall qualitativ wesentlich bessere und konsitentere Bilder aufnehmen lassen.

Beispiele:

  • --set 'Focus (absolute)=1'
  • --set Focus,\ Auto=false

Stellt den Autofokus ab und fokussiert auf unendlich.

  • --set 'Exposure (Absolute)'=3

Setzt die Belichtungszeit auf das absolute Mininum der Kamera, da bei Tageslich das Bild sonst sofort überbelichtet ist.

  • --set 'Exposure, Auto Priority'=True
  • --set 'Backlight Compensation'=0

Bei den beiden Settings habe ich noch nicht genau herausgefunden, was sie genau bezwecken, sie behalfen mir aber so zu weniger überbelichteten Bildern.

Probleme Probleme Probleme

So, die Kamera ist eingestellt, das Script angepasst, die Kamera macht im Abstand von 30 Minuten ein Bild. Dann warten wir mal ab ....

-.-

Anscheinend mag mich die Kamera nicht, manche Bilder sehen so aus, selbst mit den unempfindlichsten Einstellungen, aber warum?

Stößt man das Script sekunden später manuell an, ist das Bild wieder "normal". Wir brauchen anscheinend eine:

Belichtungsprüfung

Diesen Trick habe ich hier gefunden und etwas angepasst. Durch Imagemagick, ein Bildbearbeitungs-Tool, kann man durch eine einfache Formel herausfinden, ob ein Foto überbelichtet ist.

Durch Imagemagick kann man ua. zwei Werte auslesen:

  • Die Standard Abweichung
  • Und den Durchschnitt

Im Post wird erklärt, dass ein Überbelichtetes Bild einen hohen Durchschnittswert, und eine geringe Standardabweichung hat, da das komplette Bild annähernd weiß ist.

Deshalb habe ich mein Script so erweitert, dass nach jedem Foto beide Werte ermittelt werden, und dann den Durchschnitt durch die Standardabweichung teile:

Wenn ein Bild sehr überbelichtet ist, wird ein höhrer Wert errechnet, da der Dividend sehr groß und der Divisor sehr klein ist.


mean=$(convert $1 -format "%[mean]" info:)
dev=$(convert $1 -format "%[standard_deviation]" info:)

exposure=$(echo "$mean / $dev" | bc )   

Dann habe ich Stichartig "normale", überbelichtete und unterbelichtete Bilder getestet, und die Grenze definiert:

0 < Unterbelichtet/Normal <= 2 < Überbelichtet

Wenn ein Bild überbelichtet ist, wird von der Webcam bis zu 5 weitere Bilder aufgenommen, wenn eins davon dann nicht mehr überbelichtet ist, stoppt es.

Ich habe leider noch nicht herausgefunden, warum die Kamera manchmal falsch belichtet, aber der "Fix" ist sogar sehr robust, und ich habe deutlich weniger überbelichtete Bilder, ich musste nur die Grenze nach ca. 4 Wochen von 3 auf 2 absenken, da viele Bilder immer noch zu hell waren.

Beispiel:

bananapi@x:~$ ./webcampic
Calculating overexposure for /mnt/daten/syncthing/media/webcam/1587623395.jpg
Exposure rate: 1462
Overexposed
Calculating overexposure for /mnt/daten/syncthing/media/webcam/1587623395.jpg
Exposure rate: 2
Not overexposed

Mit USB Kernel Parametern die Kamera retten

Die Überbelichtung war jedoch nicht das einzige Problem, dazu kam das hier:

Device or resource busy

Nach einiger Zeit konnte das Script nicht mehr auf die Kamera zugreifen, es sind mir einige Tage entgangen, da ich zuerst keine Notifications in mein Script eingebaut habe, und immer dachte, dass der Switch Probleme machen würde, und ein tauschen des USB-Kabels das Problem beheben würde.

Nach kurzer Recherche im Internet schien ich aber nicht der Einzige mit dem Problem zu sein, und die Lösung schien so schön und einfach:

dwc_otg.fiq_fsm_mask=0x3
/boot/boot.scr

Dieser Kernel-Parameter macht magische Dinge, und behebt das Problem.

Ich weiß nicht was es bezweckt, Ich weiß nur, dass es irgendwas mit dem USB-Treiber anstellt, mehr nicht. Aber es tut, dass das Problem nicht mehr auftritt. Ich habe noch versucht etwas zu recherchieren, bin aber nicht wirklich schlauer geworden.

Und nach den 2 Problemen, die einige Bilder gekostet haben, läuft es nun seit mehren Wochen problemlos. Jetzt muss ich nur noch warten, bis alle Blätter gewachsen sind, damit ich dann mit

ffmpeg -framerate 30 -pattern_type glob -i '*.jpg' \
  -c:v libx264 -r 30 -pix_fmt yuv420p test.mp4

Den Film erstellen kann.

Script

#!/bin/bash

filename=/mnt/daten/syncthing/media/webcam/$(/bin/date +%s).jpg

function takePicture {
	/usr/bin/fswebcam \
		-r 1920x1080 \
		--set 'Focus (absolute)=1' \
		--set Focus,\ Auto=false \
		--set 'Exposure (Absolute)'=3 \
		--set 'Exposure, Auto Priority'=True \
		--set 'Backlight Compensation'=0 \
		--no-underlay \
		--no-timestamp \
		--no-banner \
		$filename \
		2>&1 | grep "busy"

	if [ $? -eq 0 ]; then
		telegram-send --config /home/bananapi/network_bot_config "Error while taking image"
		exit
	fi

	#filesize=$(ls -la $filename  | awk '{ print $5 }')

	calcOverexposure $filename
	if [ $? -eq 1 ]; then
		return 1
	fi


	#if (( $filesize < 500000 )); then
#		echo "File too small"
#		return 1
#	fi

}	

calcOverexposure() {
	echo "Calculating overexposure for $1"
	sleep 0.5
	mean=$(convert $1 -format "%[mean]" info:)
	dev=$(convert $1 -format "%[standard_deviation]" info:)

	exposure=$(echo "$mean / $dev" | bc )

	echo "Exposure rate: $exposure"
	
	if [ $exposure -gt 2 ]; then
		echo "Overexposed"
		return 1
	else
		echo "Not overexposed"
		return 0
	fi
}

n=0

until [ $n -ge 5 ]
do
	takePicture && exit 0
	n=$[$n+1]
	sleep 1
done	

telegram-send --config /home/bananapi/network_bot_config "overexposed image: $exposure"