- •Реферат
- •Введение
- •Постановка задачи
- •1 Аналитический обзор предметной области
- •Компьютерное зрение
- •Обзор методов детектирования объектов
- •Эмпирические методы
- •Методы характерных инвариантных признаков
- •Распознавание с помощью шаблонов, заданных разработчиком
- •Методы обнаружения лица по внешним признакам
- •Выбор алгоритма
- •Обзор методов детектирования движения
- •1.3.1 Межкадровая разность
- •1.3.2 Базовый кадр
- •1.3.3 Методы оптического потока
- •Обзор инструментальных средств для разработки программного продукта
- •Библиотека OpenCv
- •1.4.2 Среда разработки MathWorks matlab
- •1.5 Интерфейсы последовательной передачи данных
- •2 Оборудование и аппаратная реализация
- •2.1.1 Характеристики камеры
- •Передача команд по протоколу visca
- •Получение изображения с камеры
- •Работа с портом
- •3 Анализ видеоизображения. Детектор лица
- •3.1 Постановка задачи
- •3.2 Метод Виолы-Джонса
- •3.2.1 Описание алгоритма
- •3.2.2 Схема распознавания
- •3.2.3 Признаки класса
- •3.2.4 Схема обучения
- •3.2.5 Интегральное представление изображений
- •3.2.6 Обучение
- •3.2.7 Распознавание
- •3.3 Программная реализация
- •4 Анализ видеоизображения. Слежение за лицом
- •4.1Постановка задачи
- •4.2 Метод Лукаса-Канаде
- •4.2.2 Одномерный случай
- •4.2.2 Двумерный случай
- •4.2.3 Недостатки метода
- •4.3 Выбор оптимальных параметров
- •4.4 Программная реализация алгоритма
- •5 Управление поворотом камеры
- •5.1 Постановка задачи
- •5.2 Перенацеливание на заданную точку поверхности
- •5.3 Модель принятия решений
- •6 Исследование системы
- •6.1 Оценка точности перенацеливания
- •6.2 Проверка на устойчивость к смене освещения
- •6.3 Время задержки
- •6.4 Устойчивость при частичном перекрытии объекта
- •6.5 Анализ влияния шумов
- •Заключение
- •Список литературы
- •Приложение 1. Код программы
Список литературы
1. Fisher R. CVOnline: Motion and time sequence Analysis [Электронный ресурс]. – 2002
2. Morris R. An Integrated Traffic and Pedestrian Vision System [Электронный ресурс]. – 1998
3. Вежневец В. Введение в Computer Vision [Электронный ресурс]. – 2003
4. Davies D., Palmer P., Mirmehdi M. Detection and Tracking of Very Small Low Contrast Objects [Электронный ресурс]. – 1994
5. Сойфер В.А. Компьютерная обработка изображений. Часть 2. Методы и алгоритмы. Соросовский образовательный журнал, №3, 1996, с. 110 – 121.
6. Р.Гонсалес, Р.Вудс, «Цифровая обработка изображений», ISBN 5-94836-028-8, изд-во: Техносфера, Москва, 2005. – 1072 с.
7. Козлов В. Н., Функциональный анализ, Санкт-Петербург: СПбГПУ, 2012, c. 461.
8. Тули М. Справочное пособие по цифровой электронике: Пер. с англ. — М.: Энергоатомиздат, 1990.
9. Sony BRC H900 Command List
10. Sony BRC H900 Operating Manual
11.Bechtel W. The Cardinal Mercier Lectures at the Catholic University of Louvain: An Exemplar Neural Mechanism: The Brain’s Visual Processing System. 2003
12. Программно-аппаратный комплекс AxxonNext [Электронный ресурс]. - Режим доступа: http: //www. axxonnext. com.
13. Программно-аппаратный комплекс подсчета пассажиров DL-Bus [Электронный ресурс
14. G. Yang and Thomas S. Huang. «Human face detection in a complex background. Pattern Recognition», 27(1):53–63, 1994
15. C. Kotropoulos, I. Pitas. «Acoustics, Speech, and Signal Processing», 1997. ICASSP-97, 1997 IEEE International Conference on p.2537–2540 v. 4
16. T. K. Leung, M. C. Burl, P. Perona. «Finding Faces in Cluttered Scenes Using Random Labeled Graph Matching»
17. K. C. Yow, R Cipolla, «Feature-based human face detection», Image and vision computing 15 (9),p. 713–735, 1997
18. Татаренков Д. А. Анализ методов обнаружения лиц на изображении // Молодой ученый. — 2015. — №4. — С. 270-276.
19. Lanitis, A.; Taylor, C.J.; Ahmed, T.; Cootes, T.F.; Wolfson «Image Anal. Classifying variable objects using a flexible shape model» Image Processing and its Applications, 1995., p.70–74
20. Горбунов В.М. Теория принятия решений. Учебное пособие, Томск, 2010, с.67
21. Прейко М., Устройства управления роботами: схемотехника и программирование – М.: Издательство ДМК, 2004, 202с.
Приложение 1. Код программы
Файл Mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <opencv2/core/core.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/nonfree/nonfree.hpp>
#include <opencv2/objdetect/objdetect.hpp>
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
#include "cv.h"
#include "highgui.h"
#include <stdio.h>
#include <ctype.h>
#include <QMainWindow>
#include <opencv\cv.h>
#include <iostream>
#include <stdlib.h>
#include <QDebug>
#include <algorithm>
#include <limits>
#include <time.h>
#include <math.h>
#include "myport.h"
#include <QThread>
#include "tracking.h"
#undef min
#undef max
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
IplImage* first_img;
// int add_pt;
MyPort *port422;
// CvPoint2D32f *window_center;
IplImage *image;//для детектирования лица
CvRect target;//интересующая область
CvPoint pt;
CvPoint2D32f window_center;
CvPoint2D32f prev_mass_center;
CvPoint2D32f mass_center;
bool object_moving;
float sum;
// CvPoint2D32f mass_center_next;
// CvRect face_size;
bool detect_face(IplImage *gray, CvHaarClassifierCascade *haar_cascade, CvMemStorage *mem_storage, CvRect &face_rect);
QSerialPort *serial;
QByteArray command_read;
QByteArray command;
// unsigned char camera_id;
void init(const IplImage *gray, const CvRect &face_rect);
void deinit();
bool object_tracking (IplImage *gray, CvRect &face_rect);
signals:
void send_command (QByteArray command );
private slots:
void on_pushButton_up_clicked();
void on_pushButton_down_clicked();
void on_pushButton_left_clicked();
void on_pushButton_right_clicked();
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
IplImage *prev_img;
IplImage *current_img;
IplImage *previous_pyramid;
IplImage *current_pyramid;
int count_point;
CvPoint2D32f *current_points;
CvPoint2D32f *prev_points;
char *status;
CvTermCriteria tc;
int flags;
};
#endif // MAINWINDOW_H
Файл myport.h
#ifndef MYPORT_H
#define MYPORT_H
#include <QObject>
#include <QDebug>
#include <QtSerialPort/QserialPort>//Обьявляем работу с портом
#include <QMainWindow>
#include "math.h"
#include <unistd.h>
struct Settings {//Структура с настройками порта
QString name;
// // qint32 baudRate;
// QSerialPort::DataBits dataBits;
// QSerialPort::Parity parity;
// QSerialPort::StopBits stopBits;
// QSerialPort::FlowControl flowControl;
// QSerialPort::setSettingsRestoredOnClose setSettingsRestoredOnClose;
};
class MyPort : public QObject
{
Q_OBJECT
public:
explicit MyPort(QObject *parent = 0);
~MyPort();//хз
QSerialPort thisPort;
Settings SettingsPort;
//QByteArray command;
QByteArray command_read;
unsigned char camera_id = 0x83;
float s;
signals:
void finished_Port(); //Сигнал закрытия класса
void error_(QString err);//Сигнал ошибок порта
void outPort(QString data); //Сигнал вывода полученных данных
public slots:
void ClosePort(); // Слот отключения порта
void ConnectPort(void); // Слот подключения порта
void StopMoving();
void left();
void right ();
// void Write_Settings_Port();// Слот занесение настроек порта в класс
void process_Port(); //Тело
void choose_action (float prev, float next, float window_center);
void WriteToPort(QByteArray data); // Слот от правки данных в порт
private slots:
void handleError(QSerialPort::SerialPortError error);//Слот обработки ощибок
void ReadInPort(); //Слот чтения из порта по ReadyRead
};
#endif // MYPORT_H
Файл Main.cpp
#include "mainwindow.h"
#include <QApplication>
#include <QCoreApplication>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
Файл Mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QFileDialog>
#include <QDebug>
#include <QtDebug>
#include <QString>
#include <windows.h>
#include <iostream>
using namespace std;
using namespace cv;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
/*для порта и передачи команд*/
//camera_id = 0x83;
//serial = new QSerialPort(this);
//serial->setPortName("COM1");
current_img = NULL;
prev_img = NULL;
current_pyramid = NULL;
previous_pyramid = NULL;
count_point = 0;
flags = 0;
current_points = NULL;
prev_points = NULL;
status = NULL;
object_moving=false;
sum =0;
QThread *my_thread = new QThread;//Создаем поток для порта платы
MyPort *port422 = new MyPort();//Создаем обьект по классу
port422->moveToThread(my_thread);//помешаем класс в поток
port422->thisPort.moveToThread(my_thread);//Помещаем сам порт в поток
// port422->
//Загружаем обученные данные для классификатора
CvHaarClassifierCascade *cascade_frontal_face = (CvHaarClassifierCascade *)cvLoad("D:/openCV/opencv/sources/data/haarcascades/haarcascade_frontalface_alt.xml", 0, 0, 0);
//"D:/openCV/opencv/sources/data/haarcascades/haarcascade_mcs_upperbody.xml"
if (!cascade_frontal_face)
{
qDebug()<<"Error to load model"<<endl;
close();
}
CvMemStorage *MemStorage = cvCreateMemStorage(0);
tc = cvTermCriteria(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 20, 0.03);
// connect(port422, SIGNAL(error_(QString)), this, SLOT(Print(QString)));//Лог ошибок
connect(my_thread, SIGNAL(started()),port422, SLOT(process_Port()));//Переназначения метода run
connect(port422, SIGNAL(finished_Port()), my_thread, SLOT(quit()));//Переназначение метода выход
connect(my_thread, SIGNAL(finished()),port422, SLOT(deleteLater()));//Удалить к чертям поток
connect(port422, SIGNAL(finished_Port()),my_thread, SLOT(deleteLater()));//Удалить к чертям поток
connect(this,SIGNAL(send_command(QByteArray)),port422,SLOT(WriteToPort(QByteArray)));//отправка в порт данных
//Захватываем видео (можно и с камеры) с лицами
port422->ConnectPort();
CvCapture* capture_web = cvCaptureFromCAM (0);
assert( capture_web );
if (capture_web == NULL)
{
qDebug()<<"Error to catch the camera!!!!"<<endl;
cvClearMemStorage(MemStorage);
cvRelease((void **)&cascade_frontal_face);
close();
}
cvNamedWindow("frame", 1);
// cvNamedWindow("points", 1);
IplImage *gray = NULL;
window_center = cvPoint2D32f(0.f, 0.f);
prev_mass_center = cvPoint2D32f(0.f, 0.f);
mass_center = cvPoint2D32f(0.f, 0.f);
// mass_center_next = cvPoint2D32f(0.f, 0.f);
//Прямоугольник найденного лица
CvRect face_rect = cvRect(0, 0, 0, 0);
//Control control_action;
enum detector_states //Состояния нашего детектора
{
find_object,
track_object
};
detector_states state = find_object;
IplImage *frame = cvQueryFrame(capture_web);
my_thread->start();
while(true)
{
frame = cvQueryFrame(capture_web);
if (frame == NULL)
{
qDebug()<<"Error"<<endl;
break;
}
//Вся работа ведётся на изображении в градациях серого
if (!gray)
{
gray= cvCreateImage(cvSize(frame->width, frame->height), IPL_DEPTH_8U, 1);
//CvPoint2D32f window_center = cvPoint2D32f(0.f, 0.f);
window_center.x = float(frame->width/2);
window_center.y = float(frame->height/2);
// qDebug()<<"Center x:"<<prev_mass_center.x<<endl;
// qDebug()<<"Center y:"<<prev_mass_center.y<<endl;
}
cvCvtColor(frame, gray, CV_RGB2GRAY);
//Наш примитивный автомат
switch (state)
{
case find_object: //Поиск лица
while (detect_face(gray, cascade_frontal_face, MemStorage, face_rect)==false)
{
// cvShowImage("frame", frame);
// cvShowImage("points", gray);
if (cvWaitKey(33) > 0)
break;
frame = cvQueryFrame(capture_web);
// gray= cvCreateImage(cvSize(frame->width, frame->height), IPL_DEPTH_8U, 1);
cvCvtColor(frame, gray, CV_RGB2GRAY);
}
init(gray, face_rect);
state = track_object;
break;
case track_object: //Сопровождение лица
if (!object_tracking(gray, face_rect))
{
unsigned char stop []= {0x83, 0x01, 0x06, 0x01, 0x00, 0x00, 0x03, 0x03, 0xFF};//8x 01 06 01 VV WW 03 03 FF
command.clear();
command.append((char*)stop, sizeof(stop));
send_command(command);
object_moving=false; //Лицо потеряно, деинициализируем данные сопровождения и меняем состояние
qDebug()<<"lost"<<endl;
prev_mass_center.x = NULL;
prev_mass_center.y = NULL;
deinit();
state = find_object;
}
else
{
if (prev_mass_center.x!=NULL)
{
float delta_x = mass_center.x - prev_mass_center.x;
float next = mass_center.x;
// qDebug()<<"next-prev"<<delta_x<<endl;
if (object_moving==false)//если камера неподвижна
{
sum = delta_x + sum;
if ((sum)>10)//объект движется влево
{
//if (window_center-next>0)//движется от края к центра
//break;//ничего не делаем
if ((window_center.x-next)<-30)//движется от центра к краю
{
unsigned char move_right[]= {0x83, 0x01, 0x06, 0x01, 0x03, 0x00, 0x02, 0x03, 0xFF};
command.clear();
command.append((char*)move_right, sizeof(move_right));
send_command(command);
//right();//камеру смещаем вправо
object_moving==true;
sum=0;
//qDebug()<<"next-prev"<<delta_x<<endl;
}
// qDebug()<<"next-prev"<<next-prev<<endl;
}
else if ((sum)<-10)//объект движется вправо
{
if ((window_center.x-next)>0)
{
unsigned char move_left []= {0x83, 0x01, 0x06, 0x01, 0x03, 0x00, 0x01, 0x03, 0xFF};
// 8x 01 06 01 VV WW 01 03 FF
// QByteArray command;
command.clear();
command.append((char*)move_left, sizeof(move_left));
send_command(command);
// left();//камеру смещаем влево
object_moving==true;
sum=0;
}
}
}
else if (fabs(window_center.x-next)<50)//если камера подвижна
{
unsigned char stop []= {0x83, 0x01, 0x06, 0x01, 0x00, 0x00, 0x03, 0x03, 0xFF};//8x 01 06 01 VV WW 03 03 FF
command.clear();
command.append((char*)stop, sizeof(stop));
send_command(command);
object_moving==false;
qDebug()<<"rastoyanie do centra"<<window_center.x-next<<endl;
}
}//moving (prev_mass_center.x, mass_center.x, window_center.x);
}
// }
break;
}
cvDrawRect(frame, cvPoint(face_rect.x, face_rect.y), cvPoint(face_rect.x + face_rect.width, face_rect.y + face_rect.height), cvScalar(255, 0, 0));
cvShowImage("frame", frame);
if (cvWaitKey(8) > 0)
break;
}
cvReleaseCapture(&capture_web);
cvDestroyWindow("frame");
cvDestroyWindow("points");
cvClearMemStorage(MemStorage);
cvRelease((void **)&cascade_frontal_face);
port422->ClosePort();
port422->finished_Port();
//serial->close();
// my_thread->exit();
}
MainWindow::~MainWindow()
{
delete ui;
}
bool MainWindow::detect_face(IplImage *gray, CvHaarClassifierCascade *cascade, CvMemStorage *MemStorage, CvRect &face_rect)
{
cvClearMemStorage(MemStorage);
CvSeq *faces = cvHaarDetectObjects(gray, cascade, MemStorage, 1.1, 3, CV_HAAR_FIND_BIGGEST_OBJECT|CV_HAAR_SCALE_IMAGE
, cvSize(50, 50));
// //Поиск лиц
if (!faces || !faces->total)
return false;
//Возвращаем первое найденное
face_rect = *(CvRect *)cvGetSeqElem(faces, 0);
return true;
// }
}
Файл myport.cpp
#include "myport.h"
MyPort::MyPort(QObject *parent) :
QObject(parent)
{
}
MyPort::~MyPort()
{
qDebug()<<"finish!!"<<endl;
emit finished_Port();//Сигнал о завершении работы
}
void MyPort :: process_Port(){//Выполняется при старте класса
qDebug()<<"Hello!"<<endl;
connect(&thisPort,SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(handleError(QSerialPort::SerialPortError))); // подключаем проверку ошибок порта
connect(&thisPort, SIGNAL(readyRead()),this,SLOT(ReadInPort()));//подключаем чтение с порта по сигналу readyRead()
}
void MyPort :: ConnectPort(void){//процедура подключения
thisPort.setPortName("COM6");
qDebug()<<"connecting.........."<<endl;
thisPort.setSettingsRestoredOnClose(false);
thisPort.open(QIODevice::ReadWrite);
thisPort.setBaudRate(QSerialPort::Baud9600);
thisPort.setDataBits(QSerialPort::Data8);//DataBits
thisPort.setParity(QSerialPort::NoParity);
thisPort.setStopBits(QSerialPort::OneStop);
thisPort.setFlowControl(QSerialPort::NoFlowControl);
//{
if (thisPort.isOpen()){
qDebug()<<"open"<<endl;
} else {
thisPort.close();
qDebug()<<"error to open port"<<endl;;
}
// object_moving=false;
// s =0;
// } else {
// thisPort.close();
// error_(thisPort.errorString().toLocal8Bit());
// }
}
void MyPort::handleError(QSerialPort::SerialPortError error)//проверка ошибок при работе
{
// if ( (thisPort.isOpen()) && (error == QSerialPort::ResourceError)) {
// error_(thisPort.errorString().toLocal8Bit());
// DisconnectPort();
// }
}//
void MyPort::ClosePort(){//Отключаем порт
unsigned char stop []= {camera_id, 0x01, 0x06, 0x01, 0x00, 0x00, 0x03, 0x03, 0xFF};//8x 01 06 01 VV WW 03 03 FF
QByteArray command;//command.clear();
command.append((char*)stop, sizeof(stop));
WriteToPort(command);
thisPort.waitForBytesWritten(200);
thisPort.close();
qDebug()<<"port closed!!!"<<endl;;
// if(thisPort.isOpen()){
// thisPort.close();
// error_(SettingsPort.name.toLocal8Bit() + " >> Закрыт!\r");
// }
}
void MyPort::StopMoving()
{
unsigned char stop []= {camera_id, 0x01, 0x06, 0x01, 0x00, 0x00, 0x03, 0x03, 0xFF};//8x 01 06 01 VV WW 03 03 FF
QByteArray command;//command.clear();
command.append((char*)stop, sizeof(stop));
WriteToPort(command);
}
void MyPort::ReadInPort()
{
command_read.append(thisPort.readAll());
QByteArray y = command_read.toHex();
command_read.clear();
qDebug()<<"answer"<<y<<endl;
}
void MyPort::left()
{
unsigned char move_left []= {camera_id, 0x01, 0x06, 0x01, 0x03, 0x00, 0x01, 0x03, 0xFF};
// 8x 01 06 01 VV WW 01 03 FF
QByteArray command;
command.append((char*)move_left, sizeof(move_left));
WriteToPort(command);
}
void MyPort:: right()
{
unsigned char move_right[]= {camera_id, 0x01, 0x06, 0x01, 0x03, 0x00, 0x02, 0x03, 0xFF};
//command.clear();
QByteArray command;
command.append((char*)move_right, sizeof(move_right));
WriteToPort(command);
}
void MyPort :: WriteToPort(QByteArray data){//Запись данных в порт
// if(thisPort.isOpen()){
// sleep(7) ;
thisPort.write(data);
qDebug()<<"command is written"<<endl;
thisPort.waitForBytesWritten( 200);
//}
}
Файл tracking.cpp
#include "mainwindow.h"
//слежение за лицом
bool MainWindow::object_tracking (IplImage *gray, CvRect &face_rect)
{
cvCopyImage(gray, current_img);
//Вычисление нового положения точек с помощью пирамидального алгоритма анализа оптического потока Лукаса-Канаде
cvCalcOpticalFlowPyrLK(prev_img, current_img, previous_pyramid, current_pyramid,
prev_points, current_points, count_point, cvSize(20, 20), 3, status, 0, tc, flags);
flags |= CV_LKFLOW_PYR_A_READY;
if (count_point<30)
return false;
//Удаление не найденных точек, а также вычисление координат описывающего прямоугольника
float left = std::numeric_limits<float>::max();
float top = std::numeric_limits<float>::max();
float right = std::numeric_limits<float>::min();
float bottom = std::numeric_limits<float>::min();
//Центр масс
// CvPoint2D32f mass_center = cvPoint2D32f(0.f, 0.f);
// CvPoint2D32f prev_mass_center = cvPoint2D32f(0.f, 0.f);
prev_mass_center = mass_center;
int k = 0;
for (int i = 0; i < count_point; ++i)
{
if (status[i])
{
current_points[k] = current_points[i];
if (current_points[k].x < left)
left = current_points[k].x;
if (current_points[k].x > right)
right = current_points[k].x;
if (current_points[k].y < top)
top = current_points[k].y;
if (current_points[k].y > bottom)
bottom = current_points[k].y;
mass_center.x += current_points[k].x;
mass_center.y += current_points[k].y;
++k;
}
}
count_point = k;
// MainWindow wind;
mass_center.x /= (float)count_point;
mass_center.y /= (float)count_point;
//mass_center_next = mass_center;
//Вычисление расстояния от центра масс, до ближайших сторон описывающего прямоугольника
float min_x = std::min(mass_center.x - left, right - mass_center.x);
float min_y = std::min(mass_center.y - top, bottom - mass_center.y);
//Границы описывающего прямоугольника пересчитываются с учётом полученных минимальных значений + небольшой отступ на всякий случай
left = mass_center.x - min_x - min_x / 4.f;
right = mass_center.x + min_x + min_x / 4.f;
top = mass_center.y - min_y - min_y / 4.f;
bottom = mass_center.y + min_y + min_y / 4.f;
//Удаление точек, которые не попали в новый прямоугольник
k = 0;
for (int i = 0; i < count_point; ++i)
{
if (current_points[i].x > left &&
current_points[i].x < right &&
current_points[i].y > top &&
current_points[i].y < bottom)
{
current_points[k] = current_points[i];
//Вывод точек
cvDrawCircle(gray, cvPoint((int)current_points[k].x, (int)current_points[k].y), 1, cvScalar(255, 0, 255));
++k;
}
}
count_point = k;
// printf("points_count = %i\n", count_point);//записываем сколько точек нашлось
face_rect.x = (int)left;
face_rect.y = (int)top;
face_rect.width = (int)(right - left);
face_rect.height = (int)(bottom - top);
//Смена указателей на параметры
std::swap(prev_img, current_img);
std::swap(previous_pyramid, current_pyramid);
std::swap(prev_points, current_points);
cvShowImage("points", gray);
return true;
}
Санкт-Петербург
2016
