2017-09-13 35 views
0

我試圖將cv::cuda::FarnebackOpticalFlow算法的輸出轉換爲無符號字節的3個YUV平面(用於通過FFMPEG進行後續壓縮)。OpenCV CUDA錯誤-217試圖執行我的自定義函數

我在調用stream.waitForCompletion()(未在此處顯示)時收到錯誤代碼-217(「未指定的啓動失敗」);在我的內核中觸發錯誤的原因是嘗試爲輸出GpuMat對象之一分配一個值(請參閱下面的行dst_y(y, x) = ...)。

我使用的OpenCV 3.3,從源代碼編譯時,Windows 10下

我使用的CMake的cuda_add_executable()命令來定義我的項目,我已經與set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} -arch compute_50 -code sm_50)定義的CUDA標誌,雖然我」已經嘗試過變化,沒有更多的成功。我的顯卡是GTX 970

#include <opencv2/core/cuda_stream_accessor.hpp> 

using namespace cv; 
using namespace cuda; 


namespace 
{ 
    __global__ void kernelFunc(
     const PtrStepSz<float2>& src, 
     float scale_x, float scale_y, 
     PtrStepSzb dst_y, PtrStepSzb dst_u, PtrStepSzb dst_v) 
    { 
     int x = blockIdx.x * blockDim.x + threadIdx.x; 
     int y = blockIdx.y * blockDim.y + threadIdx.y; 

     if (x < src.cols && y < src.rows && y >= 0 && x >= 0) 
     { 
      // Get input: optical flow, and scale it 
      auto dx = scale_x * src(y, x).x, dy = scale_y * src(y, x).y; 

      // Luma: flow vector length, compressed using an exponential function 
      auto l = sqrt(dx*dx + dy*dy); 
      l = exp(5*l)/(exp(5*l) + 1); 
      dst_y(y, x) = 255 * l; 

      // Chroma (U and V) 
      dst_u(y, x) = 255 * (dx + 0.5); 
      dst_v(y, x) = 255 * (dy + 0.5); 
     } 
    } 

} // ns 

void compress_optical_flow_mat_to_yuv444(const GpuMat& src, 
    GpuMat& dst_y, GpuMat& dst_u, GpuMat& dst_v, 
    Stream& stream) 
{ 
    using namespace std::string_literals; 

    dst_y.create(src.size(), CV_8UC1); 
    dst_u.create(src.size(), CV_8UC1); 
    dst_v.create(src.size(), CV_8UC1); 

    dim3 cthreads(16, 16); //(32, 8); 
    dim3 cblocks(
     static_cast<int>(ceil(src.size().width/static_cast<double>(cthreads.x))), 
     static_cast<int>(ceil(src.size().height/static_cast<double>(cthreads.y)))); 

    // We scale optical flow so that the range [-0.5..0.5] covers half the width and half the height, 
    // in pixels, of the image. In other words, a given pixel may not move by more than half the 
    // image size per frame. 
    float scale_x = 0.5f/src.size().width; 
    float scale_y = 0.5f/src.size().height; 
    auto cu_str = StreamAccessor::getStream(stream); 

    kernelFunc<<<cblocks, cthreads, 0, cu_str>>>(src, scale_x, scale_y, dst_y, dst_u, dst_v); 

    auto err = cudaGetLastError(); 
    if (err != 0) 
     throw std::runtime_error("compress_optical_flow_mat_to_yuv444() kernel call failed with error "s 
      + std::to_string(err) + ": " + cudaGetErrorString(err)); 
} 

回答

1

從以下行中刪除&標誌:

__global__ void kernelFunc(
     const PtrStepSz<float2>& src, 
     float scale_x, float scale_y, 
     PtrStepSzb dst_y, PtrStepSzb dst_u, PtrStepSzb dst_v) 

__global__ void kernelFunc(
     const PtrStepSz<float2> src, 
     float scale_x, float scale_y, 
     PtrStepSzb dst_y, PtrStepSzb dst_u, PtrStepSzb dst_v) 
+0

賓果!並感謝一噸。所以,傳遞一個const引用應該可以用普通的C++工作,但是在這裏我們將東西從CPU傳遞到GPU,所以這個規則在窗口外面是可以理解的。如果nvcc提醒我的話,那本來是很好的! – JPNotADragon

+0

@JPNotADragon很高興爲您提供幫助。儘管說實話我並不完全確定爲什麼const引用不起作用。我遇到了同樣的問題,而且我無意中偶然發現了這個解決方案。如果你發現原因,請讓我知道。 – zindarod

+0

現在我想到了,CPU-GPU接口可能不是唯一需要考慮的因素。我正在使用流式處理,這意味着輸入數據在調用封裝函數後仍然可用 - 這裏不會出現這種情況,因爲PtrStep對象是由GpuMat轉換運算符生成的臨時對象。 – JPNotADragon