contrib/brl/bbas/imesh/algo/imesh_detect.cxx
Go to the documentation of this file.
00001 // This is brl/bbas/imesh/algo/imesh_detect.cxx
00002 #include "imesh_detect.h"
00003 //:
00004 // \file
00005 
00006 
00007 #include <vcl_algorithm.h>
00008 #include <vcl_limits.h>
00009 #include <vcl_cassert.h>
00010 #include <vil/vil_image_view.h>
00011 #include <vgl/algo/vgl_rotation_3d.h>
00012 #include <vgl/vgl_box_3d.h>
00013 #include <vnl/vnl_math.h>
00014 #include <vnl/vnl_double_3x3.h>
00015 #include <vnl/vnl_double_3.h>
00016 #include <imesh/algo/imesh_project.h>
00017 #include <imesh/algo/imesh_render.h>
00018 #include <imesh/imesh_operations.h>
00019 
00020 namespace{
00021 
00022 vgl_rotation_3d<double>
00023 make_rotation(const vgl_vector_3d<double>& dir)
00024 {
00025   vgl_vector_3d<double> z(normalized(dir));
00026   vgl_vector_3d<double> x = cross_product(vgl_vector_3d<double>(0,0,-1),z);
00027   if (x.sqr_length() == 0.0)
00028      x = cross_product(vgl_vector_3d<double>(0,-1,0),z);
00029   normalize(x);
00030   vgl_vector_3d<double> y = cross_product(z,x);
00031 
00032   vnl_double_3x3 A;
00033   A.set_row(0,vnl_double_3(x.x(), x.y(), x.z()));
00034   A.set_row(1,vnl_double_3(y.x(), y.y(), y.z()));
00035   A.set_row(2,vnl_double_3(z.x(), z.y(), z.z()));
00036   return vgl_rotation_3d<double>(A);
00037 }
00038 
00039 //: generate sample viewing directions from the sphere
00040 vcl_vector<vgl_vector_3d<double> >
00041 sample_sphere_directions(unsigned int num_dir_samples)
00042 {
00043   vcl_vector<vgl_vector_3d<double> > dirs;
00044   const unsigned int half_samples = num_dir_samples/2;
00045   for (unsigned int i=0; i<=half_samples; ++i) {
00046     double theta = i*2.0*vnl_math::pi/num_dir_samples;
00047     double st = vcl_sin(theta);
00048     double ct = vcl_cos(theta);
00049     unsigned int num_j_samples = static_cast<unsigned int>(st*num_dir_samples+0.5);
00050     if (num_j_samples == 0) num_j_samples = 1;
00051     for (unsigned j=0; j<num_j_samples; ++j) {
00052       double phi = j*2.0*vnl_math::pi/num_j_samples;
00053       double sp = vcl_sin(phi);
00054       double cp = vcl_cos(phi);
00055       dirs.push_back(vgl_vector_3d<double>(st*cp,st*sp,ct));
00056     }
00057   }
00058   return dirs;
00059 }
00060 // end of namespace
00061 }
00062 
00063 
00064 //: Return the set of triangles that are visible from this viewing direction
00065 // Backfacing triangles are not render or counted if \a backfacing == NULL
00066 // If \a backfacing is valid, backfacing exterior triangles are also added to this set
00067 vcl_set<unsigned int>
00068 imesh_detect_exterior_faces(const imesh_mesh& mesh,
00069                             const vgl_vector_3d<double>& dir,
00070                             unsigned int img_size,
00071                             vcl_set<unsigned int> *backfacing)
00072 {
00073   assert(mesh.faces().regularity() == 3);
00074   assert(mesh.faces().has_normals());
00075 
00076   vgl_rotation_3d<double> R = make_rotation(dir);
00077 
00078   const imesh_vertex_array<3>& verts = mesh.vertices<3>();
00079   vcl_vector<vgl_point_3d<double> > pts;
00080   vgl_box_3d<double> box;
00081   for (unsigned i=0; i<verts.size(); ++i)
00082   {
00083     pts.push_back(R*vgl_point_3d<double>(verts[i]));
00084     box.add(pts.back());
00085   }
00086   vcl_cout << box << vcl_endl;
00087 
00088   vgl_vector_3d<double> t(-box.min_x(), -box.min_y(), -box.min_z());
00089 
00090   double max_size = vcl_max(box.width(),box.height());
00091   double scale = (img_size-1)/max_size;
00092   t *= scale;
00093 
00094   vcl_vector<vgl_point_2d<double> > pts_2d(pts.size());
00095   vcl_vector<double> depths(pts.size());
00096   for (unsigned i=0; i<pts.size(); ++i)
00097   {
00098     vgl_point_3d<double>& pt = pts[i];
00099     pt.set(pt.x()*scale,pt.y()*scale,pt.z()*scale);
00100     pt += t;
00101     pts_2d[i].set(pt.x(),pt.y());
00102     depths[i] = pt.z();
00103   }
00104 
00105   unsigned int ni = static_cast<unsigned int>(vcl_ceil(scale*box.max_x()+t.x()))+1;
00106   unsigned int nj = static_cast<unsigned int>(vcl_ceil(scale*box.max_y()+t.y()))+1;
00107 
00108   vil_image_view<double> depth_img(ni,nj);
00109   depth_img.fill(vcl_numeric_limits<double>::infinity());
00110   vil_image_view<unsigned int> labels(ni,nj);
00111   labels.fill(imesh_invalid_idx);
00112 
00113   const imesh_regular_face_array<3>& tris =
00114       static_cast<const imesh_regular_face_array<3>&>(mesh.faces());
00115 
00116   vcl_vector<bool> is_backfacing(tris.size(),false);
00117   for (unsigned i=0; i<tris.size(); ++i) {
00118     const imesh_regular_face<3>& tri = tris[i];
00119     is_backfacing[i] = dot_product(tris.normal(i),dir) > 0;
00120     if (!backfacing && is_backfacing[i])
00121       continue;
00122     imesh_render_triangle_label(pts[tri[0]],
00123                                 pts[tri[1]],
00124                                 pts[tri[2]],
00125                                 i,
00126                                 labels,
00127                                 depth_img);
00128   }
00129 
00130   vcl_set<unsigned int> ext_faces;
00131   const unsigned int num_pixels = labels.ni()*labels.nj();
00132   const unsigned int* pixel = labels.top_left_ptr();
00133   for (unsigned int i=0; i<num_pixels; ++pixel, ++i)
00134   {
00135     if (*pixel != imesh_invalid_idx) {
00136       if (backfacing && is_backfacing[*pixel])
00137         backfacing->insert(*pixel);
00138       else
00139         ext_faces.insert(*pixel);
00140     }
00141   }
00142 
00143 #if 0
00144   vcl_vector<bool> ext_vert(depths.size(),false);
00145   unsigned int c=0;
00146   for (unsigned int n=0; n<depths.size(); ++n)
00147   {
00148     unsigned int i = static_cast<unsigned int>(vcl_floor(pts_2d[n].x()));
00149     unsigned int j = static_cast<unsigned int>(vcl_floor(pts_2d[n].y()));
00150     if (depths[n] <= depth_img(i,j)+1.0) {
00151       ext_vert[n] = true;
00152       ++c;
00153     }
00154   }
00155 
00156   for (unsigned int i=0; i<tris.size(); ++i)
00157   {
00158     const imesh_regular_face<3>& tri = tris[i];
00159     if (ext_vert[tri[0]] && ext_vert[tri[1]] && ext_vert[tri[2]])
00160       ext_faces.insert(i);
00161   }
00162 #endif
00163 
00164   return ext_faces;
00165 }
00166 
00167 
00168 //: Return the set of triangles that are visible in some of the many sample view directions
00169 vcl_set<unsigned int>
00170 imesh_detect_exterior_faces(const imesh_mesh& mesh,
00171                             unsigned int num_dir_samples,
00172                             unsigned int img_size)
00173 {
00174   vcl_auto_ptr<imesh_mesh> tri_mesh;
00175   const imesh_mesh* mesh_ptr = &mesh;
00176   vcl_vector<unsigned int> tri_map;
00177   if (mesh.faces().regularity() != 3) {
00178     for (unsigned int i=0; i<mesh.num_faces(); ++i)
00179     {
00180       for (unsigned int j=2; j<mesh.faces().num_verts(i); ++j)
00181         tri_map.push_back(i);
00182     }
00183     vcl_auto_ptr<imesh_vertex_array_base> verts_copy(mesh.vertices().clone());
00184     vcl_auto_ptr<imesh_face_array_base> faces_tri(imesh_triangulate(mesh.faces()));
00185     tri_mesh.reset(new imesh_mesh(verts_copy,faces_tri));
00186     tri_mesh->compute_face_normals();
00187     mesh_ptr = tri_mesh.get();
00188   }
00189   assert(mesh_ptr->faces().has_normals());
00190 
00191   vcl_vector<unsigned int> face_vote(mesh_ptr->num_faces(),0);
00192 
00193   vcl_vector<vgl_vector_3d<double> > dirs =
00194       sample_sphere_directions(num_dir_samples);
00195 
00196   for (unsigned int i=0; i<dirs.size(); ++i) {
00197     vcl_set<unsigned int> vis = imesh_detect_exterior_faces(*mesh_ptr, dirs[i], img_size);
00198     for (vcl_set<unsigned int>::const_iterator itr=vis.begin(); itr!=vis.end(); ++itr)
00199       ++face_vote[*itr];
00200   }
00201 
00202   vcl_set<unsigned int> ext;
00203   for (unsigned int i=0; i<face_vote.size(); ++i) {
00204     if (double(face_vote[i])/dirs.size() > 0.0) {
00205       if (tri_map.empty())
00206         ext.insert(i);
00207       else
00208         ext.insert(tri_map[i]);
00209     }
00210   }
00211   return ext;
00212 }
00213 
00214 
00215 //: Return the set of triangles that are visible in some of the many sample view directions
00216 //  Does render backfacing faces and classifies exterior faces as:
00217 //  - frontfacing - seen only from the front
00218 //  - backfacing  - seen only from the back
00219 //  - bifacing    - seen from both sides
00220 void
00221 imesh_detect_exterior_faces(const imesh_mesh& mesh,
00222                             vcl_set<unsigned int>& frontfacing,
00223                             vcl_set<unsigned int>& backfacing,
00224                             vcl_set<unsigned int>& bifacing,
00225                             unsigned int num_dir_samples,
00226                             unsigned int img_size)
00227 {
00228   vcl_auto_ptr<imesh_mesh> tri_mesh;
00229   const imesh_mesh* mesh_ptr = &mesh;
00230   vcl_vector<unsigned int> tri_map;
00231   if (mesh.faces().regularity() != 3) {
00232     for (unsigned int i=0; i<mesh.num_faces(); ++i)
00233     {
00234       for (unsigned int j=2; j<mesh.faces().num_verts(i); ++j)
00235         tri_map.push_back(i);
00236     }
00237     vcl_auto_ptr<imesh_vertex_array_base> verts_copy(mesh.vertices().clone());
00238     vcl_auto_ptr<imesh_face_array_base> faces_tri(imesh_triangulate(mesh.faces()));
00239     tri_mesh.reset(new imesh_mesh(verts_copy,faces_tri));
00240     tri_mesh->compute_face_normals();
00241     mesh_ptr = tri_mesh.get();
00242   }
00243   assert(mesh_ptr->faces().has_normals());
00244 
00245   vcl_vector<unsigned int> face_vote(mesh.num_faces(),0);
00246   vcl_vector<unsigned int> back_face_vote(mesh.num_faces(),0);
00247 
00248   vcl_vector<vgl_vector_3d<double> > dirs =
00249       sample_sphere_directions(num_dir_samples);
00250 
00251   for (unsigned int i=0; i<dirs.size(); ++i) {
00252     vcl_set<unsigned int> back_vis;
00253     vcl_set<unsigned int> vis = imesh_detect_exterior_faces(*mesh_ptr, dirs[i],
00254                                                             img_size, &back_vis);
00255     for (vcl_set<unsigned int>::const_iterator itr=vis.begin();
00256          itr!=vis.end(); ++itr) {
00257       unsigned int face_ind = tri_map.empty() ? *itr : tri_map[*itr];
00258       ++face_vote[face_ind];
00259      }
00260     for (vcl_set<unsigned int>::const_iterator itr=back_vis.begin();
00261          itr!=back_vis.end(); ++itr) {
00262       unsigned int face_ind = tri_map.empty() ? *itr : tri_map[*itr];
00263       ++back_face_vote[face_ind];
00264     }
00265   }
00266 
00267   frontfacing.clear();
00268   backfacing.clear();
00269   bifacing.clear();
00270   for (unsigned int i=0; i<face_vote.size(); ++i) {
00271     if (face_vote[i] > 0) {
00272       if (back_face_vote[i] > 0)
00273         bifacing.insert(i);
00274       else
00275         frontfacing.insert(i);
00276     }
00277     else if (back_face_vote[i] > 0)
00278       backfacing.insert(i);
00279   }
00280 }
00281