Компьютерное зрение на openCV

Публикация 07.05.2017

При решении задач компьютерного зрения не обойтись без использования специализированного софта. Хочу познакомить вас с таким - OpenCV - библиотека с открытым исходном кодом на C++. Обладает набором инструментов для оцифровки изображений, последующей обработки через численные алгоритмы или нейросеть.

Компьютерное зрение на openCV

Базовые алгоритмы обработки изображений: интерпретации изображений, калибровки камеры по эталону, устранение оптических искажений, определение сходства, анализ перемещения объекта, определение формы объекта и слежение за объектом, 3D-реконструкция, сегментация объекта, распознавание жестов.

Скачать библиотеку можно на официальном сайте http://sourceforge.net/projects/opencvlibrary/

Структура библиотеки OpenCV

cxcore — ядро
* содержит базовые структуры данных и алгоритмы:
— базовые операции над многомерными числовыми массивами
— матричная алгебра, математические ф-ции, генераторы случайных чисел
— Запись/восстановление структур данных в/из XML
— базовые функции 2D графики

CV — модуль обработки изображений и компьютерного зрения
— базовые операции над изображениями (фильтрация, геометрические преобразования, преобразование цветовых пространств и т. д.)
— анализ изображений (выбор отличительных признаков, морфология, поиск контуров, гистограммы)
— анализ движения, слежение за объектами
— обнаружение объектов, в частности лиц
— калибровка камер, элементы восстановления пространственной структуры

Highgui — модуль для ввода/вывода изображений и видео, создания пользовательского интерфейса
— захват видео с камер и из видео файлов, чтение/запись статических изображений.
— функции для организации простого UI (все демо приложения используют HighGUI)

Cvaux — экспериментальные и устаревшие функции
— пространств. зрение: стерео калибрация, само калибрация
— поиск стерео-соответствия, клики в графах
— нахождение и описание черт лица

CvCam — захват видео
— позволяет осуществлять захват видео с цифровых видео-камер ( поддержка прекращена и в последних версиях этот модуль отсутствует )

Структура OpenCV

Установка OpenCV под Linux

После скачивания последней версии OpenCV с сайта разработчика http://sourceforge.net/projects/opencvlibrary/ нужно распаковать архив и выполнить сборку через CMake версии 2.6 или выше.

Установка CMake выполняется стандартно:

sudo apt-get install cmake

Для отображения окон OpenCV потребуется установить библиотеки GTK+ 2.x и libgtk2.0-dev

apt-get install libgtk2.0-dev

Собираем библиотеку:

tar -xjf OpenCV-2.2.0.tar.bz2
cd OpenCV-2.2.0
cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local ./
make
make install

Для тестирования установленной библиотеки можно собрать примеры и что-нибудь запустить:

cd samples/c/
chmod +x build_all.sh
./build_all.sh
./delaunay 

Если вместо тестовой картинки вы увидите ошибку "error while loading shared libraries: libopencv_core.so.2.2: cannot open shared object file: No such file or directory", то это значит, что программа не может найти библиотеки. Нужно явно указать путь до них:

$ export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH

Если после этого опять ошибка:
OpenCV Error: Unspecified error (The function is not implemented. Rebuild the library with Windows, GTK+ 2.x or Carbon support. If you are on Ubuntu or Debian, install libgtk2.0-dev and pkg-config, then re-run cmake or configure script) in cvNamedWindow, file /usr/src/OpenCV-2.2.0/modules/highgui/src/window.cpp, line 274 terminate called after throwing an instance of 'cv::Exception' what(): /usr/src/OpenCV-2.2.0/modules/highgui/src/window.cpp:274: error: (-2) The function is not implemented. Rebuild the library with Windows, GTK+ 2.x or Carbon support. If you are on Ubuntu or Debian, install libgtk2.0-dev and pkg-config, then re-run cmake or configure script in function cvNamedWindow
Значит вы забыли установить GTK+ 2.x: libgtk2.0-dev. Запустите установку (см. выше).

Когда установка завершена заголовочные файлы будут доступны в дирректории /usr/local/include/opencv , а библиотечные файлы лежат в /usr/local/lib

Соберем программу с OpenCV:

test.cpp

//
// for testing
//
// robocraft.ru
//

#include <cv.h>
#include <highgui.h>

#include <stdlib.h>
#include <stdio.h>

int main(int argc, char* argv[])
{
        IplImage* image=0, *dst=0;

        // имя картинки
        char filename[] = "Image0.jpg";

        // получаем картинку
        image = cvLoadImage(filename, 1);

        printf("[i] image: %s\n", filename);
        assert( image != 0 );

        // покажем изображение
        cvNamedWindow( "image");
        cvShowImage( "image", image );

        // ждём нажатия клавиши
        cvWaitKey(0);

        // освобождаем ресурсы
        cvReleaseImage(& image);
        cvReleaseImage(&dst);

        // удаляем окна
        cvDestroyAllWindows();
        return 0;
}

Makefile

CC              := g++
CFLAGS          := -I/usr/local/include/opencv -L/usr/local/lib
OBJECTS         := 
LIBRARIES       := -lopencv_core -lopencv_imgproc -lopencv_highgui

.PHONY: all clean

all: test

test: 
        $(CC) $(CFLAGS) -o test test.cpp $(LIBRARIES)
        
clean:
        rm -f *.o

Запуск сборки коммандой make.

Компьютерное зрение на openCV

Hello World!

OpenCV установлен и готов к работе. Напишем свое первое приложение Hello World!

#include <cv.h>
#include <highgui.h>

int main( int argc, char** argv ) 
{
        // задаём высоту и ширину картинки
        int height = 620;
        int width = 440;
        // задаём точку для вывода текста
        CvPoint pt = cvPoint( height/4, width/2 );
        // Создаёи 8-битную, 3-канальную картинку
        IplImage* hw = cvCreateImage(cvSize(height, width), 8, 3);
        // заливаем картинку чёрным цветом
        cvSet(hw,cvScalar(0,0,0));
        // инициализация шрифта
        CvFont font;
        cvInitFont( &font, CV_FONT_HERSHEY_COMPLEX,1.0, 1.0, 0, 1, CV_AA);
        // используя шрифт выводим на картинку текст
        cvPutText(hw, "OpenCV Step By Step", pt, &font, CV_RGB(150, 0, 150) );

        // создаём окошко
        cvNamedWindow("Hello World", 0);
        // показываем картинку в созданном окне
        cvShowImage("Hello World", hw);
        // ждём нажатия клавиши
        cvWaitKey(0);
        
        // освобождаем ресурсы
        cvReleaseImage(&hw);
        cvDestroyWindow("Hello World");
        return 0;
}
OpenCV Hello World!

Загрузка изображения

Данный пример будет основой всех ваших программ на OpenCV. Мы загрузим в среду изображение из файла Image0.jpg

#include <cv.h>
#include <highgui.h>
#include <stdlib.h>
#include <stdio.h>

IplImage* image = 0;
IplImage* src = 0;

int main(int argc, char* argv[])
{
        // имя картинки задаётся первым параметром
        char* filename = argc == 2 ? argv[1] : "Image0.jpg";
        // получаем картинку
        image = cvLoadImage(filename,1);
        // клонируем картинку 
        src = cvCloneImage(image);

        printf("[i] image: %s\n", filename);
        assert( src != 0 );

        // окно для отображения картинки
        cvNamedWindow("original",CV_WINDOW_AUTOSIZE);

        // показываем картинку
        cvShowImage("original",image);

        // выводим в консоль информацию о картинке
        printf( "[i] channels:  %d\n",        image->nChannels );
        printf( "[i] pixel depth: %d bits\n",   image->depth );
        printf( "[i] width:       %d pixels\n", image->width );
        printf( "[i] height:      %d pixels\n", image->height );
        printf( "[i] image size:  %d bytes\n",  image->imageSize );
        printf( "[i] width step:  %d bytes\n",  image->widthStep );

        // ждём нажатия клавиши
        cvWaitKey(0);

        // освобождаем ресурсы
        cvReleaseImage(& image);
        cvReleaseImage(&src);
        // удаляем окно
        cvDestroyWindow("original");
        return 0;
}
Загруженное изображение в OpenCV

