2012-10-15 30 views
5

Nvidia Performance Primitives (NPP) ile iletişim kurarken, kullanıcı tarafından sağlanan görüntüyü kullanıcı tarafından sağlanan bir çekirdekle eşleştirmek için nppiFilter işlevini sağlar. 1D konvolüsyon çekirdekleri için nppiFilter düzgün çalışır. Ancak, nppiFilter, 2B çekirdekler için bir çöp resmi üretiyor. Nvidia NPP nppiFilter, 2d çekirdeği

Ben girdi olarak tipik Lena görüntüsü kullandı: enter image description here


Burada iyi çıktı üretir bir 1D büklüm çekirdeğine sahip benim deney. kernel [-1 0 1] Yukarıdaki kod

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

Çıktı - makul bir degrade görüntü benziyor: Bir 2D evrişim çekirdeği kullanırsanız enter image description here


Ancak nppiFilter bir çöp resmi çıktılar . İşte 2B kernel [-1 0 1; -1 0 1; -1 0 1] ile çalıştırmak için yukarıdaki kod değiştirildi şeyler şunlardır:

Aşağıda
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); 

2B çekirdek [-1 0 1; -1 0 1; -1 0 1] kullanarak çıkış resimdir. Yanlış yapıyorum

? http://1ordrup.dk/kasper/image/Lena_boxFilter5.jpg


Birkaç son notlar: 2D çekirdekle

, benzer bir sorun açıklanır Değerler (örneğin, NppiPoint oAnchor = {0, 0} veya {1, 1}) hata alıyorum -24, t NPP User Guide'a göre NPP_TEXTURE_BIND_ERROR'a bağlanır. Bu sorun, this StackOverflow post'da kısaca belirtilmiştir.

  • Bu kod çok ayrıntılıdır. Bu asıl soru değil, ancak bu kodu daha özlü hale getirecek herhangi bir önerisi var mı?
  • cevap

    2

    Çekirdek dizisi için bir 2D bellek ayırıcısı kullanıyorsunuz. Kernel dizileri, tipik NPP görüntüsü olduğu gibi 2B dizileri değil, yoğun 1D dizileridir.

    2D CUDA malloc'unu basit bir cuda malloc boyutu olan kernelWidth * kernelHeight * sizeof (Npp32s) ile değiştirin ve normal bir CUDA memelisini, 2B kopyalamasında değil.

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

    Bir kenara göre, 1'in "ölçek faktörü", ölçeklendirmeye dönüştürülmez. Ölçeklendirme, 2^(- ScaleFactor) faktörleriyle olur.

    +0

    Ah, harika. Şimdi 1D 'cudaMalloc' ve 1D' cudaMemcpy' deniyorum. Ayrıca, ScaleFactor = 0'nın ölçeklendirme yapmamasına benziyor, doğru mu? – solvingPuzzles

    +0

    1D malloc ve memcpy yapmak sorunu çözdü! Teşekkürler! 2d 3x3 çekirdeği ile işlenen görüntü şöyledir: http://i.stack.imgur.com/wziix.png – solvingPuzzles

    +1

    NPP "2^(- ScaleFactor)' ile ölçeklenirse, "ScaleFactor = 0" ın bir 1. bölücü, ancak 'ScaleFactor = 0' ayarının yapılması bana boş bir görüntü veriyor. – solvingPuzzles