Перейти к содержимому
Compvision.ru
privetvision

ПО управления компьютером жестами (Застрял на контурах)

Recommended Posts

Выбрал темку интересную: ПО управления компьютером жестами (например показываем два пальца и делаем что-то в ПК, показываем средний палец и ПК выключается). Но застрял, прошу помочь! Дело такое, планируется использовать несколько камер, как я понял для стереозрения и возможности отсечения задних объектов, путем получения их координат. Но сейчас задача стоит такая (пока работа с одной камерой):
1. Получить с нее кадры в потоке;
2. Перевести в CIELAB формат;
3. Поиграться с ползунками L, A, B и выделить цвет кожи;
4. Дальше мне сказали сделать точки на пальцах или что-то в этом роде. 
 
post-7361-0-00283600-1429999624_thumb.pn
Проблемы появились на 3 пункте, на скриншоте видно, что такого же цвета и книги сзади и дверь (правда на скриншоте она как по волшебству решила стать черной, хотя до этого была частями белой), в целом не получается выделить только руку. Подозреваю, что это не проблемой будет, при использовании нескольких камер или я не прав?
 
Каким образом делать детектирование точек на пальцах мне не сказали, побегав по мануалам, пришел к выводу, что надо с контурами возиться, сделал поиск контуров, выбрал самый большой и он цепляется за другие объекты такого же цвета (на скрине видно).
 
При дневном свете, параметры для порога LAB совершенно другие приходится искать, освещенность сильно играет роль. 
 
Вопрос как все-таки победить 3 пункт, чтобы нормально выделяло цвет кожи только и не цепляло остальное. И второй вопрос, в каком направлении двигаться, чтобы получить точки на пальцах? (опять же я не понимаю зачем, точнее что дальше после точек).
 
Код:

Mat vFrame, vFrameLab, vFrameLabSecond;
    vector < vector<Point> > vContours;
    vector<Vec4i> vHierarchy;
    Rect vRect;
 
mCapture >> vFrame;
 
 
    cvtColor( vFrame, vFrameLab, CV_BGR2Lab );
    cvtColor( vFrame, vFrameGRAY, CV_BGR2GRAY ); // этот кадр не используется
 
// размытие по гауссу 
GaussianBlur( vFrameLab, vFrameLab, cv::Size( mGaussBlur, mGaussBlur ), 0 );
 
// диапазон для каналов
    inRange( vFrameLab, cv::Scalar(mLmin, mAmin, mBmin), cv::Scalar(mLmax, mAmax, mBmax), vFrameLab );
    inRange( vFrameGRAY, cv::Scalar(mLmin, mAmin, mBmin), cv::Scalar(mLmax, mAmax, mBmax), vFrameGRAY );
 
 
// поиск контуров
    findContours( vFrameLab.clone(), vContours, vHierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE );
 
 
    // сортировка контуров
    std::sort( vContours.begin(), vContours.end(), compareContourAreas);
 
// аппроксимация самого большого контура
    approxPolyDP(Mat(vContours[vContours.size()-1]), vContours[vContours.size()-1], 3, true);
 
 
// рисуем самый большой контур на оригинальный кадр
    Scalar vColor( 120, 0, 255 );
    drawContours( vFrame, vContours, vContours.size()-1, vColor, CV_FILLED, 8, vHierarchy );
    vRect = boundingRect(vContours[vContours.size()-1]);
 
 
 
    // Прямоугольная обводка контура 
    rectangle(vFrame, vRect,  Scalar(0,255,0), 1, 8, 0);
 
    ui->openCVviewerOriginal->showImage( vFrame );
    ui->openCVviewerLab->showImage( vFrameLab );
    ui->openCVviewerGRAY->showImage( vFrameGRAY );

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Я слабоват в opencv и в математике в целом, но сегодня такая идея пришла. Допустим удалось выделить руку по цвету, дальше выделить прямоугольником кисть руки и посчитать гистограмму яркости, по идеи там будет график подъема и резкого падения.

post-7361-0-60027600-1430040134_thumb.pn

Вот эти точки как раз и нужны.

Потом построить по точкам многоугольник  и  определять жест по количеству ребер этого многоульника (или по кол-ву точек). Что-то вроде этого.

 final_result.png

 

Просьба подсказать, в том ли направлении я иду? 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Может будет полезно пройтись по ссылкам отсюда:

http://www.intorobotics.com/9-opencv-tutorials-hand-gesture-detection-recognition/

 

Плюс рассмотреть вариант а ASM (Active shape models), одна из самых популярных библиотек STASM, вроде видел в последней версии модель руки, но не пробовал. С лицом справляется довольно неплохо. Таких библиотек сейчас в инете много VOTR, CLM tracker-ы, просто погуглите в этом направлении.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Может будет полезно пройтись по ссылкам отсюда:

http://www.intorobotics.com/9-opencv-tutorials-hand-gesture-detection-recognition/

 

Плюс рассмотреть вариант а ASM (Active shape models), одна из самых популярных библиотек STASM, вроде видел в последней версии модель руки, но не пробовал. С лицом справляется довольно неплохо. Таких библиотек сейчас в инете много VOTR, CLM tracker-ы, просто погуглите в этом направлении.

По ссылкам прошелся, вот этот пример более менее по коду приятен.

http://s-ln.in/2013/04/18/hand-tracking-and-gesture-detection-opencv/

 

ASM, STASM это ведь все готовые библиотеки? Мне все-таки самому желательно делать, без читов.

 

Пока понял, что надо научиться выделять выпуклый многоугольник по руке, но пока не ясно как.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Да-да, вчера читал)) В этой презентации меня насторожил один момент, каким образом применяется адаптивная бинаризация для CIELAB формата? Пробовал не вышло.

 

По поводу контуров нашел вот эту статейку 

http://locv.ru/wiki/8.6.5_Выпуклость_контура_и_дефекты_выпуклости

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Вот, откопал у себя манускрипт smile.png

Может как начальный этап пригодится.
 

#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <ctype.h>
#include <time.h> 

#include <opencv2\imgproc\imgproc.hpp>
#include <opencv2\video\tracking.hpp>
#include <opencv2\highgui\highgui.hpp>

using namespace cv;
using namespace std;

// Detect Skin from YCrCb
Mat DetectYCrCb(Mat img, Scalar min, Scalar max) {
    Mat skin;
    cvtColor(img, skin, cv::COLOR_BGR2YCrCb);
    inRange(skin, min, max, skin);
    Mat rect_12 = getStructuringElement(cv::MORPH_RECT, Size(12,12) , Point(6,6));
    erode(skin, skin, rect_12,Point(),1);
    Mat rect_6 = getStructuringElement(cv::MORPH_RECT, Size(6,6) , Point(3,3));
    dilate(skin,skin,rect_6,Point(),2);
    return skin;    
}

void DetectContour(Mat img){
    Mat drawing = Mat::zeros( img.size(), CV_8UC3 );
    vector<vector<Point> > contours;
    vector<vector<Point> > bigContours;
    vector<Vec4i> hierarchy;

    findContours(img,contours, hierarchy, cv::RETR_LIST, cv::CHAIN_APPROX_SIMPLE, Point());

    if(contours.size()>0)
    {
        vector<std::vector<int> >hull( contours.size() );
        vector<vector<Vec4i>> convDef(contours.size() );
        vector<vector<Point>> hull_points(contours.size());
        vector<vector<Point>> defect_points(contours.size());


        for( int i = 0; i < contours.size(); i++ )
        {
            if(contourArea(contours[i])>5000)
            {
                convexHull( contours[i], hull[i], false );
                convexityDefects( contours[i],hull[i], convDef[i]);

                for(int k=0;k<hull[i].size();k++)
                {           
                    int ind=hull[i][k];
                    hull_points[i].push_back(contours[i][ind]);
                }

                for(int k=0;k<convDef[i].size();k++)
                {           
                    if(convDef[i][k][3]>20*256) // filter defects by depth
                    {
                    int ind_0=convDef[i][k][0];
                    int ind_1=convDef[i][k][1];
                    int ind_2=convDef[i][k][2];
                    defect_points[i].push_back(contours[i][ind_2]);
                    cv::circle(drawing,contours[i][ind_0],5,Scalar(0,255,0),-1);
                    cv::circle(drawing,contours[i][ind_1],5,Scalar(0,255,0),-1);
                    cv::circle(drawing,contours[i][ind_2],5,Scalar(0,0,255),-1);
                    cv::line(drawing,contours[i][ind_2],contours[i][ind_0],Scalar(0,0,255),1);
                    cv::line(drawing,contours[i][ind_2],contours[i][ind_1],Scalar(0,0,255),1);
                    }
                }

                drawContours( drawing, contours, i, Scalar(0,255,0), 1, 8, vector<Vec4i>(), 0, Point() );
                drawContours( drawing, hull_points, i, Scalar(255,0,0), 1, 8, vector<Vec4i>(), 0, Point() );
            }
        }
    }
    imshow( "Hull demo", drawing );
}


int main( int argc, char** argv )
{
    Mat frame,copyFrame;
    VideoCapture capture(0);
    namedWindow( "Hull demo", cv::WINDOW_AUTOSIZE );
    namedWindow( "Video", cv::WINDOW_AUTOSIZE );
    if (capture.isOpened()){
        while(true)
        {
            capture >> frame;
            imshow( "Video", frame);

            Mat skinYCrCb = DetectYCrCb(frame,Scalar(0, 100, 80), Scalar(255, 185, 135));

            DetectContour(skinYCrCb);

            int c = waitKey(10);
            if( (char)c == 27 ) 
            { 
                break; 
            } 
        }
    }
    cv::destroyAllWindows();
    return 0;
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте учётную запись или войдите для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать учётную запись

Зарегистрируйтесь для создания учётной записи. Это просто!

Зарегистрировать учётную запись

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас


  • Сейчас на странице   0 пользователей

    Нет пользователей, просматривающих эту страницу

×