kramann.info
© Guido Kramann

[stud] Login: Passwort:










kramann.info
© Guido Kramann

[stud] Login: Passwort:




Ansteuerung einer Wabcam mit Linux und Xuggler

(EN google-translate)

(PL google-translate)

Ansprechen von Geräteschnittstellen über Dateien in Linux

Beim Umgang mit der seriellen Schnittstelle wurde schon bemerkt, dass sich unter dem Betriebssystem Linux Hardwarekomponenten über Dateien ansprechen lassen.

Dieses Konzept bietet mehrere Vorteile:

  • Hardwarekomponenten können über reguläre Dateioperationen, wie fopen(..) in C, mit einem Programm kommunizieren.
  • Ein Softwareentwickler kann sehr leicht einen Wechsel der anzusprechenden Hardware durch Änderung des entsprechenden Dateinamens vornehmen.

Beispielsweise war die eingebaute serielle Schnittstelle als Datei ttyS0 im Verzeichnis /dev ansprechbar, also über /dev/ttyS0. Ein später hinzugefügter USB nach Seriell-Umsetzer hat dann den Eintrag ttyUSB gehabt. Bei der Programmentwicklung war bei einem Wechsel von der eingebauten seriellen Schnittstelle zum USB-Umsetzer nur eine Änderung der angesprochenen Datei nötig, also statt /dev/ttyS0 wurde /dev/ttyUSB0 angegeben.

/dev Verzeichnis vor und nach Anstecken des USB-Seriell-Umsetzers.

Bild 0-1: /dev Verzeichnis vor und nach Anstecken des USB-Seriell-Umsetzers.

Test einer USB-Kamera

Xuggler bietet eine Programmier-Schnittstelle zur Ansteuerung einer USB-Kamera mit Linux. Dazu werden vorbereitete Java-Klassen aus einer Library verwendet, die in einem .jar-File gepackt sind. Darüber hinaus werden auch dynamisch hinzu geladene hardware nahe Libraries benötigt, die von diesen Java-Klassen benutzt werden, um die Kameraansteuerung realisieren zu können (.so-Dateien).

Die Java-Libraries von Xuggler (.jar-Dateien) sind in dem hier verwendeten Live-Linux-System unter /opt/xuggler/share/java/jars zu finden.

Die .so-Dateien finden sich unter /opt/xuggler/lib.

Als Testprogramm, das aufzeigt, wie man eine USB-Kamera ansprechen kann, steht unter /mnt-system/Z_Beispiele/javaxuggler_testwebcam das Programm DisplayWebcamVideo.java zur Verfügung.

Damit sich dieses Programm ohne weiteres kompilieren und starten läßt, müssen der Ort, an dem sich die Klassen aus den .jar-Dateien und die dynamisch hinzu geladenen Bibliotheken bekannt gemacht werden.

Dies wurde bereits in der Datei /etc/profile ergänzt. Wäre dies nicht geschehen, so könnte dies auch durch einige Konsolenbefehle bewirkt werden:

export XUGGLE_HOME=/opt/xuggler
export LD_LIBRARY_PATH=/lib:
export PATH=/bin:

Code 0-1: Vereinbarung des Homeverzeichnisses von Xuggler, Hinzufügen von /opt/xuggler/lib zum allgemeinen Bibliothekspfad, Hinzufügen von /opt/xuggler/bin zur Variable PATH.

Beim Kompilieren und Starten müssen der Ort der benötigten .jar-Dateien über die Classpath-Option (-cp) mit angegeben werden. Alternativ kann auch die Variable CLASSPATH zuvor entsprechend gesetzt werden.

Nach Einstecken der USB-Kamera liegt als neues Device /dev/video0 vor. Dementsprechend muß die Parameterübergabe bei DisplayWebcamVideo angepaßt werden.

javac -cp /opt/xuggler/share/java/jars/xuggle-xuggler.jar    VideoImage.java
javac -cp /opt/xuggler/share/java/jars/xuggle-xuggler.jar:.  DisplayWebcamVideo.java
java  -cp /opt/xuggler/share/java/jars/xuggle-xuggler.jar:.  DisplayWebcamVideo video4linux2 /dev/video0

Code 0-2: Kompilieren und Aufrufen des Testprogramms.

Programmanpassung / Re-Engineering

