Acelerar OpenCV con OpenCL

OpenCL es una API estándar abierta, desarrollada por Khronos Group dedicada a la programación GPGPU, con OpenCL logramos acelerar los algoritmos OpenCV que se benefician de los múltiples núcleos de procesamiento con los que cuentan las modernas GPU, algunos de estos algoritmos se ejecutan más rápido en la GPU que en la CPU, para usar esta característica requerimos un hardware que la soporte, en la actualidad la mayoría de los procesadores gráficos ya sea integrados como dedicados soportan OpenCL.

image

Rendimiento en fps de algunos algoritmos OpenCV acelerados por OpenCL, se muestran los resultados de la ejecución del algoritmo en la CPU, el procesador gráfico integrado iGPU y la tarjeta gráfica dedicada GPU.

OpenCL en OpenCV 2.x

La aceleración de OpenCV mediante OpenCL se inicia en el año 2011 por AMD, en ese tiempo se añade el modulo cv::ocl el cual contenía los algoritmos acelerados por la GPU, por ejemplo, utilizamos la función cv::ocl::resize() en lugar de cv::resize() para ejecutar el código acelerado por hardware.

OpenCL en OpenCV 3.x

En esta versión se utiliza el concepto T-API (Transparent API), esta nueva arquitectura oculta la implementación del modulo cv::ocl e introduce la clase UMat, al utilizar esta clase los algoritmos son capaces de utilizar la aceleración OpenCL si la misma está activa y disponible por el hardware.

opencv con opencv t-api

El la parte superior se muestra el código que normalmente hemos venido viendo en todos nuestros tutoriales, en la parte inferior izquierda vemos como utilizar el modulo ocl y en la parte inferior derecha el uso de la T-API con la clase UMat.

Instalación de OpenCV con OpenCL activado

Para habilitar OpenCL primero debemos asegurarnos de que nuestro hardware soporta esta característica, pueden ser procesadores: Intel, AMD, NVidia, otros.

Dependiendo del hardware debemos instalar el SDK correspondiente, Intel SDK para los procesadores Intel (Core i7, i5,  i3, Intel HD Graphics, etc.), AMD APP SDK para CPU y GPU de la compañía AMD (AMD Fusion, AMD Radeon, ATI FirePro GPU, etc.), NVidia SDK Toolkit para tarjetas gráficas como: NVIDIA Tesla, NVIDIA GeForce, NVIDIA Quadro GPUs, etc.

Compilar OpenCV con CMake y activar la opción WITH_OPENCL.

opencv activar opencl en cmake

El proceso de compilación e instalación de OpenCV es exactamente igual al que hemos visto en tutoriales anteriores, salvo que previamente hemos instalado el SDK correspondiente  y además activamos la opción CMake WITH_OPENCL = ON.

Comprobar la instalación

Para probar si nuestra instalación ha sido correcta escribiremos un código que nos permite obtener la información del SDK utilizado por OpenCL y el hardware que la implementa.

vector<ocl::PlatformInfo> info;
getPlatfomsInfo(info);

PlatformInfo sdk = info.at(0);

if (sdk.deviceNumber() < 1) return;

cout << "******SDK*******" << endl;
cout << "Name: " << sdk.name() << endl;
cout << "Vendor: " << sdk.vendor() << endl;
cout << "Version: " << sdk.version() << endl;
cout << "Number of devices: " << sdk.deviceNumber() << endl;

La función cv::ocl::getPlatfomsInfo() nos devuelve la información de todos los SDK instalados, usamos sdk.devideNumber() para verificar que tenemos al menos un dispositivo disponible que soporte OpenCL. 

for (int i = 0; i < sdk.deviceNumber(); i++) {
    Device device;
    sdk.getDevice(device, i);

    cout << "\n\n*********************\n Device " << i + 1 << endl;
    cout << "Vendor ID: " << device.vendorID() << endl;
    cout << "Vendor name: " << device.vendorName() << endl;
    cout << "Name: " << device.name() << endl;
    cout << "Driver version: " << device.driverVersion() << endl;

    if (device.isAMD()) cout << "Is an AMD device" << endl;
    if (device.isIntel()) cout << "Is a Intel device" << endl;

    cout << "Global Memory size: " << device.globalMemSize() << endl;
    cout << "Memory cache size: " << device.globalMemCacheSize() << endl;
    cout << "Memory cache type: " << device.globalMemCacheType() << endl;
    cout << "Local Memory size: " << device.localMemSize() << endl;
    cout << "Local Memory type: " << device.localMemType() << endl;
    cout << "Max Clock frequency: " << device.maxClockFrequency() << endl;
}

Con el uso de sdk.getDevice() obtenemos el objeto Device que contiene la información del dispositivo correspondiente.

La función cv::ocl::setUseOpenCL(bool) nos permite activar o desactivar el uso de OpenCL, mientras que cv::ocl::useOpenCL() nos devuelve un bool que indica si estamos usando o no esta característica de aceleración por hardware.

Podrás encontrar códigos de ejemplo en la carpeta: /opencv/samples/tapi

Nuestro pequeño ejemplo utiliza la cámara para capturar un video y aplicarle el filtro blur, se muestran los fps promedio para poder observar la diferencia cuando OpenCL esté activado o no, activamos o desactivamos presionando la tecla ‘q’.

double t = (double)getTickCount();

UMat uframe;
capture >> uframe;

if (uframe.empty()) continue;

medianBlur(uframe, uframe, 3);
blur(uframe, uframe, Size(11, 11));

char key = (char)waitKey(10);

if (key == 27) break;
if (key == 'q') ocl::setUseOpenCL(!ocl::useOpenCL());

t = (double)getTickCount() - t;
double fps = getTickFrequency() / t;
double alpha = ++nframes > 50 ? 0.01 : 1. / nframes;
avgfps = avgfps * (1 - alpha) + fps * alpha;

String message = format(titleWindow.c_str(), avgfps,
    ocl::useOpenCL() ? "ON" : "OFF",
    ocl::useOpenCL() ? "desactivar" : "activar");

putText(uframe, message, Point(10, 20), FONT_HERSHEY_TRIPLEX, 0.5, Scalar(0, 255, 0), 1, CV_AA);
imshow(nameWindow, uframe);

opencv con opencl on

opencv con opencl off

Código en GitHub: Acelerar OpenCV con OpenCL

Comentarios

Temas relacionados

Entradas populares de este blog

tkinter Grid

Histogramas OpenCV Python

tkinter Canvas

Conectar SQL Server con Java