Bilineare Interpolation in C / C ++ und CUDA

8

Ich möchte das Verhalten der CUDA-bilinearen Interpolation auf der CPU emulieren, aber ich fand, dass der Rückgabewert von tex2D nicht zur bilineare Formel .

Ich schätze, dass die Interpolationskoeffizienten von float auf 9 -Bit-Festkommaformat mit 8 Bits des Bruchteils umgewandelt werden [1] ergibt unterschiedliche Werte.

Nach der Umrechnungsformel [2, Zeile 106] ergibt sich das Ergebnis von Die Umwandlung ist die gleiche wie die Eingabe float , wenn der Koeffizient 1/2^n ist, mit n=0,1,..., 8 , aber ich bekomme immer noch (nicht immer) komische Werte.

Im Folgenden beschreibe ich ein Beispiel für seltsame Werte. In diesem Fall passieren seltsame Werte immer, wenn id = 2*n+1 , kann mir jemand sagen warum?

Src-Array:

%Vor%

Texturdefinition:

%Vor%

Kernel-Funktion:

%Vor%

Bilineares Ergebnis von CUDA

%Vor%

CPU-Ergebnis:

%Vor%

Ich hinterlasse einen einfachen Code auf meinem GitHub [3] , nachdem ich das Programm ausgeführt habe zwei Dateien in D:\ .

Bearbeiten 2014/01/20

Ich führe das Programm mit verschiedenen Inkrementen aus und finde die Spezifikation von tex2D "wenn alpha multipliziert beta kleiner als 0.00390625 ist, stimmt die Rückgabe von tex2D nicht mit der bilinearen Interpolationsformel überein "

    
user1995868 15.01.2014, 03:44
quelle

3 Antworten

8

Diese Frage ist bereits zufriedenstellend beantwortet worden, deshalb möchte ich nun ein Kompendium hoffentlich nützlicher Informationen zur bilinearen Interpolation geben, wie es in C ++ implementiert werden kann und wie es in CUDA anders geht.

Mathematik hinter bilinearer Interpolation

Angenommen, die ursprüngliche Funktion T(x, y) wird im kartesischen regulären Raster der Punkte (i, j) mit 0 <= i < M1 , 0 <= j < M2 und i und j ganzen Zahlen abgetastet. Für jeden Wert von y kann zuerst 0 <= a < 1 verwendet werden, um einen beliebigen Punkt i + a zwischen i und i + 1 darzustellen. Dann kann eine lineare Interpolation entlang der y = j -Achse (die parallel zur x -Achse ist) an diesem Punkt durchgeführt werden, wobei

erhalten wird

wobei r(x,y) die Funktion ist, die die Proben von T(x,y) interpoliert. Dasselbe kann für die Zeile y = j + 1 durchgeführt werden, wobei

erhalten wird

Nun kann für jede i + a eine Interpolation entlang der Achse y an den Beispielen r(i+a,j) und r(i+a,j+1) durchgeführt werden. Wenn also 0 <= b < 1 verwendet wird, um einen beliebigen Punkt j + b zwischen j und j + 1 darzustellen, kann eine lineare Interpolation entlang der Achse x = i + a (die parallel zur Achse y ist) bearbeitet werden aus, so dass das Endergebnis bekommen

Beachten Sie, dass die Beziehungen zwischen i , j , a , b , x und y die folgenden sind

C / C ++ - Implementierung

Lassen Sie mich betonen, dass diese Implementierung, wie auch die folgenden CUDAs, davon ausgehen, dass die Proben von T sich auf dem kartesischen regulären Gitter der Punkte (i, j) mit 0 <= i < M1 befinden, 0 <= j < M2 und i und j ganze Zahlen (Einheitenabstand). Außerdem wird die Routine in einfacher Genauigkeit, komplexe ( float2 ) Arithmetik zur Verfügung gestellt, aber es kann leicht in anderen Arithmetik von Interesse gegossen werden.

%Vor%

Die if/else -Anweisungen innerhalb des obigen Codes sind lediglich Grenzüberprüfungen. Wenn das Sample außerhalb von [0, M1-1] x [0, M2-1] liegt, wird es auf 0 gesetzt.

Standard-CUDA-Implementierung

Dies ist eine "Standard" -CUDA-Implementierung, die die obige CPU-Eins verfolgt. Keine Verwendung von Texturspeicher.

%Vor%

CUDA-Implementierung mit Texture Fetch

Dies ist dieselbe Implementierung wie oben, aber auf den globalen Speicher wird jetzt vom Textur-Cache zugegriffen. Zum Beispiel wird auf T[i,j] als

zugegriffen %Vor%

(wobei natürlich ind_x = i und ind_y = j und d_texture_fetch_float als globale Bereichsvariable angenommen wird) statt

%Vor%

Beachten Sie, dass die fest verdrahteten Texturfilterfunktionen hier nicht ausgenutzt werden. Die folgende Routine hat die gleiche Genauigkeit wie die obige und könnte etwas schneller als die auf alten CUDA-Architekturen sein.

%Vor%

Texturbindung kann nach

erfolgen %Vor%

Beachten Sie, dass wir jetzt keine Überprüfung der if/else -Begrenzung benötigen, da die Textur die Samples, die außerhalb des [0, M1-1] x [0, M2-1] -Abtastbereichs liegen, dank der Anweisungen

automatisch auf Null klemmt %Vor%

CUDA-Implementierung mit Texturinterpolation

Dies ist die letzte Implementierung und verwendet die fest verdrahteten Funktionen der Texturfilterung.

%Vor%

Beachten Sie, dass die von dieser Funktion implementierte Interpolationsformel dieselbe ist wie oben, aber jetzt

wo x_B = x - 0.5 und y_B = y - 0.5 . Dies erklärt den 0.5 Offset in der Anweisung

%Vor%

In diesem Fall sollte die Texturbindung wie folgt durchgeführt werden

%Vor%

Beachten Sie, dass, wie bereits in den anderen Antworten erwähnt, a und b im 9 -bit Festkommaformat mit 8 Bits des Bruchwerts gespeichert werden, so dass dieser Ansatz sehr schnell ist, aber weniger genau als die oben genannten.

    
JackOLantern 08.12.2014, 17:51
quelle
3

Die UV-Interpolanten werden auf 9 Bits verkürzt, nicht die teilnehmenden Texelwerte. In Kapitel 10 (Texturierung) des CUDA-Handbuchs wird dies für den 1D-Fall detailliert beschrieben (einschließlich CPU-Emulationscode). Der Code ist Open Source und kann unter Ссылка

gefunden werden     
ArchaeaSoftware 16.01.2014 13:37
quelle
1

Falsche Formel der bilinearen Interpolation macht das Ergebnis des Textur-Abrufs merkwürdig.

Formel - 1: Sie können es leicht in Anhang oder Wiki cuda finden

%Vor%

Formel - 2: Multiplikationszeiten reduzieren

%Vor%

Wenn Sie das 9-Bit-Festkommaformat für Formel 1 verwenden, erhalten Sie ein Ungleichheitsergebnis beim Textur-Holen, aber Formel 2 funktioniert gut.

Fazit:
Wenn Sie die bilineare Interpolation der cuda-Textur emulieren möchten, sollten Sie Formel 3 verwenden. Probieren Sie es aus!

Formel - 3:

%Vor%     
user1995868 22.01.2014 01:13
quelle

Tags und Links