cuda nppiResize () для изображений RGB - PullRequest
0 голосов
/ 30 сентября 2019

nVidia Cuda nppiResize_32f_C1R работает нормально на градациях серого 1 x 32f, но nppiResize_32f_C3R возвращает мусор. Ясно, что обходным путем было бы вызвать эту процедуру 3 раза, сначала сняв чередование данных как планарные R, G, B, но я ожидал, что смогу выполнить его за один проход. У nVidia много примеров кода для обработки изображений в одной плоскости, но скудное количество для чередующихся цветовых плоскостей, поэтому я обращаюсь за помощью к stackoverflow. Я не знаю, как вычисляется шаг, но я понимаю, что шаг - это ширина изображения, умноженная на число байтов на индекс столбца. Так что в моем случае - без отступов - он должен быть шириной 32f x 3 для RGB.

Пробовал разные шаги / шаги в cudaMemcpy2D (). Не удается найти работоспособное решение для цветного кода RGB. Компилируется и работает нормально, ошибок нет. Первый раздел для оттенков серого (работает нормально). Второй раздел - RGB (мусор).

    // nppiResize using 2D aligned allocations

    #include <Exceptions.h>
    #include <cuda_runtime.h>
    #include <npp.h>
    #include <nppi.h>
    #include <nppdefs.h>

    #define CUDA_CALL(call) do { cudaError_t cuda_error = call; if(cuda_error != cudaSuccess) { std::cerr << "CUDA Error: " << cudaGetErrorString(cuda_error) << ", " << __FILE__ << ", line " << __LINE__ << std::endl; return(NULL);} } while(0)

    float* decimate_cuda(float* readbuff, uint32_t nSrcH, uint32_t nSrcW, uint32_t nDstH, uint32_t nDstW, uint8_t byteperpixel)
    {
        if (byteperpixel == 1){ // source : Grayscale, 1 x 32f
            size_t  srcStep; 
            size_t  dstStep;

            NppiSize oSrcSize = {nSrcW, nSrcH};
            NppiRect oSrcROI = {0, 0, nSrcW, nSrcH};
            float *devSrc;
            CUDA_CALL(cudaMallocPitch((void**)&devSrc, &srcStep, nSrcW * sizeof(float), nSrcH));
            CUDA_CALL(cudaMemcpy2D((void**)devSrc, srcStep,(void**)readbuff, nSrcW * sizeof(Npp32f), nSrcW * sizeof(Npp32f), nSrcH, cudaMemcpyHostToDevice));

            NppiSize oDstSize = {nDstW, nDstH};     
            NppiRect oDstROI = {0, 0, nDstW, nDstH}; 
            float *devDst;
            CUDA_CALL(cudaMallocPitch((void**)&devDst, &dstStep, nDstW * sizeof(float), nDstH));

NppStatus result = nppiResize_32f_C1R(devSrc,srcStep,oSrcSize,oSrcROI,devDst,dstStep,oDstSize,oDstROI,NPPI_INTER_SUPER);
            if (result != NPP_SUCCESS) {
                std::cerr << "Unable to run decimate_cuda, error " << result << std::endl;
            }

            Npp64s                 writesize;
            Npp32f                 *hostDst;
            writesize = (Npp64s)   nDstW * nDstH;         // Y
            if(NULL == (hostDst = (Npp32f *)malloc(writesize * sizeof(Npp32f)))){
                printf("Error : Unable to alloctae hostDst in decimate_cuda, exiting...\n");
                exit(1);
            }

            CUDA_CALL(cudaMemcpy2D(hostDst, nDstW * sizeof(Npp32f),(void**)devDst, dstStep, nDstW * sizeof(Npp32f),nDstH, cudaMemcpyDeviceToHost));
            CUDA_CALL(cudaFree(devSrc));
            CUDA_CALL(cudaFree(devDst));
            return(hostDst);
        }                            // source : Grayscale 1 x 32f, YYYY...
        else if (byteperpixel == 3){ // source : 3 x 32f interleaved RGBRGBRGB...
            size_t  srcStep; 
            size_t  dstStep;
            // rows = height; columns = width

            NppiSize oSrcSize = {nSrcW, nSrcH};
            NppiRect oSrcROI = {0, 0, nSrcW, nSrcH};
            float *devSrc;
CUDA_CALL(cudaMallocPitch((void**)&devSrc, &srcStep, 3 * nSrcW * sizeof(float), nSrcH));
CUDA_CALL(cudaMemcpy2D((void**)devSrc, srcStep, (void**)readbuff, 3 * nSrcW * sizeof(Npp32f), nSrcW * sizeof(Npp32f), nSrcH, cudaMemcpyHostToDevice));

            NppiSize oDstSize = {nDstW, nDstH}; 
            NppiRect oDstROI = {0, 0, nDstW, nDstH};
            float *devDst;
CUDA_CALL(cudaMallocPitch((void**)&devDst, &dstStep, 3 * nDstW * sizeof(float), nDstH));

NppStatus result = nppiResize_32f_C3R((devSrc,srcStep,oSrcSize,oSrcROI,devDst,dstStep,oDstSize,oDstROI,NPPI_INTER_SUPER);
if (result != NPP_SUCCESS) {
                std::cerr << "Unable to run decimate_cuda, error " << result << std::endl;
            }

            Npp64s                 writesize;
            Npp32f                 *hostDst;
            writesize = (Npp64s)   nDstW * nDstH * 3;          // RGB
            if(NULL == (hostDst = (Npp32f *)malloc(writesize * sizeof(Npp32f)))){
                printf("Error : Unable to alloctae hostDst in decimate_cuda, exiting...\n");
                exit(1);
            }

            CUDA_CALL(cudaMemcpy2D((void**)hostDst, nDstW * sizeof(Npp32f), (void**)devDst, dstStep, nDstW * sizeof(Npp32f),nDstH, cudaMemcpyDeviceToHost));

            CUDA_CALL(cudaFree(devSrc));
            CUDA_CALL(cudaFree(devDst));
            return(hostDst);
        }        // source - 3 x 32f, interleaved RGBRGBRGB...

        return(0);
    }

1 Ответ

1 голос
/ 30 сентября 2019

У вас были разные ошибки при звонках на cudaMemcpy2D (обе в коде 3 канала). Этот код, кажется, работает для меня:

$ cat t1521.cu
    #include <cuda_runtime.h>
    #include <npp.h>
    #include <nppi.h>
    #include <nppdefs.h>
    #include <iostream>
    #include <stdint.h>
    #include <stdio.h>
    #define CUDA_CALL(call) do { cudaError_t cuda_error = call; if(cuda_error != cudaSuccess) { std::cerr << "CUDA Error: " << cudaGetErrorString(cuda_error) << ", " << __FILE__ << ", line " << __LINE__ << std::endl; return(NULL);} } while(0)
    using namespace std;
    float* decimate_cuda(float* readbuff, uint32_t nSrcH, uint32_t nSrcW, uint32_t nDstH, uint32_t nDstW, uint8_t byteperpixel)
    {
        if (byteperpixel == 1){ // source : Grayscale, 1 x 32f
            size_t  srcStep;
            size_t  dstStep;

            NppiSize oSrcSize = {nSrcW, nSrcH};
            NppiRect oSrcROI = {0, 0, nSrcW, nSrcH};
            float *devSrc;
            CUDA_CALL(cudaMallocPitch((void**)&devSrc, &srcStep, nSrcW * sizeof(float), nSrcH));
            CUDA_CALL(cudaMemcpy2D(devSrc, srcStep,readbuff, nSrcW * sizeof(Npp32f), nSrcW * sizeof(Npp32f), nSrcH, cudaMemcpyHostToDevice));

            NppiSize oDstSize = {nDstW, nDstH};
            NppiRect oDstROI = {0, 0, nDstW, nDstH};
            float *devDst;
            CUDA_CALL(cudaMallocPitch((void**)&devDst, &dstStep, nDstW * sizeof(float), nDstH));

            NppStatus result = nppiResize_32f_C1R(devSrc,srcStep,oSrcSize,oSrcROI,devDst,dstStep,oDstSize,oDstROI,NPPI_INTER_SUPER);
            if (result != NPP_SUCCESS) {
                std::cerr << "Unable to run decimate_cuda, error " << result << std::endl;
            }

            Npp64s                 writesize;
            Npp32f                 *hostDst;
            writesize = (Npp64s)   nDstW * nDstH;         // Y
            if(NULL == (hostDst = (Npp32f *)malloc(writesize * sizeof(Npp32f)))){
                printf("Error : Unable to alloctae hostDst in decimate_cuda, exiting...\n");
                exit(1);
            }

            CUDA_CALL(cudaMemcpy2D(hostDst, nDstW * sizeof(Npp32f),devDst, dstStep, nDstW * sizeof(Npp32f),nDstH, cudaMemcpyDeviceToHost));
            CUDA_CALL(cudaFree(devSrc));
            CUDA_CALL(cudaFree(devDst));
            return(hostDst);
        }                            // source : Grayscale 1 x 32f, YYYY...
        else if (byteperpixel == 3){ // source : 3 x 32f interleaved RGBRGBRGB...
            size_t  srcStep;
            size_t  dstStep;
            // rows = height; columns = width

            NppiSize oSrcSize = {nSrcW, nSrcH};
            NppiRect oSrcROI = {0, 0, nSrcW, nSrcH};
            float *devSrc;
            CUDA_CALL(cudaMallocPitch((void**)&devSrc, &srcStep, 3 * nSrcW * sizeof(float), nSrcH));
            CUDA_CALL(cudaMemcpy2D(devSrc, srcStep,readbuff, 3 * nSrcW * sizeof(Npp32f), 3*nSrcW * sizeof(Npp32f), nSrcH, cudaMemcpyHostToDevice));

            NppiSize oDstSize = {nDstW, nDstH};
            NppiRect oDstROI = {0, 0, nDstW, nDstH};
            float *devDst;
            CUDA_CALL(cudaMallocPitch((void**)&devDst, &dstStep, 3 * nDstW * sizeof(float), nDstH));

            NppStatus result = nppiResize_32f_C3R(devSrc,srcStep,oSrcSize,oSrcROI,devDst,dstStep,oDstSize,oDstROI,NPPI_INTER_SUPER);
            if (result != NPP_SUCCESS) {
                std::cerr << "Unable to run decimate_cuda, error " << result << std::endl;
            }

            Npp64s                 writesize;
            Npp32f                 *hostDst;
            writesize = (Npp64s)   nDstW * nDstH * 3;          // RGB
            if(NULL == (hostDst = (Npp32f *)malloc(writesize * sizeof(Npp32f)))){
                printf("Error : Unable to alloctae hostDst in decimate_cuda, exiting...\n");
                exit(1);
            }

            CUDA_CALL(cudaMemcpy2D(hostDst, nDstW*3 * sizeof(Npp32f), devDst, dstStep, nDstW*3 * sizeof(Npp32f),nDstH, cudaMemcpyDeviceToHost));

            CUDA_CALL(cudaFree(devSrc));
            CUDA_CALL(cudaFree(devDst));
            return(hostDst);
        }        // source - 3 x 32f, interleaved RGBRGBRGB...

        return(0);
    }

int main(){
    uint32_t nSrcH = 480;
    uint32_t nSrcW = 640;
    uint8_t byteperpixel = 3;
    float *readbuff = (float *)malloc(nSrcW*nSrcH*byteperpixel*sizeof(float));
    for (int i = 0; i < nSrcH*nSrcW; i++){
      readbuff [i*3+0] = 1.0f;
      readbuff [i*3+1] = 2.0f;
      readbuff [i*3+2] = 3.0f;}
    uint32_t nDstW = nSrcW/2;
    uint32_t nDstH = nSrcH/2;
    float *res =  decimate_cuda(readbuff, nSrcH, nSrcW, nDstH, nDstW, byteperpixel);
    for (int i = 0; i < nDstH*nDstW*byteperpixel; i++) if (res[i] != ((i%3)+1.0f)) {std::cout << "error at: " << i << std::endl; return 0;}
    return 0;
}
$ nvcc -o t1521 t1521.cu -lnppig
$ cuda-memcheck ./t1521
========= CUDA-MEMCHECK
========= ERROR SUMMARY: 0 errors
$

В будущем будет удобно, если вы предоставите полный код, как я сделал в своем ответе. На самом деле SO требует этого, см. Пункт 1 здесь .

Кстати, использование распределенных распределений на устройстве, здесь, которые представляют сложность, которую вы не могли использовать самостоятельночерез, действительно должно быть ненужным как для корректности, так и для производительности, используя любую современную версию GPU и CUDA. Обычные линейные / плоские распределения, где высота == ширина, должны быть просто в порядке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...