Webcam am Linux-Rechner


von Prof. Jürgen Plate, Michael Prechtl

Webcam am Linux-Rechner

Eigentlich muss man zwei Sorten von Kameras unterscheiden: die extrem preiswerten und einfachen USB-Webcams, die direkt am PC angeschlossen werden, und die nicht so billigen Netzwerkkameras, die per Twisted-Pair-Kabel am Netz angeschlossen werden und ihren eigenen kleinen Webserver enthalten. Begonnen wird mit den preiswerten USB-Kameras, die Netzwerk-Kameras folgen weiter unten. Wer sich für die Kamera des Raspberry Pi interessiert, findet spezielle Infos dazu bei den Infos zum RasPi.

USB-Webcams

Für die USB-Kameras gilt Ähnliches wie für die TV-Karten: Vor der Nutzung müssen die entsprechenden Treiber eingebunden werden. Bei Linux sind das die Video4Linux-Treiber, kurz V4L2). Da benötigt man für unterschiedliche Kameramodelle auch unterschiedliche Kernel-Module. Deshalb informieren Sie sich vor dem Kauf im WWW, ob die jeweilige Kamera unterstützt wird. Ich werde an dieser Stelle nur einige prinzipielle Anmerkungen machen. Neben den USB-Modulen (usbcore, usb-uhci, usb-ohci), die fast immer schon laufen, braucht man noch das Input-Modul (input) und Video for Linux 2 (videodev). Dann wird noch das Kernel-Modul zur Kamera benötigt (ibmcam, cpia\_usb, ov511, dc2xx etc.). Durch die Module werden die entsprechenden Einträge im Device-Verzeichnis in der Regel automatisch erzeugt, meist ist es /dev/video0. Manch Linux-Urgestein wird sich noch an das Treiber-Theater mit proprietären CD-ROM-Laufwerken und später mit Scannern erinnern. Ähnliches Ungemach gab es Anfangs mit den Webcams und teilweise gibt es immer noch Kameras, bei denen zusätzliche Treiber nötig sind. Aber der Markt bei USB-Webcams ist so gross, dass man sich das nicht antun muss.

Nun fehlt nur noch die entsprechende Software, um die Devices nutzen zu können. Hat man Debian, Ubuntu oder Mint und eine Webcam, dann kann man mit einfachen Mitteln Snapshots oder Streams von der Kamera holen. Das gilt auch für den Raspberry Pi, sofern die Kamera unterstützt wird. Generell sollte man wie folgt vorgehen.

USB-Webcam testen

Suchen Sie sich eine Webcam aus, die möglichst ohne langes Gefrickel mit irgendwelchen Treibern läuft. Zur Identifikation der von der Webcam verwendeten Treiber schließt man diese am Besten an einen PC/Laptop mit Linux an. Nach dem Einstecken der Kamera können mittels lsusb oder dmesg einige nützliche Informationen geholt werden. Eine Ausgabe von dmesg sieht dann auszugsweise so aus:
# dmesg
   ...
[   12.621009] Linux video capture interface: v2.00
[   12.685253] uvcvideo: Found UVC 1.00 device USB 2.0 Camera (0c45:6340)
[   12.712522] input: USB 2.0 Camera as /devices/pci0000:00/0000:00:1d.7/usb1/1-1/1-1:1.0/input/input8
[   12.713513] uvcvideo: Found UVC 1.00 device HD 720P Webcam (0603:8f01)
[   12.718307] input: HD 720P Webcam as /devices/pci0000:00/0000:00:1d.7/usb1/1-4/1-4:1.0/input/input9
[   12.718700] usbcore: registered new interface driver uvcvideo
[   12.718709] USB Video Class driver (1.1.1)
   ...
In unserem Fall sind es zwar zwei verschiedene Kameras, aber bei beiden der Treiber uvcvideo. Falls der Befehl dmesg keine derartige Meldung zeigt, kann man mittels lsmod die Liste aller geladenen Module ansehen und dort den zu der Webcam passenden Treiber herausfinden. Dazu die Webcam abstecken, lsmod aufrufen und die Ausgabe ansehen. Dann die Webcam anstecken und nochmals lsmod aufrufen. Das neu aufgetauchte Modul ist der Treiber der Webcam.

Achtung: Falls man einen Laptop mit eingebauter Webcam besitzt sind eventuell zwei Module für Webcams geladen (außer interne und externe Webcam haben den gleiche Chipsatz).

Sieht man etwas Änliches wie oben, kann man zufrieden sein (insbesondere scheint UVC inzwischen zuverlässig zu funktionieren - und es wird kein spezieller Treiber benötigt). Es wird eine Kamera erkannt und über input0 angebunden. Das trifft inzwischen auf eine ganze Reihe von Modellen zu. Normalerweise wird auch das Device /dev/video0 (bzw. /dev/video1 ...) installiert, über das die Kamera angesprochen wird. Zur Sicherheit (oder etwa vor einem Kauf) sollte man den Namen der Webcam googeln und nachsehen, ob in den techischen Daten etwas von UVC steht.

Foto mit der USB-Webcam aufnehmen

Ist die Webcam soweit in Ordnung, kann man schon einen Versuch wagen, fswebcam und zwei Bildbetrachter, gpicview für X und fbi für die Console, zu installieren und probeweise ein Bild einzufangen. Bei Debian Linux und dessen Abkömmlingen geht das ohne besonderen Aufwand:
apt-get install fswebcam gpicview fbi
fswebcam -v -r "640×480" test.jpg
gpicview test.jpg
Im Beispiel entsteht ein Bild namens test.jpg im aktuellen Verzeichnis und wird anschliessend angesehen (640x480 Pixel sollte jede Kamera können). Hat der Rechner keinen X-Server laufen und kein grafisches Interface, dann kann das Bild mit dem "Frame Buffer Imager" fbi betrachtet werden:
fbi test.jpg
Letzteres geht natürlich nur auf einer realen Console am Rechner und nicht über eine ssh-Verbindung o. ä.

Unterstützt das Gerät V4L/V4L2 und eben UVC, so gibt es eine Reihe von weiteren Tools für die Weiterverarbeitung der Bilder, z. B. das motion-Paket oder auch luvcview. Mein aktuelles Projekt überträgt nur Einzelbilder zu bestimmten Zeiten (ffmpeg fuer einen Stream wird daher nicht benötigt).

Das eingesetzte Tool fswebcam ist ein kleines und ausgefeiltes Webcam-Programm. Es kann eine Anzahl von Frames von den meisten Geräten lesen, die V4L2-kompatibel sind, deren Mittelwert bilden, um das Rauschen zu reduzieren, und einen Titel auf das Resultat zeichnen. Dazu wird die Grafikbibliothek GD verwendet, die auch die Kompression des Bildes in PNG oder JPEG vornimmt. Letztere ist bei den meisten Distributionen per default installiert, sonst muss man sie nachinstallieren. Homepage: http://www.firestorm.cx/fswebcam/.

Für die Snapshots kann eine Reihe von Einstellungen gesetzt werden. Bei einer Kamera für Aussenaufnahmen können auch proprietäre Parameter der Kamera mittels -s-Option durchgereicht werden (siehe unten). Für Innenaufnahmen ist die Parameterzahl überschaubarer, ein Aufruf könnte lauten:

