Commit b60305dc authored by Thiago C. Santini's avatar Thiago C. Santini

Starts adding polynom-fit-based calibration, adds calibration cross-hair

parent bd22e08b
......@@ -23,7 +23,9 @@ SOURCES += \
$${TOP}/src/ThreadManager.cpp \
$${TOP}/src/ParallelPort.cpp \
$${TOP}/src/Trigger.cpp \
$${TOP}/src/GlobalTimer.cpp
$${TOP}/src/GlobalTimer.cpp \
$${TOP}/src/PolyFit.cpp \
$${TOP}/src/CalibrationMethod.cpp
HEADERS += \
$${TOP}/src/ImageProcessing.h \
......@@ -58,7 +60,9 @@ HEADERS += \
$${TOP}/else/blob_gen.h \
$${TOP}/else/canny_impl.h \
$${TOP}/else/filter_edges.h \
$${TOP}/else/find_best_edge.h
$${TOP}/else/find_best_edge.h \
$${TOP}/src/PolyFit.h \
$${TOP}/src/CalibrationMethod.h
FORMS += \
$${TOP}/src/Gui.ui
......
......@@ -97,6 +97,7 @@ void Calibration::addPoint(QPoint pupilSample)
bool Calibration::calibrate()
{
bool success = true;
int minPointsForCalibration = settings.value("calibration/minPointsForCalibration").toInt();
if (fieldPoints.size() < minPointsForCalibration) {
QMessageBox::warning(NULL, "Calibration failed.",
......
#include "CalibrationMethod.h"
CalibrationMethod::CalibrationMethod()
{
}
CalibrationMethod::~CalibrationMethod()
{
}
#ifndef CALIBRATIONMETHOD_H
#define CALIBRATIONMETHOD_H
#include <vector>
#include <opencv2/core.hpp>
#include <QString>
using namespace std;
using namespace cv;
class CalibrationMethod
{
public:
CalibrationMethod();
~CalibrationMethod();
virtual bool calibrate(vector<Point2d> leftPupil, vector<Point2d> rightPupil, vector<Point2d> field, QString &errorMsg) = 0;
virtual Point2d evaluate(Point2d leftPupil, Point2d rightPupil) = 0;
};
#endif // CALIBRATIONMETHOD_H
......@@ -99,6 +99,7 @@ void Gui::update(JournalEntry journalEntry)
cv::Scalar red(255, 0, 0);
cv::Scalar green(0, 255, 0);
cv::Scalar blue(0, 0, 255);
cv::Scalar yellow(255, 255,0);
// Left eye drawings
cv::Mat eyeCanvas;
......@@ -138,6 +139,14 @@ void Gui::update(JournalEntry journalEntry)
circle(fieldCanvas, calibration.fieldPoints[i], 5, green, -1);
}
ui->discardButton->setText(calibration.discardButtonStr);
int w = fieldCanvas.cols;
int h = fieldCanvas.rows;
QPoint mousePosition = ui->fieldCamView->mapFromGlobal(QCursor::pos());
if ( mousePosition.x() >= 0 && mousePosition.x() < w && mousePosition.y() >= 0 && mousePosition.y() < h) {
line(fieldCanvas, cv::Point(0, mousePosition.y()), cv::Point(w, mousePosition.y()), yellow, 2);
line(fieldCanvas, cv::Point(mousePosition.x(), 0), cv::Point(mousePosition.x(), h), yellow, 2);
}
}
if ( (calibration.calibrated) && (journalEntry.eye_valid!=0) ) {
int x = journalEntry.fieldProjection.x;
......
#include "PolyFit.h"
PolyFit::PolyFit(PlType plType)
{
this->plType = plType;
}
PolyFit::~PolyFit()
{
}
bool PolyFit::calibrate(vector<Point2d> leftPupil, vector<Point2d> rightPupil, vector<Point2d> field, QString &errorMsg)
{
// Ax = b
// x = A^{-1} b
// Possible terms; not using more than third order atm
Mat x, y , xx, yy, xy, xxyy, zx, zy, A, iA;
// TODO: binocular; assume only one eye and that data comes in the leftPupil variable atm
assert(leftPupil.size() == field.size());
for (unsigned int i=0; i<field.size(); i++) {
x.push_back(leftPupil[i].x);
y.push_back(leftPupil[i].y);
zx.push_back(field[i].x);
zy.push_back(field[i].y);
}
multiply(x, x, xx);
multiply(y, y, yy);
multiply(x, y, xy);
multiply(xx, yy, xxyy);
A = Mat::ones(field.size(),field.size(), CV_64F);
// TODO: depending on the polynom and number of calibration points, we can have an overdetermined system.
// Right now, we simply drop the extra equations, but we can select the set of equations that minimize error in the future.
int unknowns;
switch (plType) {
case POLY_1_X_Y_XX_YY_XY_XXYY:
unknowns = 7;
// A.col(0) was initialized with one
x.copyTo(A.col(1));
y.copyTo(A.col(2));
xx.copyTo(A.col(3));
yy.copyTo(A.col(4));
xy.copyTo(A.col(5));
xxyy.copyTo(A.col(6));
break;
default:
break;
}
if ( x.rows < unknowns ) {
errorMsg = QString("Not enough calibration points.\nGot %1\nRequired: %2\nPlease start again.").arg(x.rows).arg(unknowns);
return false;
}
A = A(Rect2d(0,0,unknowns,unknowns));
zx = zx(Rect2d(0,0,1,unknowns));
zy = zy(Rect2d(0,0,1,unknowns));
iA = A.inv(DECOMP_SVD);
zx.convertTo(zx, iA.type());
zy.convertTo(zy, iA.type());
// Determine coefficients
cx = iA*zx;
cy = iA*zy;
return true;
}
Point2d PolyFit::evaluate(Point2d leftPupil, Point2d rightPupil)
{
double x = leftPupil.x;
double y = leftPupil.y;
double xx = x*x;
double yy = y*y;
double xy = x*y;
double xxyy = xx*yy;
Point2d estimate;
switch (plType) {
case POLY_1_X_Y_XX_YY_XY_XXYY:
estimate.x = cx.at<double>(0) +
x*cx.at<double>(1) +
y*cx.at<double>(2) +
xx*cx.at<double>(3) +
yy*cx.at<double>(4) +
xy*cx.at<double>(5) +
xxyy*cx.at<double>(6);
estimate.y = cy.at<double>(0) +
x*cy.at<double>(1) +
y*cy.at<double>(2) +
xx*cy.at<double>(3) +
yy*cy.at<double>(4) +
xy*cy.at<double>(5) +
xxyy*cy.at<double>(6);
break;
default:
break;
}
return estimate;
}
#ifndef POLYFIT_H
#define POLYFIT_H
#include <iostream>
#include <vector>
#include <assert.h>
#include "opencv2/core.hpp"
#include <QString>
#include "CalibrationMethod.h"
using namespace std;
using namespace cv;
class PolyFit : public CalibrationMethod
{
public:
// TODO: Implement other polynoms, maybe even make it general form if we have time :-)
enum PlType {
POLY_1_X_Y_XX_YY_XY_XXYY
};
PolyFit(PlType plType);
~PolyFit();
bool calibrate(vector<Point2d> leftPupil, vector<Point2d> rightPupil, vector<Point2d> field, QString &errorMsg);
Point2d evaluate(Point2d leftPupil, Point2d rightPupil);
private:
PlType plType;
Mat1d cx;
Mat1d cy;
};
#endif // POLYFIT_H
......@@ -50,3 +50,5 @@ GlobalTimer gTimer;
QString gBinaryPath = "";
QString gCurrentSubjectName = "";
QString gFileIndexStr = "0000";
PolyFit *polyFit;
......@@ -15,6 +15,8 @@
#include "settings.h"
#include "GlobalTimer.h"
#include "PolyFit.h"
QString getTimestampStr();
QString getNamePrefix();
void initBanner();
......@@ -24,8 +26,10 @@ extern QString gBinaryPath;
extern QString gCurrentSubjectName;
extern QString gFileIndexStr;
extern GlobalTimer gTimer; // Only valid after first frame has been received!
extern PolyFit *polyFit;
void logMessages(QtMsgType type, const QMessageLogContext &context, const QString &msg);
#endif // UTILS_H
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment