kramann.info
© Guido Kramann

Login: Passwort:










kramann.info
© Guido Kramann

Login: Passwort:




Webcam-Ansteuerung in C unter Linux

(EN google-translate)

(PL google-translate)

Eine ausführliche Darstellung für die Ansteuerung einer Webcam in C finden Sie unter folgendem Link:

http://v4l2spec.bytesex.org/spec-single/v4l2.html - Spezifikation, Beschreibung und Anwendungsbeispiel für V4L2.

Diese Darstellung richtet sich vornehmlich an Entwickler von Treibern und Programmen zur Ansteuerung von Webcams und Audio-Geräten. Dargestellt wird eine Linux-Kernel-Programmier-Schnittstelle, die den Namen "V4L2" (Video for Linux, Version 2) trägt.

Vor Einführung dieser Schnittstelle mußten für jedes Gerät ein eigener neuer proprietärer Treiber geschrieben werden. Die Einführung von V4L2 ermöglicht hier eine Vereinheitlichung.

Um ein Gerät anzusteuern, das diese Schnittstelle verwendet, sind im allgemeinen folgende Schritte notwendig:

  1. Öffnen der Hardware,
  2. Festlegung der Hardwareeigenschaften (Video-Eingang, Helligkeit usw.)
  3. Auswählen eines Datenformats (Repräsentation der Pixelfarben in einem Datenarray),
  4. Auswählen einer Eingabe/Ausgabe-Methode (Methode zur Speichrung des Bildes in einem Puffer-Speicherbereich usw.),
  5. Schleife für die Erfassung der Einzelbilder,
  6. Schließen der Hardware.

Wir wollen hier einfach das unter dem Link bereitgestellte Beispielprogramm verwenden.

Um es anpassen zu können müssen wir herausbekommen, in welchem Format ein erfasstes Bild dann zur Verfügung steht:

Nach der Erfassung steht das Bild in dem struct buffers[0] zur Verfügung. Dieser struct besteht aus einer Variablen, in der die Länge des Speicherbereichs mit dem Bild vermerkt ist und einer weiteren Variablen, in der die Adresse vermerkt ist, ab der das Bild im Arbeitsspeicher steht.

...
struct buffer {
        void *                  start;
        size_t                  length;
};

static char *           dev_name        = NULL;
static io_method        io              = IO_METHOD_MMAP;
static int              fd              = -1;
struct buffer *         buffers         = NULL;
static unsigned int     n_buffers       = 0;
...

Code 0-1: Deklarationsteil des Beispielprogramms ab Zeile 38 mit der Deklaration des struct buffer und der Deklaration eines Arrays aus diesem struct mit dem Namen buffers.

  • Die hier verwendete Webcam liefert ein Bild mit einer Auflösung von 640 mal 480 Pixeln.
  • Die Speicherung des Bildes im Arbeitsspeicher nach seiner Erfassung erfolgt im Format V4L2_PIX_FMT_YUYV (vergl. Zeile 519).
...
        fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        fmt.fmt.pix.width       = 640; 
        fmt.fmt.pix.height      = 480;
        fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
        fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;
...

Code 0-2: Ausschnitt aus der Methode init_device().

  • Bei dem Format V4L2_PIX_FMT_YUYV werden zwei unsigned char-Werte pro Pixel benötigt.
  • Somit ergibt sich hier eine Speichergröße pro Bild von 640x480x2 = 614400 Byte (Speicherplätzen).

Das YUV-Farbmodell besitzt wie das RGB-Farbmodell drei Komponenten. Diese haben hier aber eine andere Bedeutung:

  • Y - repräsentiert die Lichtstärke
  • U und V spezifizieren in einem orthogonalen Koordinatensystem den Farbton.

Die Umrechnung zwischen RGB und YUV kann in folgender Weise geschehen:

Y = 0.299*R + 0.587*G + 0.114*B
U = (B - Y)*0.493
V = (R - Y)*0.877

Code 0-3: Umrechnung von RGB nach YUV

B = Y + U/0.493
R = Y + V/0.877
G = 1.7*Y - 0.509*R - 0.194*B

Code 0-4: Umrechnung von YUV nach RGB

Das YUV-Modell findet Anwendung in der Fernsehtechnik. Bei der Festlegung der Lichtstärke Y werden dabei die physiologischen Eigenschaften des menschlichen Auges mit berücksichtigt, von dem grünes Licht am intensivsten und blaues am schwächsten wahrgenommen wird.

Bei dem speziellen Format V4L2_PIX_FMT_YUYV handelt es sich um ein komprimiertes Format, bei dem in den zwei Byte pro Pixel das jeweils erste Byte der Y-Wert für das Pixel darstellt. Das zweite Byte gilt immer für zwei in einer Zeile benachbarte Pixel. Im linken Pixel entspricht es dem U-Wert beider Pixel, im rechten dem V-Wert für beide Pixel. Daher der Name ..YUYV. In einem angenommen Bild mit 2x2 Pixeln ergibt sich beispielsweise folgende Zuordnung:

Geometrische Anordnung und Indizierung der Pixel:
P00 P01
P10 P11

Verteilung der Y, U und V-Werte im Arbeitsspeicher für
die einzelnen Pixel (Idizierung wie bei den Pixeln):

Speicherplatz   Komponente  Pixelzuordnung
0               Y           00
1               U           00 und 01
2               Y           01
3               V           00 und 01
4               Y           10
5               U           10 und 11
6               Y           11
7               V           10 und 11

Code 0-5: Beispiel für die Repräsentation eines Bildes im Arbeitsspeicher bei Verwendung des komprimierten Formats V4L2_PIX_FMT_YUYV.


Das V4L2_PIX_FMT_YUYV Format hat in horizontale Richtung somit nur die halbe Auflösung, was die Komponenten U und V betrifft.


Übung
  • Nehmen Sie sich das Programm cap.c aus den Übungsmaterialien vor (Ordner video_capture).
  • Kompilieren Sie das Programm (g++ -o cap cap.c), schließen Sie die Webcam an und prüfen Sie, ob das Programm fehlerfrei durchläuft.
  • Reduzieren Sie in dem Programm die Capturing-Durchläufe von 100 auf 1 (s. Bereich ab Zeile 175 mainloop() ).
  • Nach Aufruf von mainloop(); in der main-Methode steht in buffers[0] das aufgezeichnete Bild bereit.
  • Lassen Sie durch Erweiterung der main-Methode in der Konsole die gespeicherten Werte in jedem der 640x480x2 Bytes als Integerwert auf der Konsole ausgeben.
  • Testen Sie die Plausibilität der angezeigten Daten, indem Sie einmal die Kamera mit der Linse auf die Tischplatte legen (dunkel) und ein anderes mal gegen das Licht halten. Passen insbesondere die Werte für Y hierzu? Läßt sich die halbe Auflösung bzgl. U und V erkennen?
  • Reduzieren Sie den in der Konsole ausgegebenen Bildausschnitt, z.B. auf 10x10 Pixel.
  • Um tatsächlich in der Konsolenausgabe ein Bild erkennen zu können soll nun die dargestellte Auflösung auf ein zehntel reduziert werden und nur der Y-Anteil dargestellt werden.
  • Wenn Y eines Pixels einen einstellbaren Schwellwert s (z.B. 20) überschreitet, soll ein # in der Konsole dargestellt werden, sonst ein .
  • Auf diese Weise kann man das von der Kamera erfasste Bild in der Konsole grob erkennen.
  • Stellen Sie den Schwellwert nun so ein, dass das Positionslicht als # erkennbar ist und möglichst wenige sonstige Störungen zu erkennen sind.