gpt4 book ai didi

c++ - 如何从 OpenCL 访问 OpenCV UMat (gpu) 缓冲区?

转载 作者:行者123 更新时间:2023-12-01 13:46:41 25 4
gpt4 key购买 nike

简介:

意向是使用 OpenCV 捕获视频,并将其用作 OpenCL 程序的输入 .两者的转移需要为高效 尽可能(如果这不是问题,为什么要使用 OpenCL,对吗?)。
我读到 OpenCV 在内部使用 OpenCL( UMat ),并且我可以访问 GPU通过访问 UMat::handle 来缓冲.但是,到目前为止,我为此所做的尝试都没有成功。

意图是重用UMat缓冲区作为 OpenCL 的输入 kernels ,并最终将结果作为图像返回另一个 UMat用于显示它。

OpenCV 框架仅用于为程序生成输入,因此,我对使用 OpenCV CL 包装器 ( cv::ocl ) 不感兴趣,而是使用普通 OpenCL ( cl::... )。这避免在完整软件中包含/链接 OpenCV 框架。

问题:

如何通过 OpenCL 访问 OpenCV UMat 缓冲区?

  • 使用 UMat 缓冲区作为 OpenCL 缓冲区(第一个选项)
  • 将 UMat 缓冲区移动到 GPU 内的 OpenCL 缓冲区。 (第二个选项)


  • 我已经取得的成就:
  • OpenCL 完全独立运行
  • OpenCV 完全独立运行
  • 将 UMat::handle 转换为 cl::Buffer 编译
  • 给定的缓冲区似乎无效。

  • DISCLAIM: please, be kind, as this is just supposed to be a very minimal example for this question.


    #include <iostream>
    #include <vector>
    #include <cassert>

    #define __CL_ENABLE_EXCEPTIONS // enable exceptions instead of error-codes
    #define CL_TARGET_OPENCL_VERSION 120
    #include <CL/cl.hpp>
    #include <opencv2/opencv.hpp>
    #include <opencv2/core/ocl.hpp>

    using namespace cv;
    using namespace std;

    int main()
    {
    // OPENCL STUFF
    // Very simplified/basic/stupid/naive OpenCL context creation
    std::vector<cl::Platform> platforms;
    cl::Platform::get(&platforms);
    assert(platforms.size()>0);
    std::vector<cl::Device> devices;
    platforms[0].getDevices( CL_DEVICE_TYPE_ALL, &devices);
    assert(devices.size()>0);
    cl_context_properties prop[3] =
    {
    CL_CONTEXT_PLATFORM,
    (cl_context_properties)(platforms[0])(),
    0
    };
    cl::Context context( devices[0], prop, nullptr, nullptr);

    std::string kernelStr = R"DELIMITER(
    kernel void replaceRB( global uchar3* content)
    {
    const size_t globalId = get_global_id(0);

    private uchar3 byte = content[globalId];
    char aux = byte.z;
    byte.z = byte.x;
    byte.x = aux;
    content[globalId] = byte;
    }
    )DELIMITER";

    cl::Program::Sources sources;
    sources.push_back(std::make_pair<const char*, size_t>(kernelStr.data(), kernelStr.size()));
    cl::Program program(context, sources);

    try
    {
    program.build({devices[0]}, "");
    }
    catch (...)
    {
    std::cout << program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(devices[0]) << std::endl;
    }

    std::vector<cl::Kernel> kernels;
    program.createKernels(&kernels);
    assert(kernels.size()>0);

    cl::CommandQueue queue(context, devices[0]);

    // OPENCV STUFF
    ocl::setUseOpenCL(true);
    cv::ocl::attachContext(platforms[0].getInfo<CL_PLATFORM_NAME>(), platforms[0](), context(), devices[0]());
    assert(ocl::haveOpenCL());

    cout << cv::ocl::Context::getDefault().ndevices() << " GPU devices are detected." << endl;

    VideoCapture cap(0); //Camera
    //VideoCapture cap("SampleVideo_1280x720_1mb.mp4"); //Video example
    assert(cap.isOpened());

    UMat frame;
    assert(cap.read(frame));

    //MIX OF BOTH opencl and opencv
    //cl::Buffer buf(context,CL_MEM_READ_WRITE, 256); // This works
    cl::Buffer buf(*((cl_mem*)frame.handle(CL_MEM_READ_WRITE)));

    int result = kernels[0].setArg(0, buf);
    std::cout << result << " == " << CL_INVALID_MEM_OBJECT << std::endl;

    queue.enqueueNDRangeKernel(kernels[0], cl::NullRange, cl::NDRange(16), cl::NDRange(4));
    queue.flush();

    //DISPLAY RESULT?
    string window_name = "Test OpenCV and OpenCL";
    namedWindow(window_name);
    imshow(window_name, frame);
    waitKey(5000);

    return 0;
    }

    最佳答案

    cv::UMat 和 opencv 的“透明 API”使用起来非常不直观,主要是因为它们向客户端隐藏了实际内存管理的非常重要的任务。

    具体来说,在您的代码中,您向 cap::read 提供了一个空的 cv::UMat。 opencv 将不得不 分配 实际帧的内存。但不能保证此内存实际上会分配在正确的设备(clbuffer)内存上。如果您调试 opencv 源代码,我不会感到惊讶,您将看到在 RAM 上分配的实际内存。因此没有有效的 cl_mem 句柄。

    你基本上有两个选择:

    选项 1:在设备上显式地预分配 cv::UMat:

    UMat frame = cv::UMat(cv::Size(width, height), format, cv::USAGE_ALLOCATE_DEVICE_MEMORY);
    assert(cap.read(frame));

    选项 2:用 cv::UMat 包装现有的预先分配的 opencl 缓冲区
    cv::UMat frame;
    cv::ocl::convertFromBuffer(
    my_cl_mem,
    pitch,
    rows,
    cols,
    format,
    frame
    );

    此外,因为 opencv 使用 opencl 的方式完全是低效的一团糟,如果提供一个预先固定的主机内存来 cap::read 然后将它异步传输到设备会更有效率,我不会感到惊讶。请注意,您可以使用 cv::Mat 包装任何主机内存指针。

    关于c++ - 如何从 OpenCL 访问 OpenCV UMat (gpu) 缓冲区?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58440529/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com