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/base/BasicFunctors.h> 41 #include "DGtal/math/linalg/SimpleMatrix.h" 48 using namespace DGtal;
105 template<
typename TPo
int,
typename TEmbeder>
107 getNormal(
const TPoint &vect,
const TEmbeder &emb ){
125 template<
typename TImage,
typename TVectorField,
typename TPo
int>
127 fillPointArea(TImage &anImage, TVectorField &imageVectorField,
128 const TPoint aPoint,
const unsigned int size,
const unsigned int value,
const Z3i::RealPoint &n){
129 typename TImage::Domain aDom(aPoint-TPoint::diagonal(size), aPoint+TPoint::diagonal(size));
130 for(
typename TImage::Domain::ConstIterator it= aDom.begin(); it != aDom.end(); it++){
131 if (anImage.domain().isInside(*it)){
132 anImage.setValue(*it, value);
133 imageVectorField.setValue(*it, n);
139 int main(
int argc,
char** argv )
151 std::string inputFileName;
152 std::string outputFileName {
"result.pgm"};
153 double meshScale = 1.0;
154 double triangleAreaUnit = 0.5;
155 unsigned int widthImageScan = {100};
156 unsigned int heightImageScan = {100};
157 bool orientAutoFrontX =
false;
158 bool orientAutoFrontY =
false;
159 bool orientAutoFrontZ =
false;
160 bool orientBack =
false;
161 bool exportNormals =
false;
162 bool setBackgroundLastDepth =
false;
163 bool backgroundNormalBack =
false;
174 app.description(
"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.\n Example:\n mesh2heightfield ${DGtal}/examples/samples/tref.off heighMap.pgm --orientAutoFrontZ --width 25 --height 25 -s 10 \n");
175 app.add_option(
"-i,--input,1", inputFileName,
"mesh file (.off)" )
177 ->check(CLI::ExistingFile);
178 app.add_option(
"-o,--output,2", outputFileName,
"sequence of discrete point file (.sdp) ",
true );
179 app.add_option(
"--meshScale,-s", meshScale,
"change the default mesh scale (each vertex multiplied by the scale) ");
180 app.add_option(
"--heightFieldMaxScan", maxScan,
"set the maximal scan deep.",
true );
181 app.add_option(
"-x,--centerX",centerX,
"choose x center of the projected image.",
true);
182 app.add_option(
"-y,--centerY",centerY,
"choose y center of the projected image.",
true);
183 app.add_option(
"-z,--centerZ",centerZ,
"choose z center of the projected image.",
true);
184 app.add_option(
"--nx", nx,
"set the x component of the projection direction.",
true);
185 app.add_option(
"--ny", ny,
"set the y component of the projection direction.",
true);
186 app.add_option(
"--nz", nz,
"set the z component of the projection direction.",
true);
187 app.add_option(
"--width", widthImageScan,
"set the width of the area to be extracted as an height field image.",
true );
188 app.add_option(
"--height", heightImageScan,
"set the height of the area to extracted as an height field image.",
true );
189 app.add_flag(
"--orientAutoFrontX", orientAutoFrontX,
"automatically orients the camera in front according the x axis." );
190 app.add_flag(
"--orientAutoFrontY", orientAutoFrontY,
"automatically orients the camera in front according the y axis." );
191 app.add_flag(
"--orientAutoFrontZ", orientAutoFrontZ,
"automatically orients the camera in front according the z axis." );
192 app.add_flag(
"--orientBack", orientBack,
"change the camera direction to back instead front as given in orientAutoFront{X,Y,Z} options.");
193 app.add_flag(
"--exportNormals", exportNormals,
"export mesh normal vectors (given in the image height field basis).");
194 app.add_flag(
"--backgroundNormalBack", backgroundNormalBack,
"set the normals of background in camera opposite direction (to obtain a black background in rendering).");
195 app.add_flag(
"--setBackgroundLastDepth", setBackgroundLastDepth,
"change the default background (black with the last filled intensity).");
197 app.get_formatter()->column_width(40);
198 CLI11_PARSE(app, argc, argv);
201 widthImageScan *= meshScale;
202 heightImageScan *= meshScale;
203 maxScan *= meshScale;
204 centerX *= meshScale;
205 centerY *= meshScale;
206 centerZ *= meshScale;
209 trace.
info() <<
"Reading input file " << inputFileName ;
213 std::pair<Z3i::RealPoint, Z3i::RealPoint> b = inputMesh.getBoundingBox();
214 double diagDist = (b.first-b.second).norm();
215 if(diagDist<2.0*sqrt(2.0)){
216 inputMesh.changeScale(2.0*sqrt(2.0)/diagDist);
219 inputMesh.quadToTriangularFaces();
220 inputMesh.changeScale(meshScale);
221 trace.
info() <<
" [done] " << std::endl ;
222 double maxArea = triangleAreaUnit+1.0 ;
223 while(maxArea> triangleAreaUnit)
225 trace.
info()<<
"Iterating mesh subdivision ... "<< maxArea;
226 maxArea = inputMesh.subDivideTriangularFaces(triangleAreaUnit);
230 std::pair<Z3i::RealPoint, Z3i::RealPoint> bb = inputMesh.getBoundingBox();
232 bb.second+Z3i::Point::diagonal(1));
235 Image3D meshVolImage(meshDomain);
236 VectorFieldImage3D meshNormalImage(meshDomain);
239 it != meshVolImage.domain().end(); it++)
241 meshVolImage.setValue(*it, 0);
242 meshNormalImage.setValue(*it, z);
246 for(
unsigned int i =0; i< inputMesh.nbFaces(); i++)
258 fillPointArea(meshVolImage, meshNormalImage, p1, 1, 1, n);
259 fillPointArea(meshVolImage, meshNormalImage, p2, 1, 1, n);
260 fillPointArea(meshVolImage, meshNormalImage, p3, 1, 1, n);
261 fillPointArea(meshVolImage, meshNormalImage, c, 1, 1, n);
266 if(orientAutoFrontX || orientAutoFrontY || orientAutoFrontZ)
268 Z3i::Point ptL = meshVolImage.domain().lowerBound();
269 Z3i::Point ptU = meshVolImage.domain().upperBound();
271 centerX=ptC[0]; centerY=ptC[1]; centerZ=ptC[2];
277 nx=(orientBack?-1.0:1.0);
278 maxScan = meshVolImage.domain().upperBound()[0]- meshVolImage.domain().lowerBound()[0];
279 centerX = centerX + (orientBack? maxScan/2: -maxScan/2) ;
283 ny=(orientBack?-1.0:1.0);
284 maxScan = meshVolImage.domain().upperBound()[1]- meshVolImage.domain().lowerBound()[1];
285 centerY = centerY + (orientBack? maxScan/2: -maxScan/2);
289 nz=(orientBack?-1.0:1.0);
290 maxScan = meshVolImage.domain().upperBound()[2]-meshVolImage.domain().lowerBound()[2];
291 centerZ = centerZ + (orientBack? maxScan/2: -maxScan/2);
295 if(maxScan > std::numeric_limits<Image2D::Value>::max())
297 trace.
info()<<
"Max depth value outside image intensity range: " << maxScan
298 <<
" (use a rescaling functor which implies a loss of precision)" << std::endl;
300 trace.
info() <<
"Processing image to output file " << outputFileName;
304 Z3i::Point ptCenter (centerX, centerY, centerZ);
306 Image2D resultingImage(aDomain2D);
307 VectorFieldImage2D resultingVectorField(aDomain2D);
311 it != resultingImage.domain().end(); it++){
312 resultingImage.setValue(*it, 0);
313 resultingVectorField.setValue(*it, z);
317 unsigned int maxDepthFound = 0;
318 for(
unsigned int k=0; k < maxScan; k++)
321 Z3i::Point c (ptCenter+normalDir*k, DGtal::functors::Round<>());
326 ImageAdapterExtractor extractedImage(meshVolImage, aDomain2D, embedder, idV);
328 it != extractedImage.domain().end(); it++)
330 if(resultingImage(*it)== 0 && extractedImage(*it)!=0)
333 resultingImage.setValue(*it, scaleFctDepth(maxScan-k));
334 resultingVectorField.setValue(*it, getNormal(meshNormalImage(embedder(*it)), embedder));
338 if (setBackgroundLastDepth)
341 it != resultingImage.domain().end(); it++){
342 if( resultingImage(*it)== 0 )
344 resultingImage.setValue(*it, scaleFctDepth(maxScan-maxDepthFound));
348 bool inverBgNormal = backgroundNormalBack;
350 it != resultingImage.domain().end(); it++){
353 resultingVectorField.setValue(*it,
Z3i::RealPoint(0, 0, inverBgNormal?-1: 1));
356 resultingImage >> outputFileName;
358 std::stringstream ss;
359 ss << outputFileName <<
".normals";
361 outN.open(ss.str().c_str(), std::ofstream::out);
363 it != resultingImage.domain().end(); it++){
364 outN << (*it)[0] <<
" " << (*it)[1] <<
" " << 0 << std::endl;
365 outN <<(*it)[0]+ resultingVectorField(*it)[0] <<
" " 366 <<(*it)[1]+resultingVectorField(*it)[1] <<
" " 367 << resultingVectorField(*it)[2];
371 return EXIT_SUCCESS;;
std::vector< unsigned int > MeshFace
void progressBar(const double currentValue, const double maximalValue)
SimpleMatrix< Component, TM, TN > inverse() const
int main(int argc, char **argv)
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)