Программирование на видеокартах GPGPU (1184391), страница 10
Текст из файла (страница 10)
Кроме того, в новом варианте мы попрежнему можем пользоваться функциями в стиле языка C (их названия тогда начинаются сcv...), либо писать программу на C++.В новом варианте (когда используются заголовочные файлы из каталога opencv2) нужноучитывать тот факт, что классы и функции библиотеки помещены в пространство имён cv и длядоступа к ним следует применять префикс cv:: (или директиву using namespace cv;),иногда — для устранения конфликта имён, скажем, с STL — префикс тоже необходим.Работа с динамической памятью в библиотеке не требует явного освобождения памяти, посколькуреализуется подсчёт ссылок на объекты в динамической памяти, но при этом для указателейследует пользоваться шаблонным классом Ptr<> (похож на std::shared_ptr), т.е., вместоT* ptr = new T(...);лучше писатьPtr<T> ptr = new T(...);тогда указатель на объект будет также иметь и счётчик ссылок на этот объект.Наиболее часто используемым типом величины в OpenCV является массив, определяемый вклассе Mat.
Значения элементов в таком массиве не совсем произвольны, они могут быть 8битными (со знаком и без), 16-битными (со знаком и без), 32-битными целыми, вещественнымиодинарной (32 бита) и двойной (64 бита) точности.Для символических названий этих базовых типов и соответствующих им значений проще всегопривести определение соответствующего перечисления из библиотеки:enum { CV_8U=0, CV_8S=1, CV_16U=2, CV_16S=3, CV_32S=4, CV_32F=5, CV_64F=6 };Возможны также многоканальные типы данных, их символические имена имеют ещё символ C ичисло каналов, например: CV_32FC1 (то же самое, что и CV_32F), CV_32FC2 (то же самое,что и CV_32FC(2), CV_8UC(12) и т.п.Самый "ходовой" конструктор объектов — Mat(nrows, ncols, type[,fillValue]),например, матрица с шестью строками и пятью столбцами, содержащая пару величин(комплексное число) и заполненная значениями 1-2j, создаётся так:Mat M(6,5,CV_32FC2,Scalar(1,-2));Теперь можно превратить M в 12-канальную 8-битовую матрицу 100x60 (старое содержимое приэтом исчезнет):M.create(100,60,CV_8UC(12));Ещё пример — трёхканальное (цветное) изображение с 1920 столбцами и 1080 строками:Mat img(Size(1920, 1080), CV_8UC3);37Обратите внимание, что здесь размеры указаны другим способом, а потому идут в другомпорядке!Простейшие примеры программПервоначальное впечатление о возможностях библиотеки можно получить на простых примерах(сами файлы приведены в приложении: TestCamera1.cpp — вывод видеопотока с камеры вокно программы; Threshold.cpp — преобразование цветного изображения из файла вбинарное чёрно-белое, используются заголовочный файл opencv2/gpu/gpu.hpp и функцияcv::gpu::threshold(),работающая с видеокартой через объекты cv::gpu::GpuMat;LoadAVI.cpp — воспроизведение видеоролика из файла формата AVI).За более подробной информацией по использованию библиотеки следует обращаться круководству "The OpenCV Reference Manual" (файл opencv23.pdf или новее).Возможно также добавление возможностей OpenCV к программам, написанным на языке Python(с установленным пакетом Numpy!), для чего содержимое каталога библиотеки OpenCV\build\python\2.7\Lib\site-packages (в предположении, что используемый Python —версии 2.7) надо скопировать в каталог Python, именуемый \Lib\site-packages\ (скореевсего, это будет файл cv2.pyd; может быть также и cv.pyd или cv.py).Проверить, что возможности OpenCV доступны в языке Python, теперь можно с помощью однойстрочки в интерпретаторе: import cv2.Если всё в порядке, модуль будет подгружен и готов к использованию, в противном случае будетвыведено сообщение об ошибке.
При благоприятном развитии событий имеет смыслпоэкспериментировать с файлом FaceDetect.py: он задействует камеру для получениявидеопотока и пытается в этом видеопотоке обнаружить лицо человека, нужно только правильноуказать значение переменной haarlocation в этой программе.Следует отметить, что программы с использованием модуля gpu могут быть успешнособраны, но будут ли они они реально использовать GPU, зависит от того, как была созданабиблиотека OpenCV: с поддержкой CUDA или без неё. Для такой поддержки передкомпиляцией библиотека должна быть сконфигурирована с параметром WITH_CUDA=ON.При этом, если во время её компиляции CUDA установлена, то компилируется полноценныйGPU-модуль. В противном случае модуль тоже создаётся, но во время исполнения вызовыфункций из него лишь возбуждают исключительную ситуацию.Появившаяся недавно версия OpenCV 3.0 радикально переработана: библиотека теперьподдерживает "прозрачное" ускорение с помощью OpenCL (т.н.
Transparent API). Во времяисполнения программы — если OpenCL-реализация наличествует и не запрещена — OpenCLбудет использоваться по умолчанию, если алгоритм имеет OpenCL-вариант. Запрещение иразрешение использования OpenCL контролируется специальной переменной окруженияOPENCV_OPENCL_RUNTIME. С её помощью можно также указать, что нужно использоватьконкретное устройство, если их несколько. Обращение к OpenCL-реализации осуществляетсяпри этом динамически, т.е., во время исполнения программы.Существовавшие в версиях 2.4.x отдельные функции и даже пространство имён "ocl"(вместе с типом oclMat) более не используются; появляется унифицированный тип данныхUMat, обслуживающий также и необходимые переносы данных на устройство и из устройства.389Графическая библиотека (программный интерфейс) OpenGLВозросшимвычислительнымвозможностямдолжнысопутствоватьсравнимыеизобразительные возможности, иначе трудно убедиться в правильности вычислений и почтиневозможно воспользоваться результатами расчётов — из-за возрастающих объёмовперерабатываемой информации.
Поэтому понятно, что нужно иметь возможностьвизуализации исходных и получаемых данных, а для визуального отображения информациинеобходима какая-нибудь графическая библиотека.Мы ограничимся знакомством только с одной из графических библиотек, но, пожалуй, самойважной и распространённой в настоящее время: кроссплатформенной, доступной из различныхязыков программирования, — библиотекой (являющейся одновременно и программныминтерфейсом) OpenGL (http://ru.wikipedia.org/wiki/OpenGL).Справедливости ради надо сказать, что воспользоваться этой библиотекой в рамках самойраспространённой (пока) операционной системы Windows сложнее всего, поскольку интерфейсOpenGL в рамках Windows "заморозился" на уровне OpenGL версии 1.1, что означаетневозможность прямого подключения к более новым функциям и предполагает динамическоеподключение к ним (т.е., во время работы программы). Кроме того, тот заголовочный файл,который обычно присутствует в системе, вообще не содержит никакой информации о новыхфункциях, хотя в файле динамической библиотеки эти функции присутствуют.А это в свою очередь значит, что имеющиеся при компиляторе Visual C++ файлы gl.h иopengl32.lib сами по себе практически бесполезны, и для реальной работы надоиспользовать также другие заголовки и статические библиотеки, реализующие "надстройку" надOpenGL и/или дополнения к ней.Возможные здесь варианты — это библиотека GLEW (OpenGL Extension Wrangler,http://glew.sourceforge.net), она создана для облегчения работы с расширениями иразличными версиями OpenGL, что актуально для пользователей Visual Studio, а такжебиблиотека GLUT (OpenGL Utility Toolkit, http://user.xmission.com/~nate/glut.html),включающая как упрощённый интерфейс к функциям OpenGL, так и функции работы с окнами всистеме и функции взаимодействия с пользователем через клавиатуру и мышь.На других возможных вариантах (например, Qt, или wxWidgets) останавливаться здесь не будем,так как они выходят за рамки данного курса.Использование GLUTРассмотрим простенький пример работы с GLUT — файл ExampleGLUT.cpp.
Для того, чтобыоткомпилировать его, понадобится заголовочный файл glut.h, для сборки программы —статические библиотеки glut32.lib (можно просто включить её в проект) и OpenGL32.lib(скорее всего, имеется — в составе Windows SDK; у меня, например, эта библиотека находится вкаталогеC:\Program Files\Microsoft SDKs\Windows\v6.1\Lib).Длязапускапрограммы также надо убедиться, что будут обнаружены glut32.dll (проще расположить еёв одном каталоге с исполняемым файлом) и opengl32.dll (почти наверняка есть вC:\WINDOWS\system32).39#include "glut.h"voidvoidvoidvoidreshape(int,int) {}display() {}keyboard(unsigned char,int,int) {}mouse(int,int,int,int) {}void main(int argc, char *argv[]){// Инициализация GLUTglutInit(&argc,argv);glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);glutInitWindowSize(512,512);// Создание окна OpenGLglutCreateWindow("Simple Window");// init ( ); // какая-нибудь другая инициализация// Регистрация функций "обратного вызова" (callback)glutReshapeFunc(reshape);glutDisplayFunc(display);glutKeyboardFunc(keyboard);glutMouseFunc(mouse);// Цикл опроса событийglutMainLoop();}Листинг программы даёт простой пример применения GLUT.
После базовой инициализациисоздаётся окно и регистрируются обработчики событий: отрисовки окна (display()) иизменения его размеров (reshape()), а также событий клавиатуры (keyboard()) и мыши(mouse()). В данном примере обработчики пусты, поэтому программа ничего полезного сделатьне может, даже окно не перерисовывается — хотя и воспроизводится.Дополняя обработчики отрисовки окна и изменения его размеров кодом отображения, аостальные обработчики — кодом изменения параметров отображаемого, мы можем получитьнесложную вычислительную программу с графическим интерфейсом.Более сложные программы, использующие OpenGL, можно найти в NVIDIA CUDA SDK.Рассмотрим, к примеру, программу nbody, иллюстрирующую поведение большого числагравитирующих тел. Открываем файл nbody_vs2008.sln (только не двойным нажатием,поскольку файл по умолчанию "норовит" открыться в VS2010, а вовсе не в VS2008!), выбираяпрограмму VS2008 для его открытия в меню по нажатию правой кнопки мыши, и пробуем создатьисполняемый файл.Легко заметить, что эта демонстрационная программа тоже использует GLUT, только здесьобработчики отрисовки, клавиатуры и мыши — вполне реальные, поэтому их можно взять вкачестве примера.