我的主要目的是用OpenCV从视频中加载帧,然后将其复制到Nvidia GPU内存中,用基于Cuda的最近邻算法调整其大小,然后将其复制回主机端,并使用cv::imshow()
对其进行可视化
不幸的是,我总是遇到分段错误。定义要复制的字节数或数据转换可能会有问题。下面,你可以找到源代码的主要部分,但这里是完整项目的repo:https://github.com/foxakarmi/imageResize
主要功能:
#include <iostream>
#include "cuda_utils.h"
#include "yololayer.h"
#include <opencv2/highgui/highgui.hpp>
void *buffers[3];
int main() {
cv::VideoCapture capture;
cv::Mat frame;
capture.open("/p.mp4");
if (!capture.isOpened()) {
std::cout << "can not open" << std::endl;
return -1;
}
capture.read(frame);
CUDA_CHECK(cudaMalloc(&buffers[0], frame.cols * frame.step[0]));
CUDA_CHECK(cudaMalloc(&buffers[1], 3 * 640 * 640));
buffers[2] = malloc(3 * 640 * 640);
while (capture.read(frame)) {
CUDA_CHECK(cudaMemcpy(buffers[0], frame.ptr(), frame.step[0] * frame.rows, cudaMemcpyHostToDevice))
cudaNearestResize((uchar *) buffers[0], (uchar *) buffers[1], frame.cols, frame.rows, 640, 640);
CUDA_CHECK(cudaMemcpy(buffers[2], buffers[1], 640 * 640 * 3, cudaMemcpyDeviceToHost))
cv::Mat foo;
foo.data = static_cast<uchar *>(buffers[2]);
cv::imshow("img", foo);
cv::waitKey(1);
}
capture.release();
return 0;
}
包含内核和 Package 函数的.cu文件:
#include <opencv2/core/hal/interface.h>
#include "yololayer.h"
#include "cuda_utils.h"
__global__ void kernelNearestNeighbourResize(uchar *src_img, uchar *dst_img, int src_w, int src_h, int dst_w, int dst_h) {
int i = blockDim.y * blockIdx.y + threadIdx.y;
int j = blockDim.x * blockIdx.x + threadIdx.x;
int channel = 3;
if (i < dst_h && j < dst_w) {
int iIn = i * src_h / dst_h;
int jIn = j * src_w / dst_h;
dst_img[(i * dst_w + j) * channel + 0] = src_img[(iIn * src_w + jIn) * channel + 0];
dst_img[(i * dst_w + j) * channel + 1] = src_img[(iIn * src_w + jIn) * channel + 1];
dst_img[(i * dst_w + j) * channel + 2] = src_img[(iIn * src_w + jIn) * channel + 2];
}
}
cudaError_t cudaNearestResize(uchar *src_img, uchar *dst_img, int src_w, int src_h, int dst_w, int dst_h) {
if (!src_img || !dst_img)
return cudaErrorInvalidDevicePointer;
if (src_w == 0 || src_h == 0 || dst_w == 0 || dst_h == 0)
return cudaErrorInvalidValue;
kernelNearestNeighbourResize <<< 3600, 256>>>(
src_img, dst_img, src_w,
src_h, dst_w, dst_h);
return cudaGetLastError();
}
1条答案
按热度按时间zf2sa74q1#
下面您可以看到一个完整的工作解决方案。
您的程式码中有3个主要问题:
1.CUDA网格的设置不正确。请参见下面我的代码中的示例(只是一个初始工作版本,您可以进一步改进)。请在此处查看一些一般信息:The CUDA Programming Model。
**注意:**网格设置会对整体性能产生有意义的影响,优化并不是一件小事。请在此处查看更多信息:是的。
1.将数据复制到设备时,使用的是
frame.ptr()
而不是frame.data
。1.您只为输出
cv::Mat foo
设置了数据指针,而没有正确初始化它。因此cv::Mat
元数据(行、列等)没有设置,cv::imshow
无法正确显示它。在我的代码中,这是不需要的-见下文。dst_img
是否已经初始化来包含第一帧,如果没有(因为它是第一帧),则初始化它和CUDA缓冲区。*有关以下代码的更多说明:
1.不需要为主机输出图像分配
buffer[2]
,而是用适当的大小初始化cv::Mat
,并使用它分配的缓冲区。1.我重命名了设备缓冲区,并为其添加了
cudaFree
。1.更安全的做法是将通道数传递给内核,而不是让它假定为3。
1.我把图像的步长(AKA stride)传递给内核,这将支持图像有填充的情况(请参见此处:stride and padding of an image)的数据。
main
的代码:CUDA内核和 Package 函数的代码: