Technische Artikel

Programming Patterns – Verschacheltete Funktionen in MATLAB

Von Loren Shure, MathWorks


In der MATLAB USENET-Newsgroup (comp.soft-sys.matlab) wird häufig gefragt, wie mehrere Elemente, z.B. Grafiken in einer GUI, Informationen miteinander austauschen können. In diesem Artikel zeigen wir Ihnen, wie man hierfür eine Anwendung mit sehr elegantem Programmcode unter Verwen-dung von verschachtelten Funktionen (nested function — einer neuen Eigenschaft in MATLAB 7) schreibt.

Nehmen wir an, wir wollen eine GUI-Anwendung erzeugen, mit der man aus einem RGB-Bild ein Binärbild erzeugen kann, indem man einen Schwellenwert vorgibt. Das Ausgangsbild und das Ergebnis müssen dazu in verschiedenen Fenstern angezeigt werden, um Konflikte zwischen den Farbtabellen zu vermeiden.

Die entscheidenden Fragen für die Programmierung sind: Wie nutzen wir den Speicher möglichst effizient (und kopieren die Bildinformationen nicht unnötigerweise) und wie definieren wir den Geltungsbereich („Scope“) der Informationen (Bilddaten und GUI-Komponenten) sinnvoll.

Lassen Sie uns zunächst einen Blick auf die verschachtelten Funktionen werfen, bevor wir uns weiter mit dem Beispielproblem beschäftigen

Verschachtelte Funktionen

  • ist innerhalb einer anderen Funktion definiert und somit eingebettet.
  • kann auf Variablen zugreifen, die in der umgebenden Funktion spezifiziert sind.

Verschachtelte Funktionen sind nicht im matlabpath sichtbar und tauchen darum auch nicht im ‚namespace’ auf. M-Files mit verschachtelten Funktionen sind darum oft robuster gegen Veränderungen ihrer Umgebung. Da die verschachtelte Funktion Zugriff auf Variablen im Geltungsbereich der äußeren Funktion hat und diese verändern kann, müssen weniger Daten kopiert werden, was bei großen Datensätzen Speicher spart. Mit verschachtelten Funktionen lassen sich Programmstrukturen und Funktionsschnittstellen vereinfachen, weil man auf Variablen im umgebenden Workspace zugreifen kann, ohne sie als Argumente übergeben zu müssen. Verschachtelte Funktionen vereinfachen daher den Programmcode und verbessern seine Leistung

Eine verschachtelte Funktion lässt sich, wie jede andere Funktion, außerhalb ihres normalen Geltungsbereichs sichtbar machen. Dazu verwendet man ein ‚function handle’, das den Kontext inklusive des Workspace enthält, in dem das Handle erzeugt wurde. Der einem Handle zugeordnete Workspace ist völlig unabhängig vom Workspace eines weiteren Handles, der sich auf die gleiche Funktion zu einem anderen Zeitpunkt und in einem anderen Kontext bezieht. Verschiedene Instanzen eines GUI können so völlig unabhängig voneinander betrieben werden. In MATLAB Central finden Sie ein Beispiel hierfür, das zeigt, wie mehrere Instanzen eines GUI unabhängig voneinander mit verschiedenen Bildern arbeiten.

Ein Beispiel-GUI mit zwei Grafikfenstern

Unser Beispiel-GUI verfügt über zwei Fenster (Abb. 1). Das erste Fenster zeigt das RGB-Bild und einen Schieber für den Schwellenwert. Im zweiten wählt man die Farbebene (Rot, Grün oder Blau) aus einem Popup-Menü. Das Bild ist dort in schwarz/weiß maskiert, um die Identifizierung der über dem Schwellenwert liegenden Bereiche zu erleichtern. Im Titel des Fensters ist der Anteil der Fläche abzulesen, der das Schwellenwertkriterium erfüllt.

prpa_fig1_w.jpg
Abb. 1: GUI mit zwei Grafikfenstern: Eines mit den Ursprungsdaten und dem eingestellten Schwellenwert, das zweite zeigt die gewählte Farbebene und die berechneten Ergebnisse. Zum Vergrößern auf das Bild klicken.

Wie realisiert man eine solches GUI möglichst speichersparend? Es soll große Datensätze verarbeiten und Berechnungen ausführen, ohne unnötige temporäre Variablen zu erzeugen. Wie können beide Abbildungen Informationen miteinander austauschen, etwa den Schwellenwert?

Abb. 2 zeigt die Datei twofigs.m, mit der die GUI-Fenster in Abb. 1 erzeugt wurden. twofigs überprüft und (sofern nötig) konvertiert zunächst die Daten. Dann initia-lisiert das Programm das GUI mit seinen Steuerelementen und Eigenschaften, z.B. dessen Position. Bei Betätigung des Schiebereglers oder der Farbebenenwahl rufen Callbacks die Funktion updateResultFig auf. Auch die Initialisierung endet mit einem Aufruf an updateResultFig, wonach beide Abbildungen sichtbar sind.

