1

Grayscale kernel only reading first pixel

The following is my grayscale.cl kernel implementation. The problem that I am facing is that the kernel seems to perform the grayscale calculation only on the first pixel and assigns that value to all other pixels with the iteration.

Am I using read_imagef and write_imagef correctly?

grayscale.cl

__kernel void grayscale(
    __read_only image2d_t inputImage,
    __write_only image2d_t outputImage,
    const int width,
    const int height)
{
    int x = get_global_id(0); // X-coordinate
    int y = get_global_id(1); // Y-coordinate

    if (x < get_image_width(inputImage) && y < get_image_height(inputImage)) {
        int2 coord = (int2)(x, y);
        float4 pixel = read_imagef(inputImage, CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP | CLK_FILTER_NEAREST, coord);

        // Converts un-normalised values
        float f_x = pixel.x * 255.0f;
        float f_y = pixel.y * 255.0f;
        float f_z = pixel.z * 255.0f;

        printf("Processing pixel: (%d, %d) : %f, %f, %f\n", x, y, f_x, f_y, f_z);
        
        // Grayscale calculation
        float gray = 0.299f * f_x + 0.587f * f_y + 0.114f * f_z;

        // Write the grayscale value to the output image
        write_imagef(outputImage, coord, (float4)(gray, gray, gray, 1.0f));
    }
}

Kernel Debug output

Processing pixel: (292, 233) : 23.000000, 5.000000, 3.000000
Processing pixel: (293, 233) : 23.000000, 5.000000, 3.000000
Processing pixel: (294, 233) : 23.000000, 5.000000, 3.000000
Processing pixel: (295, 233) : 23.000000, 5.000000, 3.000000

The following is the respective (summarised) host code for context.

Getting image using OpenCV

// Load the input image using OpenCV
    cv::Mat image = cv::imread(image_path, cv::IMREAD_COLOR);
    if(image.empty()){
        logger.log("Failed to load image", Logger::LogLevel::ERROR);
    }

    // Display image (if necessary)
    if(DISPLAY_IMAGES){
        cv::imshow("Reference Image Window", image);
        cv::waitKey(0);
    }

    // Convert to RGBA and get image dimensions
    cv::cvtColor(image, image, cv::COLOR_BGR2RGBA);
    *width = image.cols;
    *height = image.rows;

    // Flatten image into uchar array
    std::vector<unsigned char> _input_data(image.data, image.data + image.total() * 4);

Image Objects

// Define cl_image variables and format
        cl_image_format input_format;
        input_format.image_channel_order = CL_RGBA;     // RGB
        input_format.image_channel_data_type = CL_UNORM_INT8;

        cl_image_format output_format;
        output_format.image_channel_order = CL_R;       // Single channel (grayscale)
        output_format.image_channel_data_type = CL_FLOAT;

// Create memory objects
        cl_mem input_image = clCreateImage2D(*context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, &input_format, width, height, 0, input_data.data(), &err_num);
        if(err_num != CL_SUCCESS){
            logger.log("Failed to create cl_image input_image mem object", Logger::LogLevel::ERROR);
        }

        cl_mem output_image = clCreateImage2D(*context, CL_MEM_WRITE_ONLY, &output_format, width, height, 0, nullptr, &err_num);
        if(err_num != CL_SUCCESS){
            logger.log("Failed to create cl_image output_image mem object", Logger::LogLevel::ERROR);
        }

Kernel: Writing, Executing, and Reading

// Initialise input image
        size_t origin[3] = {0, 0, 0};
        size_t region[3] = {width, height, 1};

        // Set kernel arguments
        err_num = clSetKernelArg(*kernel, 0, sizeof(cl_mem), &input_image);
        err_num |= clSetKernelArg(*kernel, 1, sizeof(cl_mem), &output_image);
        err_num |= clSetKernelArg(*kernel, 2, sizeof(int), &width);
        err_num |= clSetKernelArg(*kernel, 3, sizeof(int), &height);
        if(err_num != CL_SUCCESS){
            logger.log("Failed to set kernel arguments", Logger::LogLevel::ERROR);
        }

        err_num = clEnqueueWriteImage(*command_queue, input_image, CL_TRUE, origin, region, 0, 0, input_data.data(), 0, nullptr, &write_event);
        if(err_num != CL_SUCCESS){
            logger.log("Failed to write cl_image", Logger::LogLevel::ERROR);
        }

        // Perform kernel
        err_num = clEnqueueNDRangeKernel(*command_queue, *kernel, 2, nullptr, global_work_size, nullptr, 0, nullptr, &kernel_event);
        if(err_num != CL_SUCCESS){
            logger.log("Failed when executing kernel", Logger::LogLevel::ERROR);
        }

        // Read back image data
        err_num = clEnqueueReadImage(*command_queue, output_image, CL_TRUE, origin, region, 0, 0, output_data.data(), 0, nullptr, &read_event);
        if(err_num != CL_SUCCESS){
            logger.log("Failed to read back image data from kernel", Logger::LogLevel::ERROR);
        }

I'm new to OpenCL so any help will be much appreciated.

Thanks in advance!

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.