chronojump r415 - in trunk: . src/angle



Author: xaviblas
Date: Thu Aug 28 14:10:28 2008
New Revision: 415
URL: http://svn.gnome.org/viewvc/chronojump?rev=415&view=rev

Log:
kneeAngle: lots of optimizations (v1.1)


Modified:
   trunk/changelog.txt
   trunk/src/angle/kneeAngle.cpp

Modified: trunk/changelog.txt
==============================================================================
--- trunk/changelog.txt	(original)
+++ trunk/changelog.txt	Thu Aug 28 14:10:28 2008
@@ -1,5 +1,8 @@
 CHRONOJUMP DETAILED CHANGELOG:
 
+28 ago 2008
+	kneeAngle: lots of optimizations (v1.1)
+
 26 ago 2008 (2)
 	0.7.5.1
 	added Logibrick people to authors. Improved about dialog.

Modified: trunk/src/angle/kneeAngle.cpp
==============================================================================
--- trunk/src/angle/kneeAngle.cpp	(original)
+++ trunk/src/angle/kneeAngle.cpp	Thu Aug 28 14:10:28 2008
@@ -15,21 +15,23 @@
  *  along with this program; if not, write to the Free Software
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
- * Coded by:
+ * Coded by (v.1.0):
  * Sharad Shankar & Onkar Nath Mishra
  * http://www.logicbrick.com/
  * 
- * further informations by:
+ * Updated by:
  * Xavier de Blas 
  * xaviblas gmail com
+ *
+ * version: 1.1
+ *
  */
 
 /*
  * This is suitable to detect minimum angle on the flexion previous to a CMJ jump
- * samples working:
- * http://mail.gnome.org/archives/chronojump-list/2008-July/jpgHJAmzYjAYc.jpg
- * http://mail.gnome.org/archives/chronojump-list/2008-July/jpgs187Y8WoDS.jpg
- * http://mail.gnome.org/archives/chronojump-list/2008-July/jpgHjtofoGHLo.jpg
+ * check samples working:
+ * http://vimeo.com/album/28658
+ *
  * more info here:
  * http://mail.gnome.org/archives/chronojump-list/2008-July/msg00005.html
  */
@@ -38,9 +40,12 @@
  * CONSTRAINTS:
  * 
  * -Person have to be "looking" to the right of the camera
- * -Camera have to be fixed and the legs of the person will be most of the image
- * -Black trousers should be use
- * -Initially user should stand straight for 1-2 frames so that some values can be set. 
+ * -Camera view area will be (having jumper stand up):
+ *   below: the foot preferrably has not to be shown
+ *   above: the top part of the image will be the right hand (fully included)
+ * -Black trousers should be use. Rest of the clothes should not be black.
+ * -White background is highly recommended
+ * -Initially user should stand straight for 1-2 frames so that some values can be set by the program. 
  *
  */
 
@@ -109,6 +114,16 @@
 #include <string>
 using namespace std;
 
+//config variables
+bool showContour = true;
+bool debug = false;
+int playDelay = 5; //milliseconds between photogrammes wen playing. Used as a waitkey. 
+			//not put values lower than 5 or the enter when executing will be the first pause
+			//eg: 5 (fast) 1000 (one second each photogramme)
+int playDelayFoundAngle = 150; //as above, but used when angle is found. 
+				//Useful to see better the detected angle when something is detected
+				//recommended values: 50 - 200
+
 
 /*
  * takes as input arguement the bounding rectangle of the largest contour and the image containing the bounding rectangle
@@ -121,13 +136,14 @@
 	CvPoint pt;
 	pt.x =0;pt.y=0;
 	int starty = roirect.y;
-	int endy = starty + roirect.height*2/3;
+	int endy = starty + roirect.height*2/3; /* meu: why 2/3 */
 	CvMat *srcmat,src_stub;
 	srcmat = cvGetMat(img,&src_stub);
 	uchar *srcdata = srcmat->data.ptr;
 	int width = img->width;
 	int minx = img->width;
 	int miny = img->height;
+
 	for(int y=starty;y<endy;y++)
 	{
 		uchar *srcdataptr = srcdata + y*img->width;
@@ -147,8 +163,8 @@
 	}
 	pt.x = minx;
 	pt.y = miny;
-	return pt;
 
+	return pt;
 }
 
 /*
@@ -161,7 +177,10 @@
 {
 	CvPoint pt;
 	pt.x = 0; pt.y = 0;
-	int endy = roirect.y+roirect.height*9/10;
+	
+	//int endy = roirect.y+roirect.height*9/10; //this is ok if shoes or platform is shown in standup image
+	int endy = roirect.y+roirect.height;
+
 	CvMat *srcmat,src_stub;
 	srcmat = cvGetMat(img,&src_stub);
 	uchar *srcdata = srcmat->data.ptr;
@@ -186,6 +205,7 @@
 	}
 	pt.x = maxx;
 	pt.y = maxy;
+
 	return pt;
 }
 
@@ -199,7 +219,16 @@
 {
 	CvPoint pt;
 	pt.x = 0; pt.y = 0;
-	int endy = roirect.y+roirect.height*9/10;
+	
+	
+	/* if foot is in the image, is better to try to avoid it capturing above, if not then capture all
+	 * maybe force user to capture without foot, or ask and put a boolean
+	 */
+
+	//int endy = roirect.y+roirect.height*9/10; //this is ok if shoes or platform is shown in standup image
+	int endy = roirect.y+roirect.height;
+	
+
 	CvMat *srcmat,src_stub;
 	srcmat = cvGetMat(img,&src_stub);
 	uchar *srcdata = srcmat->data.ptr;
@@ -229,6 +258,7 @@
 	pt.y = miny;
 	return pt;
 }
+
 /*
  * takes input argument as the gray form of input frame and a temp image
  * Returns the bounding rectangle of the contour having maximum height
@@ -260,116 +290,366 @@
 		}
 		cvDrawContours(temp,src_contour,cvScalarAll(255),cvScalarAll(255),0,-1);
 	}
+
+	//show temp image (contour) little
+	if(showContour) {
+		cvNamedWindow("temp",1);
+		cvResize(temp, temp, CV_INTER_LINEAR);
+
+		double scale = 4;
+		IplImage* tempSmall = cvCreateImage( cvSize( cvRound (img->width/scale), cvRound (img->height/scale)), 8, 1 );
+		cvResize( temp, tempSmall, CV_INTER_LINEAR );
+
+		cvShowImage("temp", tempSmall);
+	}
+	
 	cvReleaseMemStorage(&storage);
 	cvReleaseImage(&tempcopy);
 	return maxrect;
 }
 
+CvPoint FixHipPoint1(IplImage* img, CvPoint hip, CvPoint knee)
+{
+	CvPoint ptHK;
+	ptHK.x =0;ptHK.y=0;
+	CvMat *srcmat,src_stub;
+	srcmat = cvGetMat(img,&src_stub);
+	uchar *srcdata = srcmat->data.ptr;
+	int width = img->width;
+
+	//find at 3/2 of hip (surely under the hand)
+	int y=hip.y*.66 + knee.y*.33;
+
+	uchar *srcdataptr = srcdata + y*img->width;
+	int startX = 0;
+	int countX = 0;
+	bool found = false;
+	for(int x=0;x<width;x++)
+	{
+		if(srcdataptr[x] > 0)
+		{
+			if(!found) {
+				startX = x;
+				countX = x;
+				found = true;
+			}
+			countX ++;
+		}
+	}
+	ptHK.x = (startX + countX) /2;
+	ptHK.y = y;
+	
+	return ptHK;
+}
+
+CvPoint FixHipPoint2(IplImage* img, int hipFirstY, CvPoint knee, CvPoint ptHK)
+{
+			
+	/* this was hippoint in 1/3 of the leg (close to the hip but just below the hand)
+	 * now do a line from knee to this hippoint and cross this line with first hippoint and x axe
+	 * we will have the first hippoint but centered on the hip (without problems with the hand)
+	 */
+
+	CvPoint kneePrima;
+	kneePrima.x = knee.x - ptHK.x; 
+	kneePrima.y = knee.y - ptHK.y; 
+
+	/*
+	 * y = (kneePrima.y / kneePrima.x) * x + d
+	 * x = (kneePrima.x / kneePrima.y) * y - d
+	 * d = -x +(kneePrima.x / kneePrima.y) * y
+	 */
+
+	double d = -knee.x + ( (kneePrima.x / (double)kneePrima.y) * knee.y);
+
+	/*
+	 * x = (kneePrima.x / kneePrima.y) * y - d
+	 */
+	 
+	CvPoint HCenter;
+	HCenter.x =0; 
+	HCenter.y = hipFirstY;
+
+	HCenter.x = ( (kneePrima.x / (double)kneePrima.y) * HCenter.y ) - d;
+
+	if(debug) {
+		printf("hipy(%d) ",hipFirstY);
+		printf("knee(%d,%d) ",knee.x, knee.y);
+		printf("ptHK(%d,%d) ",ptHK.x, ptHK.y);
+		printf("kneePrima(%d,%d) ",kneePrima.x, kneePrima.y);
+		printf("HCenter(%d,%d) ",HCenter.x, HCenter.y);
+		printf("kneePrima x/y:%.2f ", kneePrima.x / (double)kneePrima.y);
+		printf("d:%.1f", d);
+		printf("\n");
+	}
+
+	return HCenter;
+}
+
+/* at first photogramm where knee or foot is detected (it will not be too horizontal) find it's width and use all the time to fix kneex
+ * at knee is called only done one time (because in max flexion, the back is line with the knee and there will be problems knowing knee width
+ * at foot is called all the time
+ */
+int FindWidth(IplImage* img, CvPoint kneeOrFoot)
+{
+	CvMat *srcmat,src_stub;
+	srcmat = cvGetMat(img,&src_stub);
+	uchar *srcdata = srcmat->data.ptr;
+	int width = img->width;
+
+	int y=kneeOrFoot.y;
+
+	uchar *srcdataptr = srcdata + y*img->width;
+	int countX = 0;
+	for(int x=kneeOrFoot.x-1;srcdataptr[x];x--)
+	{
+		countX ++;
+	}
+
+	return countX;;
+}
+
+double getDistance(CvPoint p1, CvPoint p2)
+{
+	return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
+}
+
+bool upperSimilarThanLower(CvPoint hipPoint, CvPoint kneePoint, CvPoint footPoint)
+{
+	double upper = getDistance(kneePoint, hipPoint); 
+	double lower = getDistance(kneePoint, footPoint);
+	double big = 0; 
+	double little = 0;
+	
+	if(upper > lower) {
+		big = upper;
+		little = lower;
+	} else {
+		big = lower;
+		little = upper;
+	}
+
+	if(debug)
+		printf("upper(%.1f), lower(%.1f), big/little (%.2f)\n",upper, lower, big/(double)little);
+
+	//if one is not n times or more bigger than the other
+	//consider that if camera hides shoes and a bit more up, 2 times is risky in a maximal flexion
+	//consider also that this data is previous to fixing
+	double n = 2.5;
+	if(big / (double)little < n)
+		return true;
+	else 
+		return false;
+}
 
 int main(int argc,char **argv)
 {
+	//TODO:
+	//add args for debug, record to file, speed, fondAngle value, ...
+	//currently this variables are global and defined at the top of the file
+	
 	if(argc < 2)
 	{
 		cout<<"Provide file location as a first argument..."<<endl;
-				exit(1);
+		exit(1);
 	}
 	CvCapture* capture = NULL;
 	capture = cvCaptureFromAVI(argv[1]);
 	if(!capture)
-    {
-        exit(0);
-    }
+	{
+		exit(0);
+	}
 	IplImage *frame=0,*frame_copy=0,*gray=0,*segmented=0,*edge=0,*temp=0,*output=0;
 	IplImage *result=0;
 	int minwidth = 0;
-	bool findangle = false;
+	
+	bool foundAngle = false; //found angle on current frame
+	bool foundAngleOneTime = false; //found angle at least one time on the video
+
 	double knee2Hip,knee2Foot,hip2Foot,theta;
-	//CvFont font;
 	string text,angle;
 	double mintheta = 360;
 	char buffer[15];
 	cvNamedWindow("frame",1);
-	for(;;)
-    {
-        frame = cvQueryFrame(capture);
-        if(!frame)
-            break;
-        if( !frame_copy )
-                frame_copy = cvCreateImage( cvSize(frame->width,frame->height),IPL_DEPTH_8U, frame->nChannels );
-        if( frame->origin == IPL_ORIGIN_TL )
-            cvCopy( frame, frame_copy, 0 );
-        else
-            cvFlip( frame, frame_copy, 0 );
-
-        if(!gray)
-        {
-        	gray = 		cvCreateImage(cvGetSize(frame),IPL_DEPTH_8U,1);
-        	segmented =	cvCreateImage(cvGetSize(frame),IPL_DEPTH_8U,1);
-        	edge =	cvCreateImage(cvGetSize(frame),IPL_DEPTH_8U,1);
-        	temp = cvCreateImage(cvGetSize(frame),IPL_DEPTH_8U,1);
-        	output = cvCreateImage(cvGetSize(frame),IPL_DEPTH_8U,1);
-        	result = cvCreateImage(cvGetSize(frame),IPL_DEPTH_8U,3);
-        }
-
-        cvSmooth(frame_copy,frame_copy,2,5,5);
-        cvCvtColor(frame_copy,gray,CV_BGR2GRAY);
-        cvThreshold(gray,segmented,30,255,CV_THRESH_BINARY_INV);
-        CvRect maxrect = findLargestContour(segmented,output);
-        CvPoint hipPoint = FindHipPoint(output,maxrect);
-        CvPoint kneePoint = FindKneePoint(output,maxrect,hipPoint.y);
-        CvPoint footPoint = FindToePoint(output,maxrect,kneePoint.x,kneePoint.y);
-        findangle = false;
-        if(minwidth == 0)
-        {
-        	minwidth = kneePoint.x - hipPoint.x;
-        }
-        else
-        {
-        	if((double)(kneePoint.x- hipPoint.x) > 1.25*minwidth)
-        		findangle = true;
-        }
-
-        //Increases the x coordinate of the hip point by 10
-		//Decreases the x coordinate of the knee point and foot point by 10
-        //Finds angle between Hip to Knee line and Knee to Toe line
-        if(findangle)
-        {
-		    hipPoint.x +=10;
-		    kneePoint.x -=10;
-		    footPoint.x -=10;
-    	    knee2Foot=sqrt((kneePoint.x-footPoint.x)*(kneePoint.x-footPoint.x)+(kneePoint.y-footPoint.y)*(kneePoint.y-footPoint.y));
-    	    knee2Hip=sqrt((kneePoint.x-hipPoint.x)*(kneePoint.x-hipPoint.x)+(kneePoint.y-hipPoint.y)*(kneePoint.y-hipPoint.y));
-    	    hip2Foot=sqrt((hipPoint.x-footPoint.x)*(hipPoint.x-footPoint.x)+(hipPoint.y-footPoint.y)*(hipPoint.y-footPoint.y));
-		    theta = (180.0/M_PI)*acos(((knee2Foot*knee2Foot+knee2Hip*knee2Hip)-hip2Foot*hip2Foot)/(2*knee2Foot*knee2Hip));
-		    cvLine(frame_copy,kneePoint,hipPoint,CV_RGB(0,0,255),1,1);
-		    cvLine(frame_copy,kneePoint,footPoint,CV_RGB(0,0,255),1,1);
-		    //Finds the minimum angle between Hip to Knee line and Knee to Toe line
-		    if(theta < mintheta)
-		    {
-		    	mintheta = theta;
-		    	cvCopy(frame_copy,result);
-		    }
-
-        }
-        cvShowImage("frame",frame_copy);
-
-        if(cvWaitKey(50)>0)
-        {
-    	    cvWaitKey(0);
-        }
-
-    }
 
-	cvNamedWindow("Minimum Frame",1);
+	int kneePointWidth = -1;
+	int footPointWidth;
 
-	char *name = new char[10];
-	sprintf(name,"Minimum Angle= %f",mintheta);
+	char *label = new char[30];
 	CvFont font;
-	cvInitFont(&font, CV_FONT_HERSHEY_SIMPLEX, 0.7,0.5, 0.1);
-	cvPutText(result, name,cvPoint(25,25),&font,cvScalar(0,0,255));
+	int fontLineType = CV_AA; // change it to 8 to see non-antialiased graphics
+	cvInitFont(&font, CV_FONT_HERSHEY_COMPLEX, .7, .7, 0.0, 1, fontLineType);
+	
+	char key;
+	bool shouldEnd = false;
+
+	//for(;;)
+	while(!shouldEnd) 
+	{
+
+		frame = cvQueryFrame(capture);
+		if(!frame)
+			break;
+		if( !frame_copy )
+			frame_copy = cvCreateImage( cvSize(frame->width,frame->height),IPL_DEPTH_8U, frame->nChannels );
+		if( frame->origin == IPL_ORIGIN_TL )
+			cvCopy( frame, frame_copy, 0 );
+		else
+			cvFlip( frame, frame_copy, 0 );
+
+		if(!gray)
+		{
+			gray = 		cvCreateImage(cvGetSize(frame),IPL_DEPTH_8U,1);
+			segmented =	cvCreateImage(cvGetSize(frame),IPL_DEPTH_8U,1);
+			edge =	cvCreateImage(cvGetSize(frame),IPL_DEPTH_8U,1);
+			temp = cvCreateImage(cvGetSize(frame),IPL_DEPTH_8U,1);
+			output = cvCreateImage(cvGetSize(frame),IPL_DEPTH_8U,1);
+			result = cvCreateImage(cvGetSize(frame),IPL_DEPTH_8U,3);
+		}
+
+		cvSmooth(frame_copy,frame_copy,2,5,5);
+		cvCvtColor(frame_copy,gray,CV_BGR2GRAY);
+		cvThreshold(gray,segmented,30,255,CV_THRESH_BINARY_INV);
+		CvRect maxrect = findLargestContour(segmented,output);
+		CvPoint hipPoint = FindHipPoint(output,maxrect);
+		CvPoint kneePoint = FindKneePoint(output,maxrect,hipPoint.y);
+		CvPoint footPoint = FindToePoint(output,maxrect,kneePoint.x,kneePoint.y);
+		foundAngle = false;
+		if(minwidth == 0)
+		{
+			minwidth = kneePoint.x - hipPoint.x;
+		}
+		else
+		{
+			if((double)(kneePoint.x- hipPoint.x) > 1.15*minwidth 
+					&&
+					upperSimilarThanLower(hipPoint, kneePoint, footPoint)
+					)
+				/* get lower this 1.25 because now we use mid leg to solve the hand problem and width is lower*/
+				/*1.25 again, because we use hip y again*/
+				foundAngle = true;
+				foundAngleOneTime = true;
+		}
+
+		//Finds angle between Hip to Knee line and Knee to Toe line
+		if(foundAngle)
+		{
+			cvCircle(frame_copy,kneePoint,2, CV_RGB(255,0,255),1,8,0);
+			
+			//fix kneepoint.x at the right 1/3 of the knee width
+			kneePoint.x -= kneePointWidth /3;
+			cvCircle(frame_copy,kneePoint,3, CV_RGB(255,0,0),1,8,0);
+
+
+			//fix hipPoint ...
+			int hipPointFirstY = hipPoint.y;
+			cvCircle(frame_copy,hipPoint,2, CV_RGB(255,0,255),1,8,0);
+			
+			//... find at 3/2 of hip (surely under the hand) ...
+			hipPoint = FixHipPoint1(output, hipPoint, kneePoint);
+			cvCircle(frame_copy,hipPoint,2, CV_RGB(255,0,255),1,8,0);
+
+			//... cross first hippoint with the knee-hippoint line to find real hippoint
+			hipPoint = FixHipPoint2(output, hipPointFirstY, kneePoint, hipPoint);
+			cvCircle(frame_copy,hipPoint,3, CV_RGB(255,0,0),1,8,0);
+			
+			//find width of knee, only one time and will be used for all the prhotogrammes
+			if(kneePointWidth == -1) {
+				kneePointWidth = FindWidth(output, kneePoint);
+			}
+
+			//find width of foot for each photogramme
+			footPointWidth = FindWidth(output, footPoint);
+			cvCircle(frame_copy,footPoint,2, CV_RGB(255,0,255),1,8,0);
+			
+			//fix footpoint.x at the 1/2 of the foot width
+			footPoint.x -= footPointWidth /2;
+			cvCircle(frame_copy,footPoint,3, CV_RGB(255,0,0),1,8,0);
+
+			//draw 2 main lines
+			knee2Foot = getDistance(kneePoint, footPoint);
+			knee2Hip = getDistance(kneePoint, hipPoint);
+			hip2Foot = getDistance(hipPoint, footPoint);
+			theta = (180.0/M_PI)*acos(((knee2Foot*knee2Foot+knee2Hip*knee2Hip)-hip2Foot*hip2Foot)/(2*knee2Foot*knee2Hip));
+			cvLine(frame_copy,kneePoint,hipPoint,CV_RGB(0,0,255),1,1);
+			cvLine(frame_copy,kneePoint,footPoint,CV_RGB(0,0,255),1,1);
+			//Finds the minimum angle between Hip to Knee line and Knee to Toe line
+			if(theta < mintheta)
+			{
+				mintheta = theta;
+				cvCopy(frame_copy,result);
+			}
+
+			cvRectangle(frame_copy,
+					cvPoint(maxrect.x,maxrect.y),
+					cvPoint(maxrect.x + maxrect.width, maxrect.y + maxrect.height),
+					CV_RGB(255,0,0),1,1);
+
+			//print angles
+			sprintf(label, "current: %.1f", theta);
+			cvPutText(frame_copy, label, cvPoint(5,frame->height /2),&font,cvScalar(0,0,255));
+			sprintf(label,     "min:     %.1f", mintheta);
+			cvPutText(frame_copy, label, cvPoint(5,frame->height /2 +30),&font,cvScalar(0,0,255));
+		}
+
+
+		cvShowImage("frame",frame_copy);
+
+		/* wait key for pause
+		 * if ESC, q, Q then exit
+		 */
+
+		int myDelay = playDelay;
+		if(foundAngle)
+			myDelay = playDelayFoundAngle;
+		
+		key = (char) cvWaitKey(myDelay);
+		if(key == 27 || key == 'q' || key == 'Q' ) // 'ESC'
+			shouldEnd = true;
+		else if (key >0)
+		{
+			//if paused, print "pause"
+			sprintf(label,"Pause");
+			cvPutText(frame_copy, label,cvPoint(frame->width -100,25),&font,cvScalar(0,0,255));
+			cvShowImage("frame",frame_copy);
+
+			key = (char) cvWaitKey(0);
+			if(key == 27 || key == 'q' || key == 'Q' ) // 'ESC'
+				shouldEnd = true;
+		}
+
+	}
+
+	if(foundAngleOneTime) {
+		cvNamedWindow("Minimum Frame",1);
+
+		sprintf(label,"Minimum Angle= %.3f",mintheta);
+		cvPutText(result, label,cvPoint(25,25),&font,cvScalar(0,0,255));
+
+		cvShowImage("Minimum Frame", result);
+		cvWaitKey(0);
+	}
+
+
+	/* show all windows*/	
+	/*
+	cvNamedWindow("gray",1);
+	cvShowImage("gray", gray);
+
+	cvNamedWindow("segmented",1);
+	cvShowImage("segmented", segmented);
+
+	cvNamedWindow("edge",1);
+	cvShowImage("edge", edge);
+
+	cvNamedWindow("temp",1);
+	cvShowImage("temp", temp);
+
+	cvNamedWindow("output",1);
+	cvShowImage("output", output);
+	*/
+
 
-	cvShowImage("Minimum Frame", result);
-	cvWaitKey(0);
 	cvDestroyAllWindows();
 	cvReleaseImage(&frame_copy);
 	cvReleaseImage(&gray);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]