opengaze/src/personal_calibrator.cpp
2019-01-10 13:26:03 +01:00

145 lines
5.1 KiB
C++

#include "personal_calibrator.hpp"
using namespace cv;
using namespace std;
void CallBackFunc(int event, int x, int y, int flags, void* is_click) {
if (event == EVENT_LBUTTONDOWN){
bool* temp = (bool*)is_click;
*temp = true;
}
}
PersonalCalibrator::PersonalCalibrator (int screen_width, int screen_height) {
cv::namedWindow("calibration", CV_WINDOW_NORMAL);
cv::setWindowProperty("calibration", CV_WND_PROP_FULLSCREEN, CV_WINDOW_FULLSCREEN);
// set the mouse
is_click_ = false;
//set the callback function for any mouse event
setMouseCallback("calibration", CallBackFunc, &is_click_); // wait for clicking
screen_width_ = screen_width;
screen_height_ = screen_height;
center_radius_ = (int)((float)screen_width_ / 200.0f);
}
PersonalCalibrator::~PersonalCalibrator() {
cv::setWindowProperty("calibration", CV_WND_PROP_FULLSCREEN, CV_WINDOW_NORMAL);
cv::destroyWindow("calibration");
}
void PersonalCalibrator::generatePoints(int num_points) {
index_point_ = -1;
srand(time(NULL));
Point2i current_point;
for (int num = 0; num < num_points; ++num) {
current_point.x = (rand() % screen_width_); // range is [0, 1]
current_point.y = (rand() % screen_height_); // range is [0, 1]
points_.emplace_back(current_point);
}
}
void PersonalCalibrator::initialWindow() {
// get the focus of the window
namedWindow("GetFocus", CV_WINDOW_NORMAL);
cv::Mat img = cv::Mat::zeros(100, 100, CV_8UC3);
cv::imshow("GetFocus", img);
cv::setWindowProperty("GetFocus", CV_WND_PROP_FULLSCREEN, CV_WINDOW_FULLSCREEN);
waitKey(1);
cv::setWindowProperty("GetFocus", CV_WND_PROP_FULLSCREEN, CV_WINDOW_NORMAL);
cv::destroyWindow("GetFocus");
// show instruction
cv::Mat show_img = cv::Mat::zeros(screen_height_, screen_width_, CV_8UC3);
string show_text = "Please click/touch when looking at the dots";
cv::putText(show_img, show_text, cv::Point(400,600), FONT_HERSHEY_COMPLEX_SMALL, 2, cv::Scalar(255,255,255), 2);
imshow("calibration", show_img);
cv::waitKey(3000);
for (int i=255; i > 0; i-=5) { //Gradient disappear, nice!
show_img = cv::Mat::zeros(screen_height_, screen_width_, CV_8UC3);
cv::putText(show_img, show_text, cv::Point(400,600), FONT_HERSHEY_COMPLEX_SMALL, 2, cv::Scalar(i,i,i), 2);
imshow("calibration", show_img);
cv::waitKey(1);
}
}
bool PersonalCalibrator::showNextPoint() {
cv::Mat show_img = cv::Mat::zeros(screen_height_, screen_width_, CV_8UC3);
index_point_ ++;
cv::circle(show_img, cv::Point(points_[index_point_].x, points_[index_point_].y), center_radius_, cv::Scalar(255, 255, 255), -1);
is_click_ = false;
while (true) {
imshow("calibration", show_img);
int key = cv::waitKey(10); // wait for interaction
if (key == 27) // if press the ESC key
return false;
if (is_click_) {
break;
}
}
return true;
}
void PersonalCalibrator::confirmClicking() {
cv::Mat show_img = cv::Mat::zeros(screen_height_, screen_width_, CV_8UC3);
cv::circle(show_img, cv::Point(points_[index_point_].x, points_[index_point_].y), center_radius_, cv::Scalar(0, 200, 0), -1);
imshow("calibration", show_img);
cv::waitKey(500);
}
// this polyfit function is copied from opencv/modules/contrib/src/polyfit.cpp
// This original code was written by
// Onkar Raut
// Graduate Student,
// University of North Carolina at Charlotte
cv::Mat polyfit(const Mat& src_x, const Mat& src_y, int order)
{
CV_Assert((src_x.rows>0)&&(src_y.rows>0)&&(src_x.cols>0)&&(src_y.cols>0)&&(order>=1));
Mat matrix;
Mat bias = Mat::ones((int)src_x.rows, 1, CV_32FC1);
Mat input_x = Mat::zeros(src_x.rows, order*src_x.cols, CV_32FC1);
Mat copy;
for(int i=1; i<=order;i++){
copy = src_x.clone();
pow(copy,i,copy);
copy.copyTo(input_x(Rect((i-1)*src_x.cols, 0, copy.cols, copy.rows)));
}
Mat new_mat;
cv::hconcat(input_x, bias, new_mat);
cout << "new_mat: " << new_mat << endl;
cv::solve(new_mat, src_y, matrix, DECOMP_NORMAL);
cout << "model_matrix: " << matrix << endl;
Mat calibrated = new_mat * matrix;
cout << "calibrated: " << calibrated << endl;
double dist_original = norm(src_x, src_y, NORM_L2);
cout << "dist_original: " << dist_original << endl;
double dist_calibrated = norm(calibrated, src_y, NORM_L2);
cout << "dist_calibrated: " << dist_calibrated << endl;
return matrix;
}
void PersonalCalibrator::generateModel(vector<Point2f> prediction, vector<Point2f> ground_truth, int order) {
cv::Mat input_x = cv::Mat((int)prediction.size(), 2, CV_32FC1, prediction.data());
cv::Mat input_y = cv::Mat((int)ground_truth.size(), 2, CV_32FC1, ground_truth.data());
cout << "input_x: " << input_x << endl;
cout << "input_y: " << input_y << endl;
cv::Mat model_matrix;
model_matrix_ = polyfit(input_x, input_y, order);
}
void PersonalCalibrator::saveModel(std::string file_path) {
cv::FileStorage storage(file_path, cv::FileStorage::WRITE);
storage << model_matrix_;
storage.release();
}