Skip to main content

Simple Moving Average Beispiel Matlab


Statistische Analyse Unsere Fachstatistiker beraten Sie gern, wie Sie Ihre Recherche - und Datenerfassungsmethoden optimal gestalten können. Wenn Sie Ihre Daten noch nicht gesammelt haben, können Sie eine Excel-Datei erstellen. Siehe Beispiel. Wir sind in der Lage, Ihnen mit allen statistischen Analyse-Bedürfnisse zu helfen, egal, ob Sie an einem bestimmten Forschungsgebiet arbeiten oder eine große und vielfältige Datenmenge interpretieren. Ivory Research statistische Dienstleistungen umfassen: Grundlagen Statistische Statistik (Mittelwert, Median, Modus, Standardabweichung, Reichweite, Diagramme amp Graphen) Wahrscheinlichkeit (Grundlegende Theoreme zur Wahrscheinlichkeit Bedingte Wahrscheinlichkeit) Diskrete Wahrscheinlichkeitsverteilungen (Binomial, Poisson, Geometrisch, Hypergeometrisch) Kontinuierliche Wahrscheinlichkeit Verteilung (Normal, T, Chi-Quadrat, F) Z-Score Konfidenzintervall für Mittelwert, Standardabweichung und Proportion Hypothesentest über Mittelwert und Anteil Hypothesentest über Standardabweichung und Varianz ANOVA (Einweg Zweiweg) MANOVA Korrelation (Pearsons-Korrelation, Rangkorrelation ) Biostatistik Lineare Regression (Einfache lineare Regression Multiple lineare Regression) Nicht-lineare Regression Logistische Regression Nicht-parametrischer Test (Chi-Quadrat, Run-Test) Signaltest Mann Whitney U-Test, Wilcoxons gepaartes Zeichenrangtest, Kruskal Wallis Test) Statistische Qualitätskontrolle (Diagramm, R-Diagramm, C-Diagramm, P-Diagramm, NP-Diagramm) Entscheidungslehre Spieltheorie Lineares Programmieren Problem Zeitreihenanalyse (Gleitender Durchschnitt, Exponentialglättung, Anpassungstrend und Saisonmodelle) Indexnummern Geschäftsstatistiken ÖkonometrieKapitel 22 Bildverarbeitung mit MATLAB und GPU MATLAB (MathWorks, Natick, MA, USA) ist ein Softwarepaket für numerische Datenverarbeitung, das in verschiedenen wissenschaftlichen Disziplinen wie der Mathematik eingesetzt werden kann , Physik, Elektronik, Ingenieurwesen und Biologie. Mehr als 40 Toolboxes gibt es im aktuellen Release (R2013b ab September 2013), zu dem zahlreiche integrierte Funktionen gehören, die durch den Zugriff auf eine Programmiersprache auf hohem Niveau erweitert werden. Da Bilder durch 2D - oder 3D-Matrizen dargestellt werden können und die MATLAB-Prozessor-Engine auf Matrixdarstellung aller Elemente beruht, eignet sich MATLAB besonders für die Implementierung und das Testen von Bildverarbeitungs-Workflows. Die Bildverarbeitungs-Toolbox (IPT) beinhaltet alle notwendigen Werkzeuge für die universelle Bildverarbeitung mit mehr als 300 Funktionen, die optimiert wurden, um eine hohe Genauigkeit und hohe Verarbeitungsgeschwindigkeit zu bieten. Darüber hinaus wurde die integrierte Parallel Computing Toolbox (PCT) kürzlich erweitert und unterstützt nun die Grafikverarbeitungseinheit (GPU) für einige Funktionen des IPT. Für viele Bildverarbeitungsanwendungen müssen wir jedoch unseren eigenen Code entweder in MATLAB oder, im Falle von GPU-beschleunigten Anwendungen, die eine spezifische Kontrolle über GPU-Ressourcen erfordern, in CUDA (Nvidia Corporation, Santa Clara, CA, USA) schreiben. In diesem Kapitel widmet sich der erste Teil einigen wesentlichen Werkzeugen der IPT, die in der Bildanalyse und - bewertung sowie bei der Extraktion von nützlichen Informationen für die weitere Verarbeitung und Bewertung genutzt werden können. Dazu gehören das Abrufen von Informationen über digitale Bilder, Bildanpassung und Verarbeitung sowie Feature-Extraktion und Video-Handling. Der zweite Teil ist der GPU-Beschleunigung der Bildverarbeitungstechniken entweder durch die Verwendung der integrierten PCT-Funktionen oder durch das Schreiben eigener Funktionen gewidmet. Jeder Abschnitt wird von MATLAB-Beispielcode begleitet. Die Funktionen und der Code in diesem Kapitel werden aus der MATLAB-Dokumentation 1, 2 übernommen, sofern nicht anders angegeben. 2. Bildverarbeitung auf CPU 2.1. Grundlegende Bildkonzepte 2.1.1. Pixeldarstellung Ein digitales Bild ist eine visuelle Darstellung einer Szene, die unter Verwendung einer digitalen optischen Vorrichtung erhalten werden kann. Es besteht aus einer Anzahl von Bildelementen, Pixeln und kann entweder zweidimensional (2D) oder dreidimensional (3D) sein. In der wissenschaftlichen Bildverarbeitung sind jedoch die 1-Bit-Binärbilder (Pixelwerte 0 oder 1), die 8-Bit-Graustufenbilder (Pixelbereich 0-255) und die 16 - Bit-Farbbildern (Pixelbereich 0-65535) 3. Fig. 1 zeigt die Graustufenvariation von Schwarz zu Weiß für ein 8-Bit-Bild. Variation der Graustufenintensitäten für ein 8-Bit-Bild. 2.1.2. MATLAB-Pixelkonvention MATLAB verwendet eine einstufige Indexierung, wobei das erste Pixel entlang einer beliebigen Dimension index1 hat, während viele andere Plattformen nullbasiert sind und den ersten Index als 0 betrachten. Nach der Konvention beginnt das Zählen von Pixelindizes von oben links Ecke eines Bildes, wobei die ersten und zweiten Indizes jeweils nach unten bzw. nach rechts abfallen. Abbildung 2 zeigt, wie MATLAB ein 512512 Pixel-Bild indiziert. Diese Information ist besonders wichtig, wenn der Benutzer beabsichtigt, eine Transformation auf ein bestimmtes Pixel oder eine Nachbarschaft von Pixeln anzuwenden. MATLABs-Pixelindexierungskonvention. 2.1.3. Bildformate Verschiedene Bildformate werden von MATLAB unterstützt, einschließlich der am häufigsten verwendeten, wie JPEG, TIFF, BMP, GIF und PNG. Bilder können gelesen, verarbeitet und in einem anderen Format als ihrem ursprünglichen gespeichert werden. Verschiedene Parameter wie Auflösung, Bittiefe, Kompressionsebene oder Farbraum können entsprechend den Benutzereinstellungen angepasst werden. 2.1.4. Digitale Bildverarbeitung Die digitale Bildverarbeitung bezieht sich auf die Modifikation eines digitalen Bildes mit Hilfe eines Computers, um relevante Informationen hervorzuheben. Dies kann erreicht werden, indem sowohl latente Details aufgedeckt werden als auch unerwünschte Störungen unterdrückt werden. Das Verfahren wird gewöhnlich entsprechend dem gewünschten Endresultat entworfen, das eine einfache Bildverstärkungsobjektdetektion, Segmentierung oder Verfolgungsparameterschätzung oder Zustandsklassifikation umfassen kann. Darüber hinaus kann die Struktur und Funktion des menschlichen Sehsystems beim Umgang mit Bildern, die für die Inspektion durch Menschen bestimmt sind, ein kritischer Faktor beim Entwerfen irgendeines solchen Verfahrens sein, das bestimmt, was als ein leicht unterscheidbares Merkmal wahrgenommen werden kann. 2.2. Bildvorverarbeitung Bildvorverarbeitung ist ein Verfahren, das erste Informationen über den digitalen Zustand eines Kandidatenbildes liefert. Um solche Informationen zu erhalten, müssen wir das Bild auf die Softwareplattform laden und deren Typ - und Pixelwerte untersuchen. 2.2.1. Bildeingabe und Ausgabe Wie alle anderen Daten in MATLAB werden auch Bilder durch eine Variable dargestellt. Wenn wir eine Bilddatei mit Namensbild und Format tiff betrachten, verwenden wir die Funktion imread. Kann das Bild je nach Bildtyp als 2D - oder 3D-Matrix geladen werden. Die Bildvisualisierung wird mit der Funktion imshow erreicht, um eine neue Figur zu erzeugen. Dem Aufruf eines Imshow muss ein Aufruf zur Figur vorangestellt werden. Wird stattdessen imshow eigenständig verwendet, ersetzt das neue Bild das letzte im letzten geöffneten Fenster. Das Speichern eines Bildes kann mit der Funktion imwrite erreicht werden, bei der das gewünschte Bild (d. h. Variable), das Format und der endgültige Name angegeben werden müssen. Obwohl der Name des gespeicherten Bildes frei gewählt werden kann, wird beim Aufbau einer großen Pipeline vorgeschlagen, dass der Name jedes resultierenden Bildes repräsentativ für den Verarbeitungsschritt ist, um die Prozesskohärenz aufrechtzuerhalten. Das folgende Beispiel zeigt, wie diese Reihenfolge erreicht werden kann. Die Funktion imshow kann auch von einem Zwei-Elemente-Vektor Low High begleitet werden, mit dem der Anwender den Anzeigebereich des Graustufenbildes spezifiziert. Wenn dieser Vektor leer bleibt. Werden die minimalen und maximalen Grauskalenwerte des Bildes als Schwarz-Weiß-Pixel mit den Zwischenwerten als verschiedene Grauschattierungen angezeigt. 2.2.2. Bildtypkonvertierungen Die Bildtypkonvertierung ist ein nützliches Werkzeug, da der Anwender das eingegebene Bild in einen beliebigen Typ umwandeln kann. Eine besondere und oft nützliche Umsetzung ist die Transformation einer ganzen Zahl ohne Vorzeichen in eine doppelte Genauigkeitsdarstellung. Jeder Bildverarbeitungsalgorithmus kann somit zu genaueren Ergebnissen führen, da diese Umwandlung den dynamischen Bereich der Intensitäten erhöht. Der Bereich des resultierenden Bildes beträgt 0,0 bis 1,0, wobei MATLAB bis zu 15 Dezimalstellen beibehält. Die folgenden Befehle sind Beispiele für Bildkonvertierungen. 2.2.3. Pixelinformation Ein Histogramm ist eine nützliche Intensitätsdarstellung, da es die Pixelintensitätsverteilung aufdeckt. Es kann mit der Funktion imhist erhalten werden. Diese Informationen können beispielsweise zur Auswahl eines geeigneten Schwellenwerts verwendet werden. Abgesehen davon kann ein Intensitätsprofil auch Informationen über lokale Intensitätsschwankungen aufzeigen, mit denen kleine Details modelliert werden können. Die Funktion improfile kann entweder auf vorgewählte Pixel oder als Eingabeaufforderung für den Benutzer angewendet werden, um den gewünschten Bereich manuell auszuwählen. Beispiel eines Codes für solche Prozesse folgt 1, 3. 2.2.4. Kontrasteinstellung Eine der Hauptvorverarbeitungstechniken ist die Kontrasteinstellung, da dieser Vorgang die gewünschten Merkmale verbessern kann, während andere, unerwünschte Unterdrückungen unterdrückt werden. MATLAB verfügt über verschiedene Werkzeuge zur Veränderung des Bildkontrasts. Die Funktion imcontrast liefert ein manuelles Justierwerkzeug, mit dem der Anwender experimentieren und den optimalen Kontrast finden kann. Die resultierenden Parameter können dann übernommen, gespeichert und auf einen unter den gleichen Bedingungen aufgenommenen Stapel von Bildern angewendet werden. Die Funktion imadjust kann verwendet werden, um einen Intensitätsbereich festzulegen, wenn der Benutzer die optimalen Werte kennt oder mit dem Imcontrast-Tool gefunden hat. Die gleiche Funktion liefert auch Eingang für den Gamma-Faktor der nichtlinearen Leistungsregelung. Darüber hinaus kann eine maßgeschneiderte logarithmische Transformation angewendet werden 3. Fig. 3 zeigt ein ursprüngliches Graustufenbild und sein kontrastjustiertes Gegenstück unter Verwendung der Parameter, die in dem vorhergehenden Beispiel spezifiziert wurden. Originalbild (links, 12961936 Pixel) und Kontrasteinstellung (rechts). Parameter a. B und c können durch den Benutzer definiert und angepasst werden, dh jede derartige maßgeschneiderte logarithmische Transformation kann entsprechend den spezifischen Bedürfnissen eingeführt werden. Andere Techniken, die den Kontrast beeinflussen können, sind histogrammbasiert. Ein Histogramm repräsentiert eine Graustufenintensitätsverteilung oder eine Wahrscheinlichkeitsdichtefunktion. Solches Wissen kann bei der Weiterverarbeitung helfen, indem es dem Benutzer hilft, die richtigen Werkzeuge auszuwählen 4. Die Histogrammstreckung kann durch die Imadjust-Funktion durchgeführt werden, während die Histogrammausgleichung durch die Funktion histeq durchgeführt werden kann. Die adaptive Histogramm-Entzerrung kann auch mit der Funktion adaptthisteq angewendet werden, die kleine Bildnachbarschaften anstelle des gesamten Bildes als Eingabe betrachtet. Der Parameter NumTilesValue hat die Form eines Vektors, der die Anzahl der Kacheln in jeder Richtung angibt. Andere Parameter können auch in der adapthisteq-Funktion angegeben werden, wie zB der Dynamikbereich der Ausgangsdaten oder die Histogrammform. Fig. 4 zeigt Beispiele für die Histogramm-Entzerrung bzw. die adaptive Histogramm-Entzerrung. Histogramm-Entzerrungstransformation (links) und adaptive Histogramm-Entzerrungstransformation (rechts) des Originalbildes in Abbildung 3. Beachten Sie die erweiterten Details im rechten Bild. 2.2.5. Arithmetische Operationen Arithmetische Operationen beziehen sich auf Addition, Subtraktion, Multiplikation und Division von zwei Bildern oder ein Bild und eine Konstante. Bilder, die arithmetischen Operationen unterliegen, müssen dieselben Dimensionen und Graustufenrepräsentationen aufweisen. Das resultierende Bild hat die gleichen Abmessungen wie die Eingabe. Wenn ein konstanter Wert addiert oder subtrahiert wird (anstelle eines zweiten Bildes), wird diese Konstante zu jeder Pixelintensität addiert oder subtrahiert, wodurch die Bildhelligkeit erhöht oder verringert wird. Meistens werden solche Operationen zur Detailverbesserung oder Unterdrückung unnötiger Informationen verwendet. In dem obigen Code kann der zweite Eingangsparameter (im2) durch eine skalare Konstante ersetzt werden. 2.2.6. Verschiedene Transformationen Andere nützliche Bildtransformationen umfassen das Zuschneiden, die Größenänderung und die Rotation. Zuschneiden kann verwendet werden, wenn der Benutzer nur an einem bestimmten Teil des Eingabebildes interessiert ist. Der Benutzer kann einen bestimmten Bereich von Interesse definieren und jede Transformation nur auf diesen Teil anwenden. Größenänderung kann angewendet werden, um die Bildgröße zu erweitern oder zu verkleinern. Die Bildgrößenverringerung kann insbesondere bei der Beschleunigung eines Prozesses bei größeren Bildern oder großen Datensätzen nützlich sein. Die Rotation kann besonders nützlich sein, wenn ein Bild Merkmale einer bestimmten Direktionalität aufweist. Der Benutzer kann die angewendete Interpolationsmethode aus nächster Nachbarschaft, bilinear und bikubisch spezifizieren. Inversion von Graustufen-Intensitäten kann nützlich sein, wenn die interessanten Objekte haben Intensitäten niedriger als der Hintergrund. Folgende Funktionen führen diese Prozesse aus. 2.3. Bildverarbeitung 2.3.1. Thresholding Thresholding ist eines der wichtigsten Konzepte der Bildverarbeitung, da es in fast allen Projekten Anwendung findet. Thresholding kann manuell oder automatisch, global oder lokal sein. Im manuellen Modus definiert der Benutzer einen Schwellenwert, der in der Regel von der Konzeption des Bildes abhängt (es können mehrere Versuche erforderlich sein). Im automatischen Modus ist ein genaues Verständnis des Bildes erforderlich, um die richtige Methode auszuwählen. Das IPT stellt die Funktion graythresh zur Verfügung, die auf der Otsus-Methode und dem bimodalen Zeichen eines Bildes 5 basiert. Diese globale Schwelle erzeugt ein Schwarz-Weiß-Bild, bei dem Pixel mit Intensitäten oberhalb dieses Schwellenwerts weiß werden (Wert 1) und Pixel mit Intensitäten unterhalb dieses Schwellenwertes schwarz werden (Wert 0). Diese Methode kann problemlos auf Multi-Thresholding erweitert werden, indem die IPT-Funktion Multithresh verwendet wird. Mit dieser Funktion legt der Benutzer eine geeignete Anzahl von Schwellenwerten (k) für das Bild fest. Wird dieser Parameter nicht mitgeliefert, hat er die gleiche Funktionalität wie die ursprüngliche graythresh-Funktion. Das IPT kann das Ergebnis der Multithresh-Funktion mit der Imquantisierungsfunktion visualisieren. Diese kennzeichnet die verschiedenen Bereiche des Bildes entsprechend der Anzahl der zuvor festgelegten Schwellenwerte. Das markierte Bild kann dann in ein RGB-Bild transformiert werden, wobei der Typ (z. B. uint8) der ursprünglichen Eingabe erhalten bleibt. Der folgende Code kann in diesen Prozessen verwendet werden. 5 stellt ein Beispiel einer Ein-und Mehrfachschwellenanwendung für das Originalbild von 3 bereit. Einschwelliges Bild (links) und mehrschwelliges Bild mit 5 Schwellenwerten (rechts). 2.3.2. Kantenerkennung Die Kantenerkennung ist ein wesentlicher Bestandteil der Bildverarbeitung, da sie in der Regel Objekte oder eine interne Struktur hervorhebt. Eine Kante ist eine Darstellung der Diskontinuität in einem Bild und kann eine Oberfläche charakterisieren, die zwei Objekte oder ein Objekt von dem Bildhintergrund 4 trennt. Boundaries können durch einzelne Pixel oder verbundene Sequenzen von Pixeln charakterisiert werden. Ein solches Merkmal kann bei einer weiteren Objekterkennung helfen und somit wird die Kantenerfassung in vielen Bildverarbeitungssequenzen angewendet. Das Ergebnis der Kantenerfassung ist ein binäres Bild mit Kanten, die von weißen Pixeln dargestellt werden. 2.3.3. Kantenerfassungsoperatoren erster Ordnung Die IPT umfasst die standardmäßigen Kantendetektoren erster Ordnung wie die Roberts, Sobel und Prewitt. Roberts Randdetektor stützt sich auf 22 Masken, während die anderen zwei auf 33 Masken verlassen. Ein optionaler Schwellenwert kann festgelegt werden, um die minimale Gradientengröße zu definieren. Nützlicher Code für solche Detektoren folgt. Andere Kantendetektoren erster Ordnung können auch entworfen werden. Beispiele sind die Kirsch - und die Robinson-Masken, die nicht im IPT enthalten sind, sondern einfach zu entwerfen sind. Sie sind Beispiele von Richtungsranddetektoren, die das Bild aus verschiedenen Richtungen abtasten, um Kanten mit verschiedenen Orientierungen zu detektieren. Es wird ein einziger Kern verwendet, der durch Rotationen von 0 bis 315 in Schritten von 45 acht verschiedene Masken erzeugt. Das Bild wird mit jeder Maske gefaltet und den Pixeln in dem endgültigen Bild wird die höchste Kantenerfassungsgröße zugewiesen, die von irgendeiner der Masken 4 erhalten wird. Der folgende Code stellt diese zwei Kantendetektoren 6 bzw. 4 dar. Der Punktdetektor, ein weiteres Beispiel eines Kantendetektors, erfasst helle Punkte basierend auf der Intensitätsdifferenz zwischen einem zentralen Pixel und seinen Nachbarn. Ein Punktdetektor kann durch den folgenden Code 7 spezifiziert werden. 2.3.4. Kantendetektionsoperatoren zweiter Ordnung Neben Kantendetektoren erster Ordnung können Kantendetektoren zweiter Ordnung breite Anwendung finden. Solche Detektoren sind beispielsweise Canny, Nulldurchgang und Laplace-of-Gaussian (LoG, auch Marr-Hildreth genannt). Das Canny-Verfahren verwendet die Ableitung eines Gaußschen Filters, um den Gradienten des Originalbildes zu finden, wonach es auf lokalen Maxima des resultierenden Bildes beruht. 3 Die Nulldurchgangsmethode sucht nach einem beliebigen Filter nach Nulldurchgängen. Schließlich sucht das LoG-Verfahren nach der Anwendung der LoG-Transformation nach Nulldurchgängen. Nützlicher Code für solche Detektoren folgt. In diesem Fall bezieht sich die Schwelle auf die Stärke eines Kanten-Sigmas, das sich auf die Standardabweichung des Gaußschen Filters bezieht, während das Filter auf alle Filter zutrifft, die der Benutzer vor der Kantenerfassung anwendet. Bei LoG - und Canny-Methoden können Schwelle und Sigma nicht spezifiziert werden, aber im Falle der Nulldurchgangsmethode muss der Benutzer einen Filter definieren. Fig. 6 zeigt die resultierenden Bilder nach dem Aufbringen von Roberts - und Canny-Randdetektoren. Anwendung von Roberts Randdetektor (links) und Canny Randdetektor mit einem Schwellenwert von 0,05 (rechts). 2.3.5. Bildfilterung Die räumliche Filterung ist einer der wichtigsten Prozesse in der Bildverarbeitung, da sie bestimmte Frequenzen aus einem Bild extrahieren und verarbeiten kann, während andere Frequenzen entfernt oder transformiert werden können. Normalerweise wird die Filterung zur Bildverbesserung oder zur Rauschentfernung verwendet. IPT enthält die Standard-Werkzeuge, die für die Bildfilterung benötigt werden. Die Funktion fspecial kann für das Filterdesign verwendet werden. Mittlere, mittlere, Gaußsche, Laplace-, Laplace-von-Gaussian-, Bewegungs-, Prewitt-edge - und Sobel-edge-Filter können eingeführt werden. Das erzeugte Filter wird mit der Funktion imfilter auf das Bild angewendet. Typische Beispiele für Code folgen. Der Parameter hsize ist ein Vektor, der die Anzahl der Zeilen und Spalten der Nachbarschaft repräsentiert, die beim Anwenden des Filters verwendet wird. Der Parameter Sigma ist die Standardabweichung des angewandten Gaußschen Filters. Kantendetektoren können auch angewendet werden, indem das Bild mit dem Kantenoperator gefiltert wird. Ein Beispiel folgt mit der Anwendung des zuvor erwähnten Punktflankendetektors. Neben benutzerdefinierten Filtern enthält IPT Filter, die direkt auf das Bild angewendet werden können. Solche Beispiele sind der Medianfilter (medfilt2), der Wiener-Filter (wiener2) oder der 2D-Ordnungsstatistikfilter (ordfilt2). Die Nachbarschaft in der Funktion medfilt2 gibt die Abmessungen des Bereichs an, in dem der Medianwert des Pixels gefunden wird. Die Funktion ordfilt2 ist eine verallgemeinerte Version des Medianfilters. Eine Nachbarschaft wird durch die Nicht-Null-Pixel der Domäne definiert. Und jedes Pixel in dem Bild wird durch die Ordnung - dkleinster seiner Nachbarn innerhalb dieses Bereichs 1 ersetzt. Ein Beispiel könnte der folgende Befehl sein, wobei jedes Pixel durch den sechsten kleinsten Wert ersetzt wird, der in seiner 33 Nachbarschaft gefunden wird. 7 zeigt Beispiele für Gaußsche und Ordnungsstatistik-gefilterte Bilder. Die Bilder wurden mit einem Gaußschen Filter (links hsize 9 9 und sigma 1) und einem statistischen Filter der 6. Ordnung (rechts) gefiltert. 2.3.6. Morphologische Bildverarbeitung Morphologische Bildverarbeitung bezieht sich auf die Extraktion von Deskriptoren, die interessierende Objekte beschreiben und damit deren Morphologie die verwendeten Werkzeuge bestimmen 8. Strukturelemente werden verwendet, um das Bild 3 zu untersuchen. Die Funktion bwmorph führt alle morphologischen Operationen mit geeigneten Parametern durch. Da die Verarbeitungszeit dieser Funktion mit der Bildkomplexität signifikant zunehmen kann, wird sie durch die PCT für eine erhöhte Verarbeitungsgeschwindigkeit unterstützt. Morphologische Prozesse umfassen Dilatation, Erosion, Öffnen, Schließen, Top-Hat und Bottom-Hat-Transformation, Hit-or-Miss-Transformation sowie andere Prozesse, die pixel-spezifische Änderungen durchführen. Die Parameteroperation berücksichtigt die Art des morphologischen Operators, während n die Anzahl der Wiederholungen dieses Vorgangs ist. Wenn n nicht definiert ist, wird der Prozess nur einmal angewendet. Prozesse wie Dilatation und Erosion können auch mit individuellen Funktionen angewendet werden, wenn ein maßgeschneidertes Strukturierungselement eingesetzt werden soll. Beispiele für einzelne Prozesse folgen. Fig. 8 zeigt Beispiele der Dilatation und Top-Hat-Transformation mit einem Scheibenstrukturierungselement des Radius 10. Diliertes Bild (links) und ein tophut-transformiertes Bild unter Verwendung eines Scheibenstrukturierungselements mit Radius 10 (rechts). Die Abstandstransformation wird üblicherweise auf binäre Bilder angewendet und stellt den Abstand zwischen einem weißen Pixel und seinem nächsten Nullpixel dar. Pixel im neuen Bild erhalten höhere Werte mit größerem Abstand von einem Nullpixel. Diese Transformation kann als Segmentierungsfunktion wirken und wird häufig bei der Segmentierung von überlappenden Scheiben 1, 8 verwendet. 2.3.7. Farbverarbeitung Farbbilder unterliegen der Verarbeitung in vielen wissenschaftlichen Bereichen, da unterschiedliche Farben unterschiedliche Funktionen darstellen können. Die am häufigsten verwendete Farbdarstellung ist RGB (Rot-Grün-Blau). Die Transformation von RGB-Bildern in Graustufenintensität oder Extraktion einer bestimmten Farbe kann mit dem folgenden Code erfolgen: 2.4. Feature-Extraktion Feature-Extraktion ist der Prozess, durch den erkannte Objekte nach bestimmten geometrischen Kriterien bewertet werden. Der erste Schritt dieses Prozesses besteht darin, die Objekte eines binären Bild-Imbins mit der Funktion bwlabel zu kennzeichnen. Das resultierende Bild wird als markiertes Bild (imlab) bezeichnet. Die Funktion scannt das Bild von oben nach unten und von links nach rechts, wobei jedem Pixel eine Zahl zugewiesen wird, die angibt, zu welchem ​​Objekt es gehört. Zusätzlich verfügt das IPT über die Funktion regionprops, die Merkmale markierter Objekte wie Fläche, äquivalenter Durchmesser, Exzentrizität, Umfang und Haupt - und Nebenachsenlängen mißt. Diese Funktion arbeitet mit beschrifteten Bildern, die n beschriftete Objekte enthalten. Eine vollständige Liste der Funktionen, die mit regionprops berechnet werden können, finden Sie in der MATLAB IPT-Dokumentation 1. Neben den Standardfunktionen, die im IPT enthalten sind, können kundenspezifische Merkmale entweder mit bereits berechneten Merkmalen oder mit völlig neuen Messungen gemessen werden. Ein Beispiel könnte die Messung von geometrischen Eigenschaften eines Objekts, des Dünnheitsverhältnisses und der Kompaktheit (oder Unregelmäßigkeit) unter Verwendung einer for-Schleife zur Bewertung aller n Objekte sein. Da der Benutzer viele Messungen für viele Objekte durchführen muss, ist es gewöhnlich zweckmäßig, Speicher vorzuverteilen, um die Verarbeitungszeit zu verkürzen. Mit dem folgenden Code können Sie Bildobjekte beschriften, die Merkmale messen und als Tabelle der Variablen 1, 3 speichern. Gemessene Merkmale werden in Strukturarrays gespeichert. Normalerweise erfordert die weitere Verarbeitung von Merkmalen die Transformation von Strukturanordnungen in Matrizen. MATLAB kann solche Transformationen nicht ohne die Anwendung eines Zwischenschrittes durchführen: Die Struktur-Arrays müssen zunächst in Zell-Arrays umgewandelt werden, die wiederum in Matrizen umgewandelt werden können. Beachten Sie, dass die Transponierung der Zellarray-Zellenfunktionen verwendet wurde, um Funktionen an Matrixspalten anstelle von Zeilen zuzuordnen. Aus Performancegründen ist es in der Regel am besten, die Daten so zu orientieren, dass sie spaltenweise und nicht zeilenweise bearbeitet werden. In diesem Fall erwarten wir, dass wir das Datenmerkmal nicht mehr nach Bild sondern nach Merkmal durchlaufen. 2.5. Verarbeitung von Bildern In vielen Fällen kann die Handhabung von mehreren Bildern eine aufwändige Aufgabe sein, es sei denn, ein automatisierter Prozess kann hergestellt werden. Angenommen, wir haben eine Charge von 100 Bildern, die wir verarbeiten möchten, mit einer for-Schleife und der Definition des Pfads zum Image-Verzeichnis, können wir laden, verarbeiten und speichern Sie die Bilder ein zu einer Zeit. Nach dem Speichern des ersten Bildes wird automatisch das nächste Verzeichnis geladen, verarbeitet und gespeichert. Der Vorgang wird fortgesetzt, bis das letzte Bild gespeichert ist. Der folgende Code führt diesen Vorgang aus. 2.6. Videoverarbeitung 2.6.1. Video to frames Eine interessante Anwendung für die Bildverarbeitung ist die Handhabung von Videodaten. In diesem Fall muss die Videodatei in einzelne Frames unterteilt werden. Die Funktion VideoReader kann verwendet werden, um die Datei als Variable einzugeben. Für n Rahmen wird jeder Rahmen dann als separates Bild in jedem Format gespeichert. Der folgende Code liest ein Video (genannt Film) zu einer MATLAB-Struktur und speichert die Frames eins nach dem anderen in das TIFF-Format. 9 2.6.2. Frames to video Da jedes Frame als einzelnes Bild gespeichert wird, kann es entweder einzeln oder im Batch-Modus entsprechend verarbeitet werden. Ein möglicher nächster Schritt in diesem Prozess kann sein, die verarbeiteten Bilder zu einem einzigen Video wieder zu kombinieren. Wenn aus Frames (Frame) ein neuer Film (genannt movienew) erzeugt werden soll, liefert der folgende Code das Backbone für einen solchen Prozess 9. 3. Bildverarbeitung auf GPU in MATLAB Große Mengen an Bilddaten werden in vielen technischen und experimentellen Situationen produziert, insbesondere wenn Bilder im Laufe der Zeit immer wieder aufgenommen werden oder bei Bildern mit höherer Dimensionalität als zwei. Zeitraffer-Bilderzeugung und Videoaufzeichnung können als Beispiele der ersteren erwähnt werden, während die letzteren durch irgendeine der vielen vorhandenen tomographischen Bildgebungsmodalitäten repräsentiert werden können. 4D-Computertomographie (CT), in der 3D-CT-Bilder in regelmäßigen Intervallen zur Überwachung der internen Patientenbewegung erfasst werden, ist ein Beispiel für eine Anwendung, die sich auf beide Kategorien bezieht. Es ist oft wünschenswert oder sogar kritisch, die Analyse und Verarbeitung solcher großen Bilddatensätze zu beschleunigen, insbesondere für Anwendungen, die in oder nahezu in Echtzeit laufen. Aufgrund der inhärent parallelen Natur vieler Bildverarbeitungsalgorithmen sind sie für die Implementierung auf einer Grafikverarbeitungseinheit (GPU) gut geeignet, und folglich können wir eine wesentliche Beschleunigung von einer solchen Implementierung über einen auf einer CPU laufenden Code erwarten. Trotz der Tatsache, dass GPUs heute in Desktop-Computern ubiquitär sind, sind in der aktuellen MATLAB-Version (2013b) nur 34 der mehreren hundert Funktionen des IPT durch den PCT GPU-fähig. In diesem Unterkapitel werden wir die Möglichkeiten für jemanden erforschen, der entweder die Rechenleistung der GPU direkt aus MATLAB nutzen oder einen externen GPU-Code in MATLAB-Programme einbinden möchte. Der Schwerpunkt liegt auf Bildverarbeitungsanwendungen, aber die dargestellten Techniken können mit geringem oder ohne Aufwand an andere Anwendungen angepasst werden. Im ersten Teil dieses Teils wird untersucht, wie die integrierten, GPU-fähigen Bildverarbeitungsfunktionen des PCT verwendet werden können. Im Folgenden erklären wir, wie pixelweise Manipulationen mit der GPU-fähigen Version von arrayfun durchgeführt werden können und wie wir unsere eigenen Bildverarbeitungsfunktionen schreiben können, die von über hundert elementaren MATLAB-Funktionen, die implementiert wurden, um auf GPUs laufen, implementiert zu werden. Im zweiten Teil dieses Abschnitts zeigen wir, wie mit dem PCT Kernel-Funktionen aufgerufen werden können, die in der CUDA-Programmiersprache direkt von MATLAB geschrieben werden. Damit können wir in unseren MATLAB-Anwendungen die vorhandenen Kernelfunktionen nutzen. Darüber hinaus ist es für diejenigen mit Wissen über CUDA, macht es mehr von der GPU-Potenzial von MATLAB und bietet auch eine einfache Möglichkeit, Kernel-Funktionen in der Entwicklung zu testen. Der dritte und letzte Teil ist fortgeschrittenen Benutzern gewidmet, die eine der von NVIDIA zur Verfügung gestellten CUDA-Bibliotheken nutzen möchten, die es vorziehen, ihren Code in einer anderen Sprache als CUDA zu schreiben, die keinen Zugriff auf die Parallel Computing Toolbox hat Die Zugriff auf eine vorhandene GPU-Codebibliothek haben, die sie von MATLAB anrufen möchten. Wir untersuchen, wie CUDA-Code direkt in MEX-Funktionen mit dem PCT kompiliert werden kann, gefolgt von einer Beschreibung, wie GPU-Code entweder in CUDA oder OpenCL kann von MATLAB zugänglich gemacht werden, indem Sie es in einer Bibliothek und die Schaffung einer MEX-Wrapper-Funktion um ihn herum . Schließlich zeigen wir, wie der Code für eine MEX-Wrapper-Funktion direkt in unserem externen Compiler erstellt werden kann und z. B. in einer vorhandenen Lösung von Visual Studio (Microsoft Corporation, Redmond, WA, USA) enthalten ist, so dass dies automatisch beim Bauen erfolgt die Lösung. 3.1. GpuArray und integrierte GPU-fähige Funktionen Für die Beispiele in diesem Teil benötigen wir einen Computer, der mit einer NVIDIA GPU der CUDA-Berechnungsfähigkeit 1.3 oder höher ausgestattet ist, die vom PCT 10 korrekt eingerichtet und erkannt wird. Mit den Funktionen gpuDeviceCount und gpuDevice können Sie eine GPU identifizieren und auswählen, wie in der PCT-Dokumentation 11 beschrieben. Um ein Bild auf der GPU verarbeiten zu können, müssen zunächst die entsprechenden Daten aus dem Haupt-CPU-Speicher über den PCI-Bus in den GPU-Speicher kopiert werden. In MATLAB werden Daten auf der GPU über Objekte vom Typ gpuArray aufgerufen. Der Befehl erzeugt ein neues gpuArray-Objekt namens imGpu und weist ihm eine Kopie der Bilddaten im im zu. ImGpu vom selben Typ wie im (z. B. double, single int32 etc.) sein, was die Leistung der GPU-Berechnung beeinträchtigen könnte, wie unten diskutiert wird. Lassen Sie uns jetzt davon ausgehen, dass im ist ein 30723072 Array von einzelnen Genauigkeit Gleitkommazahlen (single). Entsprechend, wenn wir alle unsere GPU-Berechnungen ausgeführt haben, rufen wir die Funktion sammeln, um das Ergebnis abzurufen. Zum Beispiel kopiert die Daten in das gpuArray-Objekt resultGpu zurück, um zu einem CPU-Speicher zu führen. Im Allgemeinen ist das Kopieren von Daten über den PCI-Bus relativ langsam, was bedeutet, dass bei der Arbeit mit großen Datensätzen sollten wir versuchen, unnötige Kopien zwischen CPU und GPU-Speicher zu vermeiden. Wenn möglich, kann es daher schneller sein, Filter, Masken oder Zwischenprodukte direkt auf der GPU zu erzeugen. Zu diesem Zweck verfügt gpuArray über mehrere statische Konstruktoren, die den Standard-MATLAB-Funktionen entsprechen. Falsch Inf. Nan Einsen . wahr . Nullen. Linspace. Logspace. Rand Randi und randn. Um den GPU-Speicher vorher zuzuweisen und zu initialisieren. Diese können durch Aufrufen von gpuArray aufgerufen werden. Konstruktor, wo Konstruktor durch den Funktionsaufruf ersetzt wird. Zum Beispiel erstellt eine 3072 3072 Array von normal verteilten Pseudozufallszahlen mit Null-Mittelwert und Standardabweichung ein. Wie bei den entsprechenden Standard-MATLAB-Funktionen gibt das letzte Funktionsargument den Array-Element-Typ (in diesem Fall single) an, und wenn er weggelassen wird, ist er standardmäßig doppelt. Obwohl dies bei der Arbeit an modernen CPUs normalerweise nicht problematisch ist, lohnt es sich zu beachten, dass NVIDIAs Consumer-GPUs bei der Verarbeitung einzelner Fließkommazahlen (single) im Vergleich zu doppelter Genauigkeit (double) oder ganzen Zahlen (int32 ). Dies bedeutet, dass dort, wo doppelte Genauigkeit nicht entscheidend ist, es eine gute Angewohnheit ist, Arrays auf der GPU als einzelne Genauigkeit zu deklarieren. Alternativ können die ersten sieben statischen Konstruktoren, die oben aufgelistet sind, durch ihre entsprechende MATLAB-Funktion aufgerufen werden, indem die Argumentliste mit gpuArr ay angehängt wird. Z. B. Erstellt ein gpuArray-Objekt, das 30723072 32-Bit-Integer (int32) enthält, die auf Null initialisiert werden. Beim Aufruf dieser Funktionen ist eine Alternative zum expliziten Angeben des Typs das gleiche Argument. This creates an array of the same type as the argument following the like argument, i. e. creates a gpuArray object of int32 values initialised to one, whereas creates a standard MATLAB array of single values initialised to one. This can be useful when creating new variables in functions that are meant to run both on the CPU and the GPU where we have no a priori knowledge of the input type. For a gpuArray object to be able to hold complex numbers, this has to be explicitly specified upon construction, either by using the complex argument when creating it directly on the GPU or by explicit casting when copying non-complex data, e. g. gpuArray(complex(im)) . To inspect the properties of a GPU array we can use the standard MATLAB functions such as size . length . isreal etc. In addition to these, the function classUnderlying returns the class underlying the GPU array (since class will just return gpuArray ) while existsOnGPU returns true if the argument is a GPU array that exists on the GPU and is accessible. Once our image data are in GPU memory, we have two options for manipulating them: either we can use the sub-set of the built-in MATLAB functions (including some functions available in toolboxes) that run on the GPU, or we can write our own functions using only element-wise operations and launch them through arrayfun or bsxfun . In the first case, we use normal MATLAB syntax with the knowledge that any of these functions are automatically executed on the GPU as long as at least one argument is of type gpuArray . Using imGpu and randNoiseGpu defined above we can create a new, noisy image on the GPU by typing: A list of the GPU-enabled MATLAB functions available on the current system, together with all static constructors of gpuArray . can be displayed by typing methods(gpuArray) . For MATLAB 2013b, the list comprises around 200 standard functions plus any additional functions in installed toolboxes 2 . For example, using the GPU-enabled function imnoise from the IPT, the same result as above can be obtained through: (where a variance of 0.09 equals a standard deviation of 0.3). Another, potentially more useful, GPU-enabled function from the IPT is imfilter . Using imGpu from earlier filters the image using a horizontal Sobel filter. Note that sobelFilter is an ordinary 2D MATLAB array, 1 2 1 0 0 0 -1 -2 -1 . but since imGpu is a GPU array, the GPU-enabled version of imfilter is automatically called and the output, filteredImGpu . will be a GPU array. The second option for manipulating GPU arrays directly from MATLAB is by calling our own functions through the built-in bsxfun or arrayfun functions. As before, if any of the input arguments to the function is a GPU array, the calculation will automatically be carried out on the selected GPU. Thus, a third way of producing a noisy version of imGpu would be to first create the function addAndOffset that performs an element-wise addition of two images and adds a constant offset: and then calling The benefit of writing functions and launching them through bsxfun or arrayfun compared to calling MATLAB functions directly on GPU arrays is a potential speedup for large functions. This is because in the former case, the whole function can automatically be compiled to a GPU function, called CUDA kernel, resulting in a single launch of GPU code (although the overhead for compiling the function will be added to the first call). In contrast, in the latter case, each operation has to be launched in sequence using the precompiled kernel functions available in MATLAB. However, when running on a GPU, arrayfun and bsxfun are limited to element-wise operations. In a typical image processing application, this means that each pixel is unaware of its neighbours, which limits the use to functions where pixels are processed independently of one another. As a result, many image filters cannot be implemented in this way, in which case we are left either to use built-in functions as described earlier, or to write our own kernel functions as described in the next part. Further, since we are constrained to element-wise manipulations, the number of built-in functions at our disposal inside our function is somewhat limited. For a complete list of the available built-in functions, as well as some further limitations when using bsxfun and arrayfun with GPU arrays, see the PCT documentation 12 . Before moving on to the next part we should stress that since GPUs are built to process large amounts of data in parallel, there is no guarantee that running code on a GPU instead of a CPU will always result in a speedup. Although image processing algorithms provide good candidates for substantial speedups, this characteristic of the GPU means that vectorisation of code and simultaneous processing of large amounts of data (i. e. avoiding loops wherever possible) becomes even more crucial than in ordinary MATLAB programs. Further, GPU memory latency and bandwidth often limit the performance of GPU code. This can be alleviated by ensuring that, as far as possible, data that are operated on at the same time are stored nearby in memory. Since arrays are stored in a sequential column-major order in MATLAB, this means avoiding random memory-access patterns where possible and organising our data so that we mostly operate on columns rather than on rows. Finally, when evaluating the performance of our GPU code we should use the function gputimeit . It is called in the same manner as the regular MATLAB function timeit . i. e. it takes as argument a function, which itself does not take any arguments, and times it, but is guaranteed to return the accurate execution time for GPU code (which timeit is not). If this is not feasible, the code section we want to time can be sandwiched between a tic and a toc . as long as we add a call to wait(gpuDevice) just before the toc . This ensures that the time is measured only after execution on the currently selected GPU has finished. (Otherwise MATLAB continues to execute ensuing lines of GPU-independent code, like toc . asynchronously without waiting for the GPU calculation to finish). Since the MATLAB profiler only measures CPU time, we need to employ a similar trick to get accurate GPU timings when profiling: if we sandwich the lines or blocks of GPU code we want to time between two calls to wait(gpuDevice) . the execution time reported for the desired line or block plus the time taken by the second call to wait gives the correct timing. 3.2. Calling CUDA kernel functions from MATLAB By using the techniques described in the previous part we can use MATLAB to perform many of our standard image processing routines on the GPU. However, it does not allow us to test our own CUDA-implemented algorithms or use existing ones in our MATLAB programs, nor does it provide a means to explicitly control GPU resources, such as global and shared memory. In this part we demonstrate how this can be remedied by creating a CUDAKernel object from a kernel function written in CUDA. Instructions on how to write CUDA code is well beyond the scope of this chapter, and therefore this part assumes some previous basic knowledge of this language. A CUDAKernel object required to launch a CUDA kernel function from MATLAB is constructed by calling the static constructor parallel. gpu. CUDAKernel . The constructor takes three MATLAB string arguments: the path to a . ptx file containing the kernel code, the interface of the kernel function, and the name of the desired entry point. For the first argument, a . ptx file with the same name as the source file, containing the corresponding code compiled into pseudo-assembly language, is automatically generated when using the NVIDIA CUDA Compiler (NVCC) with the flag - ptx to compile a . cu file (if it contains one or more kernel functions). (Note that if using an integrated development environment, you might have to instruct it not to delete . ptx files when finishing the build for example Visual Studio 2010 requires that the flag - - keep is used.) The second argument can be either the . cu file corresponding to the . ptx file specified in the first argument, from which the argument list of the desired kernel function can be derived, or the explicit argument list itself. The latter is useful when the . cu file is not available, or when the argument list contains standard data types that have been renamed through the use of the typedef keyword. The third argument specifies which kernel function in the . ptx file to use, and although NVCC mangles function names similar to a C compiler, the names in the . ptx file are guaranteed to contain the original function name. MATLAB uses substring matching when searching for the entry point and it is therefore often enough to provide the name of the original kernel function (see exceptions below). Let us assume that we have access to myFilters. cu containing several kernel functions named myFilter1 . myFilter2 . etc. and its corresponding myFilters. ptx . Then creates a CUDAKernel object called gpuFilter1 that can be used to launch the CUDA kernel function myFilter1 from MATLAB. If we further assume that myFilter1 is declared as the second argument above, myFilters. cu . could equally be replaced by the string const float , float , float . In some cases, care has to be taken when specifying the entry point. For example, if myFilter2 is a templated function instantiated for more than one template argument, each instance of the resulting function will have a name containing the string myFilter2 . Likewise, if another kernel function called myFilter1v2 is declared in the same . cu file, specifying myFilter1 as the third argument of parallel. gpu. CUDAKernel becomes ambiguous. In these cases, we should provide the mangled function names, which are given during compilation with NVCC in verbose mode, i. e. with - - ptxas-options-v specified. The full mangled name of the kernel used by a CUDAKernel object is stored in the object property EntryPoint . and can be obtained by e. g. gpuFilter1.EntryPoint. Once a CUDAKernel object has been created, we need to specify its launch parameters which is done through the ThreadBlockSize . GridSize and SharedMemorySize object properties. Thus, sets the block size to 328 threads, the grid size to 96384 blocks and the shared memory size per block to 43281024 bytes, enough to hold 256 single or int32 values, or 128 double values. In total this will launch 30723072 threads, one per pixel of our sample image. A fourth, read-only property called MaxThreadsPerBlock holds the upper limit for the total number of threads per block that we can use for the kernel function. If the kernel function is dependent on constant GPU memory, this can be set by calling setConstantMemeory . taking as the first parameter the CUDAKerner object, as the second parameter the name of the constant memory symbol and as the third parameter a MATLAB array containing the desired data. For example, we can set the constant memory declared as constant float myConstData 128 in myFilters. cu and needed in myFilter1 To execute our kernel function we call feval with our GPUKernel object as the first parameter, followed by the input parameters for our kernel. For input parameters corresponding to arguments passed by value in the CUDA kernel (here: scalars), MATLAB scalars are normally used (although single element GPU arrays also work), whereas for pointer type arguments, either GPU arrays or MATLAB arrays can be used. In the latter case, these are automatically copied to the GPU. A list of supported data types for the kernel arguments can be found in the PCT documentation 13 . In general these are the CC standard types (along with their corresponding pointers) that have MATLAB counterparts, with the addition of float2 and double2 that map to MATLABs complex single and double types, respectively. CUDAKernel objects have three additional, read-only properties related to input and output. NumRHSArguments and MaxNumLHSArguments respectively hold the expected number of input arguments and the maximum number of output arguments that the objects accepts, and ArgumentTypes holds a cell of strings naming the expected MATLAB input types. Each type is prefixed with either in or inout to signal whether it is input only (corresponding to an argument passed by value or a constant pointer in CUDA) or combined inputoutput (corresponding to a non-constant pointer in CUDA). To function in a MATLAB context, a call to a CUDA kernel through a GPUKernel object must support output variables. Therefore, pointer arguments that are not declared const in the kernel declaration are seen as output variables and, if there is more than one, they are numbered according to their order of appearance in the declaration. This means that calling gpuFilter1 above produces one output, whereas gpuFilter2 created from produces two outputs. With this information we can now call the myFilter1 kernel function through Similarly, we can call myFilter2 through The output from a CUDAKernel object is always a GPU array, which means that if the corresponding input is a MATLAB array it will be created automatically. Consider the kernel with its corresponding CUDAKernel object gpuFilter3 . Since im from our previous examples a MATLAB array, calling automatically copies im to the GPU and creates a new gpuArray object called gpuRes3 to hold the result. 3.3. MEX functions and GPU programming In the previous part we saw how, by running our own CUDA kernels directly from MATLAB, we can overcome some of the limitations present when working only with built-in MATLAB functionality. However, we are still (in release 2013b) limited to using kernel functions that take only standard type arguments, and we can access neither external libraries, such as the NVIDIA Performance Primitives, the NVIDIA CUDA Fast Fourier Transform or the NVIDIA CUDA Random Number Generation libraries, nor the GPUs texture memory with its spatial optimised layout and hardware interpolation features. Further, we need to have an NVIDIA GPU, be writing our code in CUDA and have access to the PCT to use the GPU in our MATLAB code. In this section we look at how we can use MEX functions to partly or fully circumnavigate these limitations. This again assumes previous experience of GPU programming and some knowledge of how to write and use MEX functions. A good overview of the latter can be found in the MATLAB documentation 14 . The first option, which removes the technical restrictions but still requires access to the PCT (running on a 64-bit platform) and a GPU from NVIDIA, is to write MEX functions directly containing CUDA code. The CUDA code itself is written exactly as it would be in any other application, and can either be included in the file containing the MEX function entry point or in a separate file. Although this process is well documented in the PCT documentation 15 and through the PCT examples 16 , we briefly describe it here for consistency. The main advantage of this approach over the one described later is that it enables us to write MEX functions that use GPU arrays as input and output through the underlying CC object mxGPUArray . As all MEX input and output, GPU arrays are passed to MEX functions as pointers to mxArray objects. The first step is therefore to call either mxGPUCreateFromMxArray or mxGPUCopyFromMxArray on the pointer to the mxArray containing the GPU data, in order to obtain a pointer to an mxGPUArray . In the former case, the mxGPUArray becomes read-only, whereas in the latter case the data is copied so that the returned mxGPUArray can be modified. ( mxGPUCreateFromMxArray and mxGPUCopyFromMxArray also accept pointers to mxArray objects containing CPU data, in which case the data is copied to the GPU regardless of the function used.) We can now obtain a raw pointer to device memory that can be passed to CUDA kernels by calling mxGPUGetDataReadOnly (in the case of read-only data) or mxGPUGetData (otherwise) and explicitly casting the returned pointer to the correct type. Information about the number of dimensions, dimension sizes, total number of elements, type and complexity of the underlying data of an mxGPUArray object can be further obtained through the functions mxGPUGetNumberOfDimensions . mxGPUGetDimensions . mxGPUGetNumberOfElements . mxGPUGetClassID . and mxGPUGetComplexity . We can also create a new mxGPUArray object through mxGPUCreateGPUArray . which allocates and, if we want, initialises memory on the GPU for our return data. With this we are in a position where we can treat input from MATLAB just as any other data on the GPU and perform our desired calculations. Once we are ready to return our results to MATLAB we call either mxGPUCreateMxArrayOnCPU or mxGPUCreateMxArrayOnGPU to obtain a pointer to an mxArray object that can be returned to MATLAB through plhs . The former copies the data back to the CPU making the MEX function return a standard MATLAB array whereas in the latter case the data stays on the GPU and a GPU array is returned. Finally, we should call mxGPUDestroyGPUArray on any mxGPUArray objects that we have created. This deletes them from the CPU and, unless they are referenced by another mxArray object (as will be the case if they are returned through plhs ), frees the corresponding GPU memory. Note that there are several other functions in the mxGPU family to examine, duplicate, create and copy mxGPUArray objects, and in particular for working with complex arrays, that work in a similar way and which are described in the PCT documentation 17 . For the above to work, we need to include mxGPUArray. h . in addition to mex. h . in our source file. The source file has to have the extension . cu and it should contain a call to the function mxInitGPU before launching any GPU code in order to initialise the MATLAB GPU library. Provided that the environment variable MWNVCCPATH is set to the NVCC folder path and that a copy of the PCT version of mexopts. bat or mexopts. sh ( matlabroot toolboxdistcompgpuexternsrcmex xxx 64 ) is located in the same folder as the source code, we can compile our CUDA containing MEX functions from MATLAB in the usual way using the mex command. If using external libraries, these also have to be provided, which can normally be done by passing the full library path, including file name, to the mex command after the. c ..cpp or. cu file path. A bare-bone MEX function calling the kernel function myFilter1 from earlier, which takes into account the considerations above but is stripped of any boundary or argument checking, follows: After compilation, assuming the above code is found in mexFilter1.cu . we can call the MEX function like this: Note the explicit type conversion necessary to convert the second argument to single to match the input type. Note also that, depending on the compiler and system settings, in order to have mwSize correctly identified as a 64-bit type, we might need to use the largeArraysDims flag when compiling using the mex command. The rest of this part will be dedicated to describing how we can call GPU code from MATLAB even if we do not have access to the PCT or write our code in CUDA. Since without the PCT, the mex command is not set up to compile anything except standard CC code, we have two alternatives to achieve what we want. The only drawback with these, compared to when using mxGPUArray from the PCT is that it is harder to have data in GPU memory persist when returning to MATLAB between calls to MEX functions. (This can still be achieved by explicitly casting a GPU memory pointer to an integer type of correct length which is returned to MATLAB. The integer is then passed to the next MEX function which casts it back to the correct pointer type. However, the problem with this approach lies in eliminating the risk of memory leaks although solutions for this exist, they are beyond the scope of this chapter.) This means that unless we go through any extra effort, we are left either to perform all our GPU calculations from the same MEX function before returning control to MATLAB or suffer the penalty associated with copying our data back and forth between each call. In many cases, however, this may provide less of a limitation than one might initially think, especially when using MATLAB to test GPU code under development or using MATLAB as a front-end to existing code libraries. The first alternative is to compile our GPU code, regardless of in which language it is written, into a static library using our external compiler, and then to call this library from a MEX function that we compile using the mex command. Since our MEX function cannot call GPU functions directly, a small CC wrapper function has to be written around our GPU code. A wrapper for the myFilter1 CUDA kernel, which we can place either in the same file as the CUDA code or in a separate . cu file, could look like this (again, error checking has been omitted for brevity): Once the static library, normally a . lib file under Windows or a . a file under Linux and Mac OS, has been created, we can write a MEX function calling the wrapper: Note that it is normally better, especially if using a pre-existing library, to use include to include the corresponding header files rather than, as in the example above, to manually enter the function prototype. We should now be able to compile this wrapper using the mex command, remembering to pass the path to our own library as well as to the necessary GPU runtime library. For CUDA, this is cudart. lib on Windows, libcuda. so on Linux, or libcuda. dylib on Mac OS. Thus, assuming that the code above is found in myFilter1Mex. cpp and that the library is called myLibrary. lib . on Windows the call would look like: The second alternative is to build the MEX function directly in our external compiler, without going through the mex command. By doing this, the whole process can be carried out in one step and, if we wish, we are free to keep all our code in a single file. The main advantage of this approach occurs if we are developing or using an existing GPU library which we would like to call from MATLAB, for example for testing purposes. In such a case we can add the MEX file to our normal build routine so that every time we rebuild our library we automatically get the MEX function to call it from MATLAB. A MEX function is a dynamically linked shared library which exports a single entry point called mexFunction . Hence, by mimicking the steps carried out by the mex command (found in mexopts. bat or mexopts. sh ) when calling the external compiler, we can replicate this from outside MATLAB. We can view the exact steps carried out on a particular system by calling the mex command in verbose mode, i. e. using the v flag. Detailed information on how to build MEX functions for Windows and UNIX-like systems (Linux and Mac OS) can be also found in the MATLAB documentation 18 . Here we look at a minimal example from a Windows-centric point of view, although the procedure should be similar on other systems. First, we need to specify that we want to build a dynamically linked shared library, called a dynamic-link library on Windows, and give it the correct file extension, e. g. mexw64 second, we have to provide the compiler with the path to our MEX header files, normally mex. h third, we have to pass the libraries needed to build our MEX function, called libmx. lib . libmex. lib and libmat. lib on Windows, to the linker together with their path and finally, as mentioned above, we need to export the function named mexFunction . In Visual Studio 2010, all of the above steps are done in the Project Properties page of the project in question. Under Configuration properties-gt General . we set the Target Extension to . mexw64 and the Configutation Type to Dynamic Library (.dll) . For the header files we add (MATLABROOT)externinclude to Include Directories under Configuration Properties-gt VCDirectories . For the libraries, we add libmx. liblibmex. liblibmat. lib to Additional Dependencies under Configuration Properties-gt Linker-gt Input and (MATLABROOT)externlibwin64microsoft to Additional Library Directories under Configuration properties-gt Linker-gt General . Finally, we add export:mexFunction to Additional Options under Configuration Properties-gt Linker-gt Command Line . In the above steps it is assumed that the variable MATLABROOT is set to the path of the MATLAB root, otherwise we have to change (MATLABROOT) to, for example, C :Program FilesMATLAB2013b . The code for the MEX example, finally, would look something like this: In the case of an existing code library, we can add a new component (such as a new project to an existing solution in Visual Studio) containing a MEX function calling our desired GPU functions so that it is built directly with the original library without any additional steps. 4. Conclusion In conclusion, MATLAB is a useful tool for prototyping, developing and testing image processing algorithms and pipelines. It provides the user with the option of either using the functions of the IPT or leveraging the capabilities of a high-level programming language combined with many built-in standard functions to create their own algorithms. When high performance or processing of large amounts of data is required, the computational power of a GPU can be exploited. At this point, there are three main options for image processing on GPU in MATLAB: i) we can stick entirely to MATALB code, making use of the built-in, GPU-enabled functions in the IPT and the PCT as well as our own GPU functions built from element-wise operations only ii) we can use the framework provided by the PCT to call our own CUDA kernel functions directly from MATLAB iii) we can write a MEX function in CC that can be called from MATLAB and which in turn calls the GPU code of our choice. 5. Acknowledgements The authors would like to acknowledge the European Commission FP7 ENTERVISION programme, grant agreement no. 264552

Comments