mlib - multimedia libraries Code
Status: Alpha
Brought to you by:
mark_wexler
--- a +++ b/distortion.cpp @@ -0,0 +1,283 @@ +#include <windows.h> +#include <direct.h> +#include <newutil.h> +#include <winutil.h> +#include <distortion.h> + +#pragma warning(disable: 4018) + +//#include <linear_fit.h> + +const double mouse_gain = 0.04; +const double mouse_accel = 0.005; +const double cursor_radius = 0.2; +const color grid_color(1); +const color cursor_color(0.5, 0.25, 0.25); +const color drag_color(1, 0, 0); +const color text_color(0.5); +const color fit_color(0.25, 0.25, 0.5); +const string data_directory = "C:\\Programming\\graphics\\calibrate_screen\\data"; +const string default_calib_file = data_directory + "\\calib.dat"; + +distortion::distortion() +{ + distortion_options opt; + init(opt); +} + +distortion::distortion(const distortion_options &opt) +{ + init(opt); +} + +void distortion::init(const distortion_options &opt) +{ + _opt = opt; + _grid0 = _grid = 0; + make_grid(_grid0); + make_grid(_grid); + //_fit = false; +} + +distortion::~distortion() +{ + free_grid(_grid0); + free_grid(_grid); +} + +void distortion::make_grid(v2 **&g) +{ + free_grid(g); + g = new v2*[_opt.n_grid_x + 1]; + const double i0 = double(_opt.n_grid_x)/2, j0 = double(_opt.n_grid_y)/2; + for(int i = 0; i <= _opt.n_grid_x; i++) { + g[i] = new v2[_opt.n_grid_y + 1]; + for(int j = 0; j <= _opt.n_grid_y; j++) + g[i][j] = _opt.grid_center + + v2(_opt.cell_size(0)*(i - i0), _opt.cell_size(1)*(j - j0)); + } +} + +void distortion::free_grid(v2 **&g) +{ + if(g) { + for(int i = 0; i <= _opt.n_grid_x; i++) + delete [] g[i]; + delete [] g; + g = 0; + } +} + +void distortion::show_grid(ideo *pid) +{ + pid->set_color(grid_color); + for(int i = 0; i <= _opt.n_grid_x; i++) + for(int j = 0; j <= _opt.n_grid_y - 1; j++) + pid->line(_grid[i][j], _grid[i][j + 1]); + for(int j = 0; j <= _opt.n_grid_y; j++) + for(int i = 0; i <= _opt.n_grid_x - 1; i++) + pid->line(_grid[i][j], _grid[i + 1][j]); +} + +void distortion::move_node(int i, int j, const v2 &disp) +{ + _grid[i][j] += disp; +} + +void distortion::set_node(int i, int j, const v2 &pos) +{ + _grid[i][j] = pos; +} + +/* +void distortion::fit() +{ + for(int d = 0; d < 2; d++) { + vector<fit_data_t> data; + for(int i = 0; i <= _opt.n_grid_x; i++) + for(int j = 0; j <= _opt.n_grid_y; j++) { + data.push_back(fit_data_t(Vd(_grid0[i][j](0), _grid0[i][j](1)), + _grid[i][j](d))); + } + multidimensional_polynomial_fit(data, _opt.degree, _fit_coeff[d]); + } + _fit = true; +} + +void distortion::show_fit(ideo *pid) +{ + if(!_fit) return; + pid->set_color(fit_color); + for(int i = 0; i <= _opt.n_grid_x; i++) + for(int j = 0; j <= _opt.n_grid_y - 1; j++) { + const v2 fr( + multidimensional_polynomial(Vd(_grid0[i][j](0), _grid0[i][j](1)), _fit_coeff[0]), + multidimensional_polynomial(Vd(_grid0[i][j](0), _grid0[i][j](1)), _fit_coeff[1])); + const v2 to( + multidimensional_polynomial(Vd(_grid0[i][j + 1](0), _grid0[i][j + 1](1)), _fit_coeff[0]), + multidimensional_polynomial(Vd(_grid0[i][j + 1](0), _grid0[i][j + 1](1)), _fit_coeff[1])); + pid->line(fr, to); + } + for(int j = 0; j <= _opt.n_grid_y; j++) + for(int i = 0; i <= _opt.n_grid_x - 1; i++) { + const v2 fr( + multidimensional_polynomial(Vd(_grid0[i][j](0), _grid0[i][j](1)), _fit_coeff[0]), + multidimensional_polynomial(Vd(_grid0[i][j](0), _grid0[i][j](1)), _fit_coeff[1])); + const v2 to( + multidimensional_polynomial(Vd(_grid0[i + 1][j](0), _grid0[i + 1][j](1)), _fit_coeff[0]), + multidimensional_polynomial(Vd(_grid0[i + 1][j](0), _grid0[i + 1][j](1)), _fit_coeff[1])); + pid->line(fr, to); + } +} +*/ + +// returns true if successful +bool distortion::calc(const v2 &phys, v2 &log) +{ + v2 disp(0); + double sum_weights = 0; + for(int i = 0; i <= _opt.n_grid_x; i++) + for(int j = 0; j <= _opt.n_grid_y; j++) { + double w; + const double r = (phys - _grid0[i][j]).length2(); + if(r > 0) { + w = pow(r, -_opt.calc_power/2); + if(w > _opt.max_weight) + w = _opt.max_weight; + } + else + w = _opt.max_weight; + disp += w*(_grid[i][j] - _grid0[i][j]); + sum_weights += w; + } + if(sum_weights == 0) return false; + log = phys + disp/sum_weights; + return true; +} + +void distortion::save(const string &fn, const string &comment, bool append) +{ + ensure_dir(data_directory); + char old_dir[_MAX_PATH]; + getcwd(old_dir, _MAX_PATH); + ensure_dir(data_directory, true); + + try { + string my_comment = string("screen calibration ") + date_time(); + if(comment != "") my_comment += "\n" + comment; + ofstream out((fn != "" ? fn.c_str() : default_calib_file.c_str()), append ? ios::app : ios::out); + out << "# "; + for(string::const_iterator it = my_comment.begin(); it != my_comment.end(); it++) { + if(*it != '\n') + out << *it; + else + out << endl << "# "; + } + out << endl; + out << "grid " << _opt.n_grid_x << " " << _opt.n_grid_y << endl; + for(int i = 0; i <= _opt.n_grid_x; i++) + for(int j = 0; j <= _opt.n_grid_y; j++) + out << _grid0[i][j](0) << '\t' << _grid0[i][j](1) << '\t' + << _grid[i][j](0) << '\t' << _grid[i][j](1) << endl; + out.close(); + } + catch(error err) { + chdir(old_dir); + throw(err); + } + chdir(old_dir); +} + +void distortion::load(const string &fn) +{ + free_grid(_grid0); + free_grid(_grid); + _comment = ""; + + ifstream in(fn != "" ? fn.c_str() : default_calib_file.c_str()); + string line; + while(true) { + getline(in, line); + if(!in) throw(error("distortion", "unexpected end-of-file")); + trim_space(line); + if(line == "") continue; + if(line[0] != '#') break; + line.erase(0, 1); + trim_space(line); + if(_comment != "") _comment += "\n"; + _comment += line; + } + int n_grid_x, n_grid_y; + if(sscanf(line.c_str(), "grid %d %d", &n_grid_x, &n_grid_y) != 2) + throw(error("distortion", "format error")); + _opt.n_grid_x = n_grid_x; + _opt.n_grid_y = n_grid_y; + make_grid(_grid0); + make_grid(_grid); + for(int i = 0; i <= _opt.n_grid_x; i++) + for(int j = 0; j <= _opt.n_grid_y; j++) { + if(!in) throw(error("distortion", "format error")); + in >> _grid0[i][j](0) >> _grid0[i][j](1) + >> _grid[i][j](0) >> _grid[i][j](1); + } + in.close(); +} + +void distortion::calibrate(ideo *pid) +{ + ideo_state state; + pid->get_state(state); + v2 cursor(_opt.grid_center); + bool dragging = false, drag_all; + int drag_i, drag_j; + + while(true) { + if(pid->mouse_right_button()) break; + + const bool button = pid->mouse_button(); + if(button && !dragging) { + dragging = true; + drag_all = key_down(VK_SHIFT); + double min_dist2 = DBL_MAX; + for(int i = 0; i <= _opt.n_grid_x; i++) + for(int j = 0; j <= _opt.n_grid_y; j++) { + const double dist2 = (_grid[i][j] - cursor).length2(); + if(dist2 < min_dist2) { + min_dist2 = dist2; + drag_i = i; + drag_j = j; + } + } + cursor = _grid[drag_i][drag_j]; + } + if(!button && dragging) { + dragging = false; + } + + const v2 disp = pid->mouse(); + const double dist = disp.length(); + if(dist > 0) { + const v2 dir = disp.normalize(); + cursor += (mouse_gain*dist + mouse_accel*dist*dist)*dir; + if(cursor(0) < state.rf.minx) cursor(0) = state.rf.minx; + if(cursor(0) > state.rf.maxx) cursor(0) = state.rf.maxx; + if(cursor(1) < state.rf.miny) cursor(1) = state.rf.miny; + if(cursor(1) > state.rf.maxy) cursor(1) = state.rf.maxy; + } + if(dragging) set_node(drag_i, drag_j, cursor); + pid->set_color(dragging ? drag_color : cursor_color); + pid->disk(cursor, cursor_radius); + + v2 log; + calc(cursor, log); + pid->line(cursor, log); + + pid->set_color(text_color); + pid->text_pixel(state.width, state.height, DT_RIGHT | DT_BOTTOM, + "right-click when done"); + + show_grid(pid); + + pid->show(); + } +}