fswebcam -v -S 5 -F 2 -r "1280x720" –d /dev/video0 –-no-banner snap.jpg
Die Optionen des Befehls sind relativ einfach erklärt:
-v  	"verbose mode": bietet eine detailiertere Ausgabe
-F 2  2 Frames speichern
-S 5	5 Frames überspringen und erst die folgenden speichern
        (die Kameras müssen oft erst "einrasten")
-r  	legt die Auflösung des Bildes fest, in unserem Fall HD 1280 x 720 Pixel
-d  	gibt an welches Device verwendet werden soll, in unserem Fall /dev/video0
Zum Schluss wird noch angegeben wie das aufgenommene Bild heißen soll.

Zur S-Option sei noch bemerkt, dass die ersten vorbeisausenden Frames manchmal nicht akzeptabel sind, da eine kurz zuvor eingestellte Kameraempfindlichkeit noch nicht gegriffen hat. Deswegen ist es sinnvoll, eine Frames zu überspringen. Man kann auch noch mittels -D n eine Wartezeit von n Sekunden einschieben.

Hinweis: Wenn die Auflösung nicht mithilfe der Option -r manuell eingestellt wird, nimmt das Programm die Standardauflösung (meistens nicht die optimale Auflösung). In der Regel beträgt die Standardauflösung 352 x 288 Pixel. Man erhält aber viel bessere Bilder wenn man als Auflösung z. B. 800 x 600 Pixel angibt. Oft ist aber auch die maximal mögliche Auflösung (z. B. 1200 x 1600) auch nicht optimal und man fährt mit einer etwas geringeren Auflösung besser.

fswebcam kann fast alles selbst, man muss es nur konfigurieren. Dazu gehört beispielsweise auch das Einfangen eines Bildes in regelmäßigen Zeitabständen. Persönlich neige ich jedoch dazu, solche Aufgaben dem cron-Dämon zu überlassen. Interessant ist u. a. die Möglichkeit, das Bild automatisch mit einer Beschriftung am unteren oder oberen Rand zu versehen, wobei Hintergrund- und Schriftfarbe, Transparenz, Schriftgröße usw. frei wählbar sind. Standardmäßig erfolgt die Beschriftung am unteren Bildrand. Folgende Optionen sind möglich:

--title "xxx"        Titel (1. Zeile links)
--subtitle "xxx"     Untertitel (2. Zeile links)
--timestamp "xxx"    Datum/Uhrzeit (1. Zeile rechts), z. B. "%d.%m.%Y %H:%M"
--info "xxx"         Zusatzinfo (2. Zeile rechts)
Die Timestamp-Option beherrscht alle Formen der Zeitformatierung, die von der Funktion strftime() unterstützt werden. Wenn kein Font gefunden wird (Fehlermeldung von fswebcam) muss der Pfad zu einem Font angegeben werden, z. B.:
--font "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSansMono-Bold.ttf:12"

Die Option --flip <richtung[,richtung]> erlaubt das (h)orizontale oder (v)ertikale Spiegeln des Bildes (etwa bei Deckenmontage der Kamera). Zum Beispiel --flip v oder --flip h,v. --rotate www rotiert das Bild um den angegebenen Winkel www, wobei nur die Werte 90, 180 und 270 möglich sind.

--crop <groesse[,offset]> erlaubt das Herstellen von Bildausschnitten. Beide Angaben erfolgen in der Form BxH (Breite mal Höhe). So extrahiert --crop 320x240 einen zentralen Ausschnitt von 320x240 Pixel Größe. --crop 100x100,0x0 produziert dagegen einen 100 x 100 Pixel großen Ausschnitt der linken oberen Ecke.

Mittels --scale <groesse> kann das Bild auf die angegebene Größe skaliert werden. Die Angabe erfolgt wieder in der Form BxH (Breite mal Höhe), z. B. --scale 640x480.

Weitere Optionen sind in der ausführlichen Manual-Page des Programms aufgeführt.

