chronojump r415 - in trunk: . src/angle
- From: xaviblas svn gnome org
- To: svn-commits-list gnome org
- Subject: chronojump r415 - in trunk: . src/angle
- Date: Thu, 28 Aug 2008 14:10:28 +0000 (UTC)
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]