UPDATE: Bitte beachten Sie die unten stehende zusätzliche Frage mit mehr Code;
Ich versuche, eine Kategorie für die Unschärfe eines Bildes zu programmieren. Mein Ausgangspunkt ist Jeff LaMarches Probe hier . Während dies (nach den von anderen vorgeschlagenen Korrekturen) gut funktioniert, ist es eine Größenordnung zu langsam für meine Anforderungen - auf einem 3GS dauert es vielleicht 3 Sekunden, um eine anständige Unschärfe zu machen, und ich würde es gerne auf unter 0,5 bringen sec für einen Vollbildmodus (schneller ist besser).
Er erwähnt das Accelerate-Framework als eine Leistungsverbesserung, also habe ich den letzten Tag damit verbracht, dies zu betrachten, und insbesondere vDSP_f3x3, was laut der Apple-Dokumentation
Filtert ein Bild durch Ausführen von a zweidimensionale Faltung mit einem 3x3 Kernel; einfache Präzision.
Perfekt - Ich habe eine geeignete Filtermatrix, und ich habe ein Bild ... aber das ist, wo ich ratlos bin.
vDSP_f3x3 setzt voraus, dass die Bilddaten sind (float *), aber mein Bild kommt von;
%Vor%und der Kontext stammt von CGBitmapContextCreate mit kCGImageAlphaPremultipliedFirst, also ist meine srcData wirklich ARGB mit 8 Bits pro Komponente.
Ich vermute, dass ich wirklich einen Kontext mit Float-Komponenten brauche, aber Gemäß der Quarz - Dokumentation hier ist kCGBitMapFloatComponents nur unter Mac OS und nicht unter iOS verfügbar: - (
Gibt es eine schnelle Methode, das beschleunigte Framework zu verwenden, um die ganzzahligen Komponenten in die Float-Komponenten zu konvertieren, die vDSP_f3x3 benötigt? Ich meine, ich könnte es selbst machen, aber wenn ich das mache, dann die Faltung, und dann zurück konvertiere, vermute ich, dass ich es noch langsamer gemacht habe, als es jetzt ist, da ich genauso gut falten könnte wie ich.
Vielleicht habe ich den falschen Ansatz?
Hat jemand irgendwelche Tipps für mich, etwas Bildverarbeitung auf dem iphone mit vDSP gemacht zu haben? Die Dokumentation, die ich finden kann, ist sehr referenzorientiert und nicht sehr Anfänger freundlich, wenn es um solche Dinge geht.
Wenn jemand eine Referenz für wirklich schnelle Unschärfe hat (und hohe Qualität, nicht die reduzierte Auflösung und dann das Rescale-Zeug, das ich gesehen habe und hüftig aussieht), wäre das fabelhaft!
BEARBEITEN:
Danke @Jason. Ich habe das gemacht und es funktioniert fast, aber jetzt ist mein Problem, dass, obwohl das Bild verwischt, bei jedem Aufruf links 1 Pixel verschoben wird. Es scheint auch, das Bild schwarz und weiß zu machen, aber das könnte etwas anderes sein.
Gibt es irgendetwas in diesem Code, das offensichtlich falsch ist? Ich habe es noch nicht optimiert und es ist ein bisschen grob, aber hoffentlich ist der Faltungscode klar genug.
%Vor%Ich sollte hinzufügen, dass, wenn ich die vDSP_conv-Zeile auskommentiere, und ändern Sie die folgende Zeile zu:
%Vor%Wie erwartet, ist mein Ergebnis ein Klon der ursprünglichen Quelle. In Farbe und nicht nach links verschoben. Dies bedeutet für mich, dass es die Faltung ist, die schief läuft, aber ich kann nicht sehen, wo: - (
GEDANKEN: Wenn ich darüber nachdenke, scheint mir, dass die Faltung wissen muss, dass die Eingangspixel im ARGB-Format sind, da sonst die Faltung die Werte multipliziert, ohne dass sie ihre Bedeutung kennen (dh sie multipliziert mit R *). B usw.). Dies würde erklären, warum ich ein B & amp; W Ergebnis denke, aber nicht die Verschiebung. Nochmals, ich denke, da müsste vielleicht mehr dran sein als meine naive Version hier ...
ABSCHLIESSENDER GEDANKEN: Ich denke, die Verschiebung nach links ist eine natürliche Folge des Filters und ich muss mir die Bilddimensionen ansehen und sie möglicherweise auffüllen ... also denke ich, dass der Code tatsächlich funktioniert, wenn man bedenkt, was ich gefüttert habe es.
Sie möchten auf jeden Fall in float
konvertieren, um die Filterung durchzuführen, da dies die beschleunigten Funktionen sind, und es ist viel flexibler, wenn Sie eine zusätzliche Verarbeitung durchführen möchten. Die Rechenzeit einer 2-D-Faltung (Filter) wird wahrscheinlich die Zeit, die bei der Umwandlung verbracht wird, in den Schatten stellen. Sehen Sie sich die Funktion vDSP_vfltu8()
an, die die uint8-Daten schnell in float konvertiert. vDSP_vfixu8()
konvertiert es zurück in uint8.
Um eine Unschärfe zu erzielen, werden Sie wahrscheinlich einen größeren Convolution-Kernel als 3x3 wollen, also würde ich vorschlagen, die Funktion vDSP_imgfir()
zu verwenden, die jede Kernel-Größe annimmt.
Antwort zum Bearbeiten:
Ein paar Dinge:
Sie müssen die Filterung für jeden Farbkanal unabhängig voneinander durchführen. Das heißt, Sie müssen die R-, G- und B-Komponenten in ihre eigenen Bilder (vom Typ float) aufteilen, filtern und dann in das ARGB-Bild remultiplexen.
vDSP_conv
berechnet eine 1-D-Faltung, aber um ein Bild zu verwischen, benötigen Sie wirklich eine 2-D-Faltung. vDSP_imgfir
berechnet im Wesentlichen die 2-D-Faltung. Dazu benötigen Sie einen 2D-Kernel. Sie können die Formel für eine 2-D-Gauß-Funktion nachschlagen, um den Kernel zu erzeugen.
Hinweis: Sie können tatsächlich eine 2-D-Faltung mit 1-D-Faltungen durchführen, wenn Ihr Kernel trennbar ist ( welches Gaußsche ist). Ich werde nicht darauf eingehen, was das bedeutet, aber Sie müssen im Wesentlichen eine 1-D-Faltung über die Spalten durchführen und dann eine 1-D-Faltung über die resultierenden Zeilen durchführen. Ich würde diesen Weg nicht gehen, wenn Sie nicht wissen, was Sie tun.
Während das Accelerate-Framework schneller ist als einfacher serieller Code, werden Sie wahrscheinlich niemals die größte Leistung sehen, wenn Sie ein Bild mit diesem unscharf machen.
Mein Vorschlag wäre, einen OpenGL ES 2.0-Shader (für Geräte, die diese API unterstützen) zu verwenden, um eine Unschärfe in zwei Passagen zu machen. Basierend auf meinen Benchmarks kann die GPU diese Art von Bildmanipulationsoperationen mit 14-28-facher Geschwindigkeit der CPU auf einem iPhone 4 durchführen, im Vergleich zu den vielleicht 4,5-fachen, die Apple im besten Fall für das Accelerate-Framework meldet.
Einige Codes dafür sind in diese Frage sowie im Kapitel" Nachbearbeitung von Effekten auf mobilen Geräten "im GPU Pro 2 Buch (für den der Beispielcode hier ). Wenn Sie Ihr Bild in eine Textur platzieren und dann Werte zwischen den Pixeln lesen, erhalten Sie durch die bilineare Filterung auf der GPU eine gewisse Unschärfe, die dann mit ein paar schnellen Suchvorgängen und Mittelungsoperationen kombiniert werden kann.
Wenn Sie ein Startprojekt benötigen, um Bilder zur Verarbeitung in die GPU zu leiten, können Sie meine Beispielanwendung möglicherweise aus dem Artikel hier . Diese Beispielanwendung übergibt AVFoundation-Videobilder als Texturen an einen Verarbeitungs-Shader, Sie können sie jedoch ändern, um Ihre speziellen Bilddaten zu senden und Ihre Unschärfe-Operation auszuführen. Sie sollten in der Lage sein, meinen glReadPixels()
-Code zu verwenden, um das unscharfe Bild für die spätere Verwendung wiederzuerlangen.
Seit ich diese Antwort ursprünglich geschrieben habe, habe ich ein Open-Source-Bild- und Videoverarbeitungs-Framework für diese Art von Operationen erstellt auf der GPU. Das Framework hat mehrere verschiedene Unschärfetypen, die alle sehr schnell auf Bilder oder Live-Videos angewendet werden können. Der GPUImageGaussianBlurFilter, der eine standardmäßige 9-Hit-Gaußsche Unschärfe anwendet, läuft in 16 ms für ein 640x480-Video auf dem iPhone 4. Der GPUImageFastBlurFilter ist eine modifizierte 9-Hit-Gaußsche Unschärfe, die Hardware-Filterung verwendet und in 2,0 ms für das gleiche Video-Frame. Ebenso gibt es einen GPUImageBoxBlurFilter, der eine 5-Pixel-Box verwendet und in 1,9 ms für dasselbe Bild auf derselben Hardware läuft. Ich habe auch Median und bilaterale Unschärfe-Filter, obwohl sie ein wenig Performance-Tuning benötigen.
In meinen Benchmarks kommt Accelerate diesen Geschwindigkeiten nicht besonders nahe, insbesondere wenn es um das Filtern von Live-Videos geht.
Wenn ich meine eigene Frage mit Jasons ausgezeichneter Hilfe beantworte, wird das letzte funktionierende Codefragment hier als Referenz zur Verfügung gestellt, falls es jemand anderem hilft. Wie Sie sehen können, besteht die Strategie darin, den Quell-ARGB (ich ignoriere A für Leistung und unter der Annahme, dass die Daten XRGB sind) in 3 Float-Arrays aufzuteilen, den Filter anzuwenden und das Ergebnis dann erneut zu multiplexen.
Es funktioniert ein Vergnügen - aber es ist schmerzhaft langsam. Ich benutze einen großen Kernel von 16x16, um eine starke Unschärfe zu bekommen, und auf meinem 3GS dauert es ungefähr 5 Sekunden für ein Vollbild, also wird das keine brauchbare Lösung sein.
Der nächste Schritt ist, nach Alternativen zu suchen ... aber danke, dass du mich zum Laufen gebracht hast.
%Vor%Warum verwenden Sie vDSP zur Bildfilterung? Versuchen Sie es mit vImageConvolve_ARGB8888 (). vImage ist die Bildverarbeitungskomponente von Accelerate.framework.
Tags und Links iphone image-processing accelerate-framework vdsp