OpenCV — мощная и развитая библиотека компьютерного зрения с открытым исходным кодом. Если вам понадобилось решить какую-то задачу, связанную с нетривиальной обработкой изображений, то есть большая вероятность, что OpenCV уже предлагает готовое решение.
В этой статье мы соберем и установим OpenCV из исходных кодов под Linux, а затем разработаем тестовое приложение, способное находить лица на фотографии с помощью модуля CascadeClassifier:
Установка OpenCV под Linux
Прежде чем приступать к сборке OpenCV из исходных кодов, рекомендую проверить, что он не доступен в репозиториях вашего дистрибутива Linux. Например, в Archlinux библиотеку OpenCV можно установить следующей командой:
1 |
sudo pacman -S opencv |
Однако даже в этом случае иногда есть смысл сделать сборку OpenCV самому. Основная причина для этого — так вы сможете получить самую последнюю версию как можно раньше (например, при добавлении новых возможностей или исправлении критических ошибок). Поэтому приступим к пошаговой инструкции по сборке OpenCV.
Шаг 1: Получаем исходные коды OpenCV из Git
1 2 3 |
mkdir <путь_где_мы_хотим_вести_сборку> cd <путь_где_мы_хотим_вести_сборку> git clone https://github.com/opencv/opencv.git |
Шаг 2: Подготавливаем OpenCV к сборке
1 2 3 |
mkdir release # Предполагается, что мы в каталоге, куда был склонирован git-проект cd release cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=<путь_куда_мы_хотим_установить_opencv> ../ |
В качестве каталога установки я использую домашний каталог /home/michael/OpenCV/.
Шаг 3: Собираем и устанавливаем OpenCV
1 2 |
make # Предполагается, что мы в каталоге release/ sudo make install # Если вы устанавливаете OpenCV, как и я, в домашний каталог, то sudo не нужно |
Если все прошло без ошибок, то процесс сборки и установки OpenCV завершен. Теперь можно перейти в каталог, который мы указали в параметре CMAKE_INSTALL_PREFIX. Там вы должны увидеть примерно такой набор директорий:
1 2 3 4 5 6 |
drwx------ 6 michael michael 4,0K мар 31 08:44 ./ drwx------ 171 michael michael 12K мар 31 09:30 ../ drwx------ 2 michael michael 4,0K мар 31 08:44 bin/ drwx------ 4 michael michael 4,0K мар 31 08:44 include/ drwx------ 3 michael michael 4,0K мар 31 08:44 lib/ drwx------ 3 michael michael 4,0K мар 31 08:44 share/ |
Разработка Qt-проекта с использованием OpenCV
Начнем с подготовки pro-файла:
1 2 3 4 5 6 7 8 9 10 11 |
# ... # Остальное нас сейчас не интересует INCLUDEPATH += <path_to_opencv_include> LIBS += -L<path_to_opencv_libs>/ LIBS += -lopencv_core \ -lopencv_imgproc \ -lopencv_imgcodecs \ -lopencv_highgui \ -lopencv_objdetect |
Для успешной работы с OpenCV в Qt-проекте нужно указать пути, где находятся заголовочные файлы и библиотеки. Например, если мы установили OpenCV в домашнем каталоге: ~/OpenCV, то:
1 2 |
INCLUDEPATH += $(HOME)/OpenCV/include/ LIBS += -L$(HOME)/OpenCV/lib/ |
Также не забываем подключать необходимые opencv-библиотеки:
1 2 3 4 5 |
LIBS += -lopencv_core \ -lopencv_imgproc \ -lopencv_imgcodecs \ -lopencv_highgui \ -lopencv_objdetect |
Теперь переходим к файлу mainwidget.h:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
#ifndef MAINWIDGET_H #define MAINWIDGET_H #include <opencv2/objdetect.hpp> #include <QWidget> namespace Ui { class MainWidget; } class MainWidget : public QWidget { Q_OBJECT public: explicit MainWidget( QWidget* parent = 0 ); ~MainWidget(); private slots: void onLoadImage(); private: Ui::MainWidget* ui; cv::CascadeClassifier m_faceClassifier; }; #endif // MAINWIDGET_H |
Мы лишь подготовили очень простой виджет, в котором одним из полей является объект класса OpenCV — cv::CascadeClassifier.
Реализация в mainwidget.cpp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
#include "mainwidget.h" #include "ui_mainwidget.h" #include <opencv2/imgproc.hpp> #include <opencv2/opencv.hpp> #include <QFileDialog> #include <QPainter> MainWidget::MainWidget( QWidget* parent ) : QWidget( parent ), ui( new Ui::MainWidget ) { ui->setupUi( this ); m_faceClassifier.load( "haarcascade_frontalface_default.xml" ); connect( ui->bnOpen, SIGNAL( clicked( bool ) ), SLOT( onLoadImage() ) ); } MainWidget::~MainWidget() { delete ui; } void MainWidget::onLoadImage() { QString imgPath = QFileDialog::getOpenFileName( this, trUtf8( "Открыть" ), ".", trUtf8( "Изображения (*.jpg *.png *.bmp)" ) ); if( imgPath.isEmpty() ) { return; } cv::Mat img = cv::imread( imgPath.toStdString() ); cv::Mat gray; cv::cvtColor( img, gray, cv::COLOR_BGR2GRAY ); std::vector< cv::Rect > faces; m_faceClassifier.detectMultiScale( gray, faces ); QPixmap pix( imgPath ); QPainter painter; painter.begin( &pix ); painter.setPen( Qt::green ); foreach( const cv::Rect& r, faces ) { painter.drawRect( r.x, r.y, r.width, r.height ); } painter.end(); ui->lbView->setPixmap( pix.scaled( ui->lbView->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation ) ); } |
Обратите внимание на строку:
1 |
m_faceClassifier.load( "haarcascade_frontalface_default.xml" ); |
Здесь мы загружаем классификатор haarcascade_frontalface_default.xml, обученный на распознавание лиц. Найти его можно в каталоге data/haarcascades/, который расположен в склонированном гит-репозитории OpenCV. Обратите внимание, что этот xml-файл должен находиться в одном каталоге с исполняемым файлом для правильной работы приложения.
Следующий важный фрагмент:
1 2 3 4 5 |
cv::Mat img = cv::imread( imgPath.toStdString() ); cv::Mat gray; cv::cvtColor( img, gray, cv::COLOR_BGR2GRAY ); std::vector< cv::Rect > faces; m_faceClassifier.detectMultiScale( gray, faces ); |
В этом месте мы и выполняем непосредственное распознавание для загруженной фотографии. «Волшебство» происходит в этой строке:
1 |
m_faceClassifier.detectMultiScale( gray, faces ); |
На вход detectMultiScale() получает черно-белое изображение, а возвращает вектор с прямоугольниками, соответствующими всем найденным лицам.
Далее мы просто проходим по получившемуся вектору и помечаем все лица на фотографии зеленой рамкой:
1 2 3 4 5 6 7 8 |
QPixmap pix( imgPath ); QPainter painter; painter.begin( &pix ); painter.setPen( Qt::green ); foreach( const cv::Rect& r, faces ) { painter.drawRect( r.x, r.y, r.width, r.height ); } painter.end(); |
Если вы потестируете это приложение подольше, то увидите, что часто встречаются ложные срабатывания (лица находятся там, где их нет). Но решение этой проблемы уже выходит за рамки этой статьи и требует более аккуратного подхода.
В следующей статье займемся устанавкой OpenCV в Windows.