diff --git a/sources/core/args.h b/sources/core/args.h index 88444d5d62cb12627eead2c9a8fe4cc3d6406f79..bd7841683973624f20ff057782873dc1d44adfa6 100644 --- a/sources/core/args.h +++ b/sources/core/args.h @@ -30,7 +30,8 @@ class arguments for(int i=0; i(key, data)) ; } - _map.insert(std::pair(key, data)) ; + } } ~arguments() @@ -132,7 +132,7 @@ class arguments } } //! \brief update the value \a val stored under key \a key - bool update(const std::string& key, const std::string& val) + void update(const std::string& key, const std::string& val) { _map[key] = val; } @@ -311,6 +311,16 @@ class arguments return current_args; } + friend std::ostream& operator<<(std::ostream& out, const arguments& args) + { + std::map::const_iterator it; + for(it=args._map.begin(); it!=args._map.end(); ++it) + { + out<< "[" << it->first << "] -> " << it->second << std::endl; + } + return out; + } + private: // data diff --git a/sources/core/fitter.h b/sources/core/fitter.h index 46c924addf827ca3a97be9898159bc35a5fe243c..e289f3a234c8cb3169c0892c91cc1124a53b380a 100644 --- a/sources/core/fitter.h +++ b/sources/core/fitter.h @@ -8,6 +8,7 @@ /*! \brief Fitting interface for generic fitting algorithms * \ingroup core * + * \details */ class fitter { diff --git a/sources/core/function.h b/sources/core/function.h index abc70149a9cd41bb1417eae7f2f1616f56731685..5ccebd16e0d70efb9634e77712d90c67b8e20231 100644 --- a/sources/core/function.h +++ b/sources/core/function.h @@ -761,12 +761,12 @@ class fresnel : public nonlinear_function { for(int i=0; idimY() == 1); + + set_num_residuals(1); + mutable_parameter_block_sizes()->push_back(f->nbParameters()); + } + + virtual bool Evaluate(double const* const* x, double* y, double** dy) const + { + // Check that the parameters used are within the bounds defined + // by the function + vec p_min = _f->getParametersMin(); + vec p_max = _f->getParametersMax(); + for(int i=0; i<_f->nbParameters(); ++i) + { + if(x[0][i] < p_min[i] || x[0][i] > p_max[i]) + { + return false; + } + } + + // Update the parameters vector + vec _p(_f->nbParameters()); + for(int i=0; i<_f->nbParameters(); ++i) { _p[i] = x[0][i]; } + _f->setParameters(_p); + + double _di = _xi[_f->dimX() + _j]; + + // Should add the resulting vector completely + y[0] = _di - (*_f)(_xi)[0]; + + if(dy != NULL) + { + df(dy); + } + + return true; + } + + // The parameter of the function _f should be set prior to this function + // call. If not it will produce undesirable results. + virtual void df(double ** fjac) const + { + // Get the jacobian of the function at position x_i for the current + // set of parameters (set prior to function call) + vec _jac = _f->parametersJacobian(_xi); + + // Fill the columns of the matrix + for(int j=0; j<_f->nbParameters(); ++j) + { + fjac[0][j] = -_jac[j]; + } + } + + protected: + + const vec _xi; + int _j; + nonlinear_function* _f; +}; + nonlinear_fitter_ceres::nonlinear_fitter_ceres() { } @@ -117,7 +188,7 @@ bool nonlinear_fitter_ceres::fit_data(const data* d, function* fit, const argume return false; } nonlinear_function* nf = dynamic_cast(fit); - nf->bootstrap(d, args); + #ifndef DEBUG std::cout << "<> number of parameters: " << nf->nbParameters() << std::endl; @@ -126,54 +197,113 @@ bool nonlinear_fitter_ceres::fit_data(const data* d, function* fit, const argume { return true; } +#ifdef FIT_CHANNELS + if(args.is_defined("ceres-channels")) + { + std::cout << "<> will fit the output dimensions separately" << std::endl; + std::cout << "<> make sur the function is separable." << std::endl; + return fit_channel(d, nf, args); + } + else +#endif + { + /* Bootstrap the function */ + nf->bootstrap(d, args); + + /* the following starting values provide a rough fit. */ + vec p = nf->parameters(); + + // Create the problem + ceres::Problem problem; + for(int i=0; isize(); ++i) + { + vec xi = d->get(i); + problem.AddResidualBlock(new CeresFunctor(nf, xi), NULL, &p[0]); + } + + // Solves the NL problem + ceres::Solver::Summary summary; + ceres::Solve(options, &problem, &summary); + +#ifdef DEBUG + std::cout << summary.BriefReport() << std::endl; +#endif + std::cout << "<> found parameters: " << p << std::endl; + + nf->setParameters(p); + return true; + } +} + +#ifdef FIT_CHANNELS +bool nonlinear_fitter_ceres::fit_channel(const data* d, nonlinear_function* nf, + const arguments& args) +{ /* the following starting values provide a rough fit. */ vec p = nf->parameters(); - // Create the problem - ceres::Problem problem; - for(int i=0; isize(); ++i) - { - vec xi = d->get(i); - problem.AddResidualBlock(new CeresFunctor(nf, xi), NULL, &p[0]); - } + // Convert the current function to monochromatic + nf->setDimY(1); - // Solver's options - ceres::Solver::Options options; - if(args.is_defined("ceres-max-num-iterations")) - { - options.max_num_iterations = args.get_int("ceres-max-num-iterations", 50); // Default value = 50 - } - - if(args["ceres-factorization"] == "normal-cholesky") - { - options.linear_solver_type = ceres::DENSE_NORMAL_CHOLESKY; - } - else - { - options.linear_solver_type = ceres::DENSE_QR; - } - if(args.is_defined("ceres-debug")) - { - options.minimizer_progress_to_stdout = true; // Default value = false; - } + for(int c=0; cdimY(); ++c) + { + nf->bootstrap(d, args); + // Temp parameter vector + vec temp_p = nf->parameters(); - // Solves the NL problem - ceres::Solver::Summary summary; - ceres::Solve(options, &problem, &summary); + // Create the problem + ceres::Problem problem; + for(int i=0; isize(); ++i) + { + vec xi = d->get(i); + problem.AddResidualBlock(new ColorChannelCost(nf, xi, c), NULL, &temp_p[0]); + } + // Solves the NL problem + ceres::Solver::Summary summary; + ceres::Solve(options, &problem, &summary); #ifdef DEBUG - std::cout << summary.BriefReport() << std::endl; + std::cout << summary.BriefReport() << std::endl; #endif - std::cout << "<> found parameters: " << p << std::endl; - nf->setParameters(p); - return true; + // Update the resulting parameter vector + for(int i=0; inbParameters(); ++i) + { + p[c*nf->nbParameters() + i] = temp_p[i]; + } + } + + std::cout << "<> found parameters: " << p << std::endl; + nf->setDimY(d->dimY()); + nf->setParameters(p); + + return true; } +#endif + void nonlinear_fitter_ceres::set_parameters(const arguments& args) { + if(args.is_defined("ceres-max-num-iterations")) + { + options.max_num_iterations = args.get_int("ceres-max-num-iterations", 50); // Default value = 50 + } + + if(args["ceres-factorization"] == "normal-cholesky") + { + options.linear_solver_type = ceres::DENSE_NORMAL_CHOLESKY; + } + else + { + options.linear_solver_type = ceres::DENSE_QR; + } + + if(args.is_defined("ceres-debug")) + { + options.minimizer_progress_to_stdout = true; // Default value = false; + } } diff --git a/sources/plugins/nonlinear_fitter_ceres/fitter.h b/sources/plugins/nonlinear_fitter_ceres/fitter.h index 93afb84263ad3f22062a0fef2810a7380a2603e3..f16e35885e7185e33285cd485d813f7453727847 100644 --- a/sources/plugins/nonlinear_fitter_ceres/fitter.h +++ b/sources/plugins/nonlinear_fitter_ceres/fitter.h @@ -11,6 +11,9 @@ #include #include +// CERES include +#include + /*! \brief A non-linear fitter using the CERES solver * \ingroup plugins * @@ -65,8 +68,16 @@ class nonlinear_fitter_ceres: public fitter virtual void set_parameters(const arguments& args) ; protected: // function - +#ifdef FIT_CHANNELS + // Fit a single color channel from the data + // + virtual bool fit_channel(const data*, nonlinear_function* fit, + const arguments& args) ; +#endif protected: // data + + // Fitter options + ceres::Solver::Options options; } ; diff --git a/sources/plugins/nonlinear_fresnel_schlick/function.cpp b/sources/plugins/nonlinear_fresnel_schlick/function.cpp index d475e93dd4439a7e4f1c5f9f5d6968fdd913343c..4478e6bd73e458597580a4f6625e37d571b1737a 100644 --- a/sources/plugins/nonlinear_fresnel_schlick/function.cpp +++ b/sources/plugins/nonlinear_fresnel_schlick/function.cpp @@ -17,30 +17,33 @@ ALTA_DLL_EXPORT function* provide_function() //! Load function specific files void schlick::load(std::istream& in) { - fresnel::load(in); + fresnel::load(in); - // Parse line until the next comment - while(in.peek() != '#') - { - char line[256]; - in.getline(line, 256); - } + // Parse line until the next comment + while(in.peek() != '#') + { + char line[256]; + in.getline(line, 256); + } - // Checking for the comment line #FUNC nonlinear_fresnel_schlick - std::string token; - in >> token; - if(token != "#FUNC") { std::cerr << "<> parsing the stream. The #FUNC is not the next line defined." << std::endl; } + // Checking for the comment line #FUNC nonlinear_fresnel_schlick + std::string token; + in >> token; + if(token != "#FUNC") { std::cerr << "<> parsing the stream. The #FUNC is not the next line defined." << std::endl; } - in >> token; - if(token != "nonlinear_fresnel_schlick") { std::cerr << "<> parsing the stream. function name is not the next token." << std::endl; } + in >> token; + if(token != "nonlinear_fresnel_schlick") { std::cerr << "<> parsing the stream. function name is not the next token." << std::endl; } - // R [double] - in >> token >> R; + // R [double] + for(int i=0; i> token >> R[i]; + } } void schlick::save_call(std::ostream& out, const arguments& args) const { - bool is_alta = !args.is_defined("export") || args["export"] == "alta"; + bool is_alta = !args.is_defined("export") || args["export"] == "alta"; if(is_alta) { @@ -51,32 +54,41 @@ void schlick::save_call(std::ostream& out, const arguments& args) const out << "("; f->save_call(out, args); out << ")"; } - if(is_alta) - { - out << "#FUNC nonlinear_fresnel_schlick" << std::endl ; - out << "R " << R << std::endl; - out << std::endl; - } - else - { - out << " * schlick_fresnel(L, V, N, X, Y, " << R << ")"; - } + if(is_alta) + { + out << "#FUNC nonlinear_fresnel_schlick" << std::endl ; + for(int i=0; isave_body(out, args); - bool is_shader = args["export"] == "shader" || args["export"] == "explorer"; - - if(is_shader) - { - out << std::endl; - out << "vec3 schlick_fresnel(vec3 L, vec3 V, vec3 N, vec3 X, vec3 Y, float R)" << std::endl; - out << "{" << std::endl; - out << "\tvec3 H = normalize(L + V);" << std::endl; - out << "\treturn vec3(R + (1.0f - R) * pow(1.0f - clamp(dot(H,L), 0.0f, 1.0f), 5));" << std::endl; - out << "}" << std::endl; - } + f->save_body(out, args); + bool is_shader = args["export"] == "shader" || args["export"] == "explorer"; + + if(is_shader) + { + out << std::endl; + out << "vec3 schlick_fresnel(vec3 L, vec3 V, vec3 N, vec3 X, vec3 Y, vec3 R)" << std::endl; + out << "{" << std::endl; + out << "\tvec3 H = normalize(L + V);" << std::endl; + out << "\treturn R + (vec3(1.0) - R) * pow(1.0f - clamp(dot(H,V), 0.0f, 1.0f), 5);" << std::endl; + out << "}" << std::endl; + } } @@ -91,54 +103,74 @@ vec schlick::fresnelValue(const vec& x) const vec res(_nY); for(int i=0; i<_nY; ++i) { - res[i] = R + (1.0 - R) * pow(1.0 - clamp(dotVH, 0.0, 1.0), 5.0); + res[i] = R[i] + (1.0 - R[i]) * pow(1.0 - clamp(dotVH, 0.0, 1.0), 5.0); } return res; } //! \brief Number of parameters to this non-linear function -int schlick::nbFresnelParameters() const +int schlick::nbFresnelParameters() const +{ + return dimY(); +} + +vec schlick::getFresnelParametersMin() const { - return 1; + vec m(dimY()); + for(int i=0; i