Как научить робота видеть лица даже в облаках


голова робота
Для поездки на выставку Robotics Expo 2014, мы захотели научить нашего робота Элвина распознавать лица.
Это оказалось довольно просто — достаточно было воспользоваться готовым каскадным классификатором, а в поставке OpenCV уже есть готовые обученные классификаторы для детектирования лиц и глаз.
В итоге, наш робот Элвин стал детектировать лица и произносить приветствие.
Но этот функционал, оказывается, можно использовать и для более забавных целей — например, искать лица в облаках, как сделал Shinseungback Kimyonghun.
Для этого, несколько модифицируем пример и получим:

//
// Simple face detection (for search faces in the clouds :)
//
// https://robocraft.ru
//

#include "opencv2/opencv.hpp"

#include <iostream>
#include <stdio.h>

using namespace std;
using namespace cv;

void detectAndDisplay( Mat frame );

String face_cascade_name = "/usr/share/opencv/lbpcascades/lbpcascade_frontalface.xml";
String eyes_cascade_name = "/usr/share/opencv/haarcascades/haarcascade_eye_tree_eyeglasses.xml";
CascadeClassifier face_cascade;
CascadeClassifier eyes_cascade;
String window_name = "FaceDetection";

int counter=0;
char filename[512] = {0};

int main( void )
{
    VideoCapture capture;
    Mat frame;

    // загрузка каскада для распознавания лиц и глаз
    if( !face_cascade.load( face_cascade_name ) ) {
		printf("[!] Error loading face cascade\n");
		return -1;
	}
    if( !eyes_cascade.load( eyes_cascade_name ) ) {
		printf("[!] Error loading eyes cascade\n");
		return -1;
	}

    // начинаем захват видео
    capture.open( -1 );
    if ( ! capture.isOpened() ) {
		printf("[!] Error opening video capture\n");
		return -1;
	}

	// установка разрешения для видео
	capture.set(CV_CAP_PROP_FRAME_WIDTH, 640);
	capture.set(CV_CAP_PROP_FRAME_HEIGHT, 480);

	// цикл получения кадров с камеры
    while ( capture.read(frame) ) {
        if( frame.empty() ) {
            printf("[!] No captured frame -- Break!\n");
            break;
        }

        // обработка кадра
        detectAndDisplay( frame );

        // обработка клавиатуры
        int c = waitKey(10);
        if( (char)c == 27 ) {
			break;
		}
    }
    return 0;
}

void detectAndDisplay( Mat frame )
{
    std::vector faces;
    Mat frame_gray;

    cvtColor( frame, frame_gray, COLOR_BGR2GRAY );
    equalizeHist( frame_gray, frame_gray );

    // детектор лиц
    face_cascade.detectMultiScale( frame_gray, faces, 1.1, 2, 0, Size(80, 80) );

	printf("[i] frame %d x %d detect faces: %d\n", frame.cols, frame.rows, faces.size());

    for( size_t i = 0; i < faces.size(); i++ ) {
        Mat faceROI = frame_gray( faces[i] );
        std::vector eyes;

        // на каждом лице пробуем найти глаза
        eyes_cascade.detectMultiScale( faceROI, eyes, 1.1, 2, 0 |CASCADE_SCALE_IMAGE, Size(30, 30) );
        if( eyes.size() == 2) {
#if 0
            // отрисовка рамки вокруг лица
            Point center( faces[i].x + faces[i].width/2, faces[i].y + faces[i].height/2 );
            ellipse( frame, center, Size( faces[i].width/2, faces[i].height/2 ), 0, 0, 360, Scalar( 255, 0, 0 ), 2, 8, 0 );

            for( size_t j = 0; j < eyes.size(); j++ ) {
				// отрисовка кругов вокруг глаз
                Point eye_center( faces[i].x + eyes[j].x + eyes[j].width/2, faces[i].y + eyes[j].y + eyes[j].height/2 );
                int radius = cvRound( (eyes[j].width + eyes[j].height)*0.25 );
                circle( frame, eye_center, radius, Scalar( 255, 0, 255 ), 3, 8, 0 );
            }
#endif
			printf("[i] eyes!\n");
        }

		// сохранение в файл
		Mat roiImg;
		roiImg = frame(faces[i]);
		sprintf(filename, "face_%d.png", counter++);
		imwrite(filename, roiImg);
    }
    // показываем результат
    //imshow( window_name, frame );

}

Устанавливаем OpenCV на Raspberry Pi, подключаем модуль камеры или, как в случае с Элвином, используем web-камеру, пишем Makefile и остаётся только собрать проект и проверить работу.

Вот так и получилось, что если раньше Элвин смотрел на своё отражение в телевизоре,
робот смотрит своё отражение в телевизоре
то теперь он стоит задрав голову и смотрит в окно, в поисках человеческих лиц в облаках.
К сожалению, низкое и хмурое калининградское небо пока не показало роботу никакого подходящего кандидата 🙂

UPD 2014-12-09 Элвин смотрит в небо

Ссылки
Cascade Classifier
Cloud Face
Облака–лица. Компьютерное зрение (OpenCV) на службе человеческих фантазий

По теме
RoboCraft на HackDay #34 в Калининграде
Подключение модуля камеры к Raspberry Pi


Добавить комментарий

Arduino

Что такое Arduino?
Зачем мне Arduino?
Начало работы с Arduino
Для начинающих ардуинщиков
Радиодетали (точка входа для начинающих ардуинщиков)
Первые шаги с Arduino

Разделы

  1. Преимуществ нет, за исключением читабельности: тип bool обычно имеет размер 1 байт, как и uint8_t. Думаю, компилятор в обоих случаях…

  2. Добрый день! Я недавно начал изучать программирование под STM32 и ваши уроки просто бесценны! Хотел узнать зачем использовать переменную типа…

3D-печать AI Arduino Bluetooth CraftDuino DIY Google IDE iRobot Kinect LEGO OpenCV Open Source Python Raspberry Pi RoboCraft ROS swarm ИК автоматизация андроид балансировать бионика версия видео военный датчик дрон интерфейс камера кибервесна манипулятор машинное обучение наше нейронная сеть подводный пылесос работа распознавание робот робототехника светодиод сервомашинка собака управление ходить шаг за шагом шаговый двигатель шилд юмор

OpenCV
Робототехника
Будущее за бионическими роботами?
Нейронная сеть - введение