Wykrywanie ruchu kamerą internetową i Raspberry Pi
Nov 5, 2016 · 3 minute read · CommentsZagadnienia zdjęć i wideo w kontekście Raspberry Pi kojarzą się zwykle z modułem wideo dostępnym dla Malinki. Jest to kawałek płytki z optyką, którą wpina się taśmą bezpośrednio w płytę komputera. Moduł kamery nie zawsze jest pod ręką, a poza tym bywa drogi.
Dziś pokażę jak zdziałać małe co nieco używając taniej kamerki USB i Raspberry Pi.
Postanowiłem nie skupiać się jedynie na podłączeniu kamery i udowodnieniu, że działa. Spróbowałem użyć ją do czegoś konkretniejszego. A poniżej wynik prac :).
Czego będziemy potrzebować
Oto zestaw sprzętu:
- Raspberry Pi
- Kamera USB (ja użyłem HP Webcam HD 2300). Listę kompatybilnych kamer można znaleźć pod tym linkiem.
- karta microsd z wgranym Raspbianem
- jakieś połączenie z internetem
Software
Łączymy wszystko razem, uruchamiamy i instalujemy odpowiedni soft:
sudo apt-get install fswebcam
Przy okazji sprawdzamy, jaką nazwę dostała nasza kamera w systemie:
ls /dev
U mnie kamera po podłączeniu pokazała się jako video0
.
Pierwsze zdjęcia
Mamy już wszystko na miejscu, więc możemy przystąpić do testów.
Wykonanie pierwszego zdjęcia może wyglądać tak:
fswebcam --device /dev/video0 --resolution 1280x800 --no-banner capture.jpg
Opcje według kolejności to: nazwa urządzenia, rozdzielczość, wyłączenie winiety z podpisem i nazwa pliku, do którego będziemy zapisywać wykonane zdjęcie.
Ot i cała filozofia - zdjęcie może wyglądać tak:
Krok dalej
Skoro działa, to możemy zająć się czymś zdecydowanie ciekawszym :).
Napiszmy program, który będzie zapisywał zdjęcie wtedy, kiedy kamera wykryje ruch. Ciekawe zagadnienie. Oto program, a poniżej omówienie:
# -*- coding: utf-8 -*-
import StringIO
from datetime import datetime
import subprocess
from PIL import Image
DEVICE = "/dev/video0"
THRESHOLD = 30
SENSITIVITY = 320
MIN_WIDTH, MIN_HEIGHT = 160, 120
WIDTH, HEIGHT = 1280, 720
def get_test_image():
command = "fswebcam --quiet --device %s --no-banner --resolution %sx%s -" % (
DEVICE, MIN_WIDTH, MIN_HEIGHT)
img_data = StringIO.StringIO()
img_data.write(subprocess.check_output(command, shell=True))
img_data.seek(0)
img = Image.open(img_data)
buffer = img.load()
img_data.close()
return buffer
def save_image():
time = datetime.now()
filename = "capture-%04d%02d%02d-%02d:%02d:%02d:%02d.jpg" % (
time.year, time.month, time.day, time.hour, time.minute, time.second, time.microsecond)
subprocess.call(
"fswebcam --quiet --device %s --no-banner --resolution %sx%s %s" % (DEVICE, WIDTH, HEIGHT, filename), shell=True)
print("Captured %s" % filename)
def check_distance(x, y):
pixdiff = abs(x - y)
if pixdiff > THRESHOLD:
return True
return False
class ImageCaptured(Exception):
pass
buffer_prev = get_test_image()
while(True):
buffer_current = get_test_image()
try:
changed_pixels = 0
for x in xrange(0, MIN_WIDTH):
for y in xrange(0, MIN_HEIGHT):
if check_distance(buffer_prev[x, y][1], buffer_current[x, y][1]):
changed_pixels += 1
if changed_pixels > SENSITIVITY:
save_image()
raise ImageCaptured
except ImageCaptured:
pass
buffer_prev = buffer_current
Kod można podzielić na trzy fazy.
Pierwsza faza, to pobieranie małego zdjęcia i porównanie go z poprzednio pobranym małym zdjęciem. W moim przypadku najmniejszy rozmiar jaki udało mi się wymusić to 160 na 120 pikseli, ale możecie operować na jeszcze mniejszych..
Druga faza, to sprawdzenie na ile obecne zdjęcie różni się od poprzedniego. Robimy to licząc różnicę nasycenia koloru zielonego, odpowiadających sobie punktów w obu zdjęciach (można użyć innych kolorów lub wykonać obliczenia dla wszystkich składowych). Jeśli różnica wynosi więcej niż THRESHOLD
(w moim wypadku 30), to inkrementujemy licznik zmienionych pikseli changed_pixels
. Jeśli przekroczony został poziom SENSITIVITY
(w moim przypadku 320 różnych pikseli), to przechodzimy do fazy trzeciej.
Faza trzecia, to zrobienie dużego zdjęcia, zapisanie go i rzucenie wyjątkiem (żeby nie kontynuować dalszego liczenia).
Po wszystkim następuje powrót do fazy pierwszej.
Takim to w miarę prostym sposobem możemy zyskać fajny mechanizm rejestrujący reagujący na ruch.
W niektórych wypadkach potrzebne będzie zwiększenie lub zmniejszenie wartości THRESHOLD
i/lub SENSITIVITY
, żeby kamera łapała zdjęcia dokładnie wtedy kiedy potrzebujemy.
Wartości ustalone przeze mnie pozwoliły rejestrować ruch na chodniku i parkingu przed moim domem.
Zakończenie
Nie zawsze potrzeba dedykowanych modułów do zadań które chcemy osiągnąć. Kamerka HP kosztowała około 40zł i w zupełności wystarcza do zadania, które przed nią stawiam :).