예제 #1
0
//--------------------------------------------------------------
void eyeTracker::update(ofxCvGrayscaleImage & grayImgFromCam, float threshold, float minSize, float maxSize,  float minSquareness) {

    //threshold?
    //threshold = thresh;

    grayImgPreWarp.setFromPixels(grayImgFromCam.getPixels(), grayImgFromCam.width, grayImgFromCam.height);		// TODO: there's maybe an unnecessary grayscale image (and copy) here...

    if( flipX || flipY ) {
        grayImgPreWarp.mirror(flipY, flipX);
    }

    /*  // before we were scaling and translating, but this is removed for now

     if (fabs(xoffset-1) > 0.1f || fabs(yoffset-1) > 0.1f){
    	grayImgPreWarp.translate(xoffset, yoffset);
    }

    if (fabs(scalef-1) > 0.1f){
    	grayImgPreWarp.scale(scalef, scalef);
    }*/

    grayImg = grayImgPreWarp;



    grayImgPreModification = grayImg;
    grayImg.blur(5);

    if (bUseContrast == true) {
        grayImg.applyBrightnessContrast(brightness,contrast);
    }

    if (bUseGamma == true) {
        grayImg.applyMinMaxGamma(gamma);
    }

    grayImg += edgeMask;

    threshImg = grayImg;


    threshImg.contrastStretch();
    threshImg.threshold(threshold, true);


    // the dilation of a 640 x 480 image is very slow, so let's just do a ROI near the thing we like:

    threshImg.setROI(currentEyePoint.x-50, currentEyePoint.y-50, 100,100);	// 200 pix ok?
    if (bUseDilate == true) {
        for (int i = 0; i < nDilations; i++) {
            threshImg.dilate();
        }
    }
    threshImg.resetROI();



    bFoundOne = false;

    int		whoFound = -1;

    int num = contourFinder.findContours(threshImg, minSize, maxSize, 100, false, true);
    if( num ) {

        for(int k = 0; k < num; k++) {



            float ratio =	contourFinder.blobs[k].boundingRect.width < contourFinder.blobs[k].boundingRect.height ?
                            contourFinder.blobs[k].boundingRect.width / contourFinder.blobs[k].boundingRect.height :
                            contourFinder.blobs[k].boundingRect.height / contourFinder.blobs[k].boundingRect.width;

            float arcl = contourFinder.blobs[k].length;
            float area = contourFinder.blobs[k].area;
            float compactness = (float)((arcl*arcl/area)/FOUR_PI);

            if (bUseCompactnessTest	== true && compactness > maxCompactness) {
                continue;
            }


            //printf("compactness %f \n", compactness);

            //lets ignore rectangular blobs
            if( ratio > minSquareness) {
                currentEyePoint = contourFinder.blobs[k].centroid;
                currentNormPoint.x = currentEyePoint.x;
                currentNormPoint.y = currentEyePoint.y;

                currentNormPoint.x /= w;
                currentNormPoint.y /= h;


                bFoundOne = true;
                whoFound = k;

                break;
            }
        }
    }

    if (bFoundOne && whoFound != -1) {



        // do some convex hull stuff:
        CvSeq* ptseq = cvCreateSeq( CV_SEQ_KIND_GENERIC|CV_32SC2, sizeof(CvContour),sizeof(CvPoint), storage );
        CvSeq* hull;
        CvPoint pt0;

        for(int i = 0; i < contourFinder.blobs[whoFound].nPts; i++ ) {

            pt0.x = contourFinder.blobs[whoFound].pts[i].x;
            pt0.y = contourFinder.blobs[whoFound].pts[i].y;
            cvSeqPush( ptseq, &pt0 );

        }
        hull = cvConvexHull2( ptseq, 0, CV_CLOCKWISE, 0 );
        int hullcount = hull->total;



        // -------------------------------- TRY TO GET A GOOD ELLIPSE HELLS YEAH !!

        int MYN = hullcount;
        float x[MYN], y[MYN];
        double p[6];
        double ellipseParam[5];
        float theta;
        FitEllipse fitter;
        for (int i=0; i<MYN; i++) {
            CvPoint pt = **CV_GET_SEQ_ELEM( CvPoint*, hull, i);
            x[i] = pt.x;
            y[i] =  pt.y;
        }
        double xc, yc;
        double xa, ya;
        double la, lb;
        fitter.apply(x,y,MYN);
        p[0] = fitter.Axx;
        p[1] = fitter.Axy;
        p[2] = fitter.Ayy;
        p[3] = fitter.Ax;
        p[4] = fitter.Ay;
        p[5] = fitter.Ao;

        bool bOk = solve_ellipse(p,ellipseParam);

        ofxCvBlob temp;


        if (bOk == true) {

            //float *params_ellipse = pupilGeometries[whichEye].params_ellipse;
            float axis_a = ellipseParam[0];
            float axis_b = ellipseParam[1];
            float cx 	 = ellipseParam[2];
            float cy 	 = ellipseParam[3];
            theta	 = ellipseParam[4];
            float aspect = axis_b/axis_a;

            for (int i = 0; i < 5; i++) {
                eyeTrackedEllipse.ellipseParam[i] = ellipseParam[i];
            }

            //theta = ofRandom(0,TWO_PI);


            int resolution = 24;

            ofxPoint2f ptsForRotation[resolution];

            for (int i=0; i<resolution; i++) {
                float t = TWO_PI * (float)i/(float)resolution;
                float ex = cx + (axis_a * cos(t ));
                float ey = cy + (axis_b * sin(t ));
                ptsForRotation[i].set(ex,ey);
            }

            for (int i=0; i<resolution; i++) {
                ptsForRotation[i].rotate(theta * RAD_TO_DEG, ofxPoint2f(cx, cy));
            }

            currentEyePoint.set(cx, cy);
            currentNormPoint.x = currentEyePoint.x;
            currentNormPoint.y = currentEyePoint.y;
            currentNormPoint.x /= w;
            currentNormPoint.y /= h;


        } else {


            bFoundOne = false;

        }

        cvRelease((void **)&hull);

    }
예제 #2
0
int* pupil_fitting_inliers(int width, int height, int* return_max_inliers_num)
{
	int i;
	int ep_num = gM_edge_point_N;   //ep stands for edge point
	tV2d nor_center;
	double dis_scale;

	int ellipse_point_num = 5;	//number of point that needed to fit an ellipse
	if (ep_num < ellipse_point_num) {
		printf("Error! %d points are not enough to fit ellipse\n", ep_num);
		memset(pupil_param, 0, sizeof(pupil_param));
		*return_max_inliers_num = 0;
		return NULL;
	}
	
	//Normalization
	tV2d *edge_point_nor = normalize_edge_point(&dis_scale, &nor_center, ep_num);
	
	//Ransac
	int *inliers_index = (int*)malloc(sizeof(int)*ep_num);
	int *max_inliers_index = (int*)malloc(sizeof(int)*ep_num);
	int ninliers = 0;
	int max_inliers = 0;
	int sample_num = 1000;	//number of sample
	int ransac_count = 0;
	double dis_threshold = sqrt(3.84)*dis_scale;
	double dis_error;
	
	memset(inliers_index, 0, sizeof(int)*ep_num);
	memset(max_inliers_index, 0, sizeof(int)*ep_num);
	int rand_index[5];
	double A[6][6];
	int M = 6, N = 6; //M is row; N is column
	for (i = 0; i < N; i++) {
		A[i][5] = 1;
		A[5][i] = 0;
	}
	double **ppa = (double**)malloc(sizeof(double*)*M);
	double **ppu = (double**)malloc(sizeof(double*)*M);
	double **ppv = (double**)malloc(sizeof(double*)*N);
	for (i = 0; i < M; i++) {
		ppa[i] = A[i];
		ppu[i] = (double*)malloc(sizeof(double)*N);
	}
	for (i = 0; i < N; i++) {
		ppv[i] = (double*)malloc(sizeof(double)*N);
	}
	double pd[6]; 
	int min_d_index;
	double conic_par[6] = {0};
	double ellipse_par[5] = {0};
	double best_ellipse_par[5] = {0};
	double ratio;
	while (sample_num > ransac_count) {
		get_5_random_num((ep_num-1), rand_index);
		
		//svd decomposition to solve the ellipse parameter
		for (i = 0; i < 5; i++) {
			A[i][0] = edge_point_nor[rand_index[i]].x * edge_point_nor[rand_index[i]].x;
			A[i][1] = edge_point_nor[rand_index[i]].x * edge_point_nor[rand_index[i]].y;
			A[i][2] = edge_point_nor[rand_index[i]].y * edge_point_nor[rand_index[i]].y;
			A[i][3] = edge_point_nor[rand_index[i]].x;
			A[i][4] = edge_point_nor[rand_index[i]].y;
		}
		
		svd(M, N, ppa, ppu, pd, ppv);
		min_d_index = 0;
		for (i = 1; i < N; i++) {
			if (pd[i] < pd[min_d_index])
				min_d_index = i;
		}
		
		for (i = 0; i < N; i++)
			conic_par[i] = ppv[i][min_d_index];	//the column of v that corresponds to the smallest singular value, 
		//which is the solution of the equations
		ninliers = 0;
		memset(inliers_index, 0, sizeof(int)*ep_num);
		for (i = 0; i < ep_num; i++) {
			dis_error = conic_par[0]*edge_point_nor[i].x*edge_point_nor[i].x + 
					conic_par[1]*edge_point_nor[i].x*edge_point_nor[i].y +
					conic_par[2]*edge_point_nor[i].y*edge_point_nor[i].y + 
					conic_par[3]*edge_point_nor[i].x + conic_par[4]*edge_point_nor[i].y + conic_par[5];
			if (fabs(dis_error) < dis_threshold) {
				inliers_index[ninliers] = i;
				ninliers++;
			}
		}
		
		if (ninliers > max_inliers) {
			if (solve_ellipse(conic_par, ellipse_par)) {
				denormalize_ellipse_param(ellipse_par, ellipse_par, dis_scale, nor_center);
				ratio = ellipse_par[0] / ellipse_par[1];
				if (ellipse_par[2] > 0 && ellipse_par[2] <= width-1
					&& ellipse_par[3] > 0 && ellipse_par[3] <= height-1
					&& ratio > 0.5 && ratio < 2
				) {
					memcpy(max_inliers_index, inliers_index, sizeof(int)*ep_num);
					for (i = 0; i < 5; i++) {
						best_ellipse_par[i] = ellipse_par[i];
					}
					max_inliers = ninliers;
					sample_num = (int)(log((double)(1-0.99))/log(1.0-pow(ninliers*1.0/ep_num, 5)));
				}
			}
		}
		ransac_count++;
		if (ransac_count > 1500) {
			printf("Error! ransac_count exceed! ransac break! sample_num=%d, ransac_count=%d\n", sample_num, ransac_count);
			break;
		}
	}
	//INFO("ransc end\n");
	if (best_ellipse_par[0] > 0 && best_ellipse_par[1] > 0) {
		for (i = 0; i < 5; i++) {
			pupil_param[i] = best_ellipse_par[i];
		}
	}else {
		memset(pupil_param, 0, sizeof(pupil_param));
		max_inliers = 0;
		free(max_inliers_index);
		max_inliers_index = NULL;
	}
	
	for (i = 0; i < M; i++) {
		free(ppu[i]);
		free(ppv[i]);
	}
	free(ppu);
	free(ppv);
	free(ppa);
	
	free(edge_point_nor);
	free(inliers_index);
	*return_max_inliers_num = max_inliers;
	return max_inliers_index;
}