OpenCV – Copier GpuMat dans les données de périphérique cuda

J’essaie de copier les données d’un cv::cuda::GpuMat dans une variable uint8_t* qui doit être utilisée dans un kernel.

Le GpuMat contient des données d’image de résolution 752×480 et de type CV_8UC1. Voici l’exemple de code:

 uint8_t *imgPtr; cv::Mat left, downloadedLeft; cv::cuda::GpuMat gpuLeft; left = imread("leftview.jpg", cv::IMREAD_GRAYSCALE); gpuLeft.upload(left); cudaMalloc((void **)&imgPtr, sizeof(uint8_t)*gpuLeft.rows*gpuLeft.cols); cudaMemcpyAsync(imgPtr, gpuLeft.ptr(), sizeof(uint8_t)*gpuLeft.rows*gpuLeft.cols, cudaMemcpyDeviceToDevice); // following code is just for testing and visualization... cv::cuda::GpuMat gpuImg(left.rows, left.cols, left.type(), imgPtr); gpuImg.download(downloadedLeft); imshow ("test", downloadedLeft); waitKey(0); 

Mais la sortie n’est pas comme prévu. Voici les images d’entrée et de sortie, respectivement.

CONTRIBUTION Image d'entrée

SORTIE entrez la description de l'image ici

J’ai essayé de donner le cv::Mat source au cudaMemcpy . Cela semble bien fonctionner. Le problème semble être avec les cv::cuda::GpuMat et cudaMemcpy . Une question similaire est discutée ici

De plus, si l’image est 256 ou 512, le programme semble fonctionner correctement.

Qu’est-ce qui me manque? Que faut-il faire pour que l’image 752×480 fonctionne correctement?

OpenCV GpuMat utilise le stockage ssortingded (ainsi, l’image n’est pas stockée de manière contiguë dans la mémoire). En bref, votre exemple échoue dans la plupart des cas car

  1. Vous ne copiez pas l’ensemble de l’image sur l’allocation de mémoire CUDA, et
  2. Vous ne spécifiez pas correctement la structure de la mémoire lorsque vous créez la deuxième instance GpuMat à partir du pointeur GPU.

À ma lecture de la documentation, vous voulez probablement quelque chose comme ceci:

 uint8_t *imgPtr; cv::Mat left, downloadedLeft; cv::cuda::GpuMat gpuLeft; left = imread("leftview.jpg", cv::IMREAD_GRAYSCALE); gpuLeft.upload(left); cudaMalloc((void **)&imgPtr, gpuLeft.rows*gpuLeft.step); cudaMemcpyAsync(imgPtr, gpuLeft.ptr(), gpuLeft.rows*gpuLeft.step, cudaMemcpyDeviceToDevice); // following code is just for testing and visualization... cv::cuda::GpuMat gpuImg(left.rows, left.cols, left.type(), imgPtr, gpuLeft.step); gpuImg.download(downloadedLeft); imshow ("test", downloadedLeft); waitKey(0); 

[Écrit par quelqu’un qui n’a jamais utilisé OpenCV, ni compilé ni testé, utilise à ses risques et périls]

La seule fois où votre code fonctionnerait correctement serait lorsque le pas de la ligne du GpuMat était le même que le nombre de colonnes multiplié par la taille du type stocké dans la masortingce. Ce sont probablement des images dont la taille correspond à une puissance arrondie de deux.