void MyGesture::getFingerTips(MyInputImgStruct *m){ /*** *@DOC: Gets which of the remaining Defect points are the finger tips * and returns it into the vector FingerTips **/ FingerTips.clear(); int i = 0; vector<Vec4i>::iterator d = Defects[cIdx].begin(); while(d != Defects[cIdx].end()) { Vec4i& v = (*d); int startidx = v[0]; Point ptStart(contours[cIdx][startidx]); int endidx = v[1]; Point ptEnd(contours[cIdx][endidx]); int faridx = v[2]; Point ptFar(contours[cIdx][faridx]); if(i==0){ FingerTips.push_back(ptStart); i++; } FingerTips.push_back(ptEnd); d++; i++; }//ENDOF while() if(FingerTips.size() == 0) { checkForOneFinger(m); } } //ENDOF Method: getFingerTips(MyInputImgStruct *m)
void condefects(vector<Vec4i>convexityDefectsSet, vector<Point> mycontour, Mat& drawing){ for (int cDefIt = 0; cDefIt < convexityDefectsSet.size(); cDefIt++) { int startIdx = convexityDefectsSet[cDefIt].val[0]; Point ptStart(mycontour[startIdx]); int endIdx = convexityDefectsSet[cDefIt].val[1]; Point ptEnd(mycontour[endIdx]); int defectPtIdx = convexityDefectsSet[cDefIt].val[2]; Point ptFar(mycontour[defectPtIdx]); double depth = (double)convexityDefectsSet[cDefIt].val[3] / 256.0f; // see documentation link below why this circle(drawing, ptStart, 5, CV_RGB(255, 0, 0), 2, 8); circle(drawing, ptEnd, 5, CV_RGB(255, 0, 0), 2, 8); circle(drawing, ptFar, 5, CV_RGB(255, 0, 0), 2, 8); // do something with *contour[defectPtIdx]*.. This is e.g. the defect point. } }
void MyGesture::eleminateDefects(MyInputImgStruct *m){ /*** * @DOC: Takes all the defect points into vector d. Loops through d and * measures the P2P distance between the Defect Points and decides whether * the Point will be dismissed or kept based on l>0.4lbb and Theta>85' **/ int tolerance = bRect_Height/5; float angleTol = 95; vector<Vec4i> newDefects; int startidx, endidx, faridx; vector<Vec4i>::iterator d = Defects[cIdx].begin(); while(d != Defects[cIdx].end()) { Vec4i& v = (*d); startidx = v[0]; Point ptStart(contours[cIdx][startidx]); endidx = v[1]; Point ptEnd(contours[cIdx][endidx]); faridx = v[2]; Point ptFar(contours[cIdx][faridx]); if((distanceP2P(ptStart, ptFar) > tolerance) && (distanceP2P(ptEnd, ptFar) > tolerance) && (getAngle(ptStart, ptFar, ptEnd) < angleTol)){ if(ptEnd.y > (bRect.y + bRect.height - bRect.height/4)) {/*Do Nothing*/} else if(ptStart.y > (bRect.y + bRect.height - bRect.height/4)) {/*Do Nothing*/} else { newDefects.push_back(v); } } d++; }//ENDOF While() numOfDefects = newDefects.size(); Defects[cIdx].swap(newDefects); removeRedundantEndPoints(Defects[cIdx], m); } //ENDOF Method: eleminateDefects(MyInputImgStruct *m)
void HandDetector::FindConvexityDefects(vector<Vec4i> ConvexityDefectSet, vector<Point> HandContour, Mat& LiveFrame, Point2f COM, int TiltAngle) { vector<Point> FingerTips; Point2f HandCenter; float radius; int fingers=0; //minEnclosingCircle(HandContour,HandCenter,radius); //Rect contourRect = boundingRect(HandContour); //circle(LiveFrame,HandCenter,10,CV_RGB(0,0,255),2,8); //rectangle(LiveFrame, contourRect, Scalar(0,0,255), 3); //vector<Point> palmCircle; for (int i = 0; i < ConvexityDefectSet.size(); i++) { int startId = ConvexityDefectSet[i].val[0]; Point ptStart(HandContour[startId]); int endId = ConvexityDefectSet[i].val[1]; Point ptEnd(HandContour[endId]); int farId = ConvexityDefectSet[i].val[2]; Point ptFar(HandContour[farId]); double depth = (double)((ConvexityDefectSet[i].val[3]) / 256); //for getting real pixel values //cout << "depth" << depth << endl; //display start points //circle(original,ptStart,5,CV_RGB(255,0,0),2,8); //display all end points //circle(original, ptEnd, 5, CV_RGB(255, 255, 0), 2, 8); //display all far points //circle(LiveFrame,ptFar,5,CV_RGB(255,255,0),2,8); //circle(LiveFrame, HandCenter, radius, cv::Scalar(0,255,255),2); if (depth > 10 && ptStart.y < COM.y)// { circle(LiveFrame,ptStart,5,CV_RGB(255,0,0),2,8); //circle(LiveFrame, ptStart, 4, CV_RGB(255, 0,0), 4); FingerTips.push_back(ptStart); fingers++; //palmCircle.push_back(ptStart); } } if(mMouseControl) { InitMouseControl(LiveFrame,FingerTips,COM,TiltAngle); } if(mSwipeON) { Point tempCOM; tempCOM.x = COM.x; tempCOM.y = COM.y; mSwipeGesture.SwipeInit(tempCOM, LiveFrame); } //cout<<"Fingers = "<<fingers<<endl; }
Mat CameraInteraction::Testmm(Mat frame){ vector<vector<Point> > contours; //Update the current background model and get the foreground if(backgroundFrame>0) {bg.operator ()(frame,fore);backgroundFrame--;} else {bg.operator()(frame,fore,0);} //Get background image to display it bg.getBackgroundImage(back); //Enhance edges in the foreground by applying erosion and dilation erode(fore,fore,Mat()); dilate(fore,fore,Mat()); //Find the contours in the foreground findContours(fore,contours,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_NONE); for(int i=0;i<contours.size();i++) //Ignore all small insignificant areas if(contourArea(contours[i])>=5000) { //Draw contour vector<vector<Point> > tcontours; tcontours.push_back(contours[i]); drawContours(frame,tcontours,-1,cv::Scalar(0,0,255),2); //Detect Hull in current contour vector<vector<Point> > hulls(1); vector<vector<int> > hullsI(1); convexHull(Mat(tcontours[0]),hulls[0],false); convexHull(Mat(tcontours[0]),hullsI[0],false); drawContours(frame,hulls,-1,cv::Scalar(0,255,0),2); //Find minimum area rectangle to enclose hand RotatedRect rect=minAreaRect(Mat(tcontours[0])); //Find Convex Defects vector<Vec4i> defects; if(hullsI[0].size()>0) { Point2f rect_points[4]; rect.points( rect_points ); for( int j = 0; j < 4; j++ ) line( frame, rect_points[j], rect_points[(j+1)%4], Scalar(255,0,0), 1, 8 ); Point rough_palm_center; convexityDefects(tcontours[0], hullsI[0], defects); if(defects.size()>=3) { vector<Point> palm_points; for(int j=0;j<defects.size();j++) { int startidx=defects[j][0]; Point ptStart( tcontours[0][startidx] ); int endidx=defects[j][1]; Point ptEnd( tcontours[0][endidx] ); int faridx=defects[j][2]; Point ptFar( tcontours[0][faridx] ); //Sum up all the hull and defect points to compute average rough_palm_center+=ptFar+ptStart+ptEnd; palm_points.push_back(ptFar); palm_points.push_back(ptStart); palm_points.push_back(ptEnd); } //Get palm center by 1st getting the average of all defect points, this is the rough palm center, //Then U chose the closest 3 points ang get the circle radius and center formed from them which is the palm center. rough_palm_center.x/=defects.size()*3; rough_palm_center.y/=defects.size()*3; Point closest_pt=palm_points[0]; vector<pair<double,int> > distvec; for(int i=0;i<palm_points.size();i++) distvec.push_back(make_pair(dist(rough_palm_center,palm_points[i]),i)); sort(distvec.begin(),distvec.end()); //Keep choosing 3 points till you find a circle with a valid radius //As there is a high chance that the closes points might be in a linear line or too close that it forms a very large circle pair<Point,double> soln_circle; for(int i=0;i+2<distvec.size();i++) { Point p1=palm_points[distvec[i+0].second]; Point p2=palm_points[distvec[i+1].second]; Point p3=palm_points[distvec[i+2].second]; soln_circle=circleFromPoints(p1,p2,p3);//Final palm center,radius if(soln_circle.second!=0) break; } //Find avg palm centers for the last few frames to stabilize its centers, also find the avg radius palm_centers.push_back(soln_circle); if(palm_centers.size()>10) palm_centers.erase(palm_centers.begin()); Point palm_center; double radius=0; for(int i=0;i<palm_centers.size();i++) { palm_center+=palm_centers[i].first; radius+=palm_centers[i].second; } palm_center.x/=palm_centers.size(); palm_center.y/=palm_centers.size(); radius/=palm_centers.size(); //Draw the palm center and the palm circle //The size of the palm gives the depth of the hand circle(frame,palm_center,5,Scalar(144,144,255),3); circle(frame,palm_center,radius,Scalar(144,144,255),2); //Detect fingers by finding points that form an almost isosceles triangle with certain thesholds int no_of_fingers=0; for(int j=0;j<defects.size();j++) { int startidx=defects[j][0]; Point ptStart( tcontours[0][startidx] ); int endidx=defects[j][1]; Point ptEnd( tcontours[0][endidx] ); int faridx=defects[j][2]; Point ptFar( tcontours[0][faridx] ); //X o--------------------------o Y double Xdist=sqrt(dist(palm_center,ptFar)); double Ydist=sqrt(dist(palm_center,ptStart)); double length=sqrt(dist(ptFar,ptStart)); double retLength=sqrt(dist(ptEnd,ptFar)); //Play with these thresholds to improve performance if(length<=3*radius&&Ydist>=0.4*radius&&length>=10&&retLength>=10&&max(length,retLength)/min(length,retLength)>=0.8) if(min(Xdist,Ydist)/max(Xdist,Ydist)<=0.8) { if((Xdist>=0.1*radius&&Xdist<=1.3*radius&&Xdist<Ydist)||(Ydist>=0.1*radius&&Ydist<=1.3*radius&&Xdist>Ydist)) line( frame, ptEnd, ptFar, Scalar(0,255,0), 1 ),no_of_fingers++; } } no_of_fingers=min(5,no_of_fingers); qDebug()<<"NO OF FINGERS: "<<no_of_fingers; //mouseTo(palm_center.x,palm_center.y);//Move the cursor corresponding to the palm if(no_of_fingers<4)//If no of fingers is <4 , click , else release // mouseClick(); qDebug()<<"Test"; else // mouseRelease(); qDebug()<<"Hola"; } } } if(backgroundFrame>0) putText(frame, "Recording Background", cvPoint(30,30), FONT_HERSHEY_COMPLEX_SMALL, 0.8, cvScalar(200,200,250), 1, CV_AA); // imshow("Framekj",frame); // imshow("Background",back); return frame; }