
Das IT-Magazin der ORDIX AG mit Fachbeiträgen zu Datenbanken, Unix und Java/XML.
Wie nicht anders zu erwarten, findet sich auch für das Thema der Bildverarbeitung innerhalb des Java Universums eine mächtige Werkzeug- und Algorithmensammlung: Das Framework JAI. JAI steht für Java Advanced Imaging, und wir wollen hier nun einige Grundzüge und Einsatzmöglichkeiten dieser API etwas genauer unter die Lupe nehmen.
In den frühen Java Versionen steckten im Abstract Windowing Toolkit (AWT) die Klassen und Methoden für den Umgang mit Bilddaten. Es ging hauptsächlich um die Darstellung von HTML Seiten mit eingebetteten Images. Dabei wurde nur eine sehr kleine Anzahl an Bildformaten unterstützt, wie GIF oder JPEG. Einmal eingelesen, konnte das Bild im Wesentlichen „nur" angezeigt werden, wobei es für weitergehende Operationen oder Manipulationen an Funktionalität fehlte. Für die Erstellung von einfachen Bildern existierten im frühen AWT einfache Zeichenfunktionen für Linien, Formen und primitive Füllmuster.
Das Paket Java 2D stellte die erste deutliche Erweiterung in diesem Bereich dar, wurde in das AWT integriert und hielt mit dem Release JDK 1.2 (auch bekannt als Java 2) Einzug in die Standard API. In Java 2D fanden sich erste Klassen und Methoden, um anspruchsvollere grafische und „rendering" Operationen auszuführen. Darüber hinaus wurde auch eine große Anzahl zusätzlicher Bildformate zumindest für den lesenden Zugriff unterstützt.
Neben einer eher einfach gehaltenen API zur Analyse und Manipulation von Bildern hat Java 2D hauptsächlich Funktionalitäten zur Darstellung von Bildern zu bieten. JAI stellt nun seinerseits eine Erweiterung zu Java 2D dar und kann mit Fug und Recht als umfangreiche Sammlung für Bildverarbeitungsmethoden bezeichnet werden.
In der Dokumentation zu JAI werden die folgenden Merkmale gesondert herausgestellt:
Einige dieser Punkte ergeben sich allein aus dem Java Kontext (plattformunabhängig, objektorientiert, flexibel, usw.), andere wollen wir beleuchten. Ein Punkt, der in diesem Artikel nicht weiter behandelt wird, ist die „Verteilte Bildverarbeitung". Dahinter verbirgt sich die Funktionalität, längere Ketten von Bildverarbeitungsmodulen auf verschiedene Rechner zu verteilen, unter Verwendung von Remote Method Invocation (RMI).
Im JAI findet sich eine Zweiteilung der beteiligten Klassen und Interfaces analog zum Stream Konzept aus dem JAVA I/O Bereich (InputStream, OutputStream). Grundsätzlich unterscheidet man im Kontext des JAI zwischen Bildquellen („source") und Bildsenken („sinc"). Eine typische Bildquelle ist ein Java Objekt, das eine Bilddatei einliest und bereithält (Beispielklasse aus JAI: PlanarImage). Eine typische Bildsenke ist ein Java Objekt, das die Darstellung vornimmt (Beispielklasse: ImageDisplay). Die Verbindung der Quelle mit der Senke kann z. B. bei der Instantiierung erfolgen, oder durch expliziten Methodenaufruf. Dabei kann es durchaus hybride Objekte geben, die sowohl die Rolle einer „source", als auch die Rolle einer „sinc" annehmen und die damit eine Art Durchgangsstation bilden.
Mit diesem Prinzip lassen sich ganze Ketten von Bearbeitungskomponenten bilden, die im JAI Kontext auch processing graphs heißen. Dieser Ansatz ist auch als „Dekorationsprinzip" bekannt. Für eine gewünschte Funktionalität kommt dabei nicht eine genau darauf spezialisierte Klasse zum Einsatz, sondern eine Kombination aus verschiedenen JAI Klassen, die, jede für sich, häufig nur einen einzigen Aspekt bedienen. Das System wird solange „dekoriert" bis das gesuchte Input-Output Verhalten vorliegt.
Wir sehen uns in einem ersten Beispiel die Funktionalität „Bildausschnitt vergrößern" etwas genauer an. Dieses und eine Reihe weiterer, sehr instruktiver Beispiele sind in einem Tutor-Programm des JAI zusammengefasst, welches einen sehr guten Überblick zum Themenkomplex bietet, jedoch separat aus dem Internet herunter zu laden und zu installieren ist .
...
import javax.media.jai.JAI;
import javax.media.jai.PlanarImage;
public class MagnifierTest extends JPanel {
private PlanarImage source = null;
public MagnifierTest (String filename) {
File f = new File(filename);
if ( f.exists() && f.canRead() ) {
source = JAI.create("fileload", filename);
ImageDisplay canvas = new ImageDisplay(source);
Magnifier mag = new Magnifier();
mag.setSource(canvas);
mag.setMagnification(3.0F);
mag.setSize(128, 128);
mag.setLocation(150, 150);
...
|
| Abb. 1: Auszug aus dem Java Quellcode des Beispielprogramms "Magnifier". |
![]() |
| Abb. 2: Ausschnitt-Vergrößerung mit Faktor 3 in einem Farbbild. |
In Abb. 1 sehen wir einen Auszug des zugehörigen Java Quellcodes. JAI.create(...) in Zeile 1 stellt eine zentrale Generierungsmethode des JAI Frameworks zur Verfügung, mit der in unserem Beispiel eine Bilddatei vom Datenträger eingelesen und einer Variablen vom Typ PlanarImage zugewiesen wird.
Ein Beispiel für ein hybrides Objekt ist canvas, das sich zum einen um die Darstellung des Gesamtbildes kümmert (Bildsenke), zum anderen aber gegenüber einem weiteren Objekt (Magnifier mag) als Quelle fungiert. Die Verbindung zwischen diesen beiden Instanzen geschieht in Zeile 3 mit einem expliziten Methodenaufruf, wohingegen das Verbinden per Instantiierung in Zeile 2 zum Einsatz kommt.
Das Ergebnis dieser Operation ist in dem Farbbild in
Abb. 2 zu sehen. Das Magnifier Objekt ist mit einer 3fachen Vergrößerung
ausgestattet (Zeile 4 in Abb. 1) und innerhalb der Bildgrenzen beliebig
verschiebbar.
Die eigentlichen Stärken des JAI liegen jedoch im Bereich der Bildanalyse und -manipulation, was man gemeinhin unter Bildverarbeitung zusammenfasst. Zunächst folgt jedoch eine kurze Einführung der grundlegenden Sachverhalte.
Ein 2-dimensionales, digitales Bild ist in einem
Array der Größe m x n (m Zeilen und
n Spalten) abgelegt. An jeder Koordinate
(i,j) befindet sich der Wert des
Bildpunktes, häufig auch einfach als Pixel
(kurz für picture element) bezeichnet. Vom
Typ des Bildes hängt der Typ eines Pixels ab. So setzt
sich ein Farbbild i. A. aus den 3 Einzelkanälen
Rot, Grün und Blau (sog. RGB-Bilder)
zusammen, so dass dessen Pixel ebenfalls eine
3-komponentige Größe bilden, mit
jeweils einem Wert (0-255) für den Rot-,
Grün-, und Blauanteil. Die Pixel von Grauwertbildern besitzen nur eine Komponente
für den Grad der Helligkeit an der zugehörigen
Bildposition.
![]() |
| Abb. 3: Verbesserung eines Grauwertbildes mit Auswertung von Histogrammen. |
Um Bilder analysieren oder manipulieren zu können, definiert JAI eine Reihe von Bildoperatoren, die sich in den folgenden Oberbegriffen zusammenfassen lassen, und die hier nur ansatzweise mit einer z. T. knappen Erläuterung erwähnt werden:
Der Einsatz von JAI Operatoren soll anhand eines weiteren Beispiels aus dem Tutorial veranschaulicht werden. Quelle ist ein Grauwertbild mit vorwiegend dunklen Bildbereichen (Abb. 3). Darunter ist das zugehörige Histogramm zu sehen. Ein Histogramm beinhaltet die Häufigkeiten der in einem Bild vorkommenden Grauwerte und wird häufig in einem Diagramm dargestellt. Die Häufung im niederwertigen Bereich des Histogramms (0 = Schwarz, 255 = Weiß) deutet auf ein dunkles Quellbild hin.
Man kann nun eine Bildverbesserung erreichen, indem man die Grauwertverteilung im Histogramm besser und gleichmäßiger anordnet. Das Verfahren ist auch bekannt als „Histogramm Egalisierung". Der Effekt ist im rechten Teil von Abb. 3 zu sehen: Hier sind im Zielbild deutlich mehr Details erkennbar. Diese Operation setzt sich aus Punkt- und Flächenoperatoren zusammen und besteht im Wesentlichen nur aus ein paar Java Quellcodezeilen, da die wichtigen Bestandteile des Verfahrens (Histogrammbildung, Lookup-Operationen, ...) im JAI Framework vorliegen.
Wie so oft bei der Vorstellung von eigenständigen Java Paketen kann auch in diesem Artikel zu JAI nur die Spitze des Eisberges zum Vorschein kommen. Wer in seinem System mit digitalen Bilddateien zu tun hat, und diese auch noch auswerten und manipulieren muss, bekommt mit JAI eine mächtige Werkzeugsammlung an die Hand. ORDIX hat sich dieses Themas angenommen, da es in dem oben erwähnten Projekt zur Bilddatenarchivierung um die Integration dieser API geht.
Dr. Hubert Austermeier (info@ordix.de).