1- #include " stdafx.h"
21#include " version.h"
32
43#include " Util.h"
54#include " Hand.h"
65#include " Visualizer.h"
6+ #include " HandClassifier.h"
77
88// limited to file scope
99namespace {
@@ -54,8 +54,8 @@ namespace {
5454
5555namespace ark {
5656
57- // Initialize the SVM hand classifier
58- classifier::HandClassifier & Hand::handClassifier = classifier::SVMHandClassifier (SVM_PATHS);
57+ // Initialize the SVM hand validator
58+ static classifier::SVMHandValidator & handValidator = classifier::SVMHandValidator (SVM_PATHS);
5959
6060 Hand::Hand () : FrameObject() { }
6161
@@ -93,30 +93,18 @@ namespace ark {
9393 }
9494 }
9595
96- bool Hand::checkForHand ()
96+ bool Hand::checkForHand ()
9797 {
9898#ifdef DEBUG
9999 cv::Mat visual = cv::Mat::zeros (fullMapSize.height , fullMapSize.width , CV_8UC3);
100+ cv::Mat defectVisual = cv::Mat::zeros (fullMapSize.height , fullMapSize.width , CV_8UC3);
100101#endif
101102 if (points->size () == 0 || num_points == 0 ) {
102103 return false ;
103104 }
104105
105106 computeContour (xyzMap, points.get (), points_xyz.get (), topLeftPt, num_points);
106107
107- // recompute convex hull based on new contour
108- convexHull.clear (); getConvexHull ();
109-
110- // Begin by computing defects
111- std::vector<cv::Vec4i> defects;
112-
113- if (indexHull.size () > 3 )
114- {
115- std::vector<int > tmpHull;
116-
117- cv::convexityDefects (contour, indexHull, defects);
118- }
119-
120108 // ** Find center of contour **
121109 Point2i centroid = findCenter (contour) - topLeftPt;
122110
@@ -125,7 +113,7 @@ namespace ark {
125113
126114 // Find radius and center point of largest inscribed circle above center
127115 Vec3f topPt = util::averageAroundPoint (xyzMap, (*points)[0 ] - topLeftPt,
128- params->xyzAverageSize );
116+ params->xyzAverageSize );
129117
130118 // radius of largest inscribed circle
131119 double cirrad;
@@ -243,6 +231,10 @@ namespace ark {
243231 return false ;
244232 }
245233
234+ if (contour[wristL].x > contour[wristR].x ) {
235+ std::swap (wristL, wristR);
236+ }
237+
246238 wristL_ij = contour[wristL];
247239 wristR_ij = contour[wristR];
248240 wristL_xyz = util::averageAroundPoint (xyzMap,
@@ -268,7 +260,54 @@ namespace ark {
268260 return false ;
269261 }
270262
263+ // (finished detecting wrist)
264+
265+ // ** Remove everything below wrist **
266+
267+ std::vector<Point2i> aboveWristPointsIJ;
268+ std::vector<Vec3f> aboveWristPointsXYZ;
269+
270+ if (wristR_ij.x != wristL_ij.x ) {
271+ double slope = (double )(wristR_ij.y - wristL_ij.y ) / (wristR_ij.x - wristL_ij.x );
272+
273+ for (int i = 0 ; i < num_points; ++i) {
274+ const Point2i & pt = (*points)[i];
275+ double y_hat = wristL_ij.y + (pt.x - wristL_ij.x ) * slope;
276+
277+ Vec3f & vec = xyzMap.at <Vec3f>(pt - topLeftPt);
278+
279+ if (pt.y > y_hat) {
280+ vec = 0 ;
281+ }
282+ else {
283+ aboveWristPointsIJ.push_back (pt);
284+ aboveWristPointsXYZ.push_back (vec);
285+ }
286+ }
287+ }
288+
289+ num_points = (int )aboveWristPointsIJ.size ();
290+ points->swap (aboveWristPointsIJ);
291+ points_xyz->swap (aboveWristPointsXYZ);
292+
293+ // recompute contour
294+ computeContour (xyzMap, points.get (), points_xyz.get (), topLeftPt, num_points);
295+
271296 // ** Detect fingers **
297+
298+ // recompute convex hull based on new contour
299+ convexHull.clear (); getConvexHull ();
300+
301+ // compute defects
302+ std::vector<cv::Vec4i> defects;
303+
304+ if (indexHull.size () > 3 )
305+ {
306+ std::vector<int > tmpHull;
307+
308+ cv::convexityDefects (contour, indexHull, defects);
309+ }
310+
272311 // sort all defects found by angle
273312 DefectComparer comparer (contour, defects, this ->palmCenterIJ );
274313 std::sort (defects.begin (), defects.end (), comparer);
@@ -290,19 +329,11 @@ namespace ark {
290329 // contains info about the defect
291330 cv::Vec4i defect = defects[i];
292331
293- // skip if defect is under wrist
294- if (direction == -1 ) {
295- if (wristL <= wristR) {
296- if (defect[2 ] >= wristL && defect[2 ] <= wristR) continue ;
297- }
298- else if (defect[2 ] <= wristR || defect[2 ] >= wristL) continue ;
299- }
300- else {
301- if (wristL <= wristR) {
302- if (defect[2 ] <= wristL || defect[2 ] >= wristR) continue ;
303- }
304- else if (defect[2 ] >= wristR && defect[2 ] <= wristL) continue ;
305- }
332+ #ifdef DEBUG
333+ cv::line (defectVisual, contour[defects[i][0 ]], contour[defects[i][2 ]], cv::Scalar (0 , 255 , 0 ));
334+ cv::line (defectVisual, contour[defects[i][1 ]], contour[defects[i][2 ]], cv::Scalar (0 , 0 , 255 ));
335+ cv::circle (defectVisual, contour[defects[i][2 ]], 5 , cv::Scalar (255 ,255 ,255 ), 2 );
336+ #endif
306337
307338 // point on convex hull where defect begins. fingertip candidate
308339 Point2i start = contour[defect[0 ]] - topLeftPt;
@@ -397,6 +428,8 @@ namespace ark {
397428 cv::Scalar (0 , 255 , 255 ), 2 );
398429 cv::rectangle (visual, wristL_ij - Point2i (10 , 10 ), wristL_ij + Point2i (10 , 10 ),
399430 cv::Scalar (0 , 255 , 255 ), 2 );
431+
432+ cv::imshow (" [Hand Defects Debug]" , defectVisual);
400433#endif
401434
402435 // select fingers from candidates
@@ -684,20 +717,28 @@ namespace ark {
684717 cv::imshow (" [Hand Debug]" , visual);
685718#endif
686719
720+ size_t nFin = this ->fingersIJ .size ();
721+
687722 // report not hand if there are too few/many fingers
688- if (this -> fingersIJ . size () > 6 || this -> fingersIJ . size () < 1 ) {
723+ if (nFin > 6 || nFin < 1 ) {
689724 return false ;
690725 }
726+
727+ // find dominant direction
728+
729+ if (nFin > 0 ) {
730+ Point2f fingCen = this ->fingersIJ [nFin / 2 ];
731+ if (nFin % 2 == 0 ) {
732+ fingCen += Point2f (this ->fingersIJ [nFin / 2 - 1 ]);
733+ fingCen /= 2 .0f ;
734+ }
691735
692- // Final SVM check
693- if (params->handUseSVM && handClassifier.isTrained ()) {
694- this ->isHand = true ;
695-
696- std::vector<double > features =
697- classifier::HandClassifier::extractHandFeatures (*this , xyzMap, topLeftPt, 1.0 ,
698- fullMapSize.width );
736+ this ->dominantDir = fingCen - Point2f (this ->palmCenterIJ );
737+ }
699738
700- this ->svmConfidence = handClassifier.classify (features);
739+ // Final SVM check
740+ if (params->handUseSVM && handValidator.isTrained ()) {
741+ this ->svmConfidence = handValidator.classify (*this , xyzMap, 32 , 5 , topLeftPt, fullMapSize.width );
701742 if (this ->svmConfidence < params->handSVMConfidenceThresh ) {
702743 // SVM confidence value below threshold, reverse decision & destroy the hand instance
703744 return false ;
@@ -868,7 +909,12 @@ namespace ark {
868909 return circleRadius;
869910 }
870911
871- double Hand::getSVMConfidence () const
912+ Point2f Hand::getDominantDirection () const
913+ {
914+ return dominantDir;
915+ }
916+
917+ float Hand::getSVMConfidence () const
872918 {
873919 return svmConfidence;
874920 }
0 commit comments