prpa_fig2_w.jpg
Abb. 2: Verschachtelte Funktionen eignen sich hervorragend, um auf einfache Weise eine GUI-Anwendung zu erzeugen, deren Oberfläche sich frei gestalten lässt. In Zeile 46 könnte man z.B. das ‚Parent’ von RGBdrop von fig2 in fig1 verändern und damit das Drop-Down-Menü mit nur einer kleinen Veränderung in das erste Fenster übertragen. Zum Vergrößern auf das Bild klicken.

Speichereffizienz

Der Programmcode besteht aus drei Funktionen: twoFigs (die Hauptfunktion), updateResultFig und checkRGB. Diese Funktionen sind leicht zu finden, weil sie jeweils mit einer end-Anweisung geschlossen werden (was unbedingt notwendig ist, sobald in einem Programm verschachtelte Funktionen verwendet werden!).

Die erste ausführbare Anweisung in twoFigs, checkRGB(), ruft die gleichnamige Funktion in der gleichen Datei auf. Diese Funktion benötigt keine Ein- oder Ausgaben und kann die RGB-Werte des Eingabebildes in twoFigs verändern. CheckRGB sehen Sie eingerückt am Ende der Datei; die Funktion überprüft, ob es sich um ein Integer-Bild handelt. Falls ja, findet eine Umwandlung in den Datentyp ‚single’ statt.

CheckRGB ist in die Funktion twoFigs eingebettet, wie die end-Anweisungen in der Datei und die Einrückungen zeigen. Als verschachtelte Funktion kann

checkRGB auf die Variablen von twoFigs, seiner umgebenden Funktion, zugreifen. Das bedeutet, dass wir alle Berechnungen am ursprünglichen Datenfeld RGB durchführen können, ohne eine Kopie davon anfertigen zu müssen, beispielsweise die Berechnung der Farbsättigung RGB(RGB > someValue) = someValue. Dies ist besonders vorteilhaft, wenn es sich um ein großes Bild handelt. Die Datei twoFigs.m enthält eine zweite verschachtelte Funktion, updateResultFig, die die ausgesuchte Farbebene bestimmt, den eingestellten Schwellenwert abfragt und die darüber und darunter liegenden Werte berechnet. updateresultFig errechnet also, wie viel Prozent der ausgewählten Bildebene das Schwellenwertkriterium erfüllen.

Als Ergebnis dieser Auswertung erhalten wir ein Binärbild, in dessen Titel die berechneten numerischen Werte abzulesen sind. Da updateResultFig eine verschachtelte Funktion ist, kann sie auf den Workspace der sie umgebenden Funktion zugreifen, dort den Schwellenwert und die ausgewählte Ebene auslesen und dann direkt mit den Bilddaten arbeiten.

prpa_fig3_w.jpg
Abb. 3: Mit dem GUI-Code lassen sich mehrere Bilder gleichzeitig anzeigen. Zum Vergrößern auf das Bild klicken.

Scoping – Geschickte Nutzung von Geltungsbereichen

Wenn man den Schieberegler des GUI betätigt oder eine andere Farbebene auswählt, wird eine Callback-Funktion des jeweiligen Steuerelements aufgerufen. Diese Callbacks richten sich ebenfalls an die Funktion updateResultFig und teilen damit den gleichen Workspace. Da sie auf gemeinsam genutzte Daten zugreifen können, sind die Callbacks zudem sehr robust.

Das GUI soll jedes Mal automatisch das Ergebnis anzeigen, wenn man an den Steuerelementen für den Schwellenwert und die Auswahl der Farbebene neue Werte einstellt. Diese Werte werden über die Handles, die den Steuerelementen zugeordnet sind, ausgelesen. Die Handles wiederum finden wir in einigen der Variablen der Hauptfunktion. Mit diesen Variablen und unter Verwendung der Handle Graphics®-Funktion get lassen sich die gesuchten Parameter bestimmen, ohne dazu die Variablen über eine Argumentenliste eingeben zu müssen.

Da im Beispiel beide Werte Skalare und keine großen Datenfelder sind, werden immer beide ausgelesen, obwohl sich vielleicht nur einer geändert hat; der zusätzliche Aufwand ist vernachlässigbar. (Wäre das anders, ließe sich dieser Schritt natürlich auch noch optimieren.) Mit den ausgelesenen Werten wird schließlich das Ausgabebild berechnet, der Prozentsatz des Bildes, der die gesetzten Kriterien erfüllt, aufsummiert, und beides im zweiten Fenster angezeigt.

Mit verschachtelten Funktionen lassen sich robuste und gleichzeitig elegante und speichersparende MATLAB-Anwen-dungen programmieren. Sie stellen damit eine mächtige Alternative zu anderen Programmiertechniken dar.

Veröffentlicht 2006

Eingesetzte Produkte

Artikel für ähnliche Einsatzgebiete anzeigen