示例#1
0
bool EyeCalibration::calibrate() {
	char buf[512];

	// Print starting message
	EyeCalibrationWizardFormController::getInstance()->calibrationOutputLog("Starting Calibration\n");

	// Create buffer
	if (this->eyeVectorArray == NULL)
		this->eyeVectorArray = (float*) malloc(sizeof(float) * ClientHandler::getDikablisViewingSize());

	sprintf_s(buf, "Creating buffer of size %d bytes\n", sizeof(float) * ClientHandler::getDikablisViewingSize());
	EyeCalibrationWizardFormController::getInstance()->calibrationOutputLog(buf);

	// Print the number of points used in the calibration
	sprintf_s(buf, "A total of %d points was collected.\n", calibrationPoints.size());
	EyeCalibrationWizardFormController::getInstance()->calibrationOutputLog(buf);

	if (calibrationPoints.size() < 4) {
		EyeCalibrationWizardFormController::getInstance()->calibrationOutputLog("Not enough points to calculate calibration.\n");
		return false;
	}

	// Min/Max coordinates of the polygon
	CalibrationPoint 
		minX = calibrationPoints.at(0), 
		minY = calibrationPoints.at(0), 
		maxX = calibrationPoints.at(0), 
		maxY = calibrationPoints.at(0);

	// Print each points information and get the min and max
	for (unsigned int i = 0; i < calibrationPoints.size(); i++) {
		CalibrationPoint point = calibrationPoints.at(i);
		osg::Vec3 ray = point.ray();

		// Print info
		sprintf_s(buf, "Point %d (%d, %d) has a value of (%f, %f, %f)\n", 
			i + 1,
			point.x(), point.y(),
			ray.x(), ray.y(), ray.z());
		EyeCalibrationWizardFormController::getInstance()->calibrationOutputLog(buf);

		if (minX.x() > point.x())
			minX = point;

		if (minY.y() > point.y())
			minY = point;

		if (maxX.x() < point.x())
			maxX = point;

		if (maxY.y() < point.y())
			maxY = point;
	}

	// Print Bounding Info
	{
		sprintf_s(buf, "Point with min X value (%d, %d)\n", 
			minX.x(), minX.y());
		EyeCalibrationWizardFormController::getInstance()->calibrationOutputLog(buf);

		sprintf_s(buf, "Point with min Y value (%d, %d)\n", 
			minY.x(), minY.y());
		EyeCalibrationWizardFormController::getInstance()->calibrationOutputLog(buf);

		sprintf_s(buf, "Point with max X value (%d, %d)\n", 
			maxX.x(), maxX.y());
		EyeCalibrationWizardFormController::getInstance()->calibrationOutputLog(buf);

		sprintf_s(buf, "Point with max Y value (%d, %d)\n", 
			maxY.x(), maxY.y());
		EyeCalibrationWizardFormController::getInstance()->calibrationOutputLog(buf);

		// Get center
		this->center_x = (maxX.x() - minX.x())/2;
		this->center_y = (maxY.y() - minY.y())/2;

		sprintf_s(buf, "Center point is (%d, %d)\n", 
			center_x, center_y);
		EyeCalibrationWizardFormController::getInstance()->calibrationOutputLog(buf);
	}

	// Get Convex Hull
	CalibrationPointVector boundingPoints;
	SegmentVector convexHull = calculateConvexHull(calibrationPoints);
	// Get the bounding points of the convex hull
	boundingPointsOfHull(convexHull, boundingPoints);

	// Print each segment information
	for (unsigned int i = 0; i < convexHull.size(); i++) {
		Segment segment = convexHull.at(i);
		sprintf_s(buf, "Edge %d: From (%d, %d) to (%d, %d)\n", 
			i + 1,
			segment.x1(), segment.y1(),
			segment.x2(), segment.y2());
		EyeCalibrationWizardFormController::getInstance()->calibrationOutputLog(buf);
	}

	// Resort the bounding points
	sort(boundingPoints, center_x, center_y);

	// Triangulate
	CalibrationPointVector traingles;
	triangulate(boundingPoints, traingles);

	// Check if the triangulation is valid 
	if (traingles.size() % 3 != 0) {
		EyeCalibrationWizardFormController::getInstance()->calibrationOutputLog("Error: Triangulating polygon.\n");
		return false;
	}

	// Get the remaining inner points of the convex hull
	CalibrationPointVector innerPoints;
	for (unsigned int i = 0; i < calibrationPoints.size(); i++) {
		CalibrationPoint point = calibrationPoints[i];
		bool found = false;
		for (unsigned int k = 0; k < boundingPoints.size(); k++) {
			if (point.equal(boundingPoints[k])) {
				found = true;
				break;
			}
		}

		if (!found)
			innerPoints.push_back(point);
	}

	
	unsigned int traingleCount = traingles.size() / 3;
	for (unsigned int i = 0; i < innerPoints.size(); i++) {
		CalibrationPoint P = innerPoints[i];

		for (unsigned int k = 0; k < traingleCount; k++) {
			CalibrationPoint A = traingles[3*k + 0];
			CalibrationPoint B = traingles[3*k + 1];
			CalibrationPoint C = traingles[3*k + 2];

			if (insideTriangle(A,B,C,P)) {
				traingles.erase(traingles.begin()+3*k, traingles.begin()+3*k+3);

				CalibrationPoint center, P0;

				// Triangle 1
				CalibrationPointVector tri1;
				tri1.push_back(A);
				tri1.push_back(B);
				tri1.push_back(P);

				P0 = A + (B - A)/2.f;
				center = P + (P0 - P)*(3.f/2.f);

				sort(tri1, center.x(), center.y());

				// Triangle 2
				CalibrationPointVector tri2;
				tri2.push_back(A);
				tri2.push_back(C);
				tri2.push_back(P);
				
				P0 = A + (C - A)/2.f;
				center = P + (P0 - P)*(3.f/2.f);

				sort(tri2, center.x(), center.y());

				// Triangle 3
				CalibrationPointVector tri3;
				tri3.push_back(B);
				tri3.push_back(C);
				tri3.push_back(P);

				P0 = B + (C - B)/2.f;
				center = P + (P0 - P)*(3.f/2.f);

				sort(tri3, center.x(), center.y());

				traingles.insert(traingles.end(), tri1.begin(), tri1.end());
				traingles.insert(traingles.end(), tri2.begin(), tri2.end());
				traingles.insert(traingles.end(), tri3.begin(), tri3.end());

				break;
			}
		}
	}

	if (traingles.size() % 3 != 0) {
		EyeCalibrationWizardFormController::getInstance()->calibrationOutputLog("Error: Triangulating inner points in polygon.\n");
		return false;
	}

	traingleCount = traingles.size() / 3;

	// Flip edges of the triangles
	for (int k = traingleCount - 1; k > 0 ; k--) {
		CalibrationPointVector tri1;

		tri1.push_back(traingles[3*k + 0]);
		tri1.push_back(traingles[3*k + 1]);
		tri1.push_back(traingles[3*k + 2]);

		for (int i = k - 1; i >= 0; i--) {
			CalibrationPointVector tri2;

			tri2.push_back(traingles[3*i + 0]);
			tri2.push_back(traingles[3*i + 1]);
			tri2.push_back(traingles[3*i + 2]);

			// Get shared edge if exists
			int shared = 0;
			CalibrationPointVector sharedPoints;
			CalibrationPoint nonSharedPoint;
			for (unsigned int idx1 = 0; idx1 < 3; idx1++) {
				for (unsigned int idx2 = 0; idx2 < 3; idx2++) {
					if (tri2[idx2].equal(tri1[idx1])) {
						sharedPoints.push_back(tri1[idx1]);
						shared++;
					} else {
						nonSharedPoint = tri2[idx2];
					}
				}
			}


			if (shared == 2) {
				if (isInCircumCircle(nonSharedPoint, tri1)) {
					sprintf_s(buf, "Point %d - (%d, %d): In circle of triangle (%d, %d), (%d, %d), (%d, %d)\n", 
						i + 1, nonSharedPoint.x(), nonSharedPoint.y(), 
						tri1[0].x(), tri1[0].y(), 
						tri1[1].x(), tri1[1].y(), 
						tri1[2].x(), tri1[2].y());
					EyeCalibrationWizardFormController::getInstance()->calibrationOutputLog(buf);

					// Sort tri1
					for (unsigned int idx = 0; idx < 3; idx++) {
						if (tri1[idx].equal(sharedPoints[0]) || tri1[idx].equal(sharedPoints[1])) {
							CalibrationPoint shared = tri1[idx];
							tri1.erase(tri1.begin()+idx);
							tri1.insert(tri1.begin(), shared);
						}
					}

					// Sort tri2
					for (unsigned int idx = 0; idx < 3; idx++) {
						if (tri2[idx].equal(sharedPoints[0]) || tri2[idx].equal(sharedPoints[1])) {
							CalibrationPoint shared = tri2[idx];
							tri2.erase(tri2.begin()+idx);
							tri2.insert(tri2.begin(), shared);
						}
					}

					// Clean up old triangles
					traingles.erase(traingles.begin()+3*k, traingles.begin()+3*k+3);
					traingles.erase(traingles.begin()+3*i, traingles.begin()+3*i+3);

					CalibrationPoint center, P0;

					// New Triangle 1
					CalibrationPointVector new_tri1;
					new_tri1.push_back(tri1[0]);
					new_tri1.push_back(tri1[2]);
					new_tri1.push_back(tri2[2]);

					P0 = tri1[0] + (tri2[2] - tri1[0])/2.f;
					center = tri1[2] + (P0 - tri1[2])*(3.f/2.f);

					sort(new_tri1, center.x(), center.y());

					// New Triangle 2
					CalibrationPointVector new_tri2;
					new_tri2.push_back(tri1[1]);
					new_tri2.push_back(tri1[2]);
					new_tri2.push_back(tri2[2]);

					P0 = tri1[1] + (tri2[2] - tri1[1])/2.f;
					center = tri1[2] + (P0 - tri1[2])*(3.f/2.f);

					sort(new_tri2, center.x(), center.y());

					traingles.insert(traingles.end(), new_tri1.begin(), new_tri1.end());
					traingles.insert(traingles.end(), new_tri2.begin(), new_tri2.end());

					break;
				}
			}
		}
	}

	// Draw triangles
	for (unsigned int j = 0; j < (viewingHeight+2*viewingMargin); j++) {
		for (unsigned int i = 0; i < (viewingWidth+2*viewingMargin); i++) {
			CalibrationPoint P(i - viewingMargin, j - viewingMargin, osg::Vec3(0.f, 0.f, 0.f));

			for (unsigned int k = 0; k < traingleCount; k++) {
				CalibrationPoint A = traingles[3*k + 0];
				CalibrationPoint B = traingles[3*k + 1];
				CalibrationPoint C = traingles[3*k + 2];

				if (insideTriangle(A,B,C,P)) {
					osg::Vec3 ray;

					float det = A.x()*B.y()-B.x()*A.y()+B.x()*C.y()-C.x()*B.y()+C.x()*A.y()-A.x()*C.y();
					osg::Vec3 a = (A.ray()*(B.y()-C.y())+B.ray()*(C.y()-A.y())+C.ray()*(A.y()-B.y())) / det;
					osg::Vec3 b = (A.ray()*(C.x()-B.x())+B.ray()*(A.x()-C.x())+C.ray()*(B.x()-A.x())) / det;
					osg::Vec3 c = (A.ray()*(B.x()*C.y()-C.x()*B.y())+B.ray()*(C.x()*A.y()-A.x()*C.y())+C.ray()*(A.x()*B.y()-B.x()*A.y())) / det;
					ray = a*P.x()+b*P.y()+c;

					unsigned long location = 3*(j*(viewingWidth+2*viewingMargin) + i);
					
					this->eyeVectorArray[location + 0] = ray.x();
					this->eyeVectorArray[location + 1] = ray.y();
					this->eyeVectorArray[location + 2] = ray.z();

					break;
				}
			}
		}
	}

	// Draw Outside
	for (unsigned int j = 0; j < (viewingHeight+2*viewingMargin); j++) {
		for (unsigned int i = 0; i < (viewingWidth+2*viewingMargin); i++) {
			CalibrationPoint P(i - viewingMargin, j - viewingMargin, osg::Vec3(0.f, 0.f, 0.f));

			bool inside = false;
			for (unsigned int k = 0; k < traingleCount; k++) {
				CalibrationPoint A = traingles[3*k + 0];
				CalibrationPoint B = traingles[3*k + 1];
				CalibrationPoint C = traingles[3*k + 2];

				if (insideTriangle(A,B,C,P)) {
					inside = true;
					break;
				}
			}

			if (!inside) {

				CalibrationPoint closest;
				float min_distance = -1;
				for (unsigned int k = 0; k < convexHull.size(); k++) {
					CalibrationPoint A = convexHull[k].p1();
					CalibrationPoint B = convexHull[k].p2();

					CalibrationPoint P0 = getClosestPoint(A, B, P, true);
					
					float diff_x = P0.x() - P.x();
					float diff_y = P0.y() - P.y();

					float distance = diff_x*diff_x + diff_y*diff_y;

					if (min_distance < 0 || min_distance > distance) {
						min_distance = distance;
						closest = P0;
					}
				}

				osg::Vec3 ray = closest.ray();

				unsigned long location = 3*(j*(viewingWidth+2*viewingMargin) + i);

				this->eyeVectorArray[location + 0] = ray.x();
				this->eyeVectorArray[location + 1] = ray.y();
				this->eyeVectorArray[location + 2] = ray.z();
			}
		}
	}

// Testing
#if 0
	// Draw points
	for (unsigned int c = 0; c < calibrationPoints.size(); c++) {
		CalibrationPoint point = calibrationPoints[c];

		for (int j = -10; j < 10; j++) {
			for (int i = -10; i < 10; i++) {

				int x = point.x() + i + viewingMargin;
				int y = point.y() + j + viewingMargin;

				if (x >= 0 && x < (int)(viewingWidth+2*viewingMargin) &&
					y >= 0 && y < (int)(viewingHeight+2*viewingMargin)) {

					unsigned long location = 3*(y*(viewingWidth+2*viewingMargin) + x);
					
					this->eyeVectorArray[location + 0] = 255;
					this->eyeVectorArray[location + 1] = 0;
					this->eyeVectorArray[location + 2] = 0;
				}
			}
		}
	}

	// Draw bounding points
	for (unsigned int c = 0; c < boundingPoints.size(); c++) {
		CalibrationPoint point = boundingPoints[c];

		for (int j = -10; j < 10; j++) {
			for (int i = -10; i < 10; i++) {

				int x = point.x() + i + viewingMargin;
				int y = point.y() + j + viewingMargin;

				if (x >= 0 && x < (int)(viewingWidth+2*viewingMargin) &&
					y >= 0 && y < (int)(viewingHeight+2*viewingMargin)) {

					unsigned long location = 3*(y*(viewingWidth+2*viewingMargin) + x);
					
					this->eyeVectorArray[location + 0] = 0;
					this->eyeVectorArray[location + 1] = 255;
					this->eyeVectorArray[location + 2] = 0;
				}
			}
		}
	}
#endif

	saveRayMap();

	ClientHandler* client = AppData::getInstance()->getClient();

	if (client) {
		client->setRayCalibration(this->eyeVectorArray);
		client->setHeadId(this->rbHeadId);
	} else {
		EyeCalibrationWizardFormController::getInstance()->calibrationOutputLog("Failed: Unable to find client.\n");
		return false;
	}

	EyeCalibrationWizardFormController::getInstance()->calibrationOutputLog("Done\n");

	return true;
}
示例#2
0
EyeCalibration::SegmentVector EyeCalibration::calculateConvexHull(CalibrationPointVector processingPoints) {
	// Edges
	SegmentVector segments;

	if (processingPoints.size() < 3)
		return segments;

	CalibrationPoint 
		minX = processingPoints.at(0), 
		minY = processingPoints.at(0), 
		maxX = processingPoints.at(0), 
		maxY = processingPoints.at(0);

	for (unsigned int i = 0; i < processingPoints.size(); i++) {
		CalibrationPoint point = processingPoints.at(i);
		osg::Vec3 ray = point.ray();

		if (minX.x() > point.x())
			minX = point;

		if (minY.y() > point.y())
			minY = point;

		if (maxX.x() < point.x())
			maxX = point;

		if (maxY.y() < point.y())
			maxY = point;
	}

	// Get center
	int center_x = (maxX.x() - minX.x())/2;
	int center_y = (maxY.y() - minY.y())/2;

	// Ordered Point
	CalibrationPointVector orderedPoints(processingPoints);

	// Sort Points
	sort(orderedPoints, center_x, center_y);

	// Create segments
	for (unsigned int i = 0; i < orderedPoints.size(); i++) {
		CalibrationPoint from = orderedPoints.at(i);

		for (unsigned int k = 0; k < orderedPoints.size(); k++) {
			if (i == k)
				continue;

			CalibrationPoint to = orderedPoints.at(k);

			Segment segment(from, to);
			segments.push_back(segment);
		}
	}

	unsigned int i = 0;
	unsigned int j = 0;
	while ( i < segments.size() )
	{
		//ProcessingPoints will be the points that are not in  the current segment
		CalibrationPointVector processingPoints(orderedPoints);
		Segment segment = segments.at(i);

		//this loop prepares the ProcessingPoints list for each segment
		while ( j < processingPoints.size() )
		{
			CalibrationPoint point = processingPoints.at(j);
			if((segment.x1() == point.x() && segment.y1() == point.y()) ||
				(segment.x2() == point.x() && segment.y2() == point.y()))
			{
				//eliminating the points that are already in the current segment...
				//we don't need them
				processingPoints.erase(processingPoints.begin()+j);
				j = 0;
			} else {
				j++;
			}
		}

		//checking if the current segment is an edge or notBy calling isEdge function
		if( !isEdge(processingPoints, segments.at(i)) )
		{
			segments.erase(segments.begin()+i);
			i = 0;
		} else {
			i++;
		} 
	}

	return segments;
}