BASH: Fotopułapka z Raspberry Pi
11.05.2014 | aktual.: 11.05.2014 20:07
Fotopułpka to urządzenie pozwalające rejestrować obraz tylko w momencie wystąpienia zdarzenia. Może być używane np do obserwacji przyrody, ochrony obiektów (np domki jednorodzinne).
W tym wpisie przedstawię jak zbudować proste urządzenie tego typu w oparciu o Raspberry Pi wraz z modułem kamery rev 1.3, które będzie wykrywać zdarzenia i rejestrować kilkusekundowy film po ich wystąpieniu.
Algorytm całego procesu będzie wyglądać następująco:
- pobierz nowe zdjęcie z kamery
- jeśli istnieje poprzednie, porównaj
- jeśli różnice na zdjęciu przekraczają zadany próg, rozpocznij nagrywanie
- powrót do początku
Przygotowanie karty
Jako podstawy użyjemy dystrybucji Raspian w wersji 2014-01-07 lub nowszej. Na początku należy ją wyczyścić ze zbędnych elementów takich jak środowisko graficzne, przestrzeń wymiany i innych dodatków dostarczonych do dystrybucji. W sumie ponad 1GB, które użyjemy do przechowywania nagrań. Ta część bazuje na artykule Minimalist Raspberry Pi Server Image.
Usuwamy GUI - ok 700MB środowiska graficznego. Podczas tego procesu zostaną usunięte moduły, które doinstalujemy w następnych krokach
sudo apt-get purge xserver.* x11.* xarchiver xauth xkb-data console-setup xinit lightdm lxde.* python-tk python3-tk scratch gtk.* libgtk.* openbox libxt.* lxpanel gnome.* libqt.* libxcb.* libxfont.* lxmenu.* gvfs.* xdg-.* desktop.* tcl.* shared-mime-info penguinspuzzle omxplayer gsfonts sudo apt-get --yes autoremove sudo apt-get upgrade
Usuwamy pakiety dla deweloperów ok 150MB
sudo apt-get purge gcc-4\.[0-5].* sudo apt-get purge `sudo dpkg --get-selections | grep "\-dev" | sed s/install//` gcc-4\.[0-6].* python.* sudo apt-get --yes autoremove
Wyłączamy i usuwamy przestrzeni wymiany ok 100 MB
sudo swapoff -a sudo apt-get purge dphys-swapfile sudo rm /var/swap
Pozostałe dodatki
sudo rm -rf /usr/share/doc/* /opt/vc/src/hello_pi/hello_video/test.h264 /home/pi/python_games find /usr/share/locale/* -maxdepth 0 -type d |grep -v en |xargs sudo rm -rf find /usr/share/man/* -maxdepth 0 -type d |grep -Pv 'man\d' |xargs sudo rm -rf
Instalacja programów
Na początku powinniśmy zaktualizować repozytoria używane przez apt‑get, w przeciwnym razie system pakietów nadal będzie korzystać z wcześniejszych ustawień.
sudo apt-get update
Do porównania obrazu użyjemy programu compare dostępnego w pakiecie ImageMagick. [code=bash]sudo apt‑get install imagemagick[/code]
Aby ograniczyć liczbę zapisanych danych na karcie SD, poszczególne klatki zostaną zmniejszone do rozmiaru 64x64 pikseli i będą zapisane w RAM dysku. Funkcja ta jest dostępna w naszej dystrybucji, dodamy jednie obsługę systemu plików FAT, który umożliwi nam swobodne zaalokowanie dysku o rozmiarze 8MB lub mniejszym.
sudo apt-get install dosfstools
W katalogu /home/pi tworzymy plik ramdisk.sh o następującej zawartości
#!/bin/bash mkfs.vfat /dev/ram1 8192 mkdir -p /ramcache mount /dev/ram1 /ramcache
któremu nadajemy uprawnienia uruchamiania [code=bash]chmod +x ramdisk.sh[/code]
Dodatkowo należy dodać ten plik podczas uruchamiania systemu. Można to wykonać na wiele sposobów, najprościej jednak będzie dopisać go do cron'a:
sudo su echo "@reboot root /home/pi/ramdisk.sh" >> /etc/crontab exit
Wynik, czyli kilkusekundowe nagrania wideo, zostaną umieszczone na serwerze www. Do tego użyjemy programu lighttpd.
sudo apt-get install lighttpd
W podstawowej konfiguracji zawiera stronę powitalną, którą usuniemy
sudo rm /var/www/*.html
a następnie aktywujemy listowanie katalogów, w tym celu edytujemy plik lighttpd.conf
sudo nano /etc/lighttpd/lighttpd.conf
na końcu pliku należy dopisać [code=bash]dir-listing.activate = "enable"[/code]
następnie zamykamy edytor i wykonujemy restart serwera www [code=bash]sudo /etc/init.d/lighttpd restart[/code]
Ponieważ BASH nie pozwala na porównywanie zmiennoprzecinkowe, a takie liczby uzyskamy używając programu compare, musimy doinstalować odpowiednią aplikację:
sudo apt-get install bc
Rejestracja obrazu
Aby pobrać obraz z kamery należy zastosować program raspistill. Z odpowiednimi parametrami pozwoli zmniejszyć plik, a tym samym przyspieszyć operację porównywania. W poniższym przykładzie jest to 64x64 pikseli. Dodatkowo wprowadzone zostało niewielkie opóźnienie 10ms (‑t 10), ponieważ przy niższych parametrach program może ulec zawieszeniu.
raspistill -t 10 -e bmp -o nowyplik.bmp -w 64 -h 64
Porównanie obrazu następuje przez wykonanie programu compare. Pełna specyfikacja tego modułu znajduje się na stronie programu. Użyjemy tylko jednego z podanych tam przykładów:
compare -metric PSNR rose.jpg reconstruct.jpg difference.png
Przy wykonaniu porównania w trybie pomiaru PSNR uzyskamy podobieństwo obrazów wyrażone w dB - im wyższa wartość tym bardziej podobne są do siebie zdjęcia, wynik inf będzie oznaczać nieskończoność (zdjęcia takie same). Jeżeli użyjemy większego obrazka, otrzymamy dokładniejszą wartość, ale spowoduje to, że powstaną większe opóźnienia pomiędzy kolejnymi klatkami. W gotowym programie jako próg ustawiona została wartość 27dB
Jeżeli wartość PSNR będzie mniejsza niż 27dB rozpoczynamy nagrywanie przez program raspivid
raspivid -t 30000 -w 1280 -h 720 -b 1500000 -fps 15 -o /var/www/plik.h264
parametr -t określa czas, po którym program automatycznie się zakończy, w tym przypadku jest to 30 sekund. Parametry -w -h to odpowiednio szerokość i wysokość. Parametr -b to bitrate, w zależności od szybkości karty możemy zmieniać parametry przepływności wideo. Wartość 1500000 odpowiada 1.5Mbps. FPS to liczba klatek na sekundę, a -o plik wynikowy, który w tym przypadku jest umieszczony bezpośrednio w katalogu serwera www. Warto tutaj zaznaczyć, że plik wynikowy to strumień h264 (nie kontener multimedialny). Pliki w tym formacie bez problemu odtworzymy w popularnym VLC.
Po zapętleniu w/w kroków otrzymamy prosty system rejestracji obrazów, wyzwalany w momencie wystąpienia zmiany w obrazie.
Całość w formie programu, wraz z funkcją okresowego czyszczenia karty, wygląda następująco:
#!/bin/bash #wartości początkowe tmpfolder="/ramcache" tmpnewfile="$tmpfolder/newframe.bmp" tmpoldfile="$tmpfolder/oldframe.bmp" tmpdiffile="$tmpfolder/difframe.bmp" outdir="/var/www" # długość materiału wideo, zmienna tt tt="30" ttt="$tt"000 # czyszczenie dysku po przekroczeniu parametru usedspace="95" # funkcje pozyskiwania zdjęć i wideo execphoto="raspistill -t 10 -e bmp -o $tmpnewfile -w 64 -h 64" execvideo="raspivid -t $ttt -w 1280 -h 720 -b 1500000 -fps 15 -o " #usuń stare pliki rm $tmpnewfile rm $tmpoldfile rm $tmpdiffile #zamknij wszystkie procesy odpowiadające za kamerę killall -9 raspivid killall -9 raspistill clean_disk() { # zajętość procentowa dysku used=`df -h | grep rootfs | while read a b c d e f; do echo $e | sed "s/%//"; done` # jeśli większa od zadeklarowanej stałej check=`echo "$used>$usedspace" | bc` if [ "$check" == "1" ]; then # usuń najstarsze ls -1 -tr $outdir | head -10 | while read fn; do rm $outdir/$fn done fi } # pętla nieskończona while true; do eval $execphoto # jeśli nie było wcześniej obrazu, to skopiuj nowy jako stary # a wynikiem porównania będzie "inf" if [ ! -f $tmpoldfile ]; then cp $tmpnewfile $tmpoldfile fi img=`compare -metric PSNR $tmpnewfile $tmpoldfile $tmpdiffile 2>&1` # jeśli te same obrazy if [ "$img" == "inf" ]; then img='100' fi # w bashu nie ma możliwości sprawdzenia liczb zmiennoprzecinkowych img=`echo "$img<27" | bc` if [ "$img" == "1" ]; then dt=`date +%Y-%m-%d-%H-%M-%S` cp $tmpnewfile $outdir/$dt.bmp eval "$execvideo $outdir/$dt.h264" # pobierz nowa klatkę, ponieważ w czasie tt mogło coś się zmienić eval $execphoto clean_disk fi mv $tmpnewfile $tmpoldfile done
Powyższy kod możemy umieścić w pliku, który dodajemy do uruchamiania przy starcie. Przy każdym uruchomieniu naszego Raspberry Pi rozpocznie się nagrywanie.