Nvidia Performance Primitives (NPP) bietet die nppiFilter
Funktion zum Falten eines vom Benutzer bereitgestellten Bildes mit einem vom Benutzer bereitgestellten Kernel. Für 1D-Faltungskerne funktioniert nppiFilter
ordnungsgemäß. nppiFilter
erzeugt jedoch ein Müllbild für 2D-Kernel.Nvidia NPP nppiFilter produziert Müll beim Falten mit 2d Kernel
verwenden ich die typische Lena Bild als Eingabe:
mit meinem Experiment Hier 1D Faltungskernen, die ein gute Ausgangssignal erzeugt.
#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);
}
Ausgabe des obigen Codes mit Kernel [-1 0 1]
- es sieht aus wie eine vernünftige Gradientenbild:
jedoch nppiFilter
gibt einen Müll Bild, wenn ich ein 2D Faltungskerne verwenden . Hier sind die Dinge, die ich von dem obigen Code geändert mit dem 2D-Kernel laufen [-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);
Unter dem Ausgabebild ist die Kernel-2D mit [-1 0 1; -1 0 1; -1 0 1]
.
Was mache ich falsch?
This StackOverflow post beschreibt ein ähnliches Problem, wie in Benutzer Steenstrup das Bild gezeigt: http://1ordrup.dk/kasper/image/Lena_boxFilter5.jpg
Einige abschließende Hinweise:
- Mit dem 2D-Kernel für bestimmte Anker Werte (zB
NppiPoint oAnchor = {0, 0}
oder{1, 1}
), bekomme ich Fehler-24
, die t ÜberträgtNPP_TEXTURE_BIND_ERROR
gemäß der NPP User Guide. Dieses Problem wurde kurz in this StackOverflow post erwähnt. - Dieser Code ist sehr ausführlich. Dies ist nicht die Hauptfrage, aber hat jemand irgendwelche Vorschläge, wie man diesen Code prägnanter gestalten kann?
Ah, großartig. Ich probiere die 1D 'cudaMalloc' und 1D' cudaMemcpy' jetzt aus. Es klingt auch wie 'ScaleFactor = 0' würde keine Skalierung geben, richtig? – solvingPuzzles
Doing ein 1D malloc und memcpy behoben das Problem !! Vielen Dank! Hier ist das Bild, das mit dem 2d 3x3 Kernel bearbeitet wurde: http://i.stack.imgur.com/wziix.png – solvingPuzzles
Wenn NPP um '2^(- ScaleFactor)' skaliert, dann sollte 'ScaleFactor = 0' ein a geben Divisor von 1. Jedoch, Einstellung von "ScaleFactor = 0" gibt mir ein leeres Bild. – solvingPuzzles