使用 OpenCL 进行图像卷积中的参数大小无效



我正在尝试将OpenCV结合起来,以便于图像和OpenCL的使用。任务是加载图像并将其转换为具有浮点像素值的灰度。然后我想用过滤器做图像卷积。

当我尝试执行内核时,我收到错误消息:"clEnqueueReadImage: 错误代码 -30"-> CL_INVALID_VALUES

似乎我在读回结果时得到无效值"有人可以帮助我找到错误吗?

#define _CRT_SECURE_NO_WARNINGS
#define __CL_ENABLE_EXCEPTIONS
#define PROGRAM_FILE "convolution.cl"
#define KERNEL_FUNC "laplacianFilter"
#include <iostream>
#include <fstream>
#include <CL/cl.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
int main()
{
    //////////////////////////////////////////////////////////////////////////
    //PREPROCESSING
    //////////////////////////////////////////////////////////////////////////
    cv::Mat Input, Input_f;
    cv::Mat Output, Output_f;
    //Load the Image and convert it to grayscale as float
    Input = cv::imread("hqdefault.jpg", 0);                         //loads image as grayscale; 1 channel
    //Input.convertTo(Input_f, CV_32FC1, 1/255.0);                  //scale or convert the image back later
    Input.convertTo(Input_f, CV_32FC1);
    //Create output images
    Input.copyTo(Output);
    Input_f.copyTo(Output_f);
    //uint8 image values - 0 ... 255
    //float image values - 0 ... 1      -> scaling necessary
    //cv::imshow("Input_f", Input_f);
    int imageWidth, imageHeight;
    imageWidth = Input_f.cols;
    imageHeight = Input_f.rows;
    //Create filter kernel - Laplace
    float filter[9] =
    {0,  1,  0,
     1, -4,  1,
     0,  1,  0 };
    //The filter is 3x3
    int filterWidth = 3;
    int filterSize = filterWidth * filterWidth;
    //Setup OpenCL Structure
    std::vector<cl::Platform> platforms;
    std::vector<cl::Device> devices;
    try
    {
        //Platform
        cl::Platform::get(&platforms);
        //Device
        platforms[0].getDevices(CL_DEVICE_TYPE_GPU, &devices);
        //Context
        cl::Context mycontext(devices);
        //Command Queue
        cl::CommandQueue queue(mycontext, NULL, NULL);
        //Image Format
        cl::ImageFormat format(CL_R, CL_FLOAT);                     //specifies how the image is read
                                                                    //single channel CL_FLOAT = 32 bit
        /*cl::ImageFormat format;
        format.image_channel_order = CL_R;
        format.image_channel_data_type = CL_FLOAT;*/
        //Create images on device
        cl::Image2D d_Input(mycontext,
            CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
            format,
            imageWidth,
            imageHeight,
            0 /*sizeof(float) * imageWidth*/,
            (float*)Input_f.data,
            NULL);
        cl::Image2D d_Output(mycontext,
            CL_MEM_WRITE_ONLY,
            format,
            imageWidth,
            imageHeight,
            0 /*sizeof(float) * imageWidth*/,
            NULL,
            NULL);
        //Create filter on device
        cl::Buffer d_filter(mycontext,
            CL_READ_ONLY_CACHE | CL_MEM_COPY_HOST_PTR,
            sizeof(float) * filterSize,
            (void*)&filter,
            NULL);
        //Create image sampler
        cl::Sampler sampler(mycontext,
            CL_FALSE,
            CL_ADDRESS_CLAMP_TO_EDGE,
            CL_FILTER_NEAREST,
            NULL);
        //Origin and Region
        cl::size_t<3> origin;
        origin[0] = 0;
        origin[1] = 0;
        origin[2] = 0;
        cl::size_t<3> region;
        origin[0] = imageWidth;
        origin[1] = imageHeight;
        origin[2] = 1;
        //Create Program
        std::ifstream programFile(PROGRAM_FILE);
        std::string programString(std::istreambuf_iterator<char>(programFile), (std::istreambuf_iterator<char>()));
        //std::cout << "Program String:n" << programString << std::endl;
        cl::Program::Sources source(1, std::make_pair(programString.c_str(), programString.length() + 1));
        cl::Program program(mycontext, source, NULL);
        try
        {
            program.build(devices);
        }
        catch (cl::Error& esc)
        {
            if (esc.err() == CL_BUILD_PROGRAM_FAILURE)
            {
                // Check the build status
                cl_build_status status = program.getBuildInfo<CL_PROGRAM_BUILD_STATUS>(devices[0]);
                // Get the build log
                std::string buildlog = program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(devices[0]);
                std::cerr << "Build log for " << buildlog << std::endl;
            }
        }
        //Create Kernel
        cl::Kernel kernel(program, KERNEL_FUNC, NULL);
        //Set Kernel Arguments
        kernel.setArg(0, d_Input);
        kernel.setArg(1, d_Output);
        kernel.setArg(2, imageWidth);
        kernel.setArg(3, imageHeight);
        kernel.setArg(4, d_filter);
        kernel.setArg(5, filterWidth);
        kernel.setArg(6, sampler);
        //Execute the Kernel
        cl::NDRange offset(0, 0);
        cl::NDRange global_size(imageHeight, imageWidth);       //1.height - 2.width
        cl::NDRange local_size(1, 1);
        queue.enqueueNDRangeKernel(kernel,
            offset,
            global_size,
            local_size);
        //Read back the output Image
        queue.enqueueReadImage(d_Output, CL_TRUE, origin, region, 0, 0, (float*)Output_f.data, NULL, NULL);
    }
    catch (cl::Error e)
    {
        std::cout << e.what() << ": Error code " << e.err() << std::endl;
    }
    //cv::waitKey();
    std::system("pause");
}
KERNEL CODE:
__kernel void laplacianFilter(__read_only image2d_t iimage,
                              __write_only image2d_t oimage,
                              int cols,
                              int rows, 
                              __constant float *filter, 
                              int windowSize,
                              sampler_t sampler)
{
   int col = get_global_id(0);         //columns
   int row = get_global_id(1);         //rows
   int halfWidth = windowSize/2;
   float4 pixelValue = {0.0, 0.0, 0.0, 0.0};
   float4 sum = 0.0f;
   int2 coords;
   int filterIdx = 0;
   //Convolute over the filter
   //Go over rows
   for (int i = -halfWidth; i <= halfWidth; i++)
   {
      coords.y = row + i;
      //Go over columns
      for (int j = -halfWidth; j <= halfWidth; j++)
      {
         coords.x = col + i;
         //Read pixel value and multiply by filter
         pixelValue = read_imagef(iimage, sampler, coords);
         sum = sum + pixelValue * filter[filterIdx++];
      }
   }
   //Write resulting value to correspoding pixel
   if (col < cols && row < rows)
   {
      write_imagef(oimage, (int2)(col, row), sum);
   }
}

https://www.khronos.org/registry/OpenCL/sdk/1.0/docs/man/xhtml/clEnqueueReadImage.html 说你CL_INVALID_VALUE有两个原因:

  1. 如果按源和区域指定的读取区域超出范围,或者 PTR 为 NULL 值。
  2. 如果图像是 2D 图像对象,并且原点 [2] 不等于 0,或者区域 [2] 不等于 1 或 slice_pitch 不等于 0。

你遇到了#2。为什么?因为在声明 region 之后,您再次设置origin的成员,region未初始化(并且 region[2] 不是 1(。

相关内容

最新更新