32 #include "DGtal/base/Common.h"
33 #include "DGtal/helpers/StdDefs.h"
34 #include "DGtal/images/ImageContainerBySTLVector.h"
35 #include "DGtal/io/readers/GenericReader.h"
36 #include "DGtal/io/writers/GenericWriter.h"
37 #include "DGtal/io/writers/PPMWriter.h"
38 #include "DGtal/images/ImageSelector.h"
39 #include "DGtal/io/readers/PointListReader.h"
40 #include "DGtal/images/ConstImageAdapter.h"
41 #include "DGtal/kernel/BasicPointFunctors.h"
43 #include "DGtal/io/colormaps/GrayscaleColorMap.h"
44 #include <boost/program_options/options_description.hpp>
45 #include <boost/program_options/parsers.hpp>
46 #include <boost/program_options/variables_map.hpp>
49 using namespace DGtal;
95 namespace po = boost::program_options;
98 template<
typename TImage,
typename TImageVector>
100 computerBasicNormalsFromHeightField(
const TImage &anHeightMap, TImageVector &vectorField)
102 for(
typename TImage::Domain::ConstIterator it = anHeightMap.domain().begin();
103 it != anHeightMap.domain().end(); it++){
104 if(anHeightMap.domain().isInside(*it+Z2i::Point::diagonal(1))&&
105 anHeightMap.domain().isInside(*it-Z2i::Point::diagonal(1))){
110 vectorField.setValue(*it,n);
117 template<
typename TImageVector>
119 importNormals(std::string file, TImageVector &vectorField)
122 for(
unsigned int i = 0; i< vp.size(); i=i+2){
126 vectorField.setValue(
Z2i::Point(p[0], p[1]),n);
131 template<
typename TImage2D,
typename TPo
int3D >
132 struct LambertianShadindFunctor{
133 LambertianShadindFunctor(
const TPoint3D &aLightSourceDir ):
134 myLightSourceDirection(aLightSourceDir/aLightSourceDir.norm()){}
137 unsigned int operator()(
const TPoint3D &aNormal)
const
139 int intensity = aNormal.dot(myLightSourceDirection)*std::numeric_limits<typename TImage2D::Value>::max();
140 return intensity>0? intensity:0;
142 TPoint3D myLightSourceDirection;
147 template<
typename TImage2D,
typename TPo
int3D >
148 struct LambertianShadindFunctorAllDirections{
149 LambertianShadindFunctorAllDirections(
const TPoint3D &aLightSourcePosition ):
150 myLightSourcePosition(aLightSourcePosition){}
153 unsigned int operator()(
const TPoint3D &aNormal,
const Z2i::Point &aPoint,
const double h)
const
158 l = -posL+myLightSourcePosition;
160 int intensity = aNormal.dot(l)*std::numeric_limits<typename TImage2D::Value>::max();
161 return intensity>0? intensity:0;
163 TPoint3D myLightSourcePosition;
171 template<
typename TImage2D,
typename TPo
int3D >
172 struct SpecularNayarShadindFunctor{
173 SpecularNayarShadindFunctor(
const TPoint3D &lightSourceDirection,
const double kld,
174 const double kls,
const double sigma ):
175 myLightSourceDirection(lightSourceDirection/lightSourceDirection.norm()),
176 myKld(kld), myKls(kls), mySigma(sigma){}
179 unsigned int operator()(
const TPoint3D &aNormal)
const {
180 double lambertianIntensity = std::max(aNormal.dot(myLightSourceDirection), 0.0);
181 double alpha = acos(((myLightSourceDirection+
Z3i::RealPoint(0,0,1.0))/2.0).dot(aNormal/aNormal.norm()));
182 double specularIntensity = exp(-alpha*alpha/(2.0*mySigma));
183 double resu = myKld*lambertianIntensity+myKls*specularIntensity;
185 resu = std::max(resu, 0.0);
186 resu = std::min(resu, 1.0);
187 return resu*std::numeric_limits<typename TImage2D::Value>::max();
190 TPoint3D myLightSourceDirection;
191 double myKld, myKls, mySigma;
197 template<
typename TImage2D,
typename TPo
int3D >
198 struct SpecularNayarShadindFunctorAllDirections{
199 SpecularNayarShadindFunctorAllDirections(
const TPoint3D &lightSourcePosition,
const double kld,
200 const double kls,
const double sigma ):
201 myLightSourcePosition(lightSourcePosition),
202 myKld(kld), myKls(kls), mySigma(sigma){}
205 unsigned int operator()(
const TPoint3D &aNormal,
const Z2i::Point &aPoint,
const double h)
const {
208 l = -posL+myLightSourcePosition;
211 double lambertianIntensity = std::max(aNormal.dot(l), 0.0);
212 double alpha = acos(((l+
Z3i::RealPoint(0,0,1.0))/2.0).dot(aNormal/aNormal.norm()));
213 double specularIntensity = exp(-alpha*alpha/(2.0*mySigma));
214 double resu = myKld*lambertianIntensity+myKls*specularIntensity;
216 resu = std::max(resu, 0.0);
217 resu = std::min(resu, 1.0);
218 return resu*std::numeric_limits<typename TImage2D::Value>::max();
221 TPoint3D myLightSourcePosition;
222 double myKld, myKls, mySigma;
229 template<
typename TImage2D,
typename TPo
int3D >
230 struct ImageMapReflectance{
232 ImageMapReflectance(
const std::string &filename): myImageMap (
PPMReader<TImage2D>::importPPM(filename))
235 myCenterPoint = (myImageMap.domain().upperBound()-myImageMap.domain().lowerBound())/2;
236 myImageRadius = min((myImageMap.domain().upperBound()-myImageMap.domain().lowerBound())[1], (myImageMap.domain().upperBound()-myImageMap.domain().lowerBound())[0])/2;
240 unsigned int operator()(
const TPoint3D &aNormal)
const
242 Z2i::Point p(aNormal[0]*myImageRadius,aNormal[1]*myImageRadius ) ;
244 if(myImageMap.domain().isInside(p)){
245 return myImageMap(p);
252 unsigned int myImageRadius;
257 Color operator()(
const unsigned int & aValue )
const{
264 int main(
int argc,
char** argv )
272 po::options_description general_opt(
"Allowed options are: ");
273 general_opt.add_options()
274 (
"help,h",
"display this message")
275 (
"input,i", po::value<std::string>(),
"heightfield file." )
276 (
"output,o", po::value<std::string>(),
"output image.")
277 (
"importNormal", po::value<std::string>(),
"import normals from file.")
278 (
"specularModel,s", po::value<std::vector<double> >()->multitoken(),
"use specular Nayar model with 3 param Kdiff, Kspec, sigma .")
279 (
"lx", po::value<double>(),
"x light source direction.")
280 (
"ly", po::value<double>(),
"y light source direction." )
281 (
"lz", po::value<double>(),
"z light source direction.")
282 (
"px", po::value<double>(),
"x light source position.")
283 (
"py", po::value<double>(),
"y light source position." )
284 (
"pz", po::value<double>(),
"z light source position.")
285 (
"reflectanceMap,r", po::value<std::string>(),
"specify a image as reflectance map.") ;
289 po::variables_map vm;
291 po::store(po::parse_command_line(argc, argv, general_opt), vm);
292 }
catch(
const std::exception& ex){
294 trace.
info()<<
"Error checking program options: "<< ex.what()<< endl;
297 if( !parseOK || vm.count(
"help")||argc<=1)
299 std::cout <<
"Usage: " << argv[0] <<
" [input] [output]\n"
300 <<
"Render a 2D heightfield image into a shading image. You can choose between lambertian model (diffuse reflectance) and specular model (Nayar reflectance model). You can also choose between a single directional light source (using -l{x,y,z} options) or use light source which emits in all direction (by specifying the light source position with -p{x,y,z} option). Another rendering mode is given from a bitmap reflectance map which represents the rendering for a normal vector value (mapped according the x/y coordinates). "
301 << general_opt <<
"\n";
302 std::cout <<
"Example:\n"
303 <<
"heightfield2shading -i heightfield.pgm -o shading.pgm --lx 0.0 --ly 1.0 --lz 1.0 --importNormal heightfield.pgm.normals -s 0.2 0.8 \n";
307 if(! vm.count(
"input") ||! vm.count(
"output"))
309 trace.
error() <<
" Input and output filename are needed to be defined" << endl;
313 string inputFilename = vm[
"input"].as<std::string>();
314 string outputFilename = vm[
"output"].as<std::string>();
315 double lx, ly, lz, px, py, pz;
316 bool usingAllDirectionLightSource =
false;
317 if(vm.count(
"lx") && vm.count(
"ly") && vm.count(
"lz"))
319 lx = vm[
"lx"].as<
double>();
320 ly = vm[
"ly"].as<
double>();
321 lz = vm[
"lz"].as<
double>();
323 else if(vm.count(
"px") && vm.count(
"py") && vm.count(
"pz"))
325 px = vm[
"px"].as<
double>();
326 py = vm[
"py"].as<
double>();
327 pz = vm[
"pz"].as<
double>();
328 usingAllDirectionLightSource =
true;
330 else if (!vm.count(
"reflectanceMap"))
332 trace.
error() <<
"You need to specify either the light source direction or position (if you use a all directions model)." << std::endl;
336 LambertianShadindFunctor<Image2D, Z3i::RealPoint> lShade (
Z3i::RealPoint(lx,ly,lz));
337 LambertianShadindFunctorAllDirections<Image2D, Z3i::RealPoint> lShadePosD (
Z3i::RealPoint(px ,py, pz));
338 SpecularNayarShadindFunctor<Image2D, Z3i::RealPoint> lSpecular (
Z3i::RealPoint(lx,ly,lz), 0, 0, 0);
339 SpecularNayarShadindFunctorAllDirections<Image2D, Z3i::RealPoint> lSpecularPosD (
Z3i::RealPoint(px,py,pz), 0, 0, 0);
342 bool useSpecular =
false;
343 if(vm.count(
"specularModel")){
344 std::vector<double> vectParam = vm[
"specularModel"].as<std::vector<double> > ();
345 if(vectParam.size() != 3)
347 trace.
warning() <<
"You have not specify all specular parameters... using lambertian model instead." << std::endl;
352 lSpecular.myKld = vectParam[0];
353 lSpecular.myKls = vectParam[1];
354 lSpecular.mySigma = vectParam[2];
355 lSpecularPosD.myKld = vectParam[0];
356 lSpecularPosD.myKls = vectParam[1];
357 lSpecularPosD.mySigma = vectParam[2];
358 if(vectParam[2]==0.0)
360 trace.
error()<<
"a 0 value for sigma is not possible in the Nayar model, please change it. "<< std::endl;
367 trace.
info() <<
"Reading input file " << inputFilename ;
369 Image2DNormals vectNormals (inputImage.
domain());
370 Image2D result (inputImage.
domain());
371 if(vm.count(
"importNormal")){
372 std::string normalFileName = vm[
"importNormal"].as<
string>();
373 importNormals(normalFileName, vectNormals);
375 computerBasicNormalsFromHeightField(inputImage, vectNormals);
377 if(vm.count(
"reflectanceMap"))
379 ImageMapReflectance<Image2D, Z3i::RealPoint> lMap(vm[
"reflectanceMap"].as<std::string>());
381 it != inputImage.
domain().end(); it++){
382 if(vm.count(
"reflectanceMap"))
384 result.setValue(*it, lMap(vectNormals(*it)));
397 it != inputImage.
domain().end(); it++){
398 if(usingAllDirectionLightSource)
400 result.setValue(*it, useSpecular? lSpecularPosD(vectNormals(*it), *it, inputImage(*it)):
401 lShadePosD(vectNormals(*it), *it, inputImage(*it)));
405 result.setValue(*it, useSpecular? lSpecular(vectNormals(*it)):lShade(vectNormals(*it)));
409 result >> outputFilename;
static TContainer import(const std::string &filename, std::vector< unsigned int > dimSpace=std::vector< unsigned int >())
Trace trace(traceWriterTerm)
double norm(const NormType type=L_2) const
const Domain & domain() const
std::vector< Value >::const_iterator ConstIterator