BrdfSlice(const arguments& args, int width, int height, int slice, double* content) : data(brdf_slice_parameters(args), width * height * slice), _width(width), _height(height), _slice(slice), _data(content) { // Allocate data if (args.is_defined("param") && parametrization().dimX() == 3) _phi = (M_PI / 180.0) * args.get_float("phi", 90); else _phi = 0.5*M_PI; // Is the position of the slice componnent (third coordinate) // reversed? This ensure that some params can be displayed. auto in_param = parametrization().input_parametrization(); _reverse = in_param == params::ISOTROPIC_TL_TV_PROJ_DPHI || in_param == params::SCHLICK_TL_TK_PROJ_DPHI || in_param == params::RETRO_TL_TVL_PROJ_DPHI; // Update the domain _max = max(); _min = min(); }
// Allow for a different parametrization depending on the arguments provided. static const alta::parameters brdf_slice_parameters(const arguments& args) { auto result = alta::parameters(2, 3, params::STARK_2D, params::RGB_COLOR); if(args.is_defined("param")) { params::input param = params::parse_input(args["param"]); // The param is a 2D param if(params::dimension(param) == 2) { std::cout << "<<INFO>> Specified param \"" << args["param"] << "\"" << std::endl; result = alta::parameters(result.dimX(), result.dimY(), param, result.output_parametrization()); // The oaram is a 3D param } else if(params::dimension(param) == 3) { std::cout << "<<INFO>> Specified param \"" << args["param"] << "\"" << std::endl; result = alta::parameters(3, result.dimY(), param, result.output_parametrization()); } else { std::cout << "<<ERROR>> Invalid specified param \"" << args["param"] << "\"" << std::endl; std::cout << "<<ERROR>> Must have 2D input dimension" << std::endl; } } return result; }
bool rational_fitter_parallel::fit_data(const ptr<data>& dat, ptr<function>& fit, const arguments &args) { ptr<rational_function> r = dynamic_pointer_cast<rational_function>(fit) ; if(!r) { std::cerr << "<<ERROR>> not passing the correct function class to the fitter: must be a rational_function" << std::endl ; return false ; } ptr<vertical_segment> d = dynamic_pointer_cast<vertical_segment>(dat) ; if(!d || d->confidence_interval_kind() != vertical_segment::ASYMMETRICAL_CONFIDENCE_INTERVAL) { std::cerr << "<<WARNING>> automatic convertion of the data object to vertical_segment," << std::endl; std::cerr << "<<WARNING>> we advise you to perform convertion with a separate command." << std::endl; size_t elem_size = dat->parametrization().dimX() + 3*dat->parametrization().dimY(); double* content = new double[dat->size() * elem_size]; for(int i=0; i<dat->size(); ++i) { const vec x = dat->get(i); for(int k=0; k<x.size(); ++k) { content[i + k] = x[k]; } for(int k=0; k<dat->parametrization().dimY(); ++k) { content[i + k + dat->parametrization().dimX() + dat->parametrization().dimY()] = (1.0 - args.get_float("dt", 0.1)) * x[k + dat->parametrization().dimX()]; } for(int k=0; k<dat->parametrization().dimY(); ++k) { content[i + k + dat->parametrization().dimX() + 2*dat->parametrization().dimY()] = (1.0 + args.get_float("dt", 0.1)) * x[k + dat->parametrization().dimX()]; } } ptr<vertical_segment> vs(new vertical_segment(dat->parametrization(), dat->size(), std::shared_ptr<double>(content))); d = vs; } // XXX: FIT and D may have different values of dimX() and dimY(), but // this is fine: we convert values as needed in operator(). r->setMin(d->min()); r->setMax(d->max()); const int _min_np = args.get_int("min-np", 10); const int _max_np = args.get_int("np", _min_np); std::cout << "<<INFO>> N in [" << _min_np << ", " << _max_np << "]" << std::endl ; const int nb_starting_points = args.get_int("nb-starting-points", 100); std::cout << "<<INFO>> number of data point used in start: " << nb_starting_points << std::endl; const int step = args.get_int("np-step", 1); const bool use_delta = args.is_defined("use_delta"); for(int i=_min_np; i<=_max_np; i+=step) { std::cout << "<<INFO>> fit using np+nq = " << i << std::endl ; std::cout.flush() ; timer time ; time.start() ; #ifdef _OPENMP const int nb_cores = args.get_int("nb-cores", omp_get_num_procs()); #ifdef DEBUG std::cout << "<<DEBUG>> will use " << nb_cores << " threads to compute the quadratic programs" << std::endl ; #endif omp_set_num_threads(nb_cores) ; #endif double min_delta = std::numeric_limits<double>::max(); double min_l2_dist = std::numeric_limits<double>::max(); double mean_delta = 0.0; int nb_sol_found = 0; int nb_sol_tested = 0; #pragma omp parallel for shared(r, args, nb_sol_found, nb_sol_tested, min_delta, mean_delta), schedule(dynamic,1) for(int j=1; j<i; ++j) { // Compute the number of coefficients in the numerator and in the denominator // from the current number of coefficients i and the current index in the // loop j. int temp_np = i - j; int temp_nq = j; //vec p(temp_np*r->dimY()), q(temp_nq*r->dimY()); // Allocate a rational function and set it to the correct size, dimensions // and parametrizations. ptr<rational_function> rk(NULL); #pragma omp critical (args) { rk = dynamic_pointer_cast<rational_function>( ptr<function>(plugins_manager::get_function(args, r->parametrization()))); } if(!rk) { std::cerr << "<<ERROR>> unable to obtain a rational function from the plugins manager" << std::endl; throw; } rk->setMin(r->min()) ; rk->setMax(r->max()) ; // Set the rational function size rk->setSize(temp_np, temp_nq); double delta = 1.0; double linf_dist, l2_dist; bool is_fitted = fit_data(d, temp_np, temp_nq, rk, args, delta, linf_dist, l2_dist); if(is_fitted) { #pragma omp critical (r) { ++nb_sol_found ; mean_delta += delta ; std::cout << "<<INFO>> found a solution with np=" << temp_np << ", nq = " << temp_nq << std::endl; std::cout << "<<INFO>> Linf error = " << linf_dist << std::endl; std::cout << "<<INFO>> L2 error = " << l2_dist << std::endl; std::cout << "<<INFO>> delta = " << delta << std::endl; std::cout << std::endl; // Get the solution with the minimum delta or the minimum L2 distance, // and update the main rational function r. if((use_delta && delta < min_delta) || (!use_delta && l2_dist < min_l2_dist)) { min_delta = delta ; min_l2_dist = l2_dist ; r->setSize(temp_np, temp_nq); r->update(rk); } } } #pragma omp critical (nb_sol_tested) { // Update the solution nb_sol_tested++; std::cout << "<<DEBUG>> nb solutions tested: " << nb_sol_tested << " / " << i << "\r"; std::cout.flush(); } } if(min_delta < std::numeric_limits<double>::max()) { std::cout << "<<INFO>> mean delta = " << mean_delta/nb_sol_found << std::endl; std::cout << "<<INFO>> min delta = " << min_delta << std::endl; std::cout << *(r.get()) << std::endl; time.stop(); std::cout << "<<INFO>> got a fit using N = " << i << std::endl ; std::cout << "<<INFO>> it took " << time << std::endl ; std::cout << "<<INFO>> I got " << nb_sol_found << " solutions to the QP" << std::endl ; return true ; } } return false ; }
// dat is the data object, it contains all the points to fit // np and nq are the degree of the RP to fit to the data // y is the dimension to fit on the y-data (e.g. R, G or B for RGB signals) // the function returns a rational BRDF function and a boolean bool rational_fitter_parallel::fit_data(const ptr<vertical_segment>& d, int np, int nq, int ny, rational_function_1d* r, const arguments& args, vec& p, vec& q, double& delta) { const int m = d->size(); // 2*m = number of constraints const int n = np+nq; // n = np+nq quadratic_program qp(np, nq, args.is_defined("use_delta")); // Starting with only a nb_starting_points vertical segments std::list<unsigned int> training_set; const int di = std::max((m-1) / (nb_starting_points-1), 1); for(int i=0; i<m; ++i) { if(i % di == 0) { // Create two vector of constraints vec c1(n), c2(n); get_constraint(i, np, nq, ny, d, r, c1, c2); qp.add_constraints(c1); qp.add_constraints(c2); } else { training_set.push_back(i); } } qp.set_training_set(training_set); do { #ifdef _OPENMP #ifdef DEBUG std::cout << "<<DEBUG>> thread " << omp_get_thread_num() << ", number of intervals tested = " << qp.nb_constraints()/2 << std::endl ; #endif #endif Eigen::VectorXd x(n); bool solves_qp = qp.solve_program(x, delta, p, q); r->update(p, q); if(solves_qp) { if(qp.test_constraints(ny, r, d)) { #ifdef DEBUG std::cout << "<<INFO>> got solution " << *r << std::endl ; #endif return true; } } else { #ifdef DEBUG std::cout << "<<DEBUG>> not enough coefficients" << std::endl; #endif return false; } } while(qp.nb_constraints() < 2*m); return false; }