Dri*_*ian 5 opencv image-processing opencl segmentation-fault mat
我想将OpenCL Mat传递给FGPA的手写OpenCL内核(不支持OpenCV OpenCL)。
主机代码:
Mat img = imread( "template.jpg", IMREAD_GRAYSCALE );
Mat output(img.rows, img.cols, CV_8UC1);
// Program, Context already declared
// Create Kernel
cl_kernel kernel = NULL;
kernel = clCreateKernel(program, "copy", &status);
// Create Command Queue and associate it with the device you want to execute on
cl_command_queue cmdQueue;
cmdQueue = clCreateCommandQueue(context,devices[0], 0, &status);
// Buffer, prob i do something wrong here
cl_mem buffer_img = clCreateBuffer(context,CL_MEM_READ_ONLY, sizeof(uint) * img.cols * img.rows, NULL,&status);
cl_mem buffer_outputimg = clCreateBuffer(context,CL_MEM_WRITE_ONLY, sizeof(uint) * img.cols * img.rows,NULL,&status);
status = clEnqueueWriteBuffer(cmdQueue, buffer_img,CL_FALSE,0,sizeof(uint) * img.cols * img.rows,&img,0,NULL,NULL);
// set kernel arguments
status = clSetKernelArg(kernel,0,sizeof(cl_mem),&buffer_img);
status = clSetKernelArg(kernel,1,sizeof(cl_mem),&buffer_outputimg);
size_t globalWorkSize[2];
globalWorkSize[0] = img.cols;
globalWorkSize[1] = img.rows;
status = clEnqueueNDRangeKernel(cmdQueue,kernel,2,NULL, globalWorkSize, NULL,0, NULL,NULL);
clEnqueueReadBuffer(cmdQueue,buffer_outputimg,CL_TRUE,0,sizeof(uint) * img.cols * img.rows, &output, 0, NULL, NULL);
//stop cpu till queue is finish
clFinish(cmdQueue);
Run Code Online (Sandbox Code Playgroud)
内核代码:
__kernel void copy(__global uchar * input, __global uchar * output)
{
const int x = get_global_id(0);
const int y = get_global_id(1);
//copy
output[y * get_global_size(0) + x] = input[y * get_global_size(0) + x] ;
}
Run Code Online (Sandbox Code Playgroud)
在FPGA上执行时,出现分段错误,这可能是由于OpenCV Mat的错误处理所致。
编辑:按api55的建议编辑主机代码可以解决此问题:
Mat img = imread( "scene.jpg", IMREAD_GRAYSCALE );
Mat output(img.rows, img.cols, CV_8UC1);
// Program, Context already declared
// Create Kernel
cl_kernel kernel = NULL;
kernel = clCreateKernel(program, "copy", &status);
// Create Command Queue and associate it with the device you want to execute on
cl_command_queue cmdQueue;
cmdQueue = clCreateCommandQueue(context,devices[0], 0, &status);
checkError(status, "Failed to create commadnqueue");
// Buffer
cl_mem buffer_img = clCreateBuffer(context,CL_MEM_READ_ONLY, sizeof(uchar) * img.cols * img.rows, NULL,&status);
cl_mem buffer_outputimg = clCreateBuffer(context,CL_MEM_WRITE_ONLY, sizeof(uchar) * img.cols * img.rows,NULL,&status);
checkError(status, "Failed to create buffer_mask");
status = clEnqueueWriteBuffer(cmdQueue, buffer_img,CL_FALSE,0,sizeof(uchar) * img.cols * img.rows,img.data,0,NULL,NULL);
checkError(status, "Failed to enqueue buffer_img");
status = clSetKernelArg(kernel,0,sizeof(cl_mem),&buffer_img);
status = clSetKernelArg(kernel,1,sizeof(cl_mem),&buffer_outputimg);
size_t globalWorkSize[2];
globalWorkSize[0] = img.cols;
globalWorkSize[1] = img.rows;
status = clEnqueueNDRangeKernel(cmdQueue,kernel,2,NULL, globalWorkSize, NULL,0, NULL,NULL);
clEnqueueReadBuffer(cmdQueue,buffer_outputimg,CL_TRUE,0,sizeof(uchar) * img.cols * img.rows, output.data,0,NULL,NULL);
imwrite("output.jpg", output);
Run Code Online (Sandbox Code Playgroud)
我对 opencl 没有太多经验,但我认为这是一个 opencv/c++ 问题。
opencv mat 数据位于img.data其中 的uchar*大小为sizeof(T) * channels * rows * cols。
通常,T加载图像时为 uchar,通道为 3(除非是灰度图像)。3 通道 uchar 是每像素 24 位,灰度(当您加载时)是每像素 8 位,您正在使用的uint大小是 32 位。在某些时候,它会超出内存并产生分段错误。另外,如果在结构中不使用数据指针,则可能会复制标头信息和指向数据的指针,而不是数据本身。
我建议你改变&img:
status = clEnqueueWriteBuffer(cmdQueue, buffer_img,CL_FALSE,0,sizeof(uint) * img.cols * img.rows,&img,0,NULL,NULL);
Run Code Online (Sandbox Code Playgroud)
到img.data
最后,您需要拥有正确的数据。我不确定 opencl 是否可以使用 uchar,但如果不能,请将其更改cv::Mat为另一种类型,如下所示:
img.convertTo(img, CV_32S);
Run Code Online (Sandbox Code Playgroud)
加载图像后。这会将其更改为int... opencv 不支持无符号整数矩阵...只需确保在其他位置(即sizeof(uint))进行相应更改,如果转换输入,请记住创建具有相同类型的输出。
如果您喜欢浮动,请使用CV_32Fand 如果您喜欢 double CV_64F。