00001
00002 #include "imesh_detect.h"
00003
00004
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
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
00061 }
00062
00063
00064
00065
00066
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
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
00216
00217
00218
00219
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