Ich habe eine Anwendung, bei der ich die durchschnittliche Intensität eines Bildes für ungefähr 1 Million Bilder benötige. Es fühlt sich an wie ein Job für einen GPU-Fragment-Shader, aber Fragment-Shader sind für lokale Berechnungen pro Pixel, während die Bildmittelung eine globale Operation ist.
Ein Ansatz, den ich in Betracht gezogen habe, ist das Laden des Bildes in eine Textur, das Anwenden einer 2x2-Box-Unschärfe, das Laden des Ergebnisses in eine N / 2 x N / 2 Textur und Wiederholen, bis die Ausgabe 1x1 ist. Dies würde jedoch Log-Anwendungen des Shaders erfordern.
Gibt es eine Möglichkeit, dies in einem Durchgang zu tun? Oder sollte ich einfach CUDA / OpenCL verwenden?
Die Summierungsoperation ist ein spezieller Fall der "Reduktion", einer Standardoperation in CUDA- und OpenCL-Bibliotheken. Eine nette Beschreibung dazu gibt es auf der Cuda Demos Seite . In CUDA Thrust und CUDPP sind nur zwei Beispiele für Bibliotheken, die eine Reduzierung ermöglichen. Ich bin mit OpenCL weniger vertraut, aber CLPP scheint eine gute Bibliothek zu sein, die eine Reduzierung bietet. Kopieren Sie einfach Ihren Farbpuffer in ein OpenGL-Pixelpufferobjekt, und verwenden Sie den entsprechenden OpenGL-Interoperabilitätsaufruf, um den Speicher dieses Pixelpuffers in CUDA / OpenCL zugänglich zu machen.
Wenn es mit der opengl-API geschehen muss (wie die ursprüngliche Frage erforderlich ist), besteht die Lösung darin, eine Textur zu rendern, eine Mipmap der Textur zu erstellen und die 1x1-Textur einzulesen. Sie müssen die Filterung richtig einstellen (bilinear ist geeignet, denke ich), aber es sollte nahe an die richtige Antwort, Modulo-Genauigkeitsfehler, kommen.
Mein Bauch sagt mir, ich sollte versuchen, Ihre Implementierung in OpenCL durchzuführen. Sie können Ihre Bildgröße und Grafikhardware optimieren, indem Sie die Bilder in maßgeschneiderte Datenblöcke aufteilen, die dann parallel summiert werden. Könnte sehr schnell sein.
Fragment-Shader eignen sich hervorragend für Faltungen, aber dieses Ergebnis wird normalerweise in die gl_FragColor geschrieben, daher ist es sinnvoll. Letztendlich müssen Sie jedes Pixel in der Textur durchlaufen und das Ergebnis summieren, das dann im Hauptprogramm zurückgelesen wird. Generieren von Bildstatistiken vielleicht nicht, wofür der Fragment-Shader entworfen wurde und es ist nicht klar, dass ein großer Leistungsgewinn zu haben ist, da ein bestimmter Puffer nicht garantiert ist, befindet sich im GPU-Speicher.
Es klingt so, als ob Sie diesen Algorithmus auf ein Echtzeit-Bewegungserkennungsszenario oder eine andere automatisierte Feature-Erkennungsanwendung anwenden. Es kann schneller sein, einige Statistiken aus einer Pixelprobe als das gesamte Bild zu berechnen und dann einen maschinellen Lernklassifikator zu erstellen.
Viel Glück für Sie auf jeden Fall!
Es benötigt keine CUDA, wenn Sie sich an GLSL halten möchten. Wie in der hier erwähnten CUDA-Lösung kann es in einem Fragment-Shader direkt nach vorne erfolgen. Sie benötigen jedoch etwa Protokollaufrufe (Auflösung).
Richten Sie einfach einen Shader ein, der 2x2 Pixel-Samples vom Originalbild aufnimmt und die durchschnittliche Summe dieser Samples ausgibt. Das Ergebnis ist ein Bild mit halber Auflösung in beiden Achsen. Wiederholen Sie dies, bis das Bild 1x1 px ist.
Einige Überlegungen: Verwenden Sie GL_FLOAT
Luminanz Texturen falls verfügbar, um eine genauere Summe zu erhalten. Verwenden Sie glViewport
, um den Rendering-Bereich in jeder Phase vierteilig zu machen. Das Ergebnis endet dann im oberen linken Pixel Ihres Framebuffers.
Tags und Links opengl image-processing gpu glsl