2016-12-12 2 views
1

私はopencv 3.1 cv :: cudaテンプレートのマッチングに取り組んでいますが、cv::cuda::minMaxLoc()関数が私の場合には遅すぎます。試合結果の最小サイズは128x128で、最大サイズは512x512です。平均でminMaxLoc()128x128の場合は1.65ミリ秒、350x350の場合は25ミリ秒を要します。これはこれが何百回も行われるので長すぎます。cv :: cuda :: PtrStepSzfデータの線形インデックスの使い方

私のマッチサイズは、通常GPUで何を使用するには小さすぎるかもしれないと思います。しかし、ロバート・クロベラがthrust::max_element slow in comparison cublasIsamax - More efficient implementation?で行った行に沿ってテストして、より良いパフォーマンスが得られるかどうかを確認したい。

私の問題は、リニアインデックスを使用してデータを読み取っていて、cv::cuda::PtrStepSzfがこれを許可していないことです(少なくとも私にはわかりませんでした)。私は試合の結果を再現しようとしますが、データが連続していないので、私はそれを行うことができません。私はcudaMallocPitchcudaMemcpy2Dに行く必要がありますか?cv::cuda::GPUMatと私はそれをどのように行う場合、cv::cuda::PtrStepSzfオブジェクトとして読んでいますか?

