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:
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:
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?
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 doNPP_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?
Ah, świetnie. Próbuję teraz 1D 'cudaMalloc' i 1D' cudaMemcpy'. Ponadto brzmi to tak, jakby 'ScaleFactor = 0' nie dawałoby skalowania, prawda? – solvingPuzzles
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
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