contrib/brl/bseg/bmdl/pro/processes/bmdl_generate_mesh_process.cxx
Go to the documentation of this file.
00001 //:
00002 // \file
00003 #include <bprb/bprb_func_process.h>
00004 
00005 #include <vcl_iostream.h>
00006 #include <vcl_sstream.h>
00007 #include <vcl_vector.h>
00008 #include <vcl_string.h>
00009 #include <vcl_ctime.h>
00010 #include <vcl_cstdio.h> // for std::fclose()
00011 #include <vcl_cassert.h>
00012 
00013 #include <vgl/vgl_polygon.h>
00014 #include <vgl/io/vgl_io_polygon.h>
00015 
00016 #include <vpl/vpl.h>
00017 
00018 #include <vil/vil_image_view.h>
00019 #include <vil/vil_pixel_format.h>
00020 #include <vil/vil_convert.h>
00021 
00022 #include <bmdl/bmdl_mesh.h>
00023 
00024 #include <imesh/imesh_vertex.h>
00025 #include <imesh/imesh_fileio.h>
00026 #include <imesh/imesh_detection.h>
00027 #include <imesh/imesh_operations.h>
00028 #include <imesh/algo/imesh_operations.h>
00029 
00030 #include <vpgl/vpgl_camera.h>
00031 #include <vpgl/file_formats/vpgl_geo_camera.h>
00032 #include <vpgl/vpgl_lvcs_sptr.h>
00033 #include <vpgl/vpgl_lvcs.h>
00034 #include <vul/vul_file.h>
00035 
00036 #if HAS_ZLIB
00037 #include <minizip/zip.h>
00038 #endif
00039 
00040 #define WRITEBUFFERSIZE (16384)
00041 
00042 
00043 void update_mesh_coord(imesh_mesh& imesh, vpgl_geo_camera* cam)
00044 {
00045   imesh_vertex_array<3>& vertices = imesh.vertices<3>();
00046   for (unsigned v=0; v<vertices.size(); v++) {
00047     unsigned int x = (unsigned int)vertices(v,0); // explicit cast from double
00048     unsigned int y = (unsigned int)vertices(v,1);
00049     unsigned int z = (unsigned int)vertices(v,2);
00050     vpgl_lvcs_sptr lvcs = cam->lvcs();
00051     double lon, lat, elev;
00052     cam->img_to_wgs(x, y, z, lon, lat, elev);
00053     vertices[v][0] = lon;
00054     vertices[v][1] = lat;
00055     vertices[v][2] = elev;
00056   }
00057 }
00058 
00059 void generate_kml(vcl_string& kml_filename,
00060                   imesh_mesh& mesh,
00061                   vpgl_geo_camera* lidar_cam)
00062 {
00063   vcl_ofstream os(kml_filename.c_str());
00064 
00065   os << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
00066      << "<kml xmlns=\"http://earth.google.com/kml/2.1\">\n"
00067      << "<Document>\n"
00068      << "  <name>" << vul_file::strip_directory(kml_filename.c_str()) << "</name>\n"
00069      << "  <open>1</open>\n"
00070      << "  <Placemark>\n"
00071   // << "    <name>" << model_name.c_str() << "</name>\n"
00072      << "    <visibility>1</visibility>\n"
00073      << "    <MultiGeometry>\n";
00074 
00075   // write each building into kml
00076   if (!mesh.has_half_edges())
00077     mesh.build_edge_graph();
00078 
00079   imesh_half_edge_set he = mesh.half_edges();
00080   vcl_vector<vcl_set<unsigned int> > cc = imesh_detect_connected_components(he);
00081   for (unsigned i=0; i<cc.size(); i++) {
00082     vcl_set<unsigned int> sel_faces = cc[i];
00083     imesh_mesh building = imesh_submesh_from_faces(mesh, sel_faces);
00084     update_mesh_coord(building, lidar_cam);
00085     imesh_write_kml(os, building);
00086   }
00087 
00088   os << "    </MultiGeometry>\n"
00089      << "  </Placemark>\n"
00090      << "</Document>\n"
00091      << "</kml>\n";
00092 
00093   os.close();
00094   imesh_write_obj("meshes.obj", mesh);
00095 }
00096 
00097 
00098 //: Write the KML file for wrapping a COLLADA mesh
00099 // \a lookat and \a location are (long,lat,alt) vectors
00100 // \a orientation is a (heading,tilt,roll) vector
00101 void
00102 write_kml_collada_wrapper(vcl_ostream& os,
00103                           const vcl_string& object_name,
00104                           const vgl_point_3d<double>& lookat,
00105                           const vgl_point_3d<double>& location,
00106                           const vgl_point_3d<double>& orientation,
00107                           const vcl_string& filename)
00108 {
00109   os.precision(16);
00110   os << "<?xml version='1.0' encoding='UTF-8'?>\n"
00111      << "<kml xmlns='http://earth.google.com/kml/2.1'>\n"
00112      << "<Folder>\n"
00113      << "  <name>" << object_name << "</name>\n"
00114      << "  <description><![CDATA[Created with <a href=\"http://sourceforge.vxl.net\">VXL</a>]]></description>\n"
00115      << "  <DocumentSource>Brown University imesh library</DocumentSource>\n"
00116      << "  <visibility>1</visibility>\n"
00117      << "  <LookAt>\n"
00118      << "    <heading>0</heading>\n"
00119      << "    <tilt>45</tilt>\n"
00120      << "    <longitude>" << lookat.x() << "</longitude>\n"
00121      << "    <latitude>" << lookat.y() << "</latitude>\n"
00122      << "    <altitude>" << lookat.z() << "</altitude>\n"
00123      << "    <range>200</range>\n"
00124      << "    <altitudeMode>absolute</altitudeMode>\n"
00125      << "  </LookAt>\n"
00126      << "  <Folder>\n"
00127      << "    <name>Tour</name>\n"
00128      << "    <Placemark>\n"
00129      << "      <name>Camera</name>\n"
00130      << "      <visibility>1</visibility>\n"
00131      << "    </Placemark>\n"
00132      << "  </Folder>\n"
00133      << "  <Placemark>\n"
00134      << "    <name>Model</name>\n"
00135      << "    <description><![CDATA[]]></description>\n"
00136      << "    <Style id='default'>\n"
00137      << "    </Style>\n"
00138      << "    <Model>\n"
00139      << "      <altitudeMode>relativeToGround</altitudeMode>\n"
00140      << "      <Location>\n"
00141      << "        <longitude>" << location.x()  << "</longitude>\n"
00142      << "        <latitude>" << location.y()  << "</latitude>\n"
00143      << "        <altitude>" << location.z() << "</altitude>\n"
00144      << "      </Location>\n"
00145      << "      <Orientation>\n"
00146      << "        <heading>" << orientation.x() << "</heading>\n"
00147      << "        <tilt>" << orientation.y() << "</tilt>\n"
00148      << "        <roll>" << orientation.z() << "</roll>\n"
00149      << "      </Orientation>\n"
00150      << "      <Scale>\n"
00151      << "        <x>1.0</x>\n"
00152      << "        <y>1.0</y>\n"
00153      << "        <z>1.0</z>\n"
00154      << "      </Scale>\n"
00155      << "      <Link>\n"
00156      << "        <href>" << filename << "</href>\n"
00157      << "      </Link>\n"
00158      << "    </Model>\n"
00159      << "  </Placemark>\n"
00160      << "</Folder>\n"
00161      << "</kml>\n";
00162 }
00163 #if (HAS_ZLIB)
00164 int zip_kmz(zipFile& zf, const char* filenameinzip)
00165 {
00166   FILE * fin;
00167   int size_read;
00168   zip_fileinfo zi;
00169   unsigned long crcFile=0;
00170   int size_buf=0;
00171   void* buf=NULL;
00172 
00173   zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour =
00174   zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0;
00175   zi.dosDate = 0;
00176   zi.internal_fa = 0;
00177   zi.external_fa = 0;
00178 
00179   // Get time in seconds since Jan 1 1970
00180   vcl_time_t time_secs;
00181   vcl_time(&time_secs);
00182 
00183   // Convert time to struct tm form
00184   struct vcl_tm *time;
00185   time = vcl_localtime(&time_secs);
00186   zi.tmz_date.tm_sec  = time->tm_sec;
00187   zi.tmz_date.tm_min  = time->tm_min;
00188   zi.tmz_date.tm_hour = time->tm_hour;
00189   zi.tmz_date.tm_mday = time->tm_mday;
00190   zi.tmz_date.tm_mon  = time->tm_mon ;
00191   zi.tmz_date.tm_year = time->tm_year;
00192 
00193   int err = 0;
00194   int opt_compress_level=Z_DEFAULT_COMPRESSION;
00195   const char* password=0;
00196 
00197   err = zipOpenNewFileInZip3(zf,filenameinzip,&zi,
00198                              NULL,0,NULL,0,NULL ,
00199                              (opt_compress_level != 0) ? Z_DEFLATED : 0,
00200                              opt_compress_level,0,
00201                              -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
00202                              password,crcFile);
00203 
00204   if (err != ZIP_OK) {
00205     vcl_printf("error in opening %s in zipfile\n",filenameinzip);
00206     return 0;
00207   }
00208   else {
00209     fin = vcl_fopen(filenameinzip,"rb");
00210     if (fin==NULL) {
00211         err=ZIP_ERRNO;
00212         vcl_printf("error in opening %s for reading\n",filenameinzip);
00213         return 0;
00214     }
00215   }
00216 
00217   size_buf = WRITEBUFFERSIZE;
00218   buf = (void*)malloc(size_buf);
00219   if (buf==NULL) {
00220     vcl_printf("Error allocating memory\n");
00221     return ZIP_INTERNALERROR;
00222   }
00223 
00224   do {
00225     err = ZIP_OK;
00226     size_read = (int)vcl_fread(buf,1,size_buf,fin);
00227     if (size_read < size_buf)
00228       if (feof(fin)==0) {
00229       vcl_printf("error in reading %s\n",filenameinzip);
00230       err = ZIP_ERRNO;
00231     }
00232 
00233     if (size_read>0) {
00234       err = zipWriteInFileInZip (zf,buf,size_read);
00235       if (err<0) {
00236           vcl_printf("error in writing %s in the zipfile\n", filenameinzip);
00237       }
00238     }
00239   } while ((err == ZIP_OK) && (size_read>0));
00240 
00241   if (fin)
00242     vcl_fclose(fin);
00243 
00244   if (err<0)
00245     err=ZIP_ERRNO;
00246   else {
00247     err = zipCloseFileInZip(zf);
00248     if (err!=ZIP_OK)
00249       vcl_printf("error in closing %s in the zipfile\n", filenameinzip);
00250   }
00251 
00252   int errclose = zipClose(zf,NULL);
00253 
00254   if (errclose != ZIP_OK) {
00255     vcl_printf("error in closing zipfile\n");
00256     return 0;
00257   }
00258   free(buf);
00259   return ZIP_OK;
00260 }
00261 #endif
00262 
00263 void generate_kml_collada(vcl_string& kmz_dir,
00264                           imesh_mesh& mesh,
00265                           vpgl_geo_camera* lidar_cam,
00266                           unsigned& num_of_buildings)
00267 {
00268   if (kmz_dir == "") {
00269     vcl_cerr << "Error: no filename selected.\n";
00270     return;
00271   }
00272 
00273   if (!vul_file::is_directory(kmz_dir)) {
00274     vcl_cerr << "Error: Select a directory name.\n";
00275     return;
00276   }
00277 
00278   vul_file::change_directory(kmz_dir);
00279   double origin_lat = 0,origin_lon = 0, origin_elev = 0;
00280   double lox, loy,theta;
00281   lidar_cam->lvcs()->get_origin(origin_lat,origin_lon,origin_elev);
00282   lidar_cam->lvcs()->get_transform(lox, loy,theta);
00283   // write each building into kml
00284   if (!mesh.has_half_edges())
00285     mesh.build_edge_graph();
00286 
00287   imesh_half_edge_set he = mesh.half_edges();
00288 
00289   vcl_string model_name;
00290 
00291   vcl_vector<vcl_set<unsigned int> > cc = imesh_detect_connected_components(he);
00292 
00293   for (unsigned i=0; i<cc.size(); i++) {
00294     vcl_set<unsigned int> sel_faces = cc[i];
00295     imesh_mesh building(imesh_submesh_from_faces(mesh, sel_faces));
00296     imesh_triangulate_nonconvex(building);
00297     building.compute_face_normals();
00298 
00299     // find the mean (x,y) and minimum z coordinates
00300     double minz = vcl_numeric_limits<double>::infinity();
00301     double meanx = 0.0, meany = 0.0;
00302     const imesh_vertex_array<3>& verts = building.vertices<3>();
00303     for (unsigned int v=0; v<verts.size(); ++v) {
00304       if (verts[v][2] < minz) {
00305         minz = verts[v][2];
00306       }
00307       meanx += verts[v][0];
00308       meany += verts[v][1];
00309     }
00310     meanx /= verts.size();
00311     meany /= verts.size();
00312 
00313     double lon, lat, elev;
00314     //assert(meanx >= 0 && meany <= 0 && minz >= 0);
00315     lidar_cam->img_to_wgs((unsigned int)meanx, (unsigned int)(-meany), (unsigned int)minz, lon, lat, elev);
00316 
00317     vcl_stringstream ss;
00318     ss << "structure_" << i+num_of_buildings;
00319     vcl_string kml_fname = ss.str() + ".kml";
00320     vcl_string dae_fname = ss.str() + ".dae";
00321 
00322     vcl_ofstream os (dae_fname.data());
00323     imesh_write_kml_collada(os, building);
00324     os.close();
00325 
00326     vcl_ofstream oskml(kml_fname.data());
00327     vgl_point_3d<double> lookat(lon, lat, elev);
00328     vgl_point_3d<double> location(origin_lon, origin_lat, -minz);
00329     vgl_point_3d<double> orientation(lox,loy,theta);
00330     write_kml_collada_wrapper(oskml,ss.str(),lookat,location,orientation,
00331                               vul_file::strip_directory(dae_fname));
00332     oskml.close();
00333 
00334 #if (HAS_ZLIB)
00335     vcl_string zip_fname = ss.str() + ".kmz";
00336     zipFile zipf = zipOpen(zip_fname.c_str(), APPEND_STATUS_CREATE);
00337     zip_kmz(zipf, dae_fname.c_str());
00338     zipf = zipOpen(zip_fname.c_str(), APPEND_STATUS_ADDINZIP);
00339     zip_kmz(zipf, kml_fname.c_str());
00340     vpl_unlink(kml_fname.c_str());
00341     vpl_unlink(dae_fname.c_str());
00342 #endif
00343   }
00344   num_of_buildings += cc.size();
00345 }
00346 
00347 
00348 bool generate_mesh(vcl_string fpath_poly,
00349                    vil_image_view_base_sptr label_img,
00350                    vil_image_view_base_sptr height_img,
00351                    vil_image_view_base_sptr ground_img,
00352                    vcl_string fpath_mesh,
00353                    vpgl_geo_camera* const lidar_cam,
00354                    unsigned& num_of_buildings)
00355 {
00356   if (label_img->pixel_format() != VIL_PIXEL_FORMAT_UINT_32) {
00357     vcl_cout << "bmdl_generate_mesh_process::the Label Image pixel format" << label_img->pixel_format() << " undefined" << vcl_endl;
00358     return false;
00359   }
00360   vil_image_view<vxl_uint_32> labels(label_img);
00361 
00362   vil_image_view<double> heights;
00363   if (height_img->pixel_format() == VIL_PIXEL_FORMAT_FLOAT) {
00364     vil_convert_cast(vil_image_view<float>(*height_img), heights);
00365   }
00366   else if (height_img->pixel_format() == VIL_PIXEL_FORMAT_DOUBLE) {
00367     heights = static_cast<vil_image_view<double> >(height_img.ptr());
00368   }
00369   else {
00370     vcl_cout << "bmdl_generate_mesh_process::the Height Image pixel format" << height_img->pixel_format() << " undefined" << vcl_endl;
00371     return false;
00372   }
00373 
00374   vil_image_view<double> ground;
00375   if (ground_img->pixel_format() == VIL_PIXEL_FORMAT_FLOAT) {
00376     vil_convert_cast(vil_image_view<float>(*ground_img), ground);
00377   }
00378   else if (ground_img->pixel_format() == VIL_PIXEL_FORMAT_DOUBLE) {
00379     ground = static_cast<vil_image_view<double> >(ground_img.ptr());
00380   }
00381   else {
00382     vcl_cout << "bmdl_generate_mesh_process::the Ground Image pixel format" << ground_img->pixel_format() << " undefined" << vcl_endl;
00383     return false;
00384   }
00385 
00386   // read polygons
00387   vsl_b_ifstream os(fpath_poly);
00388   unsigned char ver; //version();
00389   vsl_b_read(os, ver);
00390   unsigned int size;
00391   vsl_b_read(os, size);
00392   vgl_polygon<double> polygon;
00393   vcl_vector<vgl_polygon<double> > boundaries;
00394   for (unsigned i = 0; i < size; i++) {
00395     vsl_b_read(os, polygon);
00396     boundaries.push_back(polygon);
00397   }
00398 
00399   vcl_vector<bmdl_edge> edges;
00400   vcl_vector<bmdl_region> regions;
00401   unsigned int num_joints = bmdl_mesh::link_boundary_edges(labels, boundaries,
00402                                                            edges, regions);
00403   bmdl_mesh::simplify_edges(edges);
00404   imesh_mesh mesh;
00405   bmdl_mesh::mesh_lidar(edges, regions, num_joints, labels,
00406                         heights, ground, mesh);
00407 
00408   generate_kml_collada(fpath_mesh, mesh, lidar_cam, num_of_buildings);
00409   return true;
00410 }
00411 
00412 bool bmdl_generate_mesh_process(bprb_func_process& pro)
00413 {
00414   if (pro.n_inputs()< 6) {
00415     vcl_cout << "lidar_roi_process: The input number should be 6" << vcl_endl;
00416     return false;
00417   }
00418 
00419   unsigned int i=0;
00420   vcl_string file_poly = pro.get_input<vcl_string>(i++);
00421   vil_image_view_base_sptr label_img = pro.get_input<vil_image_view_base_sptr>(i++);
00422   vil_image_view_base_sptr height_img = pro.get_input<vil_image_view_base_sptr>(i++);
00423   vil_image_view_base_sptr ground_img = pro.get_input<vil_image_view_base_sptr>(i++);
00424   vcl_string file_mesh = pro.get_input<vcl_string>(i++);
00425   vpgl_camera_double_sptr camera = pro.get_input<vpgl_camera_double_sptr>(i++);
00426 
00427   if (!label_img) {
00428     vcl_cout << "bmdl_generate_mesh_process -- Label image is not set!\n";
00429     return false;
00430   }
00431 
00432   if (!height_img) {
00433     vcl_cout << "bmdl_generate_mesh_process -- Label image is not set!\n";
00434     return false;
00435   }
00436 
00437   if (!ground_img) {
00438     vcl_cout << "bmdl_generate_mesh_process -- Label image is not set!\n";
00439     return false;
00440   }
00441 
00442   if (camera->type_name().compare("vpgl_geo_camera") != 0) {
00443     vcl_cout << "bmdl_generate_mesh_process -- Camera input should be type of lidar!\n";
00444     return false;
00445   }
00446 
00447   vpgl_geo_camera* lidar_cam = static_cast<vpgl_geo_camera*>(camera.ptr());
00448   unsigned num_of_buildings=0;
00449   return generate_mesh(file_poly, label_img, height_img, ground_img, file_mesh, lidar_cam, num_of_buildings);
00450 }
00451 
00452 bool bmdl_generate_mesh_process_cons(bprb_func_process& pro)
00453 {
00454   vcl_vector<vcl_string> input_types;
00455   input_types.push_back("vcl_string");
00456   input_types.push_back("vil_image_view_base_sptr");
00457   input_types.push_back("vil_image_view_base_sptr");
00458   input_types.push_back("vil_image_view_base_sptr");
00459   input_types.push_back("vcl_string");
00460   input_types.push_back("vpgl_camera_double_sptr");
00461   return pro.set_input_types(input_types);
00462 }