00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100 #include <time.h>
00101 #include <vector>
00102 using namespace std;
00103
00104 #include "defs.h"
00105 #include "sampling.h"
00106 #include "mesh_type.h"
00107 #include <vcg/complex/trimesh/update/edges.h>
00108 #include <vcg/complex/trimesh/update/bounding.h>
00109 #include <vcg/math/histogram.h>
00110 #include <vcg/complex/trimesh/clean.h>
00111 #include <wrap/io_trimesh/import.h>
00112 #include <wrap/io_trimesh/export.h>
00113
00114
00115
00116
00117 using namespace vcg;
00118
00119
00121 bool NumberOfSamples = false;
00122 bool SamplesPerAreaUnit = false;
00123 bool CleaningFlag=false;
00124
00125
00126 void Usage()
00127 {
00128 printf("\nUsage: "\
00129 "metro file1 file2 [opt]\n"\
00130 "Where opt can be:\n"\
00131 " -v disable vertex sampling\n"\
00132 " -e disable edge sampling\n"\
00133 " -f disable face sampling\n"\
00134 " -u ignore unreferred vertices\n"\
00135 " -sx set the face sampling mode\n"\
00136 " where x can be:\n"\
00137 " -s0 montecarlo sampling\n"\
00138 " -s1 subdivision sampling\n"\
00139 " -s2 similar triangles sampling (Default)\n"\
00140 " -n# set the required number of samples (overrides -A)\n"\
00141 " -a# set the required number of samples per area unit (overrides -N)\n"\
00142 " -c save a mesh with error as per-vertex colour and quality\n"\
00143 " -C # # Set the min/max values used for color mapping\n"\
00144 " -L Remove duplicated and unreferenced vertices before processing\n"\
00145 " -h write files with histograms of error distribution\n"\
00146 " -G Use a static Uniform Grid as Search Structure (default)\n"\
00147 " -O Use an octree as a Search Structure\n"\
00148 " -A Use an AxisAligned Bounding Box Tree as Search Structure\n"\
00149 " -H Use an Hashed Uniform Grid as Search Structure\n"\
00150 "\n"
00151 "Default options are to sample vertexes, edge and faces by taking \n"
00152 "a number of samples that is approx. 10x the face number.\n"
00153 );
00154 exit(-1);
00155 }
00156
00157
00158
00159 std::string SaveFileName(const std::string &filename)
00160 {
00161 int pos=filename.find_last_of('.',filename.length());
00162 std::string fileout=filename.substr(0,pos)+"_metro.ply";
00163 return fileout;
00164 }
00165
00166
00167
00168 void OpenMesh(const char *filename, CMesh &m)
00169 {
00170 int err = tri::io::Importer<CMesh>::Open(m,filename);
00171 if(err) {
00172 printf("Error in reading %s: '%s'\n",filename,tri::io::Importer<CMesh>::ErrorMsg(err));
00173 if(tri::io::Importer<CMesh>::ErrorCritical(err)) exit(-1);
00174 }
00175 printf("read mesh `%s'\n", filename);
00176 if(CleaningFlag){
00177 int dup = tri::Clean<CMesh>::RemoveDuplicateVertex(m);
00178 int unref = tri::Clean<CMesh>::RemoveUnreferencedVertex(m);
00179 printf("Removed %i duplicate and %i unreferenced vertices from mesh %s\n",dup,unref,filename);
00180 }
00181 }
00182
00183
00184 int main(int argc, char**argv)
00185 {
00186 CMesh S1, S2;
00187 float ColorMin=0, ColorMax=0;
00188 double dist1_max, dist2_max;
00189 unsigned long n_samples_target, elapsed_time;
00190 double n_samples_per_area_unit;
00191 int flags;
00192
00193
00194 printf("-------------------------------\n"
00195 " Metro V.4.07 \n"
00196 " http://vcg.isti.cnr.it\n"
00197 " release date: "__DATE__"\n"
00198 "-------------------------------\n\n");
00199
00200 if(argc <= 2) Usage();
00201
00202 flags = SamplingFlags::VERTEX_SAMPLING |
00203 SamplingFlags::EDGE_SAMPLING |
00204 SamplingFlags::FACE_SAMPLING |
00205 SamplingFlags::SIMILAR_SAMPLING;
00206
00207
00208 for(int i=3; i < argc;)
00209 {
00210 if(argv[i][0]=='-')
00211 switch(argv[i][1])
00212 {
00213 case 'h' : flags |= SamplingFlags::HIST; break;
00214 case 'v' : flags &= ~SamplingFlags::VERTEX_SAMPLING; break;
00215 case 'e' : flags &= ~SamplingFlags::EDGE_SAMPLING; break;
00216 case 'f' : flags &= ~SamplingFlags::FACE_SAMPLING; break;
00217 case 'u' : flags |= SamplingFlags::INCLUDE_UNREFERENCED_VERTICES; break;
00218 case 's' :
00219 switch(argv[i][2])
00220 {
00221 case '0': flags = (flags | SamplingFlags::MONTECARLO_SAMPLING ) & (~ SamplingFlags::NO_SAMPLING );break;
00222 case '1': flags = (flags | SamplingFlags::SUBDIVISION_SAMPLING ) & (~ SamplingFlags::NO_SAMPLING );break;
00223 case '2': flags = (flags | SamplingFlags::SIMILAR_SAMPLING ) & (~ SamplingFlags::NO_SAMPLING );break;
00224 default : printf(MSG_ERR_INVALID_OPTION, argv[i]);
00225 exit(0);
00226 }
00227 break;
00228 case 'n': NumberOfSamples = true; n_samples_target = (unsigned long) atoi(&(argv[i][2])); break;
00229 case 'a': SamplesPerAreaUnit = true; n_samples_per_area_unit = (unsigned long) atoi(&(argv[i][2])); break;
00230 case 'c': flags |= SamplingFlags::SAVE_ERROR; break;
00231 case 'L': CleaningFlag=true; break;
00232 case 'C': ColorMin=float(atof(argv[i+1])); ColorMax=float(atof(argv[i+2])); i+=2; break;
00233 case 'A': flags |= SamplingFlags::USE_AABB_TREE; printf("Using AABB Tree as search structure\n"); break;
00234 case 'G': flags |= SamplingFlags::USE_STATIC_GRID; printf("Using static uniform grid as search structure\n"); break;
00235 case 'H': flags |= SamplingFlags::USE_HASH_GRID; printf("Using hashed uniform grid as search structure\n"); break;
00236 case 'O': flags |= SamplingFlags::USE_OCTREE; printf("Using octree as search structure\n"); break;
00237 default : printf(MSG_ERR_INVALID_OPTION, argv[i]);
00238 exit(0);
00239 }
00240 i++;
00241 }
00242
00243 if(!(flags & SamplingFlags::USE_HASH_GRID) && !(flags & SamplingFlags::USE_AABB_TREE) && !(flags & SamplingFlags::USE_OCTREE))
00244 flags |= SamplingFlags::USE_STATIC_GRID;
00245
00246
00247 OpenMesh(argv[1],S1);
00248 OpenMesh(argv[2],S2);
00249
00250 string S1NewName=SaveFileName(argv[1]);
00251 string S2NewName=SaveFileName(argv[2]);
00252
00253 if(!NumberOfSamples && !SamplesPerAreaUnit)
00254 {
00255 NumberOfSamples = true;
00256 n_samples_target = 10 * max(S1.fn,S2.fn);
00257 }
00258
00259
00260 tri::UpdateEdges<CMesh>::Set(S1);
00261 tri::UpdateEdges<CMesh>::Set(S2);
00262
00263
00264 tri::UpdateBounding<CMesh>::Box(S1);
00265 tri::UpdateBounding<CMesh>::Box(S2);
00266
00267
00268 Box3<CMesh::ScalarType> bbox, tmp_bbox_M1=S1.bbox, tmp_bbox_M2=S2.bbox;
00269 bbox.Add(S1.bbox);
00270 bbox.Add(S2.bbox);
00271 bbox.Offset(bbox.Diag()*0.02);
00272 S1.bbox = bbox;
00273 S2.bbox = bbox;
00274
00275
00276 int t0=clock();
00277
00278 Sampling<CMesh> ForwardSampling(S1,S2);
00279 Sampling<CMesh> BackwardSampling(S2,S1);
00280
00281
00282 printf("Mesh info:\n");
00283 printf(" M1: '%s'\n\tvertices %7i\n\tfaces %7i\n\tarea %12.4f\n", argv[1], S1.vn, S1.fn, ForwardSampling.GetArea());
00284 printf("\tbbox (%7.4f %7.4f %7.4f)-(%7.4f %7.4f %7.4f)\n", tmp_bbox_M1.min[0], tmp_bbox_M1.min[1], tmp_bbox_M1.min[2], tmp_bbox_M1.max[0], tmp_bbox_M1.max[1], tmp_bbox_M1.max[2]);
00285 printf("\tbbox diagonal %f\n", (float)tmp_bbox_M1.Diag());
00286 printf(" M2: '%s'\n\tvertices %7i\n\tfaces %7i\n\tarea %12.4f\n", argv[2], S2.vn, S2.fn, BackwardSampling.GetArea());
00287 printf("\tbbox (%7.4f %7.4f %7.4f)-(%7.4f %7.4f %7.4f)\n", tmp_bbox_M2.min[0], tmp_bbox_M2.min[1], tmp_bbox_M2.min[2], tmp_bbox_M2.max[0], tmp_bbox_M2.max[1], tmp_bbox_M2.max[2]);
00288 printf("\tbbox diagonal %f\n", (float)tmp_bbox_M2.Diag());
00289
00290
00291 printf("\nForward distance (M1 -> M2):\n");
00292 ForwardSampling.SetFlags(flags);
00293 if(NumberOfSamples)
00294 {
00295 ForwardSampling.SetSamplesTarget(n_samples_target);
00296 n_samples_per_area_unit = ForwardSampling.GetNSamplesPerAreaUnit();
00297 }
00298 else
00299 {
00300 ForwardSampling.SetSamplesPerAreaUnit(n_samples_per_area_unit);
00301 n_samples_target = ForwardSampling.GetNSamplesTarget();
00302 }
00303 printf("target # samples : %u\ntarget # samples/area : %f\n", n_samples_target, n_samples_per_area_unit);
00304 ForwardSampling.Hausdorff();
00305 dist1_max = ForwardSampling.GetDistMax();
00306 printf("\ndistances:\n max : %f (%f wrt bounding box diagonal)\n", (float)dist1_max, (float)dist1_max/bbox.Diag());
00307 printf(" mean : %f\n", ForwardSampling.GetDistMean());
00308 printf(" RMS : %f\n", ForwardSampling.GetDistRMS());
00309 printf("# vertex samples %9d\n", ForwardSampling.GetNVertexSamples());
00310 printf("# edge samples %9d\n", ForwardSampling.GetNEdgeSamples());
00311 printf("# area samples %9d\n", ForwardSampling.GetNAreaSamples());
00312 printf("# total samples %9d\n", ForwardSampling.GetNSamples());
00313 printf("# samples per area unit: %f\n\n", ForwardSampling.GetNSamplesPerAreaUnit());
00314
00315
00316 printf("\nBackward distance (M2 -> M1):\n");
00317 BackwardSampling.SetFlags(flags);
00318 if(NumberOfSamples)
00319 {
00320 BackwardSampling.SetSamplesTarget(n_samples_target);
00321 n_samples_per_area_unit = BackwardSampling.GetNSamplesPerAreaUnit();
00322 }
00323 else
00324 {
00325 BackwardSampling.SetSamplesPerAreaUnit(n_samples_per_area_unit);
00326 n_samples_target = BackwardSampling.GetNSamplesTarget();
00327 }
00328 printf("target # samples : %u\ntarget # samples/area : %f\n", n_samples_target, n_samples_per_area_unit);
00329 BackwardSampling.Hausdorff();
00330 dist2_max = BackwardSampling.GetDistMax();
00331 printf("\ndistances:\n max : %f (%f wrt bounding box diagonal)\n", (float)dist2_max, (float)dist2_max/bbox.Diag());
00332 printf(" mean : %f\n", BackwardSampling.GetDistMean());
00333 printf(" RMS : %f\n", BackwardSampling.GetDistRMS());
00334 printf("# vertex samples %9d\n", BackwardSampling.GetNVertexSamples());
00335 printf("# edge samples %9d\n", BackwardSampling.GetNEdgeSamples());
00336 printf("# area samples %9d\n", BackwardSampling.GetNAreaSamples());
00337 printf("# total samples %9d\n", BackwardSampling.GetNSamples());
00338 printf("# samples per area unit: %f\n\n", BackwardSampling.GetNSamplesPerAreaUnit());
00339
00340
00341 elapsed_time = clock() - t0;
00342 int n_total_sample=ForwardSampling.GetNSamples()+BackwardSampling.GetNSamples();
00343 double mesh_dist_max = max(dist1_max , dist2_max);
00344
00345 printf("\nHausdorff distance: %f (%f wrt bounding box diagonal)\n",(float)mesh_dist_max,(float)mesh_dist_max/bbox.Diag());
00346 printf(" Computation time : %d ms\n",(int)(1000.0*elapsed_time/CLOCKS_PER_SEC));
00347 printf(" # samples/second : %f\n\n", (float)n_total_sample/((float)elapsed_time/CLOCKS_PER_SEC));
00348
00349
00350 if(flags & SamplingFlags::SAVE_ERROR)
00351 {
00352 vcg::tri::io::PlyInfo p;
00353 p.mask|=vcg::tri::io::Mask::IOM_VERTCOLOR | vcg::tri::io::Mask::IOM_VERTQUALITY ;
00354
00355 if(ColorMax!=0 || ColorMin != 0){
00356 vcg::tri::UpdateColor<CMesh>::VertexQualityRamp(S1,ColorMin,ColorMax);
00357 vcg::tri::UpdateColor<CMesh>::VertexQualityRamp(S2,ColorMin,ColorMax);
00358 }
00359 tri::io::ExporterPLY<CMesh>::Save( S1,S1NewName.c_str(),true,p);
00360 tri::io::ExporterPLY<CMesh>::Save( S2,S2NewName.c_str(),true,p);
00361 }
00362
00363
00364 if(flags & SamplingFlags::HIST)
00365 {
00366 ForwardSampling.GetHist().FileWrite("forward_result.csv");
00367 BackwardSampling.GetHist().FileWrite("backward_result.csv");
00368 }
00369 return 0;
00370 }
00371
00372