2016-08-03 40 views
0

Endgültige Aktualisierung: Gelöst. Die WDDM-Zeitüberschreitung war ebenfalls ein Problem. Gefunden eine Lösung von: WDDM timeout fix. Danke Robert.CUDA NPP Median Filter für 16 Bit Bilder

Update: Danke Robert für das Hinweis, dass das Zentrum des Filters nicht 0,0 ist. Leider bricht der Code, den du gepostet hast, für mich auf, wenn der Filter erhöht wird, sagen wir zu 17x17. Dies könnte daran liegen, dass Sie die Ränder auf der "Seite" des Bildes nicht berücksichtigen. In jedem Fall ist hier der aktuellsten Code, aber immer noch die gleichen Probleme wie vor ausstellenden ...

//npp 
#include "npp.h" 
#include "nppi.h" 
#include "device_launch_parameters.h" 

#include <iostream> 

int main() { 

    //Image size. 
    int imageWidth = 6592; 
    int imageHeight = 4400; 

    //Misc. 
    int bytesPerPixel = 2; 
    int totalPixels = imageWidth*imageHeight; 
    int filterSize = 17; 
    int halfFilter = filterSize/2; 
    cudaError success2; 
    NppStatus success1; 

    //Mask & Origin for CUDA. 
    NppiSize cudaMask; 
    cudaMask.height = filterSize; 
    cudaMask.width = filterSize; 
    NppiPoint cudaAnchor; 
    cudaAnchor.x = halfFilter; 
    cudaAnchor.y = halfFilter; 

    //ROI for CUDA. 
    int left = halfFilter; 
    int right = (imageWidth-1) - halfFilter; 
    int top = halfFilter; 
    int bot = (imageHeight-1) - halfFilter; 
    NppiSize cudaROI; 
    cudaROI.height = bot - top; 
    cudaROI.width = right - left; 

    //Step size. 
    int step = imageWidth * bytesPerPixel; 

    //Create a new "image". 
    unsigned short* image = new unsigned short[totalPixels]; 
    for(int i=0; i<imageWidth; i++) 
     for(int j=0; j<imageHeight; j++) 
      image[j*imageWidth+i] = 10; 

    //Allocate mem on device. 
    Npp16u *dSrc, *dDst; 
    Npp8u *dBuf; 
    Npp32u bufferSize; 

    //This call always returns a bufferSize==0. That doesn't seem right... 
    success1 = nppiFilterMedianGetBufferSize_16u_C1R(cudaROI, cudaMask, &bufferSize); 
    std::cout << "get bufferSize returned: " << (int)success1 << std::endl; 
    std::cout << bufferSize << std::endl; 
    success2 = cudaMalloc((void**)&dBuf, bufferSize); 
    std::cout << "cudaMalloc 1 returned: " << (int)success2 << std::endl; 
    success2 = cudaMalloc((void**)&dSrc, totalPixels*sizeof(Npp16u)); 
    std::cout << "cudaMalloc 2 returned: " << (int)success2 << std::endl; 
    success2 = cudaMalloc((void**)&dDst, totalPixels*sizeof(Npp16u)); 
    std::cout << "cudaMalloc 3 returned: " << (int)success2 << std::endl; 

    //Copy host image to device. 
    success2 = cudaMemcpy(dSrc, image, totalPixels*sizeof(Npp16u), cudaMemcpyHostToDevice); 
    std::cout << "cudaMemcpy 1 returned: " << (int)success2 << std::endl; 


    //Copy source to destination. 
    success1 = nppiCopy_16u_C1R(dSrc, step, dDst, step, cudaROI); 
    std::cout << "npp Copy 1 returned: " << (int)success1 << std::endl; 


    //Filter. 
    Npp32u offset = top*step + left*bytesPerPixel; 
    success1 = nppiFilterMedian_16u_C1R( dSrc + offset, 
              step, 
              dDst + offset, 
              step, 
              cudaROI, cudaMask, cudaAnchor, dBuf); 
    std::cout << "npp Filter returned: " << (int)success1 << std::endl; 


    //Copy resultant back to host. 
    success2 = cudaMemcpy(image, dDst, totalPixels*sizeof(Npp16u), cudaMemcpyDeviceToHost); 
    std::cout << "cudaMemcpy 2 returned: " << (int)success2 << std::endl; 

    //Clean. 
    success2 = cudaFree(dDst); 
    success2 = cudaFree(dBuf); 
    success2 = cudaFree(dSrc); 
    delete image; 

    system("pause"); 
    return 0; 

} 

Ich versuche, einen Medianfilter für eine 29mp Bild zu berechnen. Die Filtergröße beträgt 13x13. Die Breite und Höhe des Bildes werden unten angezeigt. Aus einem unbekannten Grund wird der folgende Code abstürzen und ich frage, ob jemand weiß warum?

merkwürdige Dinge, die ich bemerkt habe:

  1. Der Fehler mit nppiFilterMedian_16u_C1R auftritt(). Die Funktion selbst gibt keine Fehlerbedingung zurück, aber das folgende cudaMemcpy(). Ohne den Filter funktioniert cudaMemcpy() einwandfrei.

  2. Auch für 16-Bit-Filter immer die Puffergröße immer wieder eine Größe von 0. I 8bit getestet haben, und 32 Bit, die Nicht-Null-Werte zurückgeben ...

  3. Ich denke, dass dies möglicherweise ein Fehler (?) mit der NPPI-Bibliothek. Es scheint Größe abhängig zu sein (wenn Sie die Breite/Höhe des Bildes verringern, funktioniert es gut für eine 13x13 Filtergröße). Allerdings müssen meine Filtergrößen bis zu 31x31 gehen.

Weitere wichtige Informationen: Windows x64-Anwendung, CUDA Runtime 7.5, NPP Version 7.5. GPU-Gerät ist ein Quadro k2200 (4 GB Global Mem).

+1

bitte Code schreiben, die –

+1

Der Medianfilter tatsächlich kompiliert ist nicht definiert (und illegale), wenn die Maske außen der definierte Eingangsbildbereich. Dies ist der Fall für die Randbereiche des Bildes, wenn Sie Ihren Code eingestellt haben. In der [äquivalenten intel ipp Dokumentation] (http://hpc.ipp.ac.cn/wp-content/uploads/2015/12/documentation_2016/en/ipp/common/ipp_manual/GUID-5D2F9418-E4F6-4F6C-B0F7 -B438CF28EA63.htm) Sie werden bemerken, dass es erforderlich ist, die Ausgabegröße zu reduzieren, um: "Um einen gültigen Vorgang zu gewährleisten, wenn Bildgrenzenpixel verarbeitet werden, sollte die Anwendung zusätzliche Rahmenpixel korrekt definieren" Sie verletzen diese Regel –

+0

Robert, Ich habe einen Code gepostet, der kompiliert. Ich schaue immer noch, was Sie über Grenzpixel erwähnen. Im Moment versuche ich nur, den ROI zu reduzieren, so dass das Kopieren/Replizieren von Grenzen nicht erforderlich ist. –

Antwort

1

Die mittlere Filterfunktion wird eine Maske über das Bild Punkt für Punkt passieren. Diese Maske hat die angegebenen Abmessungen (9x9 in Ihrem ursprünglichen Code). Der Ankerpunkt bestimmt, wie diese Maske für jedes Pixel positioniert wird. Wenn der Ankerpunkt 0,0 ist, wird die Maske wie folgt positioniert werden:

p** 
*** 
*** 

wo p die Pixelposition darstellt, und die Maskengröße ist 3x3. Für einen Ankerpunkt von 1,1, die Maskenpositionierung, pro Pixel, wäre:

*** 
*p* 
*** 

Daher sehen wir, dass der Ankerpunkt, und die Maskengröße, eine gewisse Grenze um jedes Pixel zu bestimmen, welche muss für die Median-Filterfunktion zugänglich sein. Wenn wir uns mit Pixeln im Rand des Bildes beschäftigen, müssen wir sicherstellen, dass diese Grenze auf gültigen Pixeln landet.

Der Fall, mit dem Sie begonnen haben, eine 9x9-Maske und ein 0,0-Ankerpunkt, bedeutet, dass wir nur "extra" Pixel für die Grenze am "Ende" des Bildes benötigen. Daher ist die Änderung einfach: Beschränke die ROI-Höhe, um die letzten paar Zeilen des Bildes entsprechend der Maskenabmessung nicht zu verarbeiten.Für diesen Fall können wir einfach 10 von der ROI Höhe abziehen, und die Fehler weggehe

$ cat t1223.cu 
//npp 
#include "npp.h" 
#include "nppi.h" 
#include <iostream> 

int main() { 

//When the filter size is 9x9.... 
int imageWidth = 6592; //breaks if > 5914 && imageHeight = 4400 
int imageHeight = 4400; //breaks if > 3946 && imageWidth = 6592 

//Misc. 
int bytesPerPixel = 2; 
int totalPixels = imageWidth*imageHeight; 
cudaError success2; 
NppStatus success1; 

//ROI for CUDA. 
NppiSize cudaROI; 
cudaROI.height = imageHeight-10; 
cudaROI.width = imageWidth; 

//Mask & Origin for CUDA. 
NppiSize cudaMask; NppiPoint cudaAnchor; 
cudaMask.height = 9; //filter size 
cudaMask.width = 9; 
cudaAnchor.x = 0; 
cudaAnchor.y = 0; 

//Step size. 
int step = imageWidth * bytesPerPixel; 

//Create a new "image". 
unsigned short* image = new unsigned short[totalPixels]; 
for(int i=0; i<imageWidth; i++) 
    for(int j=0; j<imageHeight; j++) 
     image[j*imageWidth+i] = 10; 


//Allocate mem on device. 
Npp16u *dSrc, *dDst; 
Npp8u *dBuf; 
Npp32u bufferSize; 

//This call always returns a bufferSize==0. That doesn't seem right... 
success1 = nppiFilterMedianGetBufferSize_16u_C1R(cudaROI, cudaMask, &bufferSize); 
std::cout << "get bufferSize returned: " << (int)success1 << std::endl; 
std::cout << bufferSize << std::endl; 
success2 = cudaMalloc((void**)&dBuf, bufferSize); 
std::cout << "cudaMalloc 1 returned: " << (int)success2 << std::endl; 
success2 = cudaMalloc((void**)&dSrc, totalPixels*sizeof(Npp16u)); 
std::cout << "cudaMalloc 2 returned: " << (int)success2 << std::endl; 
success2 = cudaMalloc((void**)&dDst, totalPixels*sizeof(Npp16u)); 
std::cout << "cudaMalloc 3 returned: " << (int)success2 << std::endl; 

//Copy host image to device. 
success2 = cudaMemcpy(dSrc, image, totalPixels*sizeof(Npp16u), cudaMemcpyHostToDevice); 
std::cout << "cudaMemcpy 1 returned: " << (int)success2 << std::endl; 

//Copy source to destination. 
success1 = nppiCopy_16u_C1R(dSrc, step, dDst, step, cudaROI); 
std::cout << "npp Copy 1 returned: " << (int)success1 << std::endl; 

//Filter. 
success1 = nppiFilterMedian_16u_C1R(dSrc, 
            step, 
            dDst, 
            step, 
            cudaROI, cudaMask, cudaAnchor, dBuf); 
std::cout << "npp Filter returned: " << (int)success1 << std::endl; 

//Copy resultant back to host. 
success2 = cudaMemcpy(image, dDst, totalPixels*sizeof(Npp16u), cudaMemcpyDeviceToHost); 
std::cout << "cudaMemcpy 2 returned: " << (int)success2 << std::endl; 

//Clean. 
success2 = cudaFree(dBuf); 
success2 = cudaFree(dSrc); 
success2 = cudaFree(dDst); 
delete image; 

return 0; 
} 
$ nvcc -arch=sm_35 -o t1223 t1223.cu -lnppi 
$ cuda-memcheck ./t1223 
========= CUDA-MEMCHECK 
get bufferSize returned: 0 
0 
cudaMalloc 1 returned: 0 
cudaMalloc 2 returned: 0 
cudaMalloc 3 returned: 0 
cudaMemcpy 1 returned: 0 
npp Copy 1 returned: 0 
npp Filter returned: 0 
cudaMemcpy 2 returned: 0 
========= ERROR SUMMARY: 0 errors 
$ 

Beachten Sie, dass, wenn der Ankerpunkt verschoben wurde (beispielsweise auf 4,4 anstelle von 0,0 im Fall oben), dann würde dies bedeuten, dass die "Grenz" -Pixel für ~ 5 Zeilen vor dem Start des Bildes verfügbar sein müssten. Wir können dies berücksichtigen, indem korrekt die ROI Einstellung und auch den Beginn der Verarbeitung ausgeglichen, indem Sie eine Zeile mit dem Quellenzeiger-Offset Zugabe zu den Median-Filter geleitet, etwa so:

success1 = nppiFilterMedian_16u_C1R(dSrc + 5*imageWidth, 

Bitte beachte, dass ich nicht bin versucht, Um ein vollständiges Tutorial zur Median-Filterung zu geben, versuchen Sie nur das Problem zu identifizieren, das zum tatsächlichen Funktionsausfall führt. Die Filtergrenzen für die linke und die rechte Seite sind ebenfalls etwas, das Sie berücksichtigen sollten. An der linken und rechten Seite der Bildgrenzen können diese Pixelmaskengrenzen zu vorherigen oder nächsten Bildzeilen indizieren, wodurch das Bild "umhüllt" wird, möglicherweise mit ungeraden Effekten in den gefilterten Pixeln.

EDIT: Reagieren auf die neue Code-Veröffentlichung, scheint das Hauptproblem jetzt zu sein, dass Sie nicht verstehen, wie Sie das Bild versetzen.

In C/C++, wenn ich einen Zeiger habe, und ich möchte diesen Zeiger um eine bestimmte Anzahl von Elementen versetzen, füge ich einfach die Anzahl der Elemente, die ich durchsetzen möchte. Es gibt keine Notwendigkeit, dies durch Bytes zu skalieren. Wenn Sie das Offset-Beispiel, das ich oben angegeben hatte, studiert hätten, hätten Sie bemerkt, dass es keine Skalierung um Bytes gibt. Wenn wir um 5 Zeilen versetzt werden wollen, wird es nur 5 multipliziert mit der Bildbreite, wie oben angezeigt.

Außerdem haben Sie den cudaROI verwendet, um Ihre src> dst-Kopieroperation zu informieren, das macht für mich keinen Sinn, also habe ich das geändert. Schließlich habe ich den Code so modifiziert, dass er mit dem Anker in der Ecke oder dem Anker in der Mitte gebaut werden kann.

Hier ist eine Modifikation des Codes, die für mich kompiliert und läuft richtig, in beiden Anker Fällen:

$ cat t1225.cu 
//npp 
#include "npp.h" 
#include "nppi.h" 
#include "device_launch_parameters.h" 

#include <iostream> 

int main() { 

    //Image size. 
    int imageWidth = 6592; 
    int imageHeight = 4400; 

    //Misc. 
    int bytesPerPixel = 2; 
    int totalPixels = imageWidth*imageHeight; 
    int filterSize = 17; 
    int halfFilter = filterSize/2; 
    cudaError success2; 
    NppStatus success1; 

    //Mask & Origin for CUDA. 
    NppiSize cudaMask; 
    cudaMask.height = filterSize; 
    cudaMask.width = filterSize; 
    NppiPoint cudaAnchor; 
#ifndef ANCHOR_CORNER 
    cudaAnchor.x = halfFilter; 
    cudaAnchor.y = halfFilter; 
#else 
    cudaAnchor.x = 0; 
    cudaAnchor.y = 0; 
#endif 
    NppiSize imgSize; 
    imgSize.width = imageWidth; 
    imgSize.height = imageHeight; 

    //ROI for CUDA. 
    int left = halfFilter; 
    int right = (imageWidth-1) - halfFilter; 
    int top = halfFilter; 
    int bot = (imageHeight-1) - halfFilter; 
    NppiSize cudaROI; 
    cudaROI.height = bot - top; 
    cudaROI.width = right - left; 

    //Step size. 
    int step = imageWidth * bytesPerPixel; 

    //Create a new "image". 
    unsigned short* image = new unsigned short[totalPixels]; 
    for(int i=0; i<imageWidth; i++) 
     for(int j=0; j<imageHeight; j++) 
      image[j*imageWidth+i] = 10; 

    //Allocate mem on device. 
    Npp16u *dSrc, *dDst; 
    Npp8u *dBuf; 
    Npp32u bufferSize; 

    //This call always returns a bufferSize==0. That doesn't seem right... 
    success1 = nppiFilterMedianGetBufferSize_16u_C1R(cudaROI, cudaMask, &bufferSize); 
    std::cout << "get bufferSize returned: " << (int)success1 << std::endl; 
    std::cout << bufferSize << std::endl; 
    success2 = cudaMalloc((void**)&dBuf, bufferSize); 
    std::cout << "cudaMalloc 1 returned: " << (int)success2 << std::endl; 
    success2 = cudaMalloc((void**)&dSrc, totalPixels*sizeof(Npp16u)); 
    std::cout << "cudaMalloc 2 returned: " << (int)success2 << std::endl; 
    success2 = cudaMalloc((void**)&dDst, totalPixels*sizeof(Npp16u)); 
    std::cout << "cudaMalloc 3 returned: " << (int)success2 << std::endl; 

    //Copy host image to device. 
    success2 = cudaMemcpy(dSrc, image, totalPixels*sizeof(Npp16u), cudaMemcpyHostToDevice); 
    std::cout << "cudaMemcpy 1 returned: " << (int)success2 << std::endl; 


    //Copy source to destination. 
    success1 = nppiCopy_16u_C1R(dSrc, step, dDst, step, imgSize); 
    std::cout << "npp Copy 1 returned: " << (int)success1 << std::endl; 


    //Filter. 
#ifndef ANCHOR_CORNER 
    Npp32u offset = top*imageWidth + left; 
#else 
    Npp32u offset = 0; 
#endif 
    success1 = nppiFilterMedian_16u_C1R( dSrc + offset, 
              step, 
              dDst + offset, 
              step, 
              cudaROI, cudaMask, cudaAnchor, dBuf); 
    std::cout << "npp Filter returned: " << (int)success1 << std::endl; 


    //Copy resultant back to host. 
    success2 = cudaMemcpy(image, dDst, totalPixels*sizeof(Npp16u), cudaMemcpyDeviceToHost); 
    std::cout << "cudaMemcpy 2 returned: " << (int)success2 << std::endl; 

    //Clean. 
    success2 = cudaFree(dDst); 
    success2 = cudaFree(dBuf); 
    success2 = cudaFree(dSrc); 
    delete image; 

    return 0; 

} 
$ nvcc -o t1225 t1225.cu -lnppi 
$ cuda-memcheck ./t1225 
========= CUDA-MEMCHECK 
get bufferSize returned: 0 
0 
cudaMalloc 1 returned: 0 
cudaMalloc 2 returned: 0 
cudaMalloc 3 returned: 0 
cudaMemcpy 1 returned: 0 
npp Copy 1 returned: 0 
npp Filter returned: 0 
cudaMemcpy 2 returned: 0 
========= ERROR SUMMARY: 0 errors 
$ nvcc -DANCHOR_CORNER -o t1225 t1225.cu -lnppi 
$ cuda-memcheck ./t1225 
========= CUDA-MEMCHECK 
get bufferSize returned: 0 
0 
cudaMalloc 1 returned: 0 
cudaMalloc 2 returned: 0 
cudaMalloc 3 returned: 0 
cudaMemcpy 1 returned: 0 
npp Copy 1 returned: 0 
npp Filter returned: 0 
cudaMemcpy 2 returned: 0 
========= ERROR SUMMARY: 0 errors 
+0

Robert, dieser Code wird abgebrochen, wenn die Filtergröße erhöht wird. Ich habe gerade eine Version des Codes mit Ihren Vorschlägen gepostet, aber mit einer großen Filtergröße bricht NPP immer noch ab. –

+0

Natürlich, wenn Sie * nichts * tun, aber die Filtergröße erhöhen (sagen wir zu 17x17), dann bricht der Code ab, weil Sie nicht den Anweisungen folgen, die ich gegeben habe. Wenn ich diesen genauen Code in meiner Antwort nehme und die Filtergröße auf 17x17 (statt der 9x9-Größe) erhöhe, und ** auch ** die ROI-Höhe um 20 reduziere (statt 10 wie in meiner Antwort), Um die größere Filtergröße zu berücksichtigen, läuft der Code für mich genauso erfolgreich ab, wie der vorhergehende Code in meiner Antwort. –

+0

Ja, ich stimme zu und versäumte es zu sagen, dass ich auch den ROI verändert habe. Wenn ich die ROI-Höhe um 20 reduziere, erhalte ich die folgenden Fehler: npp Filter zurückgegeben: -1000, CUDA FEHLER # 30 (mit FilterMedian Kernel # 4): unbekannter Fehler. –