Opencv学习笔记 - 关于OpenCV的UMat 类
Posted 坐望云起
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Opencv学习笔记 - 关于OpenCV的UMat 类相关的知识,希望对你有一定的参考价值。
一个统一的抽象 cv::UMat 允许使用 CPU 或 OpenCL 代码实现相同的 API,而无需显式调用 OpenCL 加速版本。UMat类告诉 OpenCV 函数使用特定于 OpenCL 的代码处理图像,如果系统中存在启用 OpenCL 的 GPU(否则自动切换到 CPU)。
根据 Khronos 小组的说法, OpenCL™(开放计算语言)是:一种免版税标准,用于不同处理器的跨平台并行编程。OpenCL 极大地提高了众多市场类别中各种应用程序的速度和响应能力,包括游戏和娱乐标题、科学和医疗软件、专业创意工具、视觉处理以及神经网络训练和推理。
OpenCL(开放计算语言)是一个框架,用于编写跨异构平台执行的程序,包括中央处理单元(CPU)、图形处理单元(GPU)、数字信号处理器(DSP)、现场可编程门阵列(FPGA)和其他处理器或硬件加速器。OpenCL 指定用于对这些设备和应用程序编程接口进行编程的编程语言(基于C99、C++14和C++17 )(API) 来控制平台并在计算设备上执行程序。OpenCL 为使用基于任务和数据的并行性的并行计算提供标准接口。
OpenCL+C语言计算FFT示例
#include <stdio.h>
#include <time.h>
#include "CL/opencl.h"
#define NUM_ENTRIES 1024
int main() // (int argc, const char* argv[])
// CONSTANTS
// The source code of the kernel is represented as a string
// located inside file: "fft1D_1024_kernel_src.cl". For the details see the next listing.
const char *KernelSource =
#include "fft1D_1024_kernel_src.cl"
;
// Looking up the available GPUs
const cl_uint num = 1;
clGetDeviceIDs(NULL, CL_DEVICE_TYPE_GPU, 0, NULL, (cl_uint*)&num);
cl_device_id devices[1];
clGetDeviceIDs(NULL, CL_DEVICE_TYPE_GPU, num, devices, NULL);
// create a compute context with GPU device
cl_context context = clCreateContextFromType(NULL, CL_DEVICE_TYPE_GPU, NULL, NULL, NULL);
// create a command queue
clGetDeviceIDs(NULL, CL_DEVICE_TYPE_DEFAULT, 1, devices, NULL);
cl_command_queue queue = clCreateCommandQueue(context, devices[0], 0, NULL);
// allocate the buffer memory objects
cl_mem memobjs[] = clCreateBuffer(context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, sizeof(float) * 2 * NUM_ENTRIES, NULL, NULL),
clCreateBuffer(context, CL_MEM_READ_WRITE, sizeof(float) * 2 * NUM_ENTRIES, NULL, NULL) ;
// create the compute program
// const char* fft1D_1024_kernel_src[1] = ;
cl_program program = clCreateProgramWithSource(context, 1, (const char **)& KernelSource, NULL, NULL);
// build the compute program executable
clBuildProgram(program, 0, NULL, NULL, NULL, NULL);
// create the compute kernel
cl_kernel kernel = clCreateKernel(program, "fft1D_1024", NULL);
// set the args values
size_t local_work_size[1] = 256 ;
clSetKernelArg(kernel, 0, sizeof(cl_mem), (void *)&memobjs[0]);
clSetKernelArg(kernel, 1, sizeof(cl_mem), (void *)&memobjs[1]);
clSetKernelArg(kernel, 2, sizeof(float)*(local_work_size[0] + 1) * 16, NULL);
clSetKernelArg(kernel, 3, sizeof(float)*(local_work_size[0] + 1) * 16, NULL);
// create N-D range object with work-item dimensions and execute kernel
size_t global_work_size[1] = 256 ;
global_work_size[0] = NUM_ENTRIES;
local_work_size[0] = 64; //Nvidia: 192 or 256
clEnqueueNDRangeKernel(queue, kernel, 1, NULL, global_work_size, local_work_size, 0, NULL, NULL);
OpenCV 从第二版开始就有 OpenCL 实现,但使用它们十分麻烦,需要对您的代码进行大量修改。从 3.0 版本开始,OpenCV 实现了 T-API(Transparent API),为很多“经典”功能增加了硬件加速。从那时起,它就能够自动检测、加载和利用 OpenCL 设备和加速代码。因此,您不需要实现任何 OpenCL 代码,它对用户是“透明的”。
基于Mat的双边滤波。
void MatProcessing(const std::string& name)
Mat img,dst;
img = imread(name.c_str());
cv::cvtColor(img,img,CV_BGR2GRAY);
bilateralFilter(img, dst, 0, 10, 3);
基于UMat的双边滤波。
void UMatProcessing(const std::string& name)
UMat Uimg, Udst;
Uimg = imread(name.c_str(), IMREAD_UNCHANGED).getUMat(ACCESS_READ);
cv::cvtColor(Uimg,Uimg,CV_BGR2GRAY);
bilateralFilter(Uimg, Udst, 0, 10, 3);
下面图片转载自网络上,本人并没有进行严谨测试。不过创建了一张12000*12000的图片,也是进行了双边滤波,运行了两次,上面的结果是mat的,下面的结果是umat的,确实快一点,感觉应该是图片越大用Umat优势越明显,这个测试应该和下图的走势相符。
第一次
DateTime costed for Shuffle function is: 1144.292ms
DateTime costed for Shuffle function is: 936.5605ms
第二次
DateTime costed for Shuffle function is: 1101.805ms
DateTime costed for Shuffle function is: 732.5992ms
用英特尔的说法:不要所有地方都使用 cv::UMat 数据类型。可以将 cv::UMat 用于图像,并继续将 cv::Mat 用于其他较小的数据结构,例如卷积矩阵、转置矩阵等。
也有说法是:仅当您对图像执行一些十分耗时的操作时,使用透明 API才有意义。否则,将图像copy到GPU的开销的时间也是不短的,这一点需要考虑。
以上是关于Opencv学习笔记 - 关于OpenCV的UMat 类的主要内容,如果未能解决你的问题,请参考以下文章