Wie kann dieses Testprogramm nun als Grundlage benutzt werden, eigene Java-Programme mit der Möglichkeit zu versehen, Bilder einer USB-Kamera zu verarbeiten?

Hierzu wird eine vereinfachte API entwickelt, die eine Brücke zwischen der Java-Standard-Edition und den speziellen Bibliotheksklassen darstellt.

Versuch einer Beschreibung des Vorgehens:

  1. Identifiziere ein Format, das als Brücke zwischen Standard-API und spezieller API (hier Xuggler) verwendet werden kann (hier BufferedImage).
  2. Fasse alle Vorgänge, die dem zyklischen Betrieb vorangehen in einer Initialisierungsfunktion zusammen (hier initKamera()).
  3. Generiere eine Funktion, mit der einzelne Objekte des "Brückenformats" abgeholt werden können (hier holeBild()).

Testprogramme

import java.awt.image.BufferedImage;
import java.awt.Color;

public class TestWebcamKonsole
{
    public static void main(String[] args)
    {
        BufferedImage bild = null;
        
        DisplayWebcamVideo.initKamera();

        while(true)
        {
            bild = DisplayWebcamVideo.holeBild();

            if(bild!=null)
            {
                int farbe_bildmitte = bild.getRGB(320,240);
                Color farbe_objekt = new Color(farbe_bildmitte);
                System.out.println(farbe_bildmitte
                                   +" Rotanteil:"+farbe_objekt.getRed()
                                   +" Gruenanteil:"+farbe_objekt.getGreen()
                                   +" Blauanteil:"+farbe_objekt.getBlue()
                                  );
            }

            try
            {
                Thread.sleep(10);
            }
            catch(Exception e)
            {
            }
        }
    }
}

Code 0-3: TestWebcamKonsole.java - Auslesen des mittleren Pixels und Ausgabe dessen RGB-Werte.

import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;

public class TestWebcam  extends Canvas implements Runnable
{
    private BufferedImage bild = null;

    public TestWebcam()
    {
        JFrame fenster = new JFrame();
        fenster.setBounds(10,10,680,520);
        fenster.getContentPane().add(this);
        fenster.setVisible(true);                  

        Thread thread = new Thread(this);
        thread.start();
    }

    public void run()
    {
        DisplayWebcamVideo.initKamera();

        while(true)
        {
            bild = DisplayWebcamVideo.holeBild();
            repaint();
        }    
    }

     public void paint(Graphics g)
     {         
         if(bild!=null)
         {
             g.drawImage(bild,0,0,Color.WHITE,this); 
         }
     }

    public static void main(String[] args)
    {
        TestWebcam testwebcam = new TestWebcam();
    }
}

Code 0-4: TestWebcam.java - Darstellung des Kamerabildes in einem eigenen Fenster

import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;

public class TestWebcamFilter  extends Canvas implements Runnable
{
    private BufferedImage bild = null;

    public TestWebcamFilter()
    {
        JFrame fenster = new JFrame();
        fenster.setBounds(10,10,680,520);
        fenster.getContentPane().add(this);
        fenster.setVisible(true);                  

        Thread thread = new Thread(this);
        thread.start();
    }

    public void schwellwertfilter(BufferedImage bild, int schwellwert)
    {
        for(int x=0;x<bild.getWidth();x++)
        {
             for(int y=0;y<bild.getHeight();y++)
             {
                 int rgb = bild.getRGB(x,y);
                 Color c = new Color(rgb);
                 int summe = c.getRed() + c.getGreen() + c.getBlue();
                 summe/=3;

                 if(summe>schwellwert)
                     bild.setRGB(x,y,Color.WHITE.getRGB());
                 else
                     bild.setRGB(x,y,Color.BLACK.getRGB());
             } 
        }
    }

    public void run()
    {
        DisplayWebcamVideo.initKamera();

        while(true)
        {
            bild = DisplayWebcamVideo.holeBild();
            schwellwertfilter(bild, 100);
            repaint();
        }    
    }

     public void paint(Graphics g)
     {         
         if(bild!=null)
         {
             g.drawImage(bild,0,0,Color.WHITE,this); 
         }
     }

    public static void main(String[] args)
    {
        TestWebcamFilter testwebcam = new TestWebcamFilter();
    }
}

Code 0-5: TestWebcamFilter.java - Sehr einfache aber wenig performante Umsetzung eines Schwellwertfilters (reine Testanwendung).