32 #include "DGtal/base/Common.h"
33 #include "DGtal/helpers/StdDefs.h"
34 #include "DGtal/images/ImageContainerBySTLVector.h"
35 #include "DGtal/io/writers/GenericWriter.h"
36 #include "DGtal/io/readers/MeshReader.h"
37 #include "DGtal/io/writers/MeshWriter.h"
38 #include "DGtal/images/ConstImageAdapter.h"
39 #include "DGtal/kernel/BasicPointFunctors.h"
40 #include "DGtal/math/linalg/SimpleMatrix.h"
42 #include <boost/program_options/options_description.hpp>
43 #include <boost/program_options/parsers.hpp>
44 #include <boost/program_options/variables_map.hpp>
47 using namespace DGtal;
51 namespace po = boost::program_options;
115 template<
typename TPo
int,
typename TEmbeder>
117 getNormal(
const TPoint &vect,
const TEmbeder &emb ){
135 template<
typename TImage,
typename TVectorField,
typename TPo
int>
137 fillPointArea(TImage &anImage, TVectorField &imageVectorField,
138 const TPoint aPoint,
const unsigned int size,
const unsigned int value,
const Z3i::RealPoint &n){
139 typename TImage::Domain aDom(aPoint-TPoint::diagonal(size), aPoint+TPoint::diagonal(size));
140 for(
typename TImage::Domain::ConstIterator it= aDom.begin(); it != aDom.end(); it++){
141 if (anImage.domain().isInside(*it)){
142 anImage.setValue(*it, value);
143 imageVectorField.setValue(*it, n);
149 int main(
int argc,
char** argv )
159 po::options_description general_opt(
"\nAllowed options are");
160 general_opt.add_options()
161 (
"help,h",
"display this message")
162 (
"input,i", po::value<std::string>(),
"mesh file (.off) " )
163 (
"meshScale,s", po::value<double>()->default_value(1.0),
164 "change the default mesh scale (each vertex multiplied by the scale) " )
165 (
"output,o", po::value<std::string>(),
"sequence of discrete point file (.sdp) ")
166 (
"orientAutoFrontX",
"automatically orients the camera in front according the x axis." )
167 (
"orientAutoFrontY",
"automatically orients the camera in front according the y axis." )
168 (
"orientAutoFrontZ",
"automatically orients the camera in front according the z axis." )
169 (
"orientBack",
"change the camera direction to back instead front as given in orientAutoFront{X,Y,Z} options." )
170 (
"nx", po::value<double>()->default_value(0),
"set the x component of the projection direction." )
171 (
"ny", po::value<double>()->default_value(0),
"set the y component of the projection direction." )
172 (
"nz", po::value<double>()->default_value(1),
"set the z component of the projection direction." )
173 (
"centerX,x", po::value<unsigned int>()->default_value(0),
"choose x center of the projected image." )
174 (
"centerY,y", po::value<unsigned int>()->default_value(0),
"choose y center of the projected image." )
175 (
"centerZ,z", po::value<unsigned int>()->default_value(1),
"choose z center of the projected image." )
176 (
"width", po::value<unsigned int>()->default_value(100),
"set the width of the area to be extracted as an height field image." )
177 (
"height", po::value<unsigned int>()->default_value(100),
"set the height of the area to extracted as an height field image." )
178 (
"heightFieldMaxScan", po::value<unsigned int>()->default_value(255),
"set the maximal scan deep." )
179 (
"exportNormals",
"export mesh normal vectors (given in the image height field basis)." )
180 (
"backgroundNormalBack",
"set the normals of background in camera opposite direction (to obtain a black background in rendering). " )
182 (
"setBackgroundLastDepth",
"change the default background (black with the last filled intensity).");
185 double triangleAreaUnit = 0.5;
187 po::variables_map vm;
189 po::store(po::parse_command_line(argc, argv, general_opt), vm);
190 }
catch(
const std::exception& ex){
192 trace.
info()<<
"Error checking program options: "<< ex.what()<< endl;
195 if( !parseOK || vm.count(
"help")||argc<=1)
197 std::cout <<
"Usage: " << argv[0] <<
" [input] [output]\n"
198 <<
"Convert a mesh file into a projected 2D image given from a normal direction N and from a starting point P. The 3D mesh discretized and scanned in the normal direction N, starting from P with a step 1."
199 << general_opt <<
"\n";
200 std::cout <<
"Example:\n"
201 <<
"mesh2heightfield -i ${DGtal}/examples/samples/tref.off --orientAutoFrontZ --width 25 --height 25 -o heighMap.pgm -s 10 \n";
205 if(! vm.count(
"input") ||! vm.count(
"output"))
207 trace.
error() <<
" Input and output filename are needed to be defined" << endl;
211 string inputFilename = vm[
"input"].as<std::string>();
212 string outputFilename = vm[
"output"].as<std::string>();
213 double meshScale = vm[
"meshScale"].as<
double>();
214 trace.
info() <<
"Reading input file " << inputFilename ;
218 std::pair<Z3i::RealPoint, Z3i::RealPoint> b = inputMesh.getBoundingBox();
219 double diagDist = (b.first-b.second).norm();
220 if(diagDist<2.0*sqrt(2.0)){
221 inputMesh.changeScale(2.0*sqrt(2.0)/diagDist);
224 inputMesh.quadToTriangularFaces();
225 inputMesh.changeScale(meshScale);
226 trace.
info() <<
" [done] " << std::endl ;
227 double maxArea = triangleAreaUnit+1.0 ;
228 while(maxArea> triangleAreaUnit)
230 trace.
info()<<
"Iterating mesh subdivision ... "<< maxArea;
231 maxArea = inputMesh.subDivideTriangularFaces(triangleAreaUnit);
235 std::pair<Z3i::RealPoint, Z3i::RealPoint> bb = inputMesh.getBoundingBox();
237 bb.second+Z3i::Point::diagonal(1));
240 Image3D meshVolImage(meshDomain);
241 VectorFieldImage3D meshNormalImage(meshDomain);
244 it != meshVolImage.domain().end(); it++)
246 meshVolImage.setValue(*it, 0);
247 meshNormalImage.setValue(*it, z);
251 for(
unsigned int i =0; i< inputMesh.nbFaces(); i++)
263 fillPointArea(meshVolImage, meshNormalImage, p1, 1, 1, n);
264 fillPointArea(meshVolImage, meshNormalImage, p2, 1, 1, n);
265 fillPointArea(meshVolImage, meshNormalImage, p3, 1, 1, n);
266 fillPointArea(meshVolImage, meshNormalImage, c, 1, 1, n);
270 unsigned int widthImageScan = vm[
"height"].as<
unsigned int>()*meshScale;
271 unsigned int heightImageScan = vm[
"width"].as<
unsigned int>()*meshScale;
273 int maxScan = vm[
"heightFieldMaxScan"].as<
unsigned int>()*meshScale;
274 int centerX = vm[
"centerX"].as<
unsigned int>()*meshScale;
275 int centerY = vm[
"centerY"].as<
unsigned int>()*meshScale;
276 int centerZ = vm[
"centerZ"].as<
unsigned int>()*meshScale;
278 double nx = vm[
"nx"].as<
double>();
279 double ny = vm[
"ny"].as<
double>();
280 double nz = vm[
"nz"].as<
double>();
282 if(vm.count(
"orientAutoFrontX")|| vm.count(
"orientAutoFrontY") ||
283 vm.count(
"orientAutoFrontZ"))
285 Z3i::Point ptL = meshVolImage.domain().lowerBound();
286 Z3i::Point ptU = meshVolImage.domain().upperBound();
288 centerX=ptC[0]; centerY=ptC[1]; centerZ=ptC[2];
291 bool opp = vm.count(
"orientBack");
292 if(vm.count(
"orientAutoFrontX"))
295 maxScan = meshVolImage.domain().upperBound()[0]- meshVolImage.domain().lowerBound()[0];
296 centerX = centerX + (opp? maxScan/2: -maxScan/2) ;
298 if(vm.count(
"orientAutoFrontY"))
301 maxScan = meshVolImage.domain().upperBound()[1]- meshVolImage.domain().lowerBound()[1];
302 centerY = centerY + (opp? maxScan/2: -maxScan/2);
304 if(vm.count(
"orientAutoFrontZ"))
307 maxScan = meshVolImage.domain().upperBound()[2]-meshVolImage.domain().lowerBound()[2];
308 centerZ = centerZ + (opp? maxScan/2: -maxScan/2);
312 if(maxScan > std::numeric_limits<Image2D::Value>::max())
314 trace.
info()<<
"Max depth value outside image intensity range: " << maxScan
315 <<
" (use a rescaling functor which implies a loss of precision)" << std::endl;
317 trace.
info() <<
"Processing image to output file " << outputFilename;
321 Z3i::Point ptCenter (centerX, centerY, centerZ);
323 Image2D resultingImage(aDomain2D);
324 VectorFieldImage2D resultingVectorField(aDomain2D);
328 it != resultingImage.domain().end(); it++){
329 resultingImage.setValue(*it, 0);
330 resultingVectorField.setValue(*it, z);
334 unsigned int maxDepthFound = 0;
335 for(
unsigned int k=0; k < maxScan; k++)
339 ptCenter+normalDir*k,
342 ImageAdapterExtractor extractedImage(meshVolImage, aDomain2D, embedder, idV);
344 it != extractedImage.domain().end(); it++)
346 if(resultingImage(*it)== 0 && extractedImage(*it)!=0)
349 resultingImage.setValue(*it, scaleFctDepth(maxScan-k));
350 resultingVectorField.setValue(*it, getNormal(meshNormalImage(embedder(*it)), embedder));
354 if (vm.count(
"setBackgroundLastDepth"))
357 it != resultingImage.domain().end(); it++){
358 if( resultingImage(*it)== 0 )
360 resultingImage.setValue(*it, scaleFctDepth(maxScan-maxDepthFound));
364 bool inverBgNormal = vm.count(
"backgroundNormalBack");
366 it != resultingImage.domain().end(); it++){
369 resultingVectorField.setValue(*it,
Z3i::RealPoint(0, 0, inverBgNormal?-1: 1));
372 resultingImage >> outputFilename;
373 if(vm.count(
"exportNormals")){
374 std::stringstream ss;
375 ss << outputFilename <<
".normals";
377 outN.open(ss.str().c_str(), std::ofstream::out);
379 it != resultingImage.domain().end(); it++){
380 outN << (*it)[0] <<
" " << (*it)[1] <<
" " << 0 << std::endl;
381 outN <<(*it)[0]+ resultingVectorField(*it)[0] <<
" "
382 <<(*it)[1]+resultingVectorField(*it)[1] <<
" "
383 << resultingVectorField(*it)[2];
std::vector< unsigned int > MeshFace
void progressBar(const double currentValue, const double maximalValue)
SimpleMatrix< Component, TM, TN > inverse() const
Self crossProduct(const Self &v) const
void setComponent(const DGtal::Dimension i, const DGtal::Dimension j, const Component &aValue)
Trace trace(traceWriterTerm)
double norm(const NormType type=L_2) const
std::vector< Value >::const_iterator ConstIterator
static bool importOFFFile(const std::string &filename, DGtal::Mesh< TPoint > &aMesh, bool invertVertexOrder=false)