2012-10-15 2 views
5

Nvidia Performance Primitives (NPP)은 사용자가 제공 한 이미지를 사용자 제공 커널과 컨벌루션하기위한 nppiFilter 기능을 제공합니다. 1D 컨벌루션 커널의 경우 nppiFilter이 올바르게 작동합니다. 그러나 nppiFilter은 2D 커널 용 가비지 이미지를 생성하고 있습니다. Nvidia NPP nppiFilter는 2d 커널과 컨볼 루션 할 때 쓰레기를 생성합니다.

내가 입력으로 전형적인 레나 이미지를 사용 : enter image description here


여기 좋은 출력을 생성하는 1D 컨볼 루션 커널, 내 실험입니다. 커널 [-1 0 1]와 상기 코드

#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); 
} 

출력 - 그 적당한 그라데이션 화상처럼 보이는 : I가 2D 컨볼 루션 커널을 사용하면 enter image description here


그러나 nppiFilter 가비지 화상 출력 . 여기에 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); 

는 2D 커널 [-1 0 1; -1 0 1; -1 0 1]를 사용하여 출력 이미지입니다.

내가 뭘 잘못하고 있니? http://1ordrup.dk/kasper/image/Lena_boxFilter5.jpg


몇 최종 노트 : 2 차원 커널

는 비슷한 문제를 설명 값 (예 : NppiPoint oAnchor = {0, 0} 또는 {1, 1})을 입력하면 오류 -24이 표시됩니다. NPP User Guide에 따라 NPP_TEXTURE_BIND_ERROR으로 변환됩니다. 이 문제는 this StackOverflow post에서 간략하게 언급되었습니다.

  • 이 코드는 매우 장황합니다. 이것은 주요 질문은 아니지만 누구든지이 코드를보다 간결하게 만드는 방법에 대한 제안이 있습니까?
  • 답변

    2

    커널 배열에 2D 메모리 할당기를 사용하고 있습니다. 커널 배열은 일반적인 NPP 이미지와 같이 2D 스트라이드 배열이 아닌 고밀도 1 차원 배열입니다.

    단순히 2D CUDA malloc을 kernelWidth * kernelHeight * sizeof (Npp32s) 크기의 간단한 cuda malloc으로 바꾸고 memcopy 2D가 아닌 일반적인 CUDA memcopy를 수행하십시오.

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

    "스케일 팩터"1은 스케일링을 의미하지 않습니다. 스케일링은 2^(- ScaleFactor) 요소로 발생합니다.

    +0

    아, 훌륭합니다. 저는 1D''cudaMalloc''과 1D''cudaMemcpy''를 지금 시험 중입니다. 또한, 'ScaleFactor = 0'처럼 스케일링을주지 않을 것 같은가요? – solvingPuzzles

    +0

    1D malloc과 memcpy를 사용하면 문제가 해결되었습니다 !! 감사! 다음은 2 차원 3x3 커널로 처리 된 이미지입니다 : http://i.stack.imgur.com/wziix.png – solvingPuzzles

    +1

    NPP가 '2^(- ScaleFactor)'로 비례한다면'ScaleFactor = 0'은 그러나 ScaleFactor = 0으로 설정하면 나에게 빈 이미지가 생깁니다. – solvingPuzzles

    관련 문제