Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
biastrianglemesh.cpp
1 /*
2 This file is part of the BIAS library (Basic ImageAlgorithmS).
3 
4 Copyright (C) 2003-2009 (see file CONTACT for details)
5 Multimediale Systeme der Informationsverarbeitung
6 Institut fuer Informatik
7 Christian-Albrechts-Universitaet Kiel
8 
9 
10 BIAS is free software; you can redistribute it and/or modify
11 it under the terms of the GNU Lesser General Public License as published by
12 the Free Software Foundation; either version 2.1 of the License, or
13 (at your option) any later version.
14 
15 BIAS is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Lesser General Public License for more details.
19 
20 You should have received a copy of the GNU Lesser General Public License
21 along with BIAS; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24 
25 
26 #include <Utils/ThreeDOut.hh>
27 #ifdef BIAS_HAVE_OPENSCENEGRAPH
28 #include <GLviewer/ThreeDOutOpenSceneGraph.hh>
29 #endif
30 #include <Utils/TriangleMesh.hh>
31 #include <Base/Image/ImageIO.hh>
32 #include <Base/Image/ImageConvert.hh>
33 #include <Filter/Rescale.hh>
34 #include <Base/Common/FileHandling.hh>
35 #include <Image/Camera.hh>
36 #include <Utils/Param.hh>
37 
38 #include <sstream>
39 #include <iostream>
40 
41 using namespace std;
42 using namespace BIAS;
43 
44 #define TILE_WIDTH 129
45 #define TILE_HEIGHT 129
46 
47 
48 /**
49  @file
50  @ingroup g_tools
51  @brief generate triangle mesh from depth map, see biastrianglemesh.cpp
52  @author mfranke
53 */
54 
55 //////////////////////////// methods for triangle mesh computation ///////////////////////////////
56 //
57 // Level of detail downsamples the depth map and its projection, can be used
58 // with any meshing method
59 //
60 // Different meshing methods available through here
61 //
62 // tile mode -------on-------> mesh is created in single tiles by using naive
63 // | pixelwise method
64 // |
65 // off
66 // |
67 // |
68 //
69 // reduce!= 0 ------ yes ----> method for mesh reduction by % of the triangles
70 // |
71 // |
72 // |
73 // |
74 // no
75 // |
76 // |
77 // |
78 //
79 // calling simplified mesh method
80 // starting on a coarse pyramid level, triangles of the mesh are
81 // refined using the finer levels if necessary
82 //
83 //
84 //////////////////////////////////////////////////////////////////////////////////////////
85 
86 int main(int argc, char *argv[])
87 {
88  Param params(true);
89 
90  /**** GENERAL PARAMS ****/
91  int generalGroupID = params.GetFreeGroupID();
92 
93  bool* help = params.AddParamBool("help",
94  "print out help",
95  false, 'h',
96  generalGroupID);
97 
98  params.SetGroupName(generalGroupID, "general");
99 
100 
101  /**** INPUT PARAMS ****/
102  int inputParamGroupID = params.GetFreeGroupID();
103 
104  string* inputDepthMap = params.AddParamString("DepthMap",
105  "specify depth map",
106  "",
107  'D',
108  inputParamGroupID);
109 
110  string* inputTexture = params.AddParamString("Texture",
111  "specify texture, "
112  "if not specified -> triangle mesh will be untextured",
113  "",
114  'T',
115  inputParamGroupID);
116 
117  string* inputProjection = params.AddParamString("Projection",
118  "specify projection, "
119  "if not specified -> trying to parse meta data from (1.)texture or (2.)depth map",
120  "",
121  'P',
122  inputParamGroupID);
123 
124 
125  params.SetGroupName(inputParamGroupID, "input parameters");
126 
127  /**** CONFIGURATION PARAMS ****/
128  int configParamGroupID = params.GetFreeGroupID();
129 
130  double* inputReduce = params.AddParamDouble ("Reduce",
131  "reduce the triangles in the generated mesh to X percent of the original mesh ",
132  0.0,
133  0.0,
134  99.9,
135  'r',
136  configParamGroupID);
137 
138  bool* TileMode = params.AddParamBool("TileMode",
139  "set tile mode, "
140  "default is: false",
141  false, 't',
142  configParamGroupID);
143 
144  double* MinCornerAngleDEG = params.AddParamDouble("MinCornerAngleDEG",
145  "discard triangles containing a smaller angle (in degree), "
146  "default is: 3.0",
147  3.0, 0.0, 180.0,
148  'a',
149  configParamGroupID);
150 
151  double* MaxAngleDEG =
152  params.AddParamDouble("MaxAngleDEG",
153  "maximum angle between normal and viewray in degree, "
154  "0 means frontal view, default is: 91.0 (disabled)",
155  91.0, 0.0, 180.0,
156  'A',
157  configParamGroupID);
158 
159  double* LevelOfDetail = params.AddParamDouble("LevelOfDetail",
160  "set level of detail, "
161  "1: vertex for each pixel of full resolution, "
162  "2: of half resolution",
163  1.0, 0.0, 10.0,
164  'l',
165  configParamGroupID);
166 
167 
168  params.SetGroupName(configParamGroupID, "configuration parameters");
169 
170 
171  /**** OUTPUT PARAMS ****/
172  int outputGroupID = params.GetFreeGroupID();
173 
174  string* Outfile = params.AddParamString("Outfile",
175  "write results into this file",
176  "DenseTriangleMesh.wrl",
177  'o',
178  outputGroupID);
179 #ifdef BIAS_HAVE_OPENSCENEGRAPH
180  string* osgOutFile = params.AddParamString("ostOutFile", "write results in osg file", "DenseMesh.osg", 'O', outputGroupID);
181 #endif
182 
183  params.SetGroupName(outputGroupID, "output");
184 
185  /*** end params ***/
186 
187  int fup = params.ParseCommandLine(argc, argv);
188 
189  if(*help) {
190  params.Usage();
191  return 0;
192  }
193 
194 
195  if (fup < 3) {
196  cout <<"==> Too few arguments."<<endl;
197  params.Usage();
198  exit(1);
199  }
200 
201  Camera<unsigned char> texture;
202  Camera<float> texFloat;
203  if (string(*inputTexture) == "") {
204  cout<<"no texture specified, drawing untextured triangle mesh!"<<endl;
205  } else {
206  if(ImageIO::Load(*inputTexture, texture)!=0) {
207  if(ImageIO::Load(*inputTexture, texFloat)==0){
208  float maxVal = texFloat.GetMaxPixelValue();
209  if(maxVal <= 1.0){
210  texFloat.ScaleShift(255, 0);
211  }
212  ImageConvert::ConvertST(texFloat, texture, ImageBase::ST_unsignedchar);
213  } else {
214  cout<<"texture could not be loaded!\n";
215  return -1;
216  }
217  texture.ParseMetaData();
218  }
219  }
220 
221  Camera<float> depthMap;
222  if(ImageIO::Load(*inputDepthMap, depthMap)!=0) {
223  cout<<"depth map could not be loaded!\n";
224  params.Usage();
225  if (string(*inputDepthMap)==string("UNITSPHERE")) {
226  depthMap.Init(texture.GetWidth(), texture.GetHeight(), 1);
227  depthMap.FillImageWithConstValue(1.0f);
228  }
229  else return -1;
230  }
231 
232  depthMap.ParseMetaData();
233 
234  Projection Ptmp, P, texP;
235  int pLoad = -1;
236 
237  if (string(*inputProjection) == "") {
238  cout<<"no projection specified, trying to parse from meta data..."<<endl;
239  } else {
240  pLoad = Ptmp.Load(*inputProjection);
241  }
242  // if no projection is specified, texture image and depth map meta data are searched...
243  if (pLoad != 0) {
244  if (texture.IsProjValid()) {
245  Ptmp = texture.GetProj();
246  } else if (depthMap.IsProjValid()) {
247  Ptmp = depthMap.GetProj();
248  } else {
249  cout<<"Projection could not be loaded from file or meta data!\n";
250  params.Usage();
251  return -1;
252  }
253  }
254 
255  // create projections for depth map and texture according to image sizes
256  int widthTex = texture.GetWidth();
257  int heightTex = texture.GetHeight();
258  int widthDepth = depthMap.GetWidth();
259  int heightDepth = depthMap.GetHeight();
260  unsigned int widthP, heightP;
261  Ptmp.GetParameters()->GetImageSize(widthP, heightP);
262  if(widthTex != (int)widthP || heightTex != (int)heightP){
263  texP = Ptmp;
264  texP.GetParameters()->Rescale((unsigned int)widthTex, (unsigned int)heightTex);
265 
266  // just for debugging
267  unsigned int widthTmp, heightTmp;
268  texP.GetParameters()->GetImageSize(widthTmp, heightTmp);
269  cout << "rescaling texP tex size " << widthTex << " " << heightTex << " P size "
270  << widthP << " " << heightP << " new P " << widthTmp << " " << heightTmp << endl;
271  Ptmp.GetParameters()->GetImageSize(widthTmp, heightTmp);
272  cout << "P size still the same? " << widthTmp << " " << heightTmp << endl;
273  // end just for debugging
274  } else {
275  texP = Ptmp;
276  unsigned int widthTmp, heightTmp;
277  texP.GetParameters()->GetImageSize(widthTmp, heightTmp);
278  cout << "keeping size of texP " << widthTmp << " " << heightTmp << endl;
279  }
280 
281  if(widthDepth != (int)widthP || heightDepth != (int)heightP){
282  P = Ptmp;
283 
284  P.GetParameters()->Rescale((unsigned int)widthDepth, (unsigned int)heightDepth);
285 
286  // just for debugging
287  unsigned int widthTmp, heightTmp;
288  P.GetParameters()->GetImageSize(widthTmp, heightTmp);
289  cout << "rescaling depth P depth size " << widthDepth << " " << heightDepth << " P size "
290  << widthP << " " << heightP << " new P " << widthTmp << " " << heightTmp << endl;
291  // end just for debugging
292  } else {
293  P = Ptmp;
294  unsigned int widthTmp, heightTmp;
295  P.GetParameters()->GetImageSize(widthTmp, heightTmp);
296  cout << "keeping size of depthP " << widthTmp << " " << heightTmp << endl;
297  }
298 
299  cout<<"meshing..."<<flush<<endl;
300  double minCornerAngle = (*MinCornerAngleDEG)*M_PI/180.0;
301  double maxViewingAngle = (*MaxAngleDEG)*M_PI/180.0;
302 
303 
304  cout<<"minCornerAngle = "<<minCornerAngle<<endl;
305  cout<<"maxViewingAngle = "<<maxViewingAngle<<endl;
306  TriangleMesh mesh(minCornerAngle, maxViewingAngle);
307 
308 
309  cout<<"Level of detail is "<< *LevelOfDetail<<endl;
310  if (!(*LevelOfDetail == 1.0)) {
311  //double maxlevel = log(double(depthMap.GetWidth()))/log(2.0)-6;
312  //cout<<"maximum level is "<<maxlevel<<endl;
313 
314  for (double curLevel = 1.0;
315  curLevel < *LevelOfDetail; curLevel += 1.0) {
316  Gauss<float, float> DepthSmooth;
317  DepthSmooth.SetSigma(sqrt(1.0*1.0 - 0.5*0.5));
318  Image<float> copyOfDepth = depthMap;
319  DepthSmooth.Filter7x7GreyIgnoreBelowThreshold(depthMap, copyOfDepth,
320  0.0f);
321  depthMap.Release();
322  depthMap.Init(copyOfDepth.GetWidth()/2, copyOfDepth.GetHeight()/2);
323  for (unsigned int y=0; y<depthMap.GetHeight(); y++) {
324  for (unsigned int x=0; x<depthMap.GetWidth(); x++) {
325  depthMap.GetImageDataArray()[y][x] =
326  copyOfDepth.GetImageDataArray()[2*y][2*x];
327  }
328  }
329 
330  P.GetParameters()->Rescale(depthMap.GetWidth(), depthMap.GetHeight());
331  ImageIO::Save("depth"+FileHandling::toString(curLevel), depthMap);
332  }
333 
334  }
335 
336  string vrmlfilename = *Outfile;
337  cout<<"vrml file name is now "<<vrmlfilename<<endl;
338 #ifdef BIAS_HAVE_OPENSCENEGRAPH
339  ThreeDOutOpenSceneGraph vrmlOut;
340 #else
341  ThreeDOut vrmlOut;
342 #endif
343 
344  cout<<boolalpha;
345  cout<<"Tile Mode is set to "<<*TileMode<<endl;
346 
347  if(*TileMode) {
348 
349  // tile here into small image blocks, allows for writing of huge files
350  ofstream vrmlfile(vrmlfilename.c_str());
351  vrmlOut.VRMLOutWriteHeader(vrmlfile);
352 
353  unsigned int width, height;
354  P.GetParameters()->GetImageSize(width, height);
355  unsigned int tileWidth, tileHeight;
356  bool xFinished = false;
357  bool yFinished = false;
358  // bool finished = false;
359  unsigned int xStart, yStart;
360  unsigned int tileNum = 0;
361  yStart = 0;
362  int numTiles = (height/(TILE_HEIGHT-1)+1)*(width/(TILE_WIDTH-1)+1);
363  cout<<"Writing "<< numTiles
364  <<" tiles: "<<flush;
365  cout << "inputReduce " << *LevelOfDetail <<endl;
366 // if(*LevelOfDetail != 1.0){
367 // cout << "Rescaling texture to fit depth map - depth width " << depthMap.GetWidth() << " texture width " << texture.GetWidth() << endl;
368 // cout << "downsampling by " << *inputReduce << endl;
369 // Camera<unsigned char> tmp = texture;
370 // Rescale<unsigned char, unsigned char> rescaler;
371 // rescaler.Downsample(tmp,texture, *LevelOfDetail);
372 // }
373  while(!yFinished) {
374  if(yStart+TILE_HEIGHT >= height) {
375  yFinished = true;
376  tileHeight = height-yStart;
377  } else {
378  tileHeight = TILE_HEIGHT;
379  }
380 
381  cout<< double(tileNum)/double(numTiles)*100.0<<"% "<<flush;
382  xFinished = false;
383  xStart = 0;
384  while(!xFinished) {
385  stringstream ss;
386  ss<<"mesh_from_"<<string(*inputDepthMap)<<"_t"<<tileNum;
387  tileNum++;
388  if(xStart+TILE_WIDTH >= width) {
389  xFinished = true;
390  tileWidth = width -xStart;
391  }
392  else
393  tileWidth = TILE_WIDTH;
394 
395  int res = mesh.GenerateDenseMesh(depthMap, P, texture, texP,
396  xStart, yStart, tileWidth, tileHeight);
397  if(res==0) {
398  vrmlOut.AddTriangleMesh(mesh, ss.str(),
399  *inputTexture, false);
400  vrmlOut.VRMLOutIndexedFaceSets(vrmlfile);
401  // vrmlOut.RemoveAiasvll();
402  }
403  xStart+=(tileWidth-1);
404  }
405  yStart+=(tileHeight-1);
406  }
407 
408  cout<< " finished."<<endl<<flush;
409 
410  } else { // TileMode == false
411 
412  if(*inputReduce != 0.0){ // generate DenseMesh to reduce
413  mesh.GenerateDenseMesh(depthMap,P,texture,texP,true,*inputReduce);
414  }else{
415 
416  mesh.GenerateSimplifiedMesh(depthMap, P, texture, texP, 0, 0,
417  depthMap.GetWidth(),
418  depthMap.GetHeight(), 0.8, 0.5);
419  }
420  cout<<"finished\n"<<flush;
421 
422 
423  string texturefilename = *Outfile;
424  int dotIndex = texturefilename.find_last_of(".");
425  texturefilename.replace(dotIndex+1, 3, "png");
426 
427  cout<<"Writing Texture to "<<texturefilename<<flush<<endl;
428  vrmlOut.AddTriangleMesh(mesh, "mesh_from_"+string(*inputDepthMap),
429  texturefilename, true);
430  cout<<"finished\n";
431 
432 
433  }
434 
435  cout<<"Writing VRML to "<<vrmlfilename<<flush<<endl;
436  vrmlOut.VRMLOut(vrmlfilename);
437 #ifdef BIAS_HAVE_OPENSCENEGRAPH
438  cout << "Writing osg file to " << *osgOutFile << endl;
439  vrmlOut.OpenSceneGraphOut(*osgOutFile);
440 #endif
441 
442  cout<<"finished\n";
443 
444  return 0;
445 }
void Release()
reimplemented from ImageBase
Definition: Image.cpp:1579
unsigned int AddTriangleMesh(const TriangleMesh &mesh, const std::string &name="", const std::string &textureOutputName="", bool writeOutTexture=true, bool calcNormals=false)
Adds triangle mesh as IndexedFaceSet to ThreeDOut mem.
Definition: ThreeDOut.cpp:1104
StorageType GetMaxPixelValue(unsigned short int channel=0, unsigned int *coo=NULL) const
Get the maximal pixel value if coo!=NULL the coo[0]=x of max and coo[1]=y of max. ...
Definition: Image.cpp:995
int VRMLOut(const std::string &sFilename)
flush all 3d objects to a vrml file with name sFilename, this is the function most users would call ...
Definition: ThreeDOut.cpp:3670
virtual int Load(const std::string &filename)
convenience wrapper which tries to read different formats
Definition: Projection.cpp:62
int Filter7x7GreyIgnoreBelowThreshold(const Image< InputStorageType > &src, Image< OutputStorageType > &dst, const InputStorageType &thresh)
7x7 gauss filtering, values below threshold are ignored useful for depth map filtering ...
Definition: Gauss.cpp:1135
virtual void Rescale(double ratio, const double offset=0.0)
Adapt internal parameters to resampled image.
Unified output of 3D entities via OpenGL or VRML.
Definition: ThreeDOut.hh:349
bool * AddParamBool(const std::string &name, const std::string &help, bool deflt=false, char cmdshort=0, int Group=GRP_NOSHOW)
Definition: Param.cpp:305
double * AddParamDouble(const std::string &name, const std::string &help, double deflt=0.0, double min=-DBL_MAX, double max=DBL_MAX, char cmdshort=0, int Group=GRP_NOSHOW)
Definition: Param.cpp:351
int ScaleShift(double Scale, double Shift)
scales and shifts image (all channels simultanously)
Definition: Image.cpp:1064
unsigned int GetWidth() const
Definition: ImageBase.hh:312
int ParseCommandLine(int &argc, char *argv[])
scan command line arguments for valid parameters
Definition: Param.cpp:1028
void Usage(std::ostream &os=std::cout)
print Help-Information to stdout
Definition: Param.cpp:176
const ProjectionParametersBase * GetParameters(unsigned int cam=0) const
const parameter access function
Definition: Projection.hh:194
This class hides the underlying projection model, like projection matrix, spherical camera...
Definition: Projection.hh:70
Create and represent a 3D triangle mesh.
Definition: TriangleMesh.hh:84
unsigned int GetHeight() const
Definition: ImageBase.hh:319
void SetSigma(const double si)
Definition: Gauss.hh:162
int GetFreeGroupID()
returns unused group id
Definition: Param.cpp:1421
int VRMLOutIndexedFaceSets(std::ostream &VRMLFile)
only write (previously stored) face sets into an open vrml file Will include texture into VRML as Pix...
Definition: ThreeDOut.cpp:3203
void FillImageWithConstValue(StorageType Value)
fill grey images
Definition: Image.cpp:456
a class for exporting ThreeDOut objects to OSG scene graphs
virtual int GetImageSize(unsigned int &Width, unsigned int &Height) const
Obtain image dimensions.
void Init(unsigned int Width, unsigned int Height, unsigned int channels=1, enum EStorageType storageType=ST_unsignedchar, const bool interleaved=true)
calls Init from ImageBase storageType is ignored, just dummy argument
Definition: Image.cpp:421
This class Param provides generic support for parameters.
Definition: Param.hh:231
int SetGroupName(const int group_id, const std::string &name)
sets the name for a group
Definition: Param.cpp:1448
bool IsProjValid() const
Definition: Camera.hh:221
const BIAS::Projection & GetProj() const
Definition: Camera.hh:109
std::string * AddParamString(const std::string &name, const std::string &help, std::string deflt="", char cmdshort=0, int Group=GRP_NOSHOW)
Definition: Param.cpp:327
int ParseMetaData(bool bUse2x64bitTS=true)
After ImageIO::Load() operated on AppData_, this method fills P_, Timestamp, DC_*, ...
Definition: Camera.cpp:154
int VRMLOutWriteHeader(std::ostream &vrml)
write the VRML 2.0 header into an open file
Definition: ThreeDOut.cpp:3696
const StorageType ** GetImageDataArray() const
overloaded GetImageDataArray() from ImageBase
Definition: Image.hh:153