Informatik und Kram

Da wir lange nicht wußten, wo wir das für die Uni ausgearbeitete Material unterbringen sollten und auch einen schrecklichen Drang hatten der Welt diverse Sachen aufzudrücken...

Image Processing mit Vigra und Igel

Dank unserem Praktikum an der Uni können wir euch folgenden Artikel präsentieren, aufbauend auf der Versuchsanleitung Praktikum Robotik & visuelle Sensorik.
In diesem Versuch werden wir mit den generischen Bildverarbeitungsbibliotheken Vigra und IGEL zunächst Bildsequenzen (von einer Kamera oder aus gespeicherten Bildsequenzen) einlesen, dann glätten und schließlich eine Änderungsdetektion zwischen zwei aufeinanderfolgenden Bildern verwirklichen.

Vorwarnung: IGEL basiert auf Vigra und Qt, wir haben alle hier vorgestellten Bibliotheken und Programme also nur auf Linux-Rechnern getestet!

Einlesen von Bildsequenzen und anzeigen im Fenster

Wir gingen hier von dem von IGEL mitgelieferten Example sampleimagesource.cc aus, was wir nur dahingehend ändern mussten,
dass wir den Pfad und die Laufvariablen für gespeicherte Bildsequenzen anpassen mussten.
Hiermit ist es bereits möglich, Sequenzen sowohl direkt von einer Kamera, als auch gespeicherte Bilder zu verwenden und direkt in einem Fenster anzuzeigen.

Beispielcode zum Einlesen von gespeicherten Bildsequenzen:
//Bildquelle festlegen (Hier: gespeicherte Bildsequenzen)
igel::ImageSourceFile<pix_t>*isf(NULL);

//vigra-defs für Fenster, Bildgrössen:
vigra::Rect2D r;
r.setSize(640,480);

isf = new igel::ImageSourceFile<pix_t>("Pfad/zu/den/bildern%05d.png", 
igel::ImageSource::LOOP_REVERSE, 0, 1, 390);

//Infos über die Bilder auslesen
info = isf->getInfo();

// Neues Bild erschaffen, in dass die eingelesenen Daten geschrieben werden
image_t image1(info.width(), info.height());

// Applikation erschaffen, die das Anzeigen übernimmt
MyApplication a( argc, argv);

// Fenster erschaffen
igel::window win(info.width(), info.height());

// Bild ans Fenster binden
accessor_gray_t aGray;
win.appendDrawable(DrawableImageGrayPtr(new DrawableImageGray(
image1.upperLeft(), image1.lowerRight(), aGray, aGray, aGray ,0, 0);

// Fenster anzeigen
win.show();

// Verarbeitungsschleife
for(;;){
// immer weiter Bilder einlesen
isf->grab(destImage(image1));

// HIER FINDEN DANN VERARBEITUNGSSCHRITTE
// WIE Z.B. FALTUNGEN STATT!

win.update();
a.processEvents();
}


Dieser Code liest einfach die gespeicherten Bildsequenzen und zeigt sie in einem Fenster an:


Glätten mit Binomialfilter

Beim Glätten werden benachbarte Pixel verglichen, um eventuelles Rauschen oder fehlerhafte Pixel auszugleichen. Befindet sich beispielsweise ein einziger schwarzer Pixel inmitten von weißen Pixeln, so ist es wahrscheinlich, dass dieses Pixel verfälscht ist. Die Glättung sorgt nun dafür, dass dieser Pixel (je nach Art der Glättung) heller wird oder sogar ganz die Farbe seiner Nachbarpixel annimt.

Wir verwenden hier einen Binomialfilter, der eine diskrete Variante einer kontinuierlich abnehmenden Funktion erzeugt. Die Werte des Binomialfilters ergeben sich aus den Binomialkoeffizienten. Der Binomialfilter ist ein Tiefpass-Filter, was heisst, dass er im Ortsbereich hohe Frequenzen unterdrückt, was für das gefilterte Bild bedeutet, dass harte Wechsel der Grauwerte innerhalb weniger Pixel unterdrückt werden. Durch Tiefpassfilter werden Kantenkontraste abgeschwächt und die Grauwerte werden einander angepasst, das Bild wird unschärfer und Bildrauschen wird minimiert - es kommt zu einer Weichzeichnung des Bildes. Dieser Vorgang wird meist durch Mittelwertbildung mit den im Filterkern enthaltenen Pixeln erreicht.
Hierzu eine Illustration eines 3x3 Binomialfilters von Skript Convolution, Klaus D. Tönnies:



Dieser wird nun im Frequenzraum mit dem Originalbild multipliziert, was einer Faltung im Ortsraum entspricht. Dadurch werden, wie oben erwähnt, die tiefen Frequenzen erhalten, die Hohen jedoch abgeschwächt bzw. ganz unterdrückt.
Konkret wird dazu ein Filterkern geschaffen, und dann mit vigra-eigenen Befehlen auf das Bild angewandt. Dies geschieht innerhalb der for-schleife im obigen Code-Teil:
// initialisiere Faltungs-Kern
vigra::Kernel1D<double> kernel;
kernel.initBinomial(2);

// Stelle Rand-Behandlung ein
kernel.setBoarderTreatment(BOARDER_TREATMENT_WRAP);

// die eigentliche Faltung
vigra::seperableConvolveX(srcImageRange(image1), destImage(image1), kernel1d(kernel));
vigra::seperableConvolveY(srcImageRange(image1), destImage(image1), kernel1d(kernel));



(links Originalbild, rechts geglättet)

Änderungsdetektion

Wir stellen nun durch Pixelwert-Subtraktion Änderungen zwischen zwei aufeinanderfolgenden Bildern fest und visualisieren diese in einem neuen Bild im Fenster dadurch, dass nur die Pixel, welche Differenzen aufweisen, angezeigt werden.

(Änderung ohne Filter (links) und Änderung gefiltert (rechts))


Kommentare

mmmh, das sehe ich ja erst jetzt. Lecker - das ist ja ein richtig schöner advance-mathe-info-bilderkennungs-arktikel... Echt deluxe

wenn ich später die vapi lib von der VSI abcheck, setz ich mich gleicd später an die Face- Detection. Da hab ich Bock druff.

Ideenklau! Hehe, aber da kannste direkt dein Buch aus der Bib nochmal verlängern, da is ein super Artikel speziell zu Face-Detection dabei!

Kommentar schreiben