Damit die Kommandozeile nicht zu unübersichtlich wird, kann diese aufgeteilt werden, wie folgendes Beispiel zeigt (Achtung: Nach dem '\' muss das Zeilenende kommen; kein weiteres Zeichen!):

fswebcam -D 3 -S 10 -F 10 -r 1280x720 -d /dev/video0 \
  --font "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSansMono-Bold.ttf:12" \
  --title "Kamera 1" --subtitle "http://www.netzmafia.de" \
  --timestamp "%d.%m.%Y %H:%M" --info "Zusatzinfo" $FILE
Für Titel, Untertitel, Info etc. könne auch variable Werte verwendet werden, beispielsweise durch Übergabe in Shell-Variablen. Wenn es keine variablen Parameter gibt, die sich bei jedem Aufruf ändern, kann die gesamte Konfiguration auch in einer Datei untergebracht werden, was den Aufruf auf der Kommandozeile entsprechend verkürzt.

Controls der USB-Webcam ermitteln

fswebcam erlaubt auch die Abfrage der Kamera in Hinblick auf die Möglichkeit, kameraspezifische Steuerungsvariablen wie Kontrast oder Helligkeit zu ändern. mit dem Parameter --list-controls werden alle proprietären Werte abgefragt, die der Treiber verarbeiten kann. Das folgende Beispiellisting zeigt die Abfrage zweier Kameras, eine "Logilink UA0155" und eine "HAMA Digital Eye II".
fswebcam -d /dev/video0 --list-controls

--- Opening /dev/video0...
Trying source module v4l2...
/dev/video0 opened.
No input was specified, using the first.
Available Controls        Current Value   Range
------------------        -------------   -----
Brightness                10 (57%)        -64 - 64
Contrast                  21 (32%)        0 - 64
Saturation                64 (49%)        1 - 128
Hue                       0 (50%)         -40 - 40
Gamma                     72 (0%)         72 - 500
Gain                      0 (0%)          0 - 100
Power Line Frequency      50 Hz           Disabled | 50 Hz | 60 Hz
Sharpness                 4               0 - 6
Backlight Compensation    1               0 - 2
Adjusting resolution from 384x288 to 352x288.
--- Capturing frame...
Captured frame in 0.00 seconds.
--- Processing captured image...
There are unsaved changes to the image.

fswebcam -d /dev/video1 --list-controls

--- Opening /dev/video1...
Trying source module v4l2...
/dev/video1 opened.
No input was specified, using the first.
Available Controls        Current Value   Range
------------------        -------------   -----
Brightness                -128 (0%)       -128 - 127
Contrast                  124 (32%)       60 - 255
Saturation                70 (35%)        0 - 200
Hue                       5 (52%)         -128 - 127
White Balance Temperature, Auto True            True | False
Gamma                     9               0 - 10
Power Line Frequency      50 Hz           Disabled | 50 Hz | 60 Hz
White Balance Temperature 4500 (45%)      2800 - 6500
Sharpness                 150 (75%)       0 - 200
Backlight Compensation    6               0 - 10
Adjusting resolution from 384x288 to 432x240.
--- Capturing frame...
Captured frame in 0.00 seconds.
--- Processing captured image...
There are unsaved changes to the image.
Man sieht schon im Vergleich, dass die numerische Spannweite sehr unterschiedlich ist (z. B. reicht die Helligkeit bei der "UA0155" von -64 bis +64, bei der "Digital Eye II" jedoch von -128 bis +127).

Um der Gefahr zu entgehen, gegebenenfalls falsche Werte zu übergeben, erlaubt fswebcam in jedem Fall auch Prozentangaben. Wird z. B. die Helligkeit mit 20% angegeben, rechnet das Programm den entsprechenden Zahlenwert aus (gerundet auf ganze Zahlen). die 20% ergäben dann -51 (UA0155) oder -77 (Digital Eye II).

Die Einstellung erfolgt über den Parameter -s und immer in der Form "Bezeichnung=Wert", zum Beispiel:

   ...
  -s "Backlight Compensation=75%" \
  -s "Brightness=35%" \
  -s "Contrast=45%" \
   ...

Getestet wurden noch zwei weitere Kameras: Die Logitech C270 USB Webcam und die Microsoft LifeCam HD-3000. Beide Kameras liefen sofort unter Linux, obwohl in den technischen Daten (wie üblich) immer nur Windows als Betriebssystem angegeben war. Beide Kameras haben HD-Auflösung (1280 x 720 Pixel) und ein integriertes Mikrofon mit Rauschunterdrückung. Die Logitech C270 erlaubt daneben noch Fotos, die per Software-Interpolation etwa einer 3-Megapixel-Kamera entsprechen (Windows-Software-Version). Beim Capturen von Bildern meldete fswebcam zwar eine kleine Unsauberkeit bei den angelieferten Daten, konnte aber ein korrektes JPG-Bild abspeichern. Bei schwacher Beleuchtung wirken die Bilder aber etwas flau.


Die Die Logitech C270 USB Webcam (links) und die Microsoft LifeCam HD-3000 (rechts).

Eine Überraschung bot die Microsoft LifeCam HD-3000. Abgesehen davon, dass sie unter Linux das gewünschte leistete, lieferte sie auch noch die besten Bilder von allen vier USB-Kameras. Außerdem kann sie auch noch 16:9-Breitbildformat für Videoaufzeichnungen im Kinoformat. Des Weiteren darf jegliche Helligkeitsanpassung entfallen, denn die sogenannte TrueColor-Technologie sorgt automatisch für kräftige Farben bei nahezu allen Lichtverhältnissen. Die Software-Interpolation entspricht bei der HD-300 sogar einer 4-Megapixel-Kamera. Insgesamt eine angenehme Überraschung.

Netzwerk-Webcams

Bisher war nur von USB-Webcams die Rede. Die oben beschriebenen Methoden lassen sich nahezu ohne Änderung auch auf Kameras anwenden, die über Netzwerkkabel oder WLAN erreichbar sind. Eine Netzwerk-Kamera liefert ebenfalls Einzelbilder oder Videoströme. Der Vorteil solcher Kameras besteht einerseits darin, dass die Kamera an einer beliebigen Stelle im Netz stehen kann und nicht an die Nähe eines Rechners gebunden ist. Andererseits werden bereits fertige JPG-Bilder oder MPEG-Videoströme über ein Webinterface geliefert, man hat also keinerlei Treiberprobleme. Nachteilig ist der wesentlich höhere Preis der Kameras (etwa das Drei- bis Vierfache einer guten USB-Kamera). Auch der Energiebedarf (Stromaufnahme) ist beträchtlich höher als bei USB-Kameras - schließlich birgt die Kamera in der Regel einen kompletten Computer. Für meine Tests habe ich vier Kameras verwendet: eine ältere "Axis 207", die in vielen Bereichen schon einen Standard darstellte, aber heute von der Bildauflösung her nicht mehr up-to-date ist (aber gerade zur Verfügung stand), die "Trendnet TV-IP100", die vor Jahren recht preiswert angeboten wird, die ebenfalls recht preiswerte Logilink WC0040 und die "Grandtec Megapixel IP Camera", die eine hohe Bildauflösung liefert. Informationen zu den Kameras finden Sie unter:

www.axis.com/products/
www.trendnet.com/products/
www.logilink.eu/showproduct/WC0040.htm
www.grand.com.tw/sur_mega_pixel.php

Die ersten drei Kameras liefern ein Farbbild von maximal 640 x 480 Pixeln (sind also nicht mehr die neuesten Modelle), die Grandtech schafft 1280 x 1024 Pixel. An dieser Stelle kommt es jedoch nicht so sehr auf die Auflösung oder andere Kameraeigenschaften an, sondern die vier Modelle sollen einfach die Möglichkeiten illustrieren, wie auf solche Kameras zugegriffen wird. Oft lassen sich die Methoden dann auf andere Modelle übertragen.

Über ein Webinterface oder ein mitgeliefertes Windows-Tool sind nicht nur der Videostrom oder Einzelbilder abrufbar, sondern es lassen sich auch beliebige Einstellungen vornehmen. Bei Inbetriebnahme muss die Kamera zunächst eine IP-Adresse erhalten. Bei der Gelegenheit kann man auch gleich die anderen Grundeinstellungen vornehmen. Dabei sollten die Kameras selbst nie direkt "von aussen" erreichbar sein, sondern deren Bilder über einen lokalen Webserver gefiltert werden. Beim Abgreifen der Bilder wird die Kamera natürlich über das Netzwerk angesprochen. Zum Herunterladen der Bilder können auf der Kommandozeile die Programme wget oder curl verwendet werden.

Die Axis-Kamera hat ein Fixfocus-Objektiv, bei den anderen muss man die Schärfe manuell regulieren.

Bei der Trendnet TV-IP100 war etwas Forschungsarbeit nötig, da per Default das Abliefern der Bilder nur per E-Mail oder FTP offeriert wird. Es ging dann doch recht einfach: beim Browser wird Ansicht → Seitenquelltext aufgerufen und im HTML-Wust nach einem IMG-Tag gesucht. Es präsentiert sich hübsch verpackt in einer Tabelle, aber mit etwas seltsamer Dateiangabe, z. B:

<IMG SRC="IMAGE.JPG?cidx=2009117184335312242" BORDER="0">
Der Schwanz "?cidx=200911..." ist eigentlich unnötig, es handelt sich um einen Trick der Kamerasoftware, um die Browser auszutricksen: da die Webseite immer gleich aussieht, würde ein schlauer Browser beim Klicken auf "Reload" nicht das aktuelle Bild der Kamera abrufen, sondern das im Browser-Cache befindliche abliefern. Durch das Anhängen einer Pseudo-Formulareingabe mit sich ständig ändernden Werten wird dafür gesorgt, dass immer das aktuelle Bild geholt wird. Bei der Trendnet TV-IP100 erhält man bei folgendem Aufruf ein Bild und nichts sonst:
curl -o snap.jpg http://192.168.2.100/IMAGE.JPG

Bei der Logilink WC0040 funktioniert der Abruf eines Standbildes genauso einfach, im Beispiel mit User- und Passwortangabe:

curl -o snap.jpg http://user:pass@192.168.2.102/snapshot.jpg
Ähnlich einfach kann hier übrigens auch eim MPEG-Stream abgerufen werden.

Die Axis-Kamera macht etwas Ähnliches wie die Trendnet. Sie liefert das Bild scheinbar über ein CGI-Script aus, was ebenfalls dafür sorgt, dass sich der Browser immer ein frisches Bild holt. Bei der Axis 207 können Parameter wie Helligkeit, Bildgröße usw. mitgegeben werden. Im folgenden Beispiel gebe ich die Bildgröße vor:

curl -o snap.jpg http://192.168.2.101/axis-cgi/jpg/image.cgi?resolution=640x480
Es steht zwar nicht im Handbuch, aber wenn man nur ein Bild ohne Einstellungen will, genügt auch:
curl -o snap.jpg http://192.168.2.101/axis-cgi/jpg/image.jpg
(Für Video verwenden Sie stattdessen .../mjpg/video.mjpg.)

Die "Grandtec Megapixel IP Camera" sträubte sich hingegen etwas, obwohl die Reklame ausdrücklich auch die Linux-Kompatibilität aufführte. Deren Windows-Software (zu Linux gab's nix) kommt mit massenhaft Active X und dererlei Gefickel. Etwas Forschungsarbeit liess aber den Verdacht aufkommen, dass bei der Kamera "unter der Haube" ein ARM-Linux werkelte - wenn auch mit gewöhnungsbedingtem Interface.

Jedenfalls fand sich innerhalb des Mini-Werservers, der auf der Kamera lief, auch ein Verzeichnis namens /cgi-bin mit einigen vielversprechenden Kommandos. Leider zeigte sich, dass auch ein Kommando namens still.cgi keineswegs ein Standbild lieferte, sondern einen MJPEG-Stream. Immerhin ohne Active X oder anderen Dingen, aber mit Abfrage von Username (immer "root") und Passwort. Darauf ließ sich aufbauen. Mit dem Programm curl (oder auch wget) kann das Video geladen und als JPG-Datei gespeichert werden. curl wurde eingesetzt, weil sich hier im Gegensatz zu wget die Downloadzeit begrenzen läßt. Also fischt man sich eine kurze Videsequenz heraus, aus der dann mittels avconv, das früher ffmpeg hieß, ein Frame extrahiert wird - und schon hat man ein Standbild:

# Kamerabild (Stream) holen
curl -o video.jpg -m 3 http://root:geheim@192.168.2.103/cgi-bin/still.cgi
# ein Bild extrahieren mit avconv (früher ffmpeg)
avconv -i video.jpg -s 1280x1024 snap.jpg
rm video.jpg
Sie sehen, ich gibt immer eine Möglichkeit, eine störrische Netzwerk-Kamera zu zähmen.

Nachbearbeitung

Nach dem Einfangen des Bildes in der Datei snap.jpg wird noch etwas Kosmetik betrieben, was natürlich bei allen Kameras auf die gleiche Weise erfolgen kann. Bei den Netzwerkkameras fehlen uns auch die Fatures von fswebcam zum Einfügen von Beschrifungen im Bild. Da hilft das ImageMagick-Paket weiter, insbesondere das darin enthaltene Programm convert. ImageMagick ist ein freies Softwarepaket zur Erstellung und Bearbeitung von Pixelgrafiken. Es kann nahezu alle üblichen Bildformate lesen, verändern und schreiben. Außerdem lassen sich Bilder dynamisch erzeugen. Für Perl-Programmierer gibt es sogar passende Module. ImageMagick ist in vielen Linux-Distributionen zu finden, ansonsten unter www.imagemagick.org.

Für einen eindeutigen Dateinamen eines jeden Bildes werden Datum und Uhrzeit herangezogen. Dann wird auch noch das Bild mit Datum und Uhrzeit beschriftet - je nach Bildhelligkeit schwarz oder weiss.

# Timestamp fuer Bild
TS=$(date "+%d.%m.%Y   %H:%M")
# Timestamp fuer Dateinamen
FILE=$(date "+%d%m%Y%H%M")
# abhaengig von der Helligkeit Schrift schwarz oder weiss einfuegen
# Funktion Brightness siehe unten (Vergleich "groesser" wegen Korrekturwert)
col=$(Brightness snap.jpg)
if [ $col -gt 50 ]
  then
    convert -fill white -gravity SouthEast -pointsize 20 \
            -draw "text 15,15 '$TS'" snap.jpg ${FILE}.jpg
  else
    convert -fill black -gravity SouthEast -pointsize 20 \
            -draw "text 15,15 '$TS'" snap.jpg ${FILE}.jpg
  fi
rm snap.jpg
Die Größe eines Bildes liegt, je nach Auflösung, um die 30 bis 150 KByte. Ein Tag hat 86.400 Sekunden, ein Monat (30 Tage) 2.592.000 Sekunden. Wenn Sie alle 10 Sekunden ein Bild speichern, um später einen Zeitraffer-Film daraus zu machen, sind das ungefähr 7,8 bis 39 GByte pro Monat. Also auf den Plattenplatz achten und rechzeitig alte Dateien löschen.

convert ist ja ein Tausendsassa, so kann man das Bild auch gleich noch verkleinern und mit höherer Kompressionsrate (aber geringerer Qualität) abspeichern, um Platz zu sparen. Oder man macht Schwarzweiss-Bilder daraus, oder, oder ...

Helligkeit korrigieren

Wenn die Kamera bei sehr verschiedenen Lichtverhältnissen ein halbwegs brauchbares Bild liefern soll, muss oftmals die Helligkeit justiert werden - sofern die Kamera das nicht selbst schon erledigt. Dazu muss das Bild zweimal kurz hintereinander aufgenommen werden. Das erste Bild dient nur der Helligkeitsbestimmung, das zweite Bild wird dann auf der Basis der ermittelten Helligkeit "geschossen", z. B. bei der USB-Webcam:
# Kamerabild holen, Helligkeit bestimmen
fswebcam -q -D 3 -S 10 -F 10 -r 1280x720 -d $KAMERA \
   -s "Backlight Compensation=75%" \
   --no-banner $TMP/$FILE
HELL=$(Brightness $TMP/$FILE)
# Kamerabild holen, Helligkeit anpassen
fswebcam -D 3 -S 10 -F 10 -r 1280x720 -d $KAMERA \
  -s "Backlight Compensation=75%" \
  -s "Brightness=${HELL}%" \
  -s "Contrast=45%" \
  ... $TMP/$FILE
Die Shell-Funktion Brightness (siehe unten) liefert den Helligkeitswert in Prozent. Er ergibt sich zu 100 - (ermittelte Helligkeit) [Prozent]. Ist das Bild recht dunkel, wird der Wert für den Kamera-Parameter Brightness relativ hoch gesetzt und umgekehrt.

Wie ermittelt man eigentlich die Helligkeit eines Bildes? Mathematisch kann die Bildhelligkeit eines Grauwertbildes als Mittelwert aller Grauwerte, der Kontrast als Varianz aller Grauwerte definiert werden. Die einfachste Möglichkeit zur Bestimmung der Helligkeit eines Pixels (bzw. dessen Grauwert) ergibt sich daher zu (R+G+B)/3, wobei R, G und B die Werte für die drei Grundfarben Rot, Grün und Blau sind. Da jede Farbe einen Wert zwischen 0 und 255 haben kann, ergibt sich der gleiche Bereich für den Helligkeitswert. Die Gesamthelligkeit des Bildes errechnet sich aus der Helligkeit aller Bildpunkte, wie es das folgende C-Programmfragment illustriert (t_img sei eine Struktur, die alle Bildinfo enthält):

int brightness(t_img *bild)
  {
  int  x, y, br, avg;
  t_color val;
  double  sum;

  for(x = 0; x < bild->xsize; x++)
    {
    for(y = 0; y < bild->ysize; y++)
      {
      getpixel(bild, x, y, &val);
      grau = (val.R + val.G + val.B)/3;
      sum += grau;
      }
    }
  avg = sum / (bild->xsize * bild->ysize);
  return avg;
  }
Nur lässt diese Form der Helligkeitsbestimmung die Wahrnehmungseigenschaften unsers Auges außer Acht. Wir nehmen den gelb-grünen Farbbereich wesentlich heller wahr als die anderen Farben. Das wird in anderen Farbmodellen berücksichtigt. So könnten Sie anstelle der linearen Umrechnung auch den RGB-Farbraum nach YUV umrechen. YUV verwendet zur Darstellung der Farbinformation zwei Komponenten, die Luminanz Y und die Chrominanz (Farbanteil), wobei diese wiederum aus den zwei Unterkomponenten U und V besteht:

y = r * 0.299 + g * 0.587 + b * 0.114
u = (b - y) * 0.493
v = (r - y) * 0.877

Für die Helligkeitsbestimmung wird nur der Y-Wert benötigt. Zum Glück kann man die Arbeit dem Universaltool ImageMagick überlassen und man muss nicht selbst programmieren. Das Programm convert kann nicht nur alle möglichen Bildmanipulationen vornehmen, sondern auch diverse Infos über ein Bild liefern. Das Problem ist eher, aus dem Datenwust den richtigen Wert herauszufischen. Dazu wird das Bild erst in Graustufen umgewandelt. Damit hat schon jeder Bildpunkt nicht mehr drei, sondern nur noch einen Helligkeitswert. Dann wird mittels sed der Helligkeitswert ("Mean") herausgefischt. Diser Wert liegt zwischen 0 und 1 und muss mit 100 multipliziert werden, um eine Prozentangabe zu bekommen. Der Prozentwert wird dann noch von 100 subtrahiert (siehe oben). Das erledigt bc, der Kommandozeilen-Rechner. Zum Schluss werden noch die Nachkommastellen abgeschnitten:

Brightness()
  {
  # Bildhelligkeit des Schriftfeldes ermitteln (Prozent, ganzzahlig)
  # Helligkeit von $1 ermitteln
  local data=`convert $1 -colorspace gray -verbose info: `
  local mean=`echo "$data" | sed -n '/^.*[Mm]ean:.*[(]\([0-9.]*\).*$/{ s//\1/; p; q; }'`
  echo "100-$mean*100" | bc | sed -e 's/\..*$//'
  }

Bewegung erkennen

Was geschieht, wenn ich nicht in meinem Büro bin? Wieso ist der Kaffee immer alle? Heutzutage ist es relativ einfach, solche Sachen herauszufinden. Man benötigt nur eine Webcam und ein geeignetes Programm. Bewegungserkennungsverfahren finden immer häufiger Anwendung, zum Beispiel in der Überwachungstechnik oder der Videokompression.

Eine sehr einfache Methode Bewegungen zu erkennen ist, zwei zeitlich aufeinander folgende Bilder zu vergleichen, um die Änderung von Pixeln zu erkennen. Überschreitet die Zahl (oder zusätzlich der Betrag) der Änderungen einen Schwellenwert, wird beispielsweise ein Alarm ausgelöst. Bei statischen Motiven und konstanter Beleuchtung genügt eventuell auch der Vergleich mit einem Referenzbild. Wenn man in diesem Fall das aktuelle Bild vom Referenzbild subtrahiert, liefern alle Pixel, die sich nicht verändern haben, das Ergebnis Null zurück (ein schwarzes Pixel). Dieses Verfahren funktioniert ganz gut, jedoch stösst es bei Beleuchtungsänderung und bei kleinen Veränderungen im Bild an seine Grenzen.

Hebt sich das bewegende Objekt vom Hintergrund ab (ein sich vor der Kamera bewegendes Objekt mit einer weissen Wand dahinter), ist auch die langsamste Bewegung detektierbar. Variiert der Hintergrund sehr stark und erfolgt die Bewegung sehr langsam, kann man die Bewegungserkennung austricksen. Bei Aussenaufnahmen kommen noch Effekte wie vom Wind bewegte Äste oder die Katze vom Nachbarn hinzu. Der Stubentiger soll ja im Gegensatz zu einem Einbrecher keinen Alarm auslösen. In solchen Fällen ist es günstig, nur einen Teilausschnitt des Bildes zu untersuchen.

Das Prinzip des Differenz-Algorithmus zeigt das folgende Programmfragment. Die Funktion changed liefert die Anzahl der Pixel zurück, die sich jeweils in beiden Bildern um mehr als den Wert diff unterscheiden (t_img ist wieder Struktur, die alle Bildinfo enthält):

int changed(t_img *bild1, t_img *bild2, int diff)
  {
  int y, z, chan, diffcount;
  t_color val1, val2;

  /* Zaehler fuer die Unterschiede */
  diffcount = 0; 
  /* Iteration ueber alle Pixel (x, y) */
  for(x = 0; x < bild1->xsize; x++)
    {
    for(y = 0; y < bild1->ysize; y++)
      {
      /* akt. Pixel beider Bilder einlesen */
      getpixel(bild1, x, y, &val1);
      getpixel(bild2, x, y, &val2);

      /* Grauwerte beider Pixel berechnen */
      grau1 = (val1.R + val1.G + val1.B)/3;
      grau2 = (val2.R + val2.G + val2.B)/3;

      /* ist der Unterschied groesser diff,
         den Zaehler inkrementieren */
      if(abs(grau1 - grau2) > diff)
        diffcount++;
      }
    }
  return diffcount;
  }
Vergessen Sie auch nicht, dass sich die Bilder mit den Imagemagick-Tools (convert, mogrify) vor- und nachbereiten lassen. Neben diversen Filterfunktionen lassen sich auch Ober- und Untergrenzen für die Helligkeit angeben, bei deren Über- bzw. Unterschreitung die Pixel weiß bzw. schwarz eingefärbt werden.

Sehr viel ausgefeilter kann das alles aber ein Programm zur Bewegungs-Erkennung (Motion Detection, MD). Bei manchen Kameras ist MD sogar in der Kamera selbst implementiert. Oft wird auch ein Tools für Windows mit der Webcam geliefert. Natürlich gibt es dergleichen auch für Linux. Einer der bekanntesten Vertreter dieser Programmgattung kann auch wieder über die Kommandozeile gestartet werden.

Das Programm motion empfängt nonstop Bilder von beliebig vielen Webcams oder Netzwerkkameras. Ändert sich dabei von einem Bild zum anderen eine definierte Anzahl Pixel, postuliert das Programm, dass sich etwas im zu überwachenden Bereich bewegt. In diesem Fall nimmt motion mit Hilfe von ffmpeg einen Videostream oder eine Serie von Einzelbildern auf und speichert sie auf einem Server. Des Weiteren ist es möglich, Bereiche in Bildern zu maskieren, um Bewegungen darin zu ignorieren. Letzteres hilft vor allem dann, wenn sich beispielsweise Bäume oder Sträucher im Erfassungsbereich befinden, die im Wind schaukeln - oder eben die Katze, die ihr Revier kontrolliert.

Neben der Funktion als Bewegungsmelder eignet sich motion auch, um innerhalb bestimmter Intervalle Schnappschüsse zu speichern oder fortlaufend Videos aufzunehmen. Das Werkzeug verfügt zudem über eine Möglichkeit, die aktuell empfangenen Bilder von überall mit einem Browser abzurufen. Bei der Installation von motion wird auch eine Gruppe gleichen Namens erzeugt. Alle Nutzer, die motion verwenden, müssen zu dieser Gruppe hinzugefügt werden, damit die Konfigurationsdatei von motion gelesen werden kann.

In der Konfigurationsdatei /etc/motion/motion.conf lassen sich zahlreiche Einstellungen vornehmen. Die wichtigsten für erste Versuche sind:

Falls keine Daten gespeichert werden sollen kann als target_dir das allseits beliebte /dev/null angegeben werden. Nach dem Anpassen der Konfigurationsdatei können Sie diese durch den Aufruf motion -n schon mal testen. Funktioniert alles nach Wunsch, starten Sie motion als Daemon. Gegenenfalls muss dann in der Konfigurationsdatei start_motion_daemon=yes eingestellt werden. Bewegt sich etwas vor der Kamera, sollten nun Bilder aufgenommen und gespeichert werden. Später kann der Daemon in die Startscripte aufgenommen werden. Sollten zuviele Bilder ohne erkennbare Bewegung aufgenommen werden, können Sie die Empfindlichkeit über den threshold-Wert einstellen (default: 1500).

Falls das nicht erfolgreich ist, läßt sich der Bildausschnitt maskieren. Dazu erzeugt man mit dem Grafikprogramm seiner Wahl ein Bild von der Größe des Kamerabildes (Angabe von width und height. Das Bild hat nur schwarze und weiße Flächen. Alles was schwarz ist, wird ausgeblendet. Im einfachsten Fall wäre dies also ein einfacher schwarzer Rahmen. Die Datei wird dann im Format "pgm" (Portable Gray Map) gespeichert. In der Konfigurationsdatei tragen Sie nun eine weitere Zeile ein:

mask_file /pfad/zur/maskendatei.pgm

Ein weiteres Feature von motion ist, dass man auf bestimmte Ereignisse reagieren kann. Mit der Konfigurationsoption on_event_start wird ein Programm oder Script angegeben, das motion ausführt, sobald eine Bewegung erkannt wurde. Auf diese Weise kann man sich dann Nachricht per SMS, Twitter oder E-Mail zusenden lassen. Für erste Tests können Sie beispielsweise einen Zeitstempel an eine Datei anhängen:

on_event_start 'date "+%d%m%Y%H%M" >> /home/testuser/event'

Weitere Infos enthalten die Homepage von motion und ein Zeitschriftenartikel:

www.lavrsen.dk/foswiki/bin/view/Motion
www.lavrsen.dk/foswiki/bin/view/Motion/FrequentlyAskedQuestions
Objekte mit Motion per Video überwachen

Als Alternative zu "Motion" würde sich noch "Zoneminder" anbieten, der aus etlichen Modulen besteht und über ein Web-Interface bedient wird. Neben Video4Linux für die Unterstützung der Kameras werden ein Apache-Webserver, MySQL, PHP und Perl benötigt. Für die Aufnahme von Stand- und Bewegtbildern kommen noch die die Ffmpeg- und Libjpeg-Pakete hinzu. Der Aufwand gegenüber Motion ist also beträchtlich. Um die wegen der vielen Pakete und Codecs etwas umständliche Installation bzw. Konfiguration zu erleichtern, kann das im Zoneminder-Forum stehende Script heruntergeladen und verwendet werden. Mehr über Zoneminder erfahren Sie auf dessen Homepage www.zoneminder.com. Das Installationsscript findet man unter www.zoneminder.com/forums/viewtopic.php?t=16628 und weitere Informationen für den Einstieg liefert ein Artikel in LinuxUser 09/2011.

Bilder kopieren mit SSH/SCP

Man könnte nach dem Erstellen des Fotos die Datei mittels FTP auf den Webserver übertragen. Das kann recht einfach mit Hilfe des Perl-Moduls Net::FTP erfolgen. Das Modul bildet fast alle FTP-Kommandos auf entsprechende Methoden in Perl ab. Das folgende Programm scannt ein Verzeichnis nach Bilddateien und überträgt alle Dateien per FTP-Protokoll:
#!/usr/bin/perl
use strict;
use warnings;

use Net::FTP;

# ------------------ Configuration Section ----------------------------
my $scandir = "/tmp/bilder";             # da liegen die Bilder
my $server = "ftp.sonstwo-in.de";        # Adresse des FTP-Servers
my $ftpuser = "camuser";                 # Benutzername auf dem FTP-Server
my $ftppass = "geheim";                  # Passwort des FTP-Benutzers
# ---------------------------------------------------------------------

my (@files,$file);

opendir(DIR,$scandir) or die("Verzeichnis nicht lesbar.");
@files = grep {(/\.jpg$/) && -f "$scandir/$_"} readdir(DIR);
closedir (DIR);
exit(0) if ($#files < 0); # keine Bild-Dateien vorhanden

# Connect zum Server und Einloggen
my $ftp = Net::FTP->new($server, Debug => 0, Passive => 1) or 
                  die("Keine Verbindung mit $server.");
$ftp->login($ftpuser, $ftppass) or die("Fehler beim Einloggen.");
# Uebertragungsmodus 'binaer'
$ftp->binary();
for $file(@files)
  {
  $file = $scandir . '/' . $file;
  # Datei senden
  $ftp->put($file);
  # lokale Datei loeschen
  unlink ($file);
  }
# FTP-Verbindung beenden
$ftp->quit();
Bei FTP werden jedoch alle Daten inklusive Username und Passwort im Klartext übertragen, was mir nicht so sympatisch ist. Besser erscheint mir daher der Transfer per SSH/SCP, wo alles schön verschlüsselt ist. Hier kommt das Perl-Modul Net::SCP::Expect zum Ensatz. Es bildet nicht nur die Schnittstelle zu SCP, sondern kann auch per 'Expect' den User- und Passwort-Dialog automatisieren. Im übrigen gleicht das Programm dem vorhergehenden, beim Senden wird zusätzlich das Zielverzeichnis angegeben:
#!/usr/bin/perl
use strict;
use warnings;

use Net::SCP::Expect;

# ------------------ Configuration Section ----------------------------
my $scandir = "/tmp/bilder";              # da liegen die Bilder
my $server = 'server.irgendwo-in.de';     # Adresse des SCP-Servers
my $scpuser = "camuser";                  # Benutzername auf Netzmafia
my $scppass = "geheim";                   # Passwort des SCP-Benutzers
my $destination = "/home/camuser/";       # Zielverzeichnis des Servers
# ---------------------------------------------------------------------

my (@files,$file);

opendir(DIR,$scandir) or die("Verzeichnis nicht lesbar.");
@files = grep {(/\.jpg$/) && -f "$scandir/$_"} readdir(DIR);
closedir (DIR);
exit(0) if ($#files < 0); # keine Bild-Dateien vorhanden

# Connect zum Server und Einloggen
my $scp = Net::SCP::Expect->new(host => $server,
                                user => $scpuser,
                                password => $scppass) or 
                     die("Keine Verbindung mit $server.");

for $file(@files)
  {
  $file = $scandir . '/' . $file;
  # Datei senden
  $scp->scp($file, $destination);
  # lokale Datei loeschen
  unlink ($file);
  }
# SCP-Verbindung beenden ist nicht notwendig
Beim SCP-Zugriff kann auch ein Login ohne Angabe von User/Passwort erfolgen. Dafür muss auf dem Kamerarechner ein Zertifikat erstellt und auf den Webserver übertragen werden, was mit Hilfe der beiden Kommandos ssh-keygen und ssh-copy-id erledigt werden kann. Zuerst wird ein Schlüssel-Paar (Public- und Private-Key) erstellt und dann der öffentliche Schüssel zum Webserver übertragen.

Der Private-Key ist dann dem normalen Passwort gleichgestellt. Im Gegensatz zum Passwort existiert er aber als Datei, die vor fremdem Zugriff zu schützen ist. Deswegen besteht die Möglichkeit, den Private Key mit einer Passphrase zu schützen. Die Passphrase muss in unserem Fall leer bleiben, da sonst bei Verbindungsaufnahme diese Passphrase abgefragt würde und so kein automatischer Dateitransfer möglich wäre.

Das folgende Shellscript erzeugt die Schlüssel und übertägt sie dann (den Account "camuser@www.netzmafia.de" gibt es natürlich nicht, er dient nur als Beispiel):

#!/bin/bash
# Generiert Public/Private-Keys und kopiert sie zur Netzmafia
# damit ein Login bzw. Aufbau eines SSH-Tunnels dorthin ohne
# Passwort-Eingabe moeglich ist
#
# zuerst werden die Keys generiert
ssh-keygen -t rsa
ssh-keygen -t dsa
# nun befinden sich im Verzeichnis ~/.ssh vier Dateien:
# id_rsa  id_dsa  id_rsa.pub  id_dsa.pub
#
# nun werden die public keys zur Netzmafia kopiert und dort
# an die Datei ~/.ssh/authorized_keys angehaengt
ssh-copy-id -i ~/.ssh/id_rsa.pub camuser@www.netzmafia.de
ssh-copy-id -i ~/.ssh/id_dsa.pub camuser@www.netzmafia.de
Ab jetzt kann sich der lokale user vom Cam-Server als "camuser@www.netzmafia.de" ohne Passworteingabe auf Netzmafia einloggen. Der Transfer der Datei(en) kann mit dem Kommandozeilenprogrmm scp erfolgen (oder in Perl mit dem Modul Net::SCP nach obigem Muster).

Wenn es nicht klappen sollte und trotzdem noch ein Passwort angefordert wird, stimmen in fast immer die Zugriffsrechte nicht. Das Verzeichnis .ssh und die Datei authorized_keys darin dürfen nur für den User zugreifbar sein (→ chmod 700 .ssh .ssh/authorized_keys). Das Home-Directory des jeweiligen Users darf auch nur für diesen beschreibbar sein.

Bilder im Web zeigen

Oft will man die Bilder der Webcam mit anderen teilen, wobei es nicht unbedingt immer facebook sein muss - die Präsentation in entsprechendem Rahmen auf einer eigenen Weseite kann attaktiver sein und man gibt vor allem die Rechte an der Bildveröffentlichung nicht aus der Hand. Es ist übrigens immer eine gute Idee, Kameraserver und Webserver auf getrennten Systemen laufen zu lassen. Der Kameraserver steht daheim hinter dem DSL-Router und der Webserver ist bei irgend einem Provider gemietet.

Für eine Webcam-Anwendung genügt es, in regelmäßigen Abständen immer dasselbe Bild zu speichern und im passenden Verzeichnis des Webservers abzulegen. Gegebenenfalls müssen Sie zur Überlistung des Browsers verfahren wie die Trendnet-Kamera. Alternativ könnte das aktuelle Bild auch per CGI-Programm abgerufen werden. Auch können Sie eine bestimmte Anzahl von Bildern rotierend speichern (es fällt immer das älteste Bild weg und ein neues kommt hinzu), wie es in folgendem Perl-Listing skizziert wird ($MAX enthält die Anzahl der zu speichernden Bilder), Die Dateien heißen dann 1.jpg, 2.jpg, 3.jpg usw.:

use strict;
use warnings;
use LWP::Simple;

my $MAX = 10;                     # Maximalzahl Bilder
my $file_base = '/var/www/cam/';  # Bilderverzeichnis

# z. B. Abruf TV-IP100
my $url = 'http://192.168.2.100/IMAGE.JPG';
 ...
# Bild-Dateien "rotieren"
my $id = $MAX;
while (my $id > 1)
  {
  my $prev = $id - 1;
  my $old = $file_base . $id . '.jpg';
  my $pred = $file_base . $prev . '.jpg';
  unlink($old);
  rename($pred, $old);
  $id--;
  }
# Die neue Datei holen
$file = $file_base . "1" . '.jpg';
my $res = getstore($url, $file);
  ...

Hat jede Datei einen individuellen Namen (z. B. aus Datum und Uhrzeit gebildet) sammeln sich zwar viele Dateien an, die gelegentlich altersabhängig gelöscht werden sollten, aber mit der Präsentation gibt es keine direkten Probleme. Es gibt ja genug fertige Tools für Bildergalerien. Wenn der Name aber immer gleich bleibt oder, wie im Beispiel weiter oben, nur wenige Dateien "rotiert" werden, tauchen plötzlich Probleme mit dem Browser auf. Der Browser speichert das Bild lokal in seinem Cache. Beim Firefox kann man beispielsweise den Cache erforschen, indem man "about:cache" in der URL-Zeile eingibt.

Das generele Problem liegt daran, dass der Browser beim erneuten Laden der Webseite (oder einem Refresh über Meta-Anweisung) feststellt, dass sich ein Bild gleichen Namens bereits im Cache befindet und statt das neue Bild über das Netz zu laden, zeigt er das aus dem Cache an. So ist auch Mittags noch der Sonnenaufgang zu sehen. Eine Lösungsmöglichkeit wäre, das Bild über ein CGI-Script auszuliefern - da ist der Browser so schlau, zu wissen, dass er jedemal neu darauf zugreifen muss. Wir können aber auch den gleichen Trick anwenden, wie die Trendnet-Kamera:

Der Browser wird getäuscht, indem der Name der Bilddatei manipuliert wird. Das kann mit etwas Javascript auf der Client-Seite geschehen. Einerseits wird im Body-Tag ein Refresh-Intervall definiert, damit die Seite regelmäßig neu gelanden wird und entsprechend auch ein neues Bild kommt. Andererseits sorgt ein Javascript-Zweizeiler dafür, dass mit einem sinnlosen, zufälligen Zusatz versehen, der dem Browser vorgaukelt, es handle sich um etwas Neues. Daraufhin lädt der Browser brav das frische Bild. Wichtig ist, dass beim Bilderlink eine ID hinzugefügt wird, damit das Javascript das Element auf der Webseite finden kann.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"> 
<html>
<head>
<title>Das Bild</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<script type="text/javascript">
RefreshImage = function()
  // macht neuen Bilderlink
  {
  // wo ist das Bild auf der Seite?
  img = document.getElementById("cam");
  // mit "neuem" Namen laden
  img.src = "/webcam/bild.jpg?rand=" + Math.random();
  }
</script>
</head>

<!-- Hier kommt alle 30 Sekunden der Refresh -->
<body onload="window.setInterval(RefreshImage, 30*1000);">

<!-- Hier ist das Bild, das automatisch nachgeladen wird -->
<div align="center">
<img id="cam" src="/webcam/bild.jpg" />
</div>

</body>
</html>

Der Browser sieht nur folgendes:

<body onload="window.setInterval(refreshImage, 30*1000);">

    <div align="center">
        <img id="cam" src="bild.jpg?rand=0.9121381653654791"></img>
    </div>

</body>

Die beschriebene Lösung ist sehr einfach und klappt mit nahezu jedem Browser - sofern Javascript eingeschaltet ist (nachdem aber kaum noch eine Webseite ohne Javascript daherkommt, ist das in der Regel der Fall). Natürlich gibt es noch weitere Methoden, entweder das Nachladen des Bildes alleine per Javascript und Ajax oder, wie oben erwähnt, Auslieferung des Bildes per Script oder komplett dynamische Webseiten mittels PHP und Content Management System.

Nachtblind?

Ist die Kamera nachtblind bzw. soll sie auch nachts etwas "sehen"? Dann hilft ein kleiner Infrarot-Scheinwerfer. Manche Kameras, z. B. die von Trendnet, haben sogar schon eine kleine Infrarot-Beleuchtung eingebaut. Bei der Trendnet-Kamera sorgt eine Photozelle dafür, das die sechs Infrarot-LEDs nur bei Dunkelheit mit Strom versorgt werden. Aber nicht alle elektronischen Kameras sind für infrarotes Licht empfindlich. Ausprobieren können Sie das ganz einfach, indem Sie ihre Fernseh-Fernbedienung vor die Kamera halten (mit der Infrarot-LED in Richtung zur Kamera) und mal eine Taste drücken. Schon sieht man im Kamerabild die LED blinkern, was zumindest ein Indikator für einen Nachteinsatz sein kann.

Der hier vorgestellte Eigenbau-Infrarot-Scheinwerfer besteht aus 40 preiswerten Infrarot-LEDs und acht Widerständen. Er lässt sich auch vom Lötanfänger ganz einfach auf einer Lochrasterplatte aufbauen. Profis machen sich natürlich eine Platine, insbesondere wenn mehr als ein Scheinwerfer gebraucht wird. Bei 12 V Versorgungsspannung nimmt der Scheinwerfer ca. 200 mA auf, er sollte also ggf. vom Computer aus ein- und ausgeschaltet werden können (per Relais oder MOSFET-Schalttransistor). Die Schaltung des Scheinwerfers ist so einfach, das im folgenden Bild nur die Verdrahtung gezeigt werden muss. Es werden jeweils 5 LEDs und ein 100-Ohm-Widerstand in Reihe geschaltet.

Für den Außeneinsatz muss dann noch ein passendes Gehäuse mit Klarsichtdeckel spendiert werden.

Wetterfestes Gehäuse

Kameras, die im Freien hängen, müssen Temperaturschwankungen, Regen, Sturm und Schnee widerstehen. Die Gehäuse sollten wasserdicht sein, sonst ziehen sie Feuchtigkeit, es beschlagen die Linsen oder die Elektronik im Inneren korrodiert. Entsprechend geschützte Modelle stecken in Metallgehäusen, ihre Linsen sind verdeckt von abgedichteten Glasscheiben. Diese Netzwerkkameras, z. B. von Mobotix, kosten um die 500 Euro und wetterfeste Kamera-Gehäuse kosten zwischen 80 und 300 Euro. Dafür sind sie von innen beheizt (230 V) und können so weder einfrieren noch beschlagen.

Die alternative ist ein (unbeheiztes) Low-Cost-Gehäuse für die USB-Webcam. Hier dient als Wetterschutzgehäuse ein 100-W-Halogenstrahler aus dem das gesamte Innenleben entfernt wurde. Das Gehäuse bietet genügend Platz für die Kamera. Für größere Kameras muss man sich dann das jeweils passende Gehäuse suchen (150- oder 500-W-Lampe).

Bei der "Logilink UA0155" wurde der hintere Teil der Halterung abgesägt, wobei der Teil mit dem Kugelgelenk unversehrt blieb. Dann kann man die Kamera einfach ins Gehäuse kleben, wobei die Möglichkeit, die Kamera über das Kugelgelenk auszurichten, erhalten bleibt. Um den USB-Stecker aus dem Gehäuse herausführen zu können, musste der kleine Anschlusskasten entfernt und die Kabeldurchführung mit einer Rundfeile etwas vergrößert werden. Anschließend wird die Öffnung wieder verschlossen und ggf. mit Silikon abgedichtet.

Gegebenenfalls kann das Gehäuse mit einem Heizwiderstand ausgerüstet werden, der im Winter das Vereisen der Glasscheibe verhindert. Dafür sollte aber immer eine getrennte Stromversorgung verwendet werden. Einerseits muss ja nur bei Minustemperaturen geheizt werden und andererseits liefert die USB-Schnittstelle nicht wirklich genügend Strom zum Heizen.

Kamera-Server ohne Festplatte

Nachdem der Kamera-Server nicht viel zu tun hat, bietet es sich an, einen sogenannten Thin-Client, einen Barbone oder sogar den Raspberry Pi zu verwenden. Damit es keine beweglichen Teile gibt (Verschleiß) kann eine Solid State Disk (SSD), eine interne Flash-Speicherkarte oder eine SD-Karte als Massenspeicher dienen. Das Logging kann ggf. abgeschaltet werden (entweder ganz oder durch Umleitung nach /dev/null).

Dabei ergibt sich allerdings ein schwerwiegender Nachteil: die interne Flash-Speicherkarte, SD-Karte oder SSD des Rechners wird belastet, da die Bilder erst auf der Platte zwischengespeichert werden, bevor sie auf den Webserver übertragen werden. Mit der oben geschilderten Helligkeitsanpassung ggf. sogar zweimal. Das ständige Löschen und Wiederbeschreiben ist trotz aller schlauer Algorithmen der Controllerbausteine Gift für die Lebensdauer der Solid-State-Speicher. Deshalb sollte für alle Dateien eine RAM-Disk eingerichtet werden - bei der sogar ein noch schnellerer Zugriff als Nebeneffekt hinzukommt. Dazu gibt es zwei Möglichkeiten:

Die Verwendung des tmpfs-Dateisystems:
Das tmpfs-Dateisystem ist eigentlich kein reines RAM-Dateisystem, sondern die Daten landen im Festplatten-Swap, sobald der Speicherplatz im RAM knapp wird. Mit dem folgenden Shell-Befehl wird das Verzeichnis /root/tmp zur RAM-Disk:

# mount -t tmpfs none /root/tmp
oder, falls die Größe festgelegt werden soll:
# mount -t tmpfs -o size=20M none /root/tmp
Es werden dynamisch immer so viele Ressourcen abgezweigt, wie gerade benötigt werden, auch wenn eine Größe angegeben wurde. Ist das Laufwerk also leer, belegt es auch keinen Platz im RAM. Es ist möglich, diese Partition standardmäßig beim Systemstart einzubinden, indem man eine Zeile in die Datei /etc/fstab einfügt:
tmpfs    /root/tmp    tmpfs    defaults,size=20M      0       0
Die Verwendung des ramfs-Dateisystems:
Das ramfs-Dateisystem lagert im Gegensatz zum tmpfs keine Daten in den Swap aus, ist also ein reines RAM-Dateisystem. Die Kommandos sind fast identisch wie oben:
sudo mount -t ramfs ramfs /root/tmp
Damit erhält man eine RAM-Disk, die sich ebenfalls dynamisch der benötigten Größe anpasst. Um die Partition beim Systemstart automatisch einzuhängen, fügt folgende Zeile in der Datei /etc/fstab hinzu:
ramfs   /root/tmp     ramfs   defaults        0       0
Das ramfs-Dateisystem hat im Gegensatz zu tmpfs keine Mountoptionen und bietet somit auch keine Möglichkeit, die Größe zu limitieren. Eventuell hat das System dann keinen freien Hauptspeicher mehr zur Verfügung und kann nur noch auf die Festplatte auslagern.

Download des gesamten Skripts


Copyright © Hochschule München, FB 04, Prof. Jürgen Plate
Letzte Aktualisierung: