Une nouvelle version du portail de gestion des comptes externes sera mise en production lundi 09 août. Elle permettra d'allonger la validité d'un compte externe jusqu'à 3 ans. Pour plus de détails sur cette version consulter : https://doc-si.inria.fr/x/FCeS

Commit d534ba6a authored by Laurent Belcour's avatar Laurent Belcour
Browse files

Adding the isotropic Lafortune class

parent 0f40d776
......@@ -5,116 +5,6 @@
#include <string>
#include <fstream>
#ifdef OLD
clustering::clustering(const data* d, const arguments& args)
{
// List of the indices of the clustering
std::vector<int> indices;
vec findices = args.get_vec("cluster-dim", d->dimX(), -1.0f);
for(int i=0; i<findices.size() && findices[i] != -1.0f; ++i)
{
int id = (int)findices[i];
indices.push_back(id);
assert(id >= 0 && id < d->dimX());
}
std::cout << "<<DEBUG>> the resulting data will have " << indices.size() << " dimensions" << std::endl;
// We cannot have null cluster size of full rank.
assert(indices.size() > 0 && indices.size() < d->dimX());
// Fit the slice into the domain of definition of the data
vec compressed_vec = args.get_vec("cluster-slice", d->dimX(), std::numeric_limits<float>::max());
for(int i=0; i<d->dimX(); ++i)
{
compressed_vec[i] = std::min<double>(compressed_vec[i], d->max()[i]);
compressed_vec[i] = std::max<double>(compressed_vec[i], d->min()[i]);
}
// Set the limit of the new domain and dimensions
_nX = indices.size();
_nY = d->dimY();
_min = vec(_nX);
_max = vec(_nX);
for(int i=0; i<_nX; ++i)
{
_min[i] = d->min()[indices[i]];
_max[i] = d->max()[indices[i]];
}
for(int i=0; i<d->size(); ++i)
{
vec p = d->get(i);
bool reject = false;
for(int i=0; i<d->dimX(); ++i)
{
if(is_in<int>(indices, i) == -1 && p[i] != compressed_vec[i])
{
reject = true;
}
}
if(reject)
{
continue;
}
vec e(dimX()+dimY());
for(int i=0; i<_nX; ++i)
{
e[i] = p[indices[i]];
}
for(int i=0; i<_nY; ++i)
{
e[_nX + i] = p[d->dimX() + i];
}
_data.push_back(e);
}
std::cout << "<<INFO>> clustering left " << _data.size() << " elements" << std::endl;
save("cluster.txt");
}
void clustering::save(const std::string& filename)
{
std::ofstream file(filename.c_str(), std::ios_base::trunc);
file << "#DIM " << _nX << " " << _nY << std::endl;
for(int i=0; i<size(); ++i)
{
for(int j=0; j<_nX+_nY; ++j)
{
file << _data[i][j] << "\t";
}
file << std::endl;
}
file.close();
}
vec clustering::get(int i) const
{
return _data[i];
}
vec clustering::operator[](int i) const
{
return _data[i];
}
int clustering::size() const
{
return _data.size();
}
vec clustering::min() const
{
return _min;
}
vec clustering::max() const
{
return _max;
}
#else
template<class T> void clustering(const T* in_data, int _nY, params::input in_param, params::input out_param, std::vector<vec>& out_data)
{
......@@ -127,45 +17,55 @@ template<class T> void clustering(const T* in_data, int _nY, params::input in_pa
std::cout << "out dim = " << out_nX << std::endl;
#endif
for(int i=0; i<in_data->size(); ++i)
{
vec p = in_data->get(i);
vec e (out_nX + _nY);
// Fill the input part of the vector
params::convert(&p[0], in_param, out_param, &e[0]);
// Search for duplicates
bool already_exist = false;
for(unsigned int j=0; j<out_data.size(); ++j)
{
vec test_e = out_data[j];
double dist = 0.0;
for(int k=0; k<out_nX; ++k)
{
const double temp = test_e[k]-e[k];
dist += temp*temp;
}
if(dist < 1.0E-5)
already_exist = true;
}
if(!already_exist)
{
// Fill the output part of the vector
for(int j=0; j<_nY; ++j)
e[out_nX + j] = p[in_nX + j];
for(int i=0; i<in_data->size(); ++i)
{
vec p = in_data->get(i);
vec e (out_nX + _nY);
// Fill the input part of the vector
params::convert(&p[0], in_param, out_param, &e[0]);
// Search for duplicates only when the reparametrization is compressing
// the space.
if(out_nX < in_nX)
{
bool already_exist = false;
for(unsigned int j=0; j<out_data.size(); ++j)
{
vec test_e = out_data[j];
double dist = 0.0;
for(int k=0; k<out_nX; ++k)
{
const double temp = test_e[k]-e[k];
dist += temp*temp;
}
if(dist < 1.0E-5)
already_exist = true;
}
if(!already_exist)
{
// Fill the output part of the vector
for(int j=0; j<_nY; ++j)
e[out_nX + j] = p[in_nX + j];
#ifdef DEBUG
std::cout << " in = " << p << std::endl;
std::cout << "out = " << e << std::endl;
std::cout << " in = " << p << std::endl;
std::cout << "out = " << e << std::endl;
#endif
out_data.push_back(e);
}
}
out_data.push_back(e);
}
}
else
{
// Fill the output part of the vector
for(int j=0; j<_nY; ++j)
e[out_nX + j] = p[in_nX + j];
out_data.push_back(e);
}
}
}
#endif
#include "function.h"
#include <string>
#include <sstream>
#include <iostream>
#include <fstream>
#include <limits>
#include <algorithm>
#include <cmath>
#include <core/common.h>
ALTA_DLL_EXPORT function* provide_function()
{
return new isotropic_lafortune_function();
}
// Overload the function operator
vec isotropic_lafortune_function::operator()(const vec& x) const
{
return value(x);
}
vec isotropic_lafortune_function::value(const vec& x) const
{
// Get BRDF value
vec res(dimY());
double dx, dy, dz;
dx = x[0]*x[3];
dy = x[1]*x[4];
dz = x[2]*x[5];
// For each color channel
for(int i=0; i<dimY(); ++i)
{
res[i] = _kd[i];
// For each lobe
for(int n=0; n<_n; ++n)
{
double Cx, Cz, N;
getCurrentLobe(n, i, Cx, Cz, N);
double d = Cx*(dx + dy) + Cz*dz;
if(d > 0.0)
{
res[i] += pow(d, N);
}
}
}
return res;
}
vec isotropic_lafortune_function::value(const vec& x, const vec& p) const
{
// Test input parameters for correct size
assert(p.size() == nbParameters());
// Get BRDF value
vec res(dimY());
double dx, dy, dz;
dx = x[0]*x[3];
dy = x[1]*x[4];
dz = x[2]*x[5];
// For each color channel
for(int i=0; i<dimY(); ++i)
{
// Start with the diffuse term
res[i] = _kd[i];
// For each lobe
for(int n=0; n<_n; ++n)
{
double Cx, Cz, N;
Cx = p[(n*dimY() + i)*3 + 0];
Cz = p[(n*dimY() + i)*3 + 1];
N = p[(n*dimY() + i)*3 + 2];
const double d = Cx*(dx + dy) + Cz*dz;
if(d > 0.0)
res[i] += pow(d, N);
}
}
return res;
}
// Set the number of lobes of the Lafortune BRDF
void isotropic_lafortune_function::setNbLobes(int N)
{
_n = N;
// Update the length of the vectors
_C.resize(_n*_nY*2) ;
_N.resize(_n*_nY) ;
}
// Reset the output dimension
void isotropic_lafortune_function::setDimY(int nY)
{
_nY = nY ;
// Update the length of the vectors
_C.resize(_n*_nY*2) ;
_N.resize(_n*_nY) ;
_kd.resize(_nY);
for(int i=0; i<nY; ++i)
_kd[i] = 0.0;
}
//! Number of parameters to this non-linear function
int isotropic_lafortune_function::nbParameters() const
{
return (3*_n)*dimY();
}
//! Get the vector of parameters for the function
vec isotropic_lafortune_function::parameters() const
{
vec res((3*_n)*dimY());
for(int n=0; n<_n; ++n)
for(int i=0; i<dimY(); ++i)
{
res[(n*dimY() + i)*3 + 0] = _C[(n*dimY() + i)*2 + 0];
res[(n*dimY() + i)*3 + 1] = _C[(n*dimY() + i)*2 + 1];
res[(n*dimY() + i)*3 + 2] = _N[n*dimY() + i];
}
return res;
}
//! Update the vector of parameters for the function
void isotropic_lafortune_function::setParameters(const vec& p)
{
// Safety check the number of parameters
assert(p.size() == nbParameters());
for(int n=0; n<_n; ++n)
for(int i=0; i<dimY(); ++i)
{
_C[(n*dimY() + i)*2 + 0] = p[(n*dimY() + i)*3 + 0];
_C[(n*dimY() + i)*2 + 1] = p[(n*dimY() + i)*3 + 1];
_N[n*dimY() + i] = p[(n*dimY() + i)*3 + 2];
}
}
//! Obtain the derivatives of the function with respect to the
//! parameters.
vec isotropic_lafortune_function::parametersJacobian(const vec& x) const
{
double dx, dy, dz;
dx = x[0]*x[3];
dy = x[1]*x[4];
dz = x[2]*x[5];
vec jac(dimY()*nbParameters());
for(int i=0; i<dimY(); ++i)
{
for(int n=0; n<_n; ++n)
for(int j=0; j<dimY(); ++j)
{
// index of the current monochromatic lobe
int index = i*nbParameters() + 3*(n*dimY() + j);
double Cx, Cz, N;
getCurrentLobe(n, j, Cx, Cz, N);
double d = Cx*(dx + dy) + Cz*dz;
if(i == j && d > 0.0)
{
// df / dCx
jac[index+0] = (dx + dy) * N * std::pow(d, N-1.0);
// df / dCz
jac[index+1] = dz * N * std::pow(d, N-1.0);
// df / dN
if(d <= 0.0)
jac[index+2] = 0.0;
else
jac[index+2] = std::log(d) * std::pow(d, N);
}
else
{
jac[index+0] = 0.0;
jac[index+1] = 0.0;
jac[index+2] = 0.0;
}
}
}
return jac;
}
void isotropic_lafortune_function::bootstrap(const data* d, const arguments& args)
{
// Check the arguments for the number of lobes
this->setNbLobes(args.get_int("lobes", 1));
// Set the diffuse component
vec x0 = d->get(0);
for(int i=0; i<d->dimY(); ++i)
_kd[i] = x0[d->dimX() + i];
for(int i=1; i<d->size(); ++i)
{
vec xi = d->get(i);
for(int j=0; j<d->dimY(); ++j)
_kd[j] = std::min(xi[d->dimX() + j], _kd[j]);
}
std::cout << "<<INFO>> found diffuse: " << _kd << std::endl;
// The remaining data will be equal to one
for(int n=0; n<_n; ++n)
for(int i=0; i<dimY(); ++i)
{
_C[(n*dimY() + i)*2 + 0] = 0.0;
_C[(n*dimY() + i)*2 + 1] = 1.0;
_N[n*dimY() + i] = (double)_n;
}
}
std::ofstream& type_definition(std::ofstream& out, int nY)
{
if(nY == 1)
out << "float " ;
else
out << "vec" << nY ;
return out;
}
std::ofstream& type_affectation(std::ofstream& out, const std::string& name, const vec& x, int nY, int n=0, int s=0, int S=1)
{
out << name << " = ";
if(nY != 1)
out << "vec" << nY << "(";
for(int i=0; i<nY; ++i)
{
if(i != 0) out << ", ";
out << x[n*nY*S + i*S+s];
}
if(nY != 1)
out << ")";
out << ";" << std::endl;
return out;
}
//! Load function specific files
void isotropic_lafortune_function::load(const std::string& filename)
{
std::ifstream file(filename.c_str()) ;
if(!file.is_open())
{
std::cerr << "<<ERROR>> unable to open file \"" << filename << "\"" << std::endl ;
throw ;
}
_nX = 0 ; _nY = 0 ;
_n = 0;
double x, y, dy ;
while(file.peek() == '#')
{
std::string line ;
std::getline(file, line) ;
std::stringstream linestream(line) ;
linestream.ignore(1) ;
std::string comment ;
linestream >> comment ;
if(comment == std::string("DIM"))
{
linestream >> _nX >> _nY ;
}
else if(comment == std::string("NB_LOBES"))
{
linestream >> _n ;
}
}
_kd = vec(_nY);
setNbLobes(_n);
// Parse the diffuse
for(int i=0; i<_nY; ++i)
{
file >> _kd[i];
}
// Parse the lobe
for(int n=0; n<_n; ++n)
{
// TODO find a way to discard those lines
while(file.peek() == '#')
{
std::string line ;
std::getline(file, line) ;
}
// std::cout << (char)file.peek() << std::endl;
for(int i=0; i<_nY; ++i)
{
file >> _C[(n*_nY + i)*2 + 0] >> _C[(n*_nY + i)*2 + 1];
}
// TODO find a way to discard those lines
while(file.peek() == '#')
{
std::string line ;
std::getline(file, line) ;
}
for(int i=0; i<_nY; ++i)
{
file >> _N[i];
}
}
std::cout << "<<INFO>> Kd = " << _kd << std::endl;
std::cout << "<<INFO>> Cd = " << _C << std::endl;
std::cout << "<<INFO>> N = " << _N << std::endl;
}
void isotropic_lafortune_function::save(const std::string& filename) const
{
std::ofstream file(filename.c_str(), std::ios_base::trunc);
file << "#DIM " << _nX << " " << _nY << std::endl ;
file << "#NB_LOBES " << _n << std::endl ;
for(int i=0; i<_nY; ++i)
{
file << _kd[i] << std::endl;
}
file << std::endl;
for(int n=0; n<_n; ++n)
{
file << "#Lobe number " << n << std::endl;
file << "#Cxy Cz" << std::endl;
for(int i=0; i<_nY; ++i)
{
file << _C[(n*_nY + i)*2 + 0] << " " << _C[(n*_nY + i)*2 + 1] << std::endl;
}
file << std::endl;
file << "#N" << std::endl;
for(int i=0; i<_nY; ++i)
{
file << _N[i] << std::endl;
}
file << std::endl;
}
}
//! \brief Output the function using a BRDF Explorer formating.
//! \todo Finish
void isotropic_lafortune_function::save_brdfexplorer(const std::string& filename,
const arguments& args) const