Поддерживаемые типы форматов изображений:

  • Windows bitmaps - BMP, DIB
  • JPEG files - JPEG, JPG, JPE
  • Portable Network Graphics - PNG
  • Portable image format - PBM, PGM, PPM
  • Sun rasters - SR, RAS
  • TIFF files - TIFF, TIF

Для обращения к изображению можно делать такие вызовы:

image->nChannels // число каналов картинки (RGB, хотя в OpenCV - BGR ) (1-4)
image->depth    // глубина в битах
image->width    // ширина картинки в пикселях 
image->height   // высота картинки в пикселях
image->imageSize // память занимаемая картинкой (==image->height*image->widthStep)
image->widthStep // расстояние между соседними по вертикали точками изображения (число байт в одной строчке картинки
- может потребоваться для самостоятельного обхода всех пикселей изображения)

Загрузка видео

Загрузка видео не на много сложнее, чем загрузка изображения за тем исключением, что будет цикл, который перебирает кадры.
Задержка между кадрами задана в 33 миллисекунды т.к. такая задержка позволяет обрабатывать видеопоток с стандартной частотой 30 кадров в секунду.

#include <cv.h>
#include <highgui.h>
#include <stdlib.h>
#include <stdio.h>

IplImage* frame =0;

int main(int argc, char* argv[])
{
        // имя файла задаётся первым параметром
        char* filename = argc == 2 ? argv[1] : "test.avi";

        printf("[i] file: %s\n", filename);

        // окно для отображения картинки
        cvNamedWindow("original",CV_WINDOW_AUTOSIZE);

        // получаем информацию о видео-файле
        CvCapture* capture = cvCreateFileCapture( filename );

        while(1){
                // получаем следующий кадр
                frame = cvQueryFrame( capture ); 
                if( !frame ) {
                        break;
                }

                // здесь можно вставить
                // процедуру обработки

                // показываем кадр
                cvShowImage( "original", frame );

                char c = cvWaitKey(33);
                if (c == 27) { // если нажата ESC - выходим
                        break;
                }
        }

        // освобождаем ресурсы
        cvReleaseCapture( &capture );
        // удаляем окно
        cvDestroyWindow("original");
        return 0;
}

Для захвата видео с камеры нужно немного модифицировать код - вместо функции cvCreateFileCapture() будет использоваться cvCreateCameraCapture(). При нажатии ESC воспроизведение прервется и окно закроется, а при нажатии Enter текущий кадр сохранится в jpg файл.

#include <cv.h>
#include <highgui.h>
#include <stdlib.h>
#include <stdio.h>

int main(int argc, char* argv[])
{
        // получаем любую подключённую камеру
        CvCapture* capture = cvCreateCameraCapture(CV_CAP_ANY); //cvCaptureFromCAM( 0 );
        assert( capture );

        //cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, 640);//1280); 
        //cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, 480);//960); 

        // узнаем ширину и высоту кадра
        double width = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH);
        double height = cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT);
        printf("[i] %.0f x %.0f\n", width, height );

        IplImage* frame=0;

        cvNamedWindow("capture", CV_WINDOW_AUTOSIZE);

        printf("[i] press Enter for capture image and Esc for quit!\n\n");

        int counter=0;
        char filename[512];

        while(true){
                // получаем кадр
                frame = cvQueryFrame( capture );

                // показываем
                cvShowImage("capture", frame);
        
                char c = cvWaitKey(33);
                if (c == 27) { // нажата ESC
                        break;
                }
                else if(c == 13) { // Enter
                        // сохраняем кадр в файл
                        sprintf(filename, "Image%d.jpg", counter);
                        printf("[i] capture... %s\n", filename);
                        cvSaveImage(filename, frame);
                        counter++;
                }
        }
        // освобождаем ресурсы
        cvReleaseCapture( &capture );
        cvDestroyWindow("capture");
        return 0;
}

OpenCV v1.0 показывает и сохраняет картинку минимального разрешения камеры 320x240.

Видео с камеры OpenCV

Распознавание объектов по шаблону

Для распознавание областей на исходном изображении по шаблону существует функция cvMatchTemplate(). Функция накладывает шаблон изображения на текущее изображение и согласно выбранному алгоритму выполняет поиск корреляции между ними. Определение границ найденного шаблона на исходном изображении выполняется функцией cvMinMaxLoc, а для нормализации алгоритма поиска cvNormalize().

//
// пример cvMatchTemplate()
// сравнение изображение с шаблоном
//

#include <cv.h>
#include <highgui.h>
#include <stdlib.h>
#include <stdio.h>

IplImage* image = 0;
IplImage* templ = 0;

int main(int argc, char* argv[])
{
        // имя картинки задаётся первым параметром
        char* filename = argc >= 2 ? argv[1] : "Image0.jpg";
        // получаем картинку
        image = cvLoadImage(filename,1);

        printf("[i] image: %s\n", filename);
        assert( image != 0 );

        // шаблон
        char* filename2 = argc >= 3 ? argv[2] : "eye.jpg";
        printf("[i] template: %s\n", filename2);

        templ = cvLoadImage(filename2,1);
        assert( templ != 0 );

        cvNamedWindow("origianl", CV_WINDOW_AUTOSIZE);
        cvNamedWindow("template", CV_WINDOW_AUTOSIZE);
        cvNamedWindow("Match", CV_WINDOW_AUTOSIZE);  
        cvNamedWindow("res", CV_WINDOW_AUTOSIZE); 

        // размер шаблона
        int width = templ->width;
        int height = templ->height;

        // оригинал и шаблон
        cvShowImage( "origianl", image);
        cvShowImage( "template", templ);

        // изображение для хранения результата сравнения
        // размер результата: если image WxH и templ wxh, то result = (W-w+1)x(H-h+1)
        IplImage *res = cvCreateImage( cvSize( (image->width-templ->width+1), (image->height-templ->height+1)), IPL_DEPTH_32F, 1 );

        // сравнение изображения с шаблоном
        cvMatchTemplate(image, templ, res, CV_TM_SQDIFF);

        // покажем что получили
        cvShowImage( "res", res);

        // определение лучшее положение для сравнения
        // (поиск минимумов и максимумов на изображении)
        double    minval, maxval;
        CvPoint    minloc, maxloc;
        cvMinMaxLoc(res, &minval, &maxval, &minloc, &maxloc, 0);
        
        // нормализуем
        cvNormalize(res,res,1,0,CV_MINMAX);
        cvNamedWindow("res norm", CV_WINDOW_AUTOSIZE); 
        cvShowImage( "res norm", res);

        // выделим область прямоугольником
        cvRectangle(image, cvPoint(minloc.x, minloc.y), cvPoint(minloc.x+templ->width-1, minloc.y+templ->height-1), CV_RGB(255, 0, 0), 1, 8);

        // показываем изображение
        cvShowImage("Match", image);

        // ждём нажатия клавиши
        cvWaitKey(0);

        // освобождаем ресурсы
        cvReleaseImage( &image );
        cvReleaseImage( &templ );
        cvReleaseImage( &res );
        cvDestroyAllWindows(); 
        return 0;
}
OpenCV распознавание объектов по шаблону
* комментарии публикуются после модерации
Нет комментариев