2012-10-15 7 views
5

Nvidia Performance Primitives (NPP) zapewnia funkcję nppiFilter dla zawijania obrazu dostarczonego przez użytkownika za pomocą jądra dostarczonego przez użytkownika. W przypadku ziaren splotów 1D, nppiFilter działa poprawnie. Jednak nppiFilter tworzy obraz śmieciowy dla jądra 2D.Nvidia NPP nppiFilter produkuje śmieci, gdy zawijanie z jądrem 2d

użyłem typowej Lena obraz jako wejście: enter image description here


Oto mój eksperyment z 1D jądra splotu, który daje dobre wyjście.

#include <npp.h> // provided in CUDA SDK 
#include <ImagesCPU.h> // these image libraries are also in CUDA SDK 
#include <ImagesNPP.h> 
#include <ImageIO.h> 

void test_nppiFilter() 
{ 
    npp::ImageCPU_8u_C1 oHostSrc; 
    npp::loadImage("Lena.pgm", oHostSrc); 
    npp::ImageNPP_8u_C1 oDeviceSrc(oHostSrc); // malloc and memcpy to GPU 
    NppiSize kernelSize = {3, 1}; // dimensions of convolution kernel (filter) 
    NppiSize oSizeROI = {oHostSrc.width() - kernelSize.width + 1, oHostSrc.height() - kernelSize.height + 1}; 
    npp::ImageNPP_8u_C1 oDeviceDst(oSizeROI.width, oSizeROI.height); // allocate device image of appropriately reduced size 
    npp::ImageCPU_8u_C1 oHostDst(oDeviceDst.size()); 
    NppiPoint oAnchor = {2, 1}; // found that oAnchor = {2,1} or {3,1} works for kernel [-1 0 1] 
    NppStatus eStatusNPP; 

    Npp32s hostKernel[3] = {-1, 0, 1}; // convolving with this should do edge detection 
    Npp32s* deviceKernel; 
    size_t deviceKernelPitch; 
    cudaMallocPitch((void**)&deviceKernel, &deviceKernelPitch, kernelSize.width*sizeof(Npp32s), kernelSize.height*sizeof(Npp32s)); 
    cudaMemcpy2D(deviceKernel, deviceKernelPitch, hostKernel, 
        sizeof(Npp32s)*kernelSize.width, // sPitch 
        sizeof(Npp32s)*kernelSize.width, // width 
        kernelSize.height, // height 
        cudaMemcpyHostToDevice); 
    Npp32s divisor = 1; // no scaling 

    eStatusNPP = nppiFilter_8u_C1R(oDeviceSrc.data(), oDeviceSrc.pitch(), 
              oDeviceDst.data(), oDeviceDst.pitch(), 
              oSizeROI, deviceKernel, kernelSize, oAnchor, divisor); 

    cout << "NppiFilter error status " << eStatusNPP << endl; // prints 0 (no errors) 
    oDeviceDst.copyTo(oHostDst.data(), oHostDst.pitch()); // memcpy to host 
    saveImage("Lena_filter_1d.pgm", oHostDst); 
} 

Wyjście powyższego kodu z jądrem [-1 0 1] - wygląda na rozsądną gradientu obrazu: enter image description here


Jednak nppiFilter generuje obraz śmieci czy używam jądra 2D splot . Oto rzeczy, które zostały zmienione z powyższego kodu, które są prowadzone z jądrem 2D [-1 0 1; -1 0 1; -1 0 1]:

NppiSize kernelSize = {3, 3}; 
Npp32s hostKernel[9] = {-1, 0, 1, -1, 0, 1, -1, 0, 1}; 
NppiPoint oAnchor = {2, 2}; // note: using anchor {1,1} or {0,0} causes error -24 (NPP_TEXTURE_BIND_ERROR) 
saveImage("Lena_filter_2d.pgm", oHostDst); 

Poniżej znajduje się obraz wyjściowy stosuje się jądro 2D [-1 0 1; -1 0 1; -1 0 1].

Co robię źle?

enter image description here

This StackOverflow post opisuje podobny problem, jak pokazano w Użytkownik Steenstrup za obrazem: http://1ordrup.dk/kasper/image/Lena_boxFilter5.jpg


Kilka końcowe Uwagi:

  • z jądrem 2D, dla pewnej kotwicy wartości (np. NppiPoint oAnchor = {0, 0} lub {1, 1}), pojawia się błąd -24, który Ranslates do NPP_TEXTURE_BIND_ERROR zgodnie z NPP User Guide. Ten problem został krótko wymieniony w dokumencie this StackOverflow post.
  • Ten kod jest bardzo szczegółowy. To nie jest główne pytanie, ale czy ktoś ma jakieś sugestie, jak uczynić ten kod bardziej zwięzłym?

Odpowiedz

2

Korzystasz z alokatora pamięci 2D dla tablicy jądra. Macierze jądra są gęstymi tablicami 1D, a nie macierzą ukośną, jak typowy obraz NPP.

Po prostu wymień malloc 2D CUDA na zwykłe cudocentrum o rozmiarze kernelWidth * kernelHeight * sizeof (Npp32s) i wykonaj normalną notkę CUDA, a nie memkopię 2D.

//1D instead of 2D 
cudaMalloc((void**)&deviceKernel, kernelSize.width * kernelSize.height * sizeof(Npp32s)); 
cudaMemcpy(deviceKernel, hostKernel, kernelSize.width * kernelSize.height * sizeof(Npp32s), cudaMemcpyHostToDevice); 

Tak na marginesie, „współczynnika skalowania” z 1 nie przekłada się bez skalowania. Skalowanie odbywa się za pomocą współczynników 2^(- ScaleFactor).

+0

Ah, świetnie. Próbuję teraz 1D 'cudaMalloc' i 1D' cudaMemcpy'. Ponadto brzmi to tak, jakby 'ScaleFactor = 0' nie dawałoby skalowania, prawda? – solvingPuzzles

+0

Robiąc 1D malloc i memcpy naprawiono problem !! Dzięki! Oto obraz przetworzony za pomocą jądra 2d 3x3: http://i.stack.imgur.com/wziix.png – solvingPuzzles

+1

Jeśli skala NPP ma wartość '2^(- ScaleFactor)', to myślę, że 'ScaleFactor = 0' powinien dać dzielnik 1. Jednak ustawienie 'ScaleFactor = 0' daje mi puste zdjęcie. – solvingPuzzles

Powiązane problemy