__global__ void minLoc(const cv::cuda::PtrStepSzf data, 
           float* minVal, 
           float * minValLoc 
         ) 
    { 
     int dsize = data.cols*data.rows 
     __shared__ volatile T vals[nTPB]; 
     __shared__ volatile int idxs[nTPB]; 
     __shared__ volatile int last_block; 
     int idx = threadIdx.x+blockDim.x*blockIdx.x; 
     last_block = 0; 
     T my_val = FLOAT_MIN; 
     int my_idx = -1; 
     // sweep from global memory 
     while (idx < dsize) 
     { 
      //data(idx) is an illegal call;The legal one is data(x,y) 
      // How do I do it? 
      if (data(idx) > my_val) 
      { 
       my_val = data(idx); my_idx = idx; 
      } 
       idx += blockDim.x*gridDim.x; 
     } 

       // ... rest of the kernel 
    } 

    void callMinLocKernel(cv::InputArray _input,  
       cv::Point minValLoc, 
       float minVal, 
       cv::cuda::Stream _stream) 
    { 
     const cv::cuda::GpuMat input = _input.getGpuMat(); 
     dim3 cthreads(32, 32); 
     dim3 cblocks(
      static_cast<int>(std::ceil(input1.size().width/
       static_cast<double>(cthreads.x))), 
      static_cast<int>(std::ceil(input1.size().height/
       static_cast<double>(cthreads.y)))); 

     // code that creates and upload d_min, d_minLoc 
     float h_min = 9999; 
     int h_minLoc = -1; 
     float * d_min = 0; 
     int * d_minLoc = 0; 
     //gpuErrchk is defined on other place 
     gpuErrchk(cudaMalloc((void**)&d_min, sizeof(h_min))); 
     gpuErrchk(cudaMalloc((void**)&d_minLoc, sizeof(h_minLoc)); 
     gpuErrchk(cudaMemcpy(d_min, &h_min, sizeof(h_min), cudaMemcpyHostToDevice)); 
     gpuErrchk(cudaMemcpy(d_minLoc, &h_minLoc, sizeof(h_minLoc), cudaMemcpyHostToDevice)); 

     cudaStream_t stream = cv::cuda::StreamAccessor::getStream(_stream); 
     minLoc<<<cblocks, cthreads, 0, stream>>>(input,d_min,d_minLoc); 
     gpuErrchk(cudaGetLastError()); 
     //code to read the answer 
     gpuErrchk(cudaMemcpy(&h_min, d_min, sizeof(h_min), cudaMemcpyDeviceToHost)); 
     gpuErrchk(cudaMemcpy(&h_minLoc, d_minLoc, sizeof(h_minLoc), cudaMemcpyDeviceToHost)); 

     minValLoc = cv::point(h_minLoc/data.cols,h_minLoc%data.cols) 
     minVal = h_min;  
    } 

    int main() 
    { 
     //read Background and template 
     cv::Mat input = imread("cat.jpg",0); 
     cv::Mat templ = imread("catNose.jpg",0) 

     //convert to floats 
     cv::Mat float_input, float_templ; 
     input.convertTo(float_input,CV_32FC1); 
     input.convertTo(float_templ,CV_32FC1); 

     //upload Bckg and template to gpu 
     cv::cuda::GpuMat d_src,d_templ, d_match; 
     Size size = float_input.size(); 
     d_src.upload(float_input); 
     d_templ.upload(float_templ); 


     double min_val, max_val; 
     Point min_loc, max_loc; 

     Ptr<cv::cuda::TemplateMatching> alg = cuda::createTemplateMatching(d_src.type(), CV_TM_SQDIFF); 
     alg->match(d_src, d_templ, d_match); 
     cv::cuda::Normalize(d_match,d_match); 
     //Too slow 
     //cv::cuda::minMaxLoc(d_match, &min_val, &max_val, &min_loc, &max_loc); 

     callMinLocKernel(d_match,min_val,min_loc); 

     return 0; 
} 

答えて

1

cv::cuda::PtrStepSzfで線形インデックスを実際に使用する方法が見つかりませんでした。私は1つがあるかどうかわからない。このフォーマットが使用されているときのように、2つの下付き文字しか使用できません。

#define nTPB 1024 
#define FLOAT_MAX 9999.0f 
void callMinLocKernel(cv::InputArray _input,  
     cv::Point minValLoc, 
     float minVal, 
     cv::cuda::Stream _stream) 
{ 
    const cv::cuda::GpuMat input = _input.getGpuMat(); 
    const float* linSrc = input.ptr<float>(); 
    size_t step   = input.step; 
    dim3 cthreads(nTPB); 
    dim3 cblocks(
    static_cast<int>(std::ceil(input.size().width*input1.size().height/
     static_cast<double>(nTPB)))); 

    // code that creates and upload d_min, d_minLoc 
    float h_min = 9999; 
    int h_minLoc = -1; 
    float * d_min = 0; 
    int * d_minLoc = 0; 
    //gpuErrchk is defined on other place 
    gpuErrchk(cudaMalloc((void**)&d_min, sizeof(h_min))); 
    gpuErrchk(cudaMalloc((void**)&d_minLoc, sizeof(h_minLoc)); 
    gpuErrchk(cudaMemcpy(d_min, &h_min, sizeof(h_min), cudaMemcpyHostToDevice)); 
    gpuErrchk(cudaMemcpy(d_minLoc, &h_minLoc, sizeof(h_minLoc), cudaMemcpyHostToDevice)); 

    cudaStream_t stream = cv::cuda::StreamAccessor::getStream(_stream); 
    minLoc<<<cblocks, cthreads, 0, stream>>>(input,d_min,d_minLoc); 
    gpuErrchk(cudaGetLastError()); 
    //code to read the answer 
    gpuErrchk(cudaMemcpy(&h_min, d_min, sizeof(h_min), cudaMemcpyDeviceToHost)); 
    gpuErrchk(cudaMemcpy(&h_minLoc, d_minLoc, sizeof(h_minLoc), cudaMemcpyDeviceToHost)); 

    minValLoc = cv::point(h_minLoc/data.cols,h_minLoc%data.cols) 
    minVal = h_min; 
} 

とカーネルの内部:代わりに、私は次のようにカーネルラッパーにcv::cuda::GpuMat input変数にポインタptrを使用

__global__ void minLoc(const float* data, 
         const size_t step, 
         cv::Size dataSz, 
         float* minVal, 
         float * minValLoc 
        ) 
{ 

    __shared__ volatile T vals[nTPB]; 
    __shared__ volatile int idxs[nTPB]; 
    __shared__ volatile int last_block; 

    int idx   = threadIdx.x+blockDim.x*blockIdx.x; 
    const int dsize = dataSz.height*dataSz.width; 
    last_block = 0; 
    float my_val = FLOAT_MAX; 
    int my_idx = -1; 
    // sweep from global memory 
    while (idx < dsize) 
    { 
     int row = idx/dataSz.width; 
     int id = (row*step/sizeof(float)) + idx % dataSz.width; 
     if (data[id] < my_val) 
     { 
      my_val = data[id]; 
      my_idx = idx; 
     } 
     idx += blockDim.x*gridDim.x; 
    } 

      // ... rest of the kernel 
} 

stepをそれがsizeof(typeVariable) で割っする必要ので、バイトであります私はこの助けて欲しい!

関連する問題