Система технического зрения на видеокарте

В последней версии OpenCV появилась возможность проводить большую часть вычислений на видеокарте, а не на центральном процессоре. Правда для этого нужна видеокарта от nvidia с поддержкой технологии CUDA. Разработчики OpenCV реализовали многие функции библиотеки на языке CUDA и сделали к ним интерфейсы на C++. Таким образом, чтобы использовать видеокарту, не нужно знать CUDA. Нужно лишь знать базовые принципы использования модуля OpenCV GPU. Их мы в данной стать и рассмотрим. Также приведу сравнение производительности вычислений на центральном процессоре и видеокарте.
 
 
 

Все средства для работы с видеокартой лежат в файле opencv2/gpu/gpu.hpp. Т.е. необходимо добавить строку:

#include <opencv2/gpu/gpu.hpp>

Классы и функции для работы с видеокартой лежат в пространстве имён cv::gpu. Для краткости переобозначу это пространство имён как cg:

namespace cg = cv::gpu;

Как и во всей библиотеке OpenCV основным элементом данных в модуле GPU является матрица. Здесь для матрицы написан отдельный класс - cv::gpu::GpuMat. Данные матрицы этого класса хранятся в видеопамяти. Они могут обрабатываться параллельно работе центрального процессора. После обработки их можно выгрузить в оперативную память, т.е. в класс cv::Mat.

cv::Mat image( IMAGE_RESOLUTION, CV_8UC1, cv::Scalar::all( 0 ) );
cg::GpuMat gpuImage( IMAGE_RESOLUTION, CV_8UC1, cv::Scalar::all( 0 ) );
gpuImage.upload( image );

Данная операция займёт некоторое время. На моём компьютере на это уходит 700 мкс.
Чтобы загрузить данные в видеопамять, можно сделать так:

cv::Mat image( IMAGE_RESOLUTION, CV_8UC1, cv::Scalar::all( 0 ) );
cg::GpuMat gpuImage( IMAGE_RESOLUTION, CV_8UC1, cv::Scalar::all( 0 ) );
gpuImage.download( image );

При разработке собственных алгоритмов технического зрения необходимо минимизировать обмен данными между видеопамятью и оперативной памятью. Т.к. он может значительно повлиять на производительность программы.
Одним из преимуществ видеокарт является их умение выполнять матричные вычисления в несколько потоков параллельно. Чтобы узнать сколько параллельных потоков поддерживает ваша видеокарта, создайте cg::DeviceInfo и вызовите multiProcessorCount:

cg::DeviceInfo info;
qDebug( ) << "Multi processors count: " << info.multiProcessorCount( );

Модель видеокарты:

qDebug( ) << "Current device name: " << info.name( ).c_str( );

Общее кличество видеопамяти:

qDebug( ) << "Total memory: " << info.totalMemory( );

Для представления потока вычисления на видеокарте существует класс cv::gpu::Stream. Он имеет методы для постановки в очередь на параллельное выполнение команд по обмену между видеопамятью и ОЗУ. Так же функции OpenCV GPU, которые можно выполнить параллельно, принимают ссылку на поток выполнения.

Чтобы сравнить производительность вычислений на видеокарте и на процессоре я написал несколько тестов производительности на базе Qt. Можете их скачать здесь. К моему удивлению, у меня видеокарта nvidia GeForce 9600M GS считает в разы медленнее чем процессор intel Centrino 2.

Я реализовал детектор движения, описанный в предыдущей статье на видеокарте. Его можете скачать здесь.

И последнее, что я хочу сказать. Чтобы использовать OpenCV GPU, OpenCV нужно собрать с поддержкой CUDA. В Linux это можно сделать, только если в системе компилятором по умолчанию является gcc версии меньше чем 4.5.

Leave a Reply

You must be logged in to post a comment.