2013-06-26 3 views
2

Я использую распознавание жестов руки, используя изображение ROS, OpenCV и Kinect. Я прочитал следующее paper, в котором хранится расстояние от самых больших контуров от центра руки в одной колонке и угол (от 0 до 359) между точкой контура, центральной точкой и неподвижной точкой в ​​другом столбце biggest_contour.size() x 2 матрица. Я затем нанесен на матрице с осью Х является углом от 0 до 360 градусов, а оси у является расстоянием от центра ладони следующих образом:распознавание признака руки в Opencv

Первого пальмового изображения https://sites.google.com/site/tushardobhal/images/45.jpg и соответствующий участок: https://sites.google.com/site/tushardobhal/images/rec1.jpg

вторая фотография ладони (sites.google.com/site/tushardobhal/images/122.jpg?attredirects=0) и соответствующий ему график: plot_\m/ (sites.google.com/site/tushardobhal/images/rec5.jpg?attredirects=0)

Я хочу сравнить жесты в реальном времени с ними в базе данных. Так как я не мог понять метод Finger Earth Movers Distance, показанный в документе, я попытался выполнить сопоставление шаблонов OpenCV, которым удалось дать хорошие результаты, если только два жестова не были близки (например, показанная \ m/и позы с двумя пальцами). Может ли кто-нибудь сказать мне хороший алгоритм для сравнения двух созданных выше матриц ориентации и расстояния. Это похоже на сопоставление гистограмм? Хотя я также пробовал метод EMD OpenCV, но он не дал хорошего результата.

Вот моя версия кода OpenCV, которая обнаруживает жесты в статических изображениях. Тем не менее, я делаю распознавание жестов в реальном времени. Я использую только версию кода OpenCV, чтобы проверить, работает ли мой алгоритм со статическими изображениями.

#include <opencv/cv.h> 
#include <opencv2/core/core.hpp> 
#include <opencv2/highgui/highgui.hpp> 
#include <iostream> 
#include <math.h> 

using namespace cv; 
using namespace std; 

class histogram1D { 

public: 

Mat getCon(Mat m) 
{ 
    vector<vector<Point> > cont; 
    double area, max = 0; 
    int x =0; 
    findContours(m,cont,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_NONE); 
    for(int i=0;i<cont.size();i++) 
    { 
     area = contourArea(cont[i]); 
     if(area>max) 
      { 
       max = area; 
       x=i; 
      } 
    } 
    Mat c(m.size(), m.type(), Scalar(0)); 
    drawContours(c, cont, x, Scalar(255), 1); 
    Rect rect = boundingRect(cont[x]); 
    Point cen(rect.x+rect.width/2, rect.y+(0.75*rect.height)); 

    float rad = sqrt(pow(rect.width/2, 2) + pow(rect.height/2, 2)); 

    Mat sig(cont[x].size(), 2, CV_32F, Scalar(0)); 
    for(int i = 0; i < cont[x].size(); i++) 
    { 
     float dis = norm(cont[x][i] - cen)/(rad); 
     //if(dis <= 1.0) 
     // dis = 0; 
     sig.at<float>(i,0) = dis; 
     double a1 = atan2(cont[x][i].y - cen.y, cont[x][i].x - cen.x); 
     double a2 = atan2(rect.y + rect.height - cen.y, rect.x - cen.x); 
     double a = a1 - a2; 
     if(a<0) a = (2*CV_PI) + a; 
     if(a > 2*CV_PI) a = a - 2*CV_PI; 
     sig.at<float>(i,1) = a/(2*CV_PI); 
    } 
    //Sorting it according to increasing order of angles 
    for(int i = 0; i < sig.rows; i++) 
    { 
     for(int j = 0; j < sig.rows-1; j++) 
     { 
      if(sig.at<float>(j,1) > sig.at<float>(j+1,1)) 
      { 
       float temp = sig.at<float>(j,0); 
       sig.at<float>(j,0) = sig.at<float>(j+1,0); 
       sig.at<float>(j+1,0) = temp; 

       float tem = sig.at<float>(j,1); 
       sig.at<float>(j,1) = sig.at<float>(j+1,1); 
       sig.at<float>(j+1,1) = tem; 
      } 
     } 
    } 
    return sig; 
} 


Mat getRec(Mat hi) 
{ 
    Mat rec(hi.rows, 360, CV_8U, Scalar(0)); 
    for(int i =0; i<hi.rows;i++) 
    { 
     line(rec,Point(hi.at<float>(i,1)*360, 0),Point(hi.at<float>(i,1)*360,hi.at<float>(i,0)*hi.rows*0.5),Scalar::all(255)); 

    } 
    flip(rec,rec,0); 
    return rec; 
} 


double getDist(Mat sig1, Mat sig2) 
{ 
    double d; 
    int size1, size2, f=0; 
    if(sig1.rows<sig2.rows) 
    { size1 = sig1.rows; size2 = sig2.rows;f = 0;} 
    else 
    { size1 = sig2.rows; size2 = sig1.rows; f= 1;} 

    /*for(int i = 0; i < size1; i++) 
    { 
     d += fabs((sig1.at<float>(i,0)) - (sig2.at<float>(i,0))); 
    } 
    for(int i = size1; i < size2; i++) 
    { 
     if(f==0) 
     d += (sig2.at<float>(i,0)); 
     if(f==1) 
     d += (sig1.at<float>(i,0)); 
    } 

    return d;*/ 
    Mat res; 
    if(f==0) 
    { 
     int r = sig2.rows - sig1.rows + 1; 
     int c = 1; 
     res.create(c, r, CV_32FC1); 
     matchTemplate(sig2, sig1, res, CV_TM_CCORR_NORMED); 
    } 
    else 
    { 
      int r = sig1.rows - sig2.rows + 1; 
      int c = 1; 
      res.create(r, c, CV_32FC1); 
      matchTemplate(sig1, sig2, res, CV_TM_CCORR_NORMED); 
    } 

    minMaxLoc(res, NULL, &d, NULL, NULL, Mat()); 

    return d; 

} 
}; 

int main() 
{ 
    Mat im1 = imread("131.jpg",CV_LOAD_IMAGE_GRAYSCALE); 
    Mat im2 = imread("145.jpg",CV_LOAD_IMAGE_GRAYSCALE); 
    Mat im3 = imread("122.jpg",CV_LOAD_IMAGE_GRAYSCALE); 
    Mat im5 = imread("82.jpg",CV_LOAD_IMAGE_GRAYSCALE); 


    if (im1.empty()) 
    { 
     cout << "Cannot load image!" << endl; 
    waitKey(); 
     return -1; 
    } 


histogram1D h; 
    resize(im1, im1, Size(80,120)); 
    resize(im2, im2, Size(80,120)); 
    resize(im3, im3, Size(80,120)); 
    resize(im5, im5, Size(80,120)); 


    blur(im1, im1, Size(3,3)); 
    blur(im2, im2, Size(3,3)); 
    blur(im3, im3, Size(3,3)); 
    blur(im5, im5, Size(3,3)); 


    Mat hi1 = h.getCon(im1); 
    Mat rec1 = h.getRec(hi1); 
    //FileStorage fs("test.yml", FileStorage::WRITE); 
    //fs << "hi" << hi; 


    Mat hi2 = h.getCon(im2); 
    Mat rec2 = h.getRec(hi2); 

    Mat hi3 = h.getCon(im3); 
    Mat rec3 = h.getRec(hi3); 

    Mat hi5 = h.getCon(im5); 
    Mat rec5 = h.getRec(hi5); 




    /*float ch = EMD(hi1, hi1, CV_DIST_L1); 
    float ch1 = EMD(hi1, hi2, CV_DIST_L1); 
    float ch2 = EMD(hi1, hi3, CV_DIST_L1); 
    float ch3 = EMD(hi1, hi5, CV_DIST_L1);*/ 

    float ch = h.getDist(hi1, hi1); 
    float ch1 = h.getDist(hi1, hi2); 
    float ch2 = h.getDist(hi1, hi3); 
    float ch3 = h.getDist(hi1, hi5); 

    /*double ch = comparehist(hi1, hi1, CV_COMP_CsigQR); 
    double ch1 = comparehist(hi1, hi2, CV_COMP_CsigQR); 
    double ch2 = comparehist(hi1, hi3, CV_COMP_CsigQR); 
    double ch3 = comparehist(hi1, hi5, CV_COMP_CsigQR);*/ 

    // imshow("rec1.jpg", rec1); imshow("rec2.jpg", rec2); imshow("rec3.jpg", rec3); imshow("rec5.jpg", rec5); 
     cout<<ch<<" "<<ch1<<" "<<ch2<<" "<<ch3<<endl; 



    waitKey(); 
return(0); 
} 
+0

В чем ваш вопрос? Похоже, ваш метод работает хорошо. – Aurelius

+0

Спасибо за редактирование. Нет, это плохо работает. Он работает, если я использую совершенно разные жесты, но не удается, когда похожие жесты сравниваются, особенно в режиме реального времени. –

+0

Итак, я хочу знать хороший алгоритм для сравнения матрицы типа гистограммы ориентации, такой как FEMD, приведенной в упомянутой статье, о которой я не мог понять –

ответ

0

За то, что я понимаю, дело в том, что EMD позволяет частичное соответствие поэтому вам aren't быть в состоянии идентифицировать 2 подобных жестов (ваш 2º жест подкрепляются как подмножество первого (индекс и мизинец имеет расстояние между 0 2 изображением), а о том, как реализовать я ДВО пытаюсь сделать это слишком

0

Я использовал подобный подход объясняется в этом paper:.

с первого изображения , вы создаете контур и сохраняете их как шаблоны, тогда вы вычисляете разницу между каждой точкой контура с точкой шаблона. Вы добавляете ошибку/шаблон, вы выбираете шаблон с наименьшей ошибкой (или ничего)

это приложение распознавателя жестов $ 1, но используется иначе, если вы ищете youtube, вы найдете видеоролик об этом.