void from_nvm_scene(std::string const & nvm_file, std::vector<TextureView> * texture_views) { std::vector<mve::NVMCameraInfo> nvm_cams; mve::Bundle::Ptr bundle = mve::load_nvm_bundle(nvm_file, &nvm_cams); mve::Bundle::Cameras& cameras = bundle->get_cameras(); ProgressCounter view_counter("\tLoading", cameras.size()); #pragma omp parallel for for (std::size_t i = 0; i < cameras.size(); ++i) { view_counter.progress<SIMPLE>(); mve::CameraInfo& mve_cam = cameras[i]; mve::NVMCameraInfo const& nvm_cam = nvm_cams[i]; mve::ByteImage::Ptr image = mve::image::load_file(nvm_cam.filename); int const maxdim = std::max(image->width(), image->height()); mve_cam.flen = mve_cam.flen / static_cast<float>(maxdim); image = mve::image::image_undistort_vsfm<uint8_t> (image, mve_cam.flen, nvm_cam.radial_distortion); texture_views->push_back(TextureView(i, mve_cam, image)); view_counter.inc(); } }
TEX_NAMESPACE_BEGIN void from_mve_scene(std::string const & scene_dir, std::string const & embedding_name, std::vector<TextureView> * texture_views) { mve::Scene::Ptr scene; try { scene = mve::Scene::create(scene_dir); } catch (std::exception& e) { std::cerr << "Could not open scene: " << e.what() << std::endl; std::exit(EXIT_FAILURE); } std::size_t num_views = scene->get_views().size(); texture_views->reserve(num_views); ProgressCounter view_counter("\tLoading", num_views); for (std::size_t i = 0; i < num_views; ++i) { view_counter.progress<SIMPLE>(); mve::View::Ptr view = scene->get_view_by_id(i); if (view == NULL) { view_counter.inc(); continue; } if (!view->has_embedding(embedding_name)) { std::cout << "Warning: View " << view->get_name() << " has no embedding " << embedding_name << std::endl; continue; } mve::ByteImage::Ptr image = view->get_byte_image(embedding_name); if (image == NULL) { std::cerr << "Embedding " << embedding_name << " of view " << view->get_name() << " is not a byte embedding!" << std::endl; exit(EXIT_FAILURE); } if (image->channels() < 3) { std::cerr << "Embedding " << embedding_name << " of view " << view->get_name() << " is not a color image!" << std::endl; exit(EXIT_FAILURE); } texture_views->push_back(TextureView(view->get_id(), view->get_camera(), image)); view_counter.inc(); } }
void calculate_data_costs(mve::TriangleMesh::ConstPtr mesh, std::vector<TextureView> * texture_views, Settings const & settings, ST * data_costs) { mve::TriangleMesh::FaceList const & faces = mesh->get_faces(); mve::TriangleMesh::VertexList const & vertices = mesh->get_vertices(); mve::TriangleMesh::NormalList const & face_normals = mesh->get_face_normals(); std::size_t const num_faces = faces.size() / 3; std::size_t const num_views = texture_views->size(); CollisionModel3D* model = newCollisionModel3D(true); if (settings.geometric_visibility_test) { /* Build up acceleration structure for the visibility test. */ ProgressCounter face_counter("\tBuilding collision model", num_faces); model->setTriangleNumber(num_faces); for (std::size_t i = 0; i < faces.size(); i += 3) { face_counter.progress<SIMPLE>(); math::Vec3f v1 = vertices[faces[i]]; math::Vec3f v2 = vertices[faces[i + 1]]; math::Vec3f v3 = vertices[faces[i + 2]]; model->addTriangle(*v1, *v2, *v3); face_counter.inc(); } model->finalize(); } std::vector<std::vector<ProjectedFaceInfo> > projected_face_infos(num_faces); ProgressCounter view_counter("\tCalculating face qualities", num_views); #pragma omp parallel { std::vector<std::pair<std::size_t, ProjectedFaceInfo> > projected_face_view_infos; #pragma omp for schedule(dynamic) for (std::uint16_t j = 0; j < texture_views->size(); ++j) { view_counter.progress<SIMPLE>(); TextureView * texture_view = &texture_views->at(j); texture_view->load_image(); texture_view->generate_validity_mask(); if (settings.data_term == GMI) { texture_view->generate_gradient_magnitude(); texture_view->erode_validity_mask(); } math::Vec3f const & view_pos = texture_view->get_pos(); math::Vec3f const & viewing_direction = texture_view->get_viewing_direction(); for (std::size_t i = 0; i < faces.size(); i += 3) { std::size_t face_id = i / 3; math::Vec3f const & v1 = vertices[faces[i]]; math::Vec3f const & v2 = vertices[faces[i + 1]]; math::Vec3f const & v3 = vertices[faces[i + 2]]; math::Vec3f const & face_normal = face_normals[face_id]; math::Vec3f const face_center = (v1 + v2 + v3) / 3.0f; /* Check visibility and compute quality */ math::Vec3f view_to_face_vec = (face_center - view_pos).normalized(); math::Vec3f face_to_view_vec = (view_pos - face_center).normalized(); /* Backface culling */ float viewing_angle = face_to_view_vec.dot(face_normal); if (viewing_angle < 0.0f || viewing_direction.dot(view_to_face_vec) < 0.0f) continue; if (std::acos(viewing_angle) > MATH_DEG2RAD(75.0f)) continue; /* Projects into the valid part of the TextureView? */ if (!texture_view->inside(v1, v2, v3)) continue; if (settings.geometric_visibility_test) { /* Viewing rays do not collide? */ bool visible = true; math::Vec3f const * samples[] = {&v1, &v2, &v3}; // TODO: random monte carlo samples... for (std::size_t k = 0; k < sizeof(samples) / sizeof(samples[0]); ++k) { math::Vec3f vertex = *samples[k]; math::Vec3f dir = view_pos - vertex; float const dir_length = dir.norm(); dir.normalize(); if (model->rayCollision(*vertex, *dir, false, dir_length * 0.0001f, dir_length)) { visible = false; break; } } if (!visible) continue; } ProjectedFaceInfo info = {j, 0.0f, math::Vec3f(0.0f, 0.0f, 0.0f)}; /* Calculate quality. */ texture_view->get_face_info(v1, v2, v3, &info, settings); if (info.quality == 0.0) continue; /* Change color space. */ mve::image::color_rgb_to_ycbcr(*(info.mean_color)); std::pair<std::size_t, ProjectedFaceInfo> pair(face_id, info); projected_face_view_infos.push_back(pair); } texture_view->release_image(); texture_view->release_validity_mask(); if (settings.data_term == GMI) { texture_view->release_gradient_magnitude(); } view_counter.inc(); } //std::sort(projected_face_view_infos.begin(), projected_face_view_infos.end()); #pragma omp critical { for (std::size_t i = projected_face_view_infos.size(); 0 < i; --i) { std::size_t face_id = projected_face_view_infos[i - 1].first; ProjectedFaceInfo const & info = projected_face_view_infos[i - 1].second; projected_face_infos[face_id].push_back(info); } projected_face_view_infos.clear(); } } delete model; model = NULL; ProgressCounter face_counter("\tPostprocessing face infos", num_faces); #pragma omp parallel for schedule(dynamic) for (std::size_t i = 0; i < projected_face_infos.size(); ++i) { face_counter.progress<SIMPLE>(); std::vector<ProjectedFaceInfo> & infos = projected_face_infos[i]; if (settings.outlier_removal != NONE) { photometric_outlier_detection(&infos, settings); infos.erase(std::remove_if(infos.begin(), infos.end(), [](ProjectedFaceInfo const & info) -> bool {return info.quality == 0.0f;}), infos.end()); } std::sort(infos.begin(), infos.end()); face_counter.inc(); } /* Determine the function for the normlization. */ float max_quality = 0.0f; for (std::size_t i = 0; i < projected_face_infos.size(); ++i) for (std::size_t j = 0; j < projected_face_infos[i].size(); ++j) max_quality = std::max(max_quality, projected_face_infos[i][j].quality); Histogram hist_qualities(0.0f, max_quality, 10000); for (std::size_t i = 0; i < projected_face_infos.size(); ++i) for (std::size_t j = 0; j < projected_face_infos[i].size(); ++j) hist_qualities.add_value(projected_face_infos[i][j].quality); float percentile = hist_qualities.get_approx_percentile(0.995f); /* Calculate the costs. */ assert(num_faces < std::numeric_limits<std::uint32_t>::max()); assert(num_views < std::numeric_limits<std::uint16_t>::max()); assert(MRF_MAX_ENERGYTERM < std::numeric_limits<float>::max()); for (std::uint32_t i = 0; i < static_cast<std::uint32_t>(projected_face_infos.size()); ++i) { for (std::size_t j = 0; j < projected_face_infos[i].size(); ++j) { ProjectedFaceInfo const & info = projected_face_infos[i][j]; /* Clamp to percentile and normalize. */ float normalized_quality = std::min(1.0f, info.quality / percentile); float data_cost = (1.0f - normalized_quality) * MRF_MAX_ENERGYTERM; data_costs->set_value(i, info.view_id, data_cost); } /* Ensure that all memory is freeed. */ projected_face_infos[i].clear(); projected_face_infos[i].shrink_to_fit(); } std::cout << "\tMaximum quality of a face within an image: " << max_quality << std::endl; std::cout << "\tClamping qualities to " << percentile << " within normalization." << std::endl; }
void calculate_face_projection_infos(mve::TriangleMesh::ConstPtr mesh, std::vector<TextureView> * texture_views, Settings const & settings, FaceProjectionInfos * face_projection_infos) { std::vector<unsigned int> const & faces = mesh->get_faces(); std::vector<math::Vec3f> const & vertices = mesh->get_vertices(); mve::TriangleMesh::NormalList const & face_normals = mesh->get_face_normals(); std::size_t const num_views = texture_views->size(); util::WallTimer timer; std::cout << "\tBuilding BVH from " << faces.size() / 3 << " faces... " << std::flush; BVHTree bvh_tree(faces, vertices); std::cout << "done. (Took: " << timer.get_elapsed() << " ms)" << std::endl; ProgressCounter view_counter("\tCalculating face qualities", num_views); #pragma omp parallel { std::vector<std::pair<std::size_t, FaceProjectionInfo> > projected_face_view_infos; #pragma omp for schedule(dynamic) for (std::uint16_t j = 0; j < texture_views->size(); ++j) { view_counter.progress<SIMPLE>(); TextureView * texture_view = &texture_views->at(j); texture_view->load_image(); texture_view->generate_validity_mask(); if (settings.data_term == DATA_TERM_GMI) { texture_view->generate_gradient_magnitude(); texture_view->erode_validity_mask(); } math::Vec3f const & view_pos = texture_view->get_pos(); math::Vec3f const & viewing_direction = texture_view->get_viewing_direction(); for (std::size_t i = 0; i < faces.size(); i += 3) { std::size_t face_id = i / 3; math::Vec3f const & v1 = vertices[faces[i]]; math::Vec3f const & v2 = vertices[faces[i + 1]]; math::Vec3f const & v3 = vertices[faces[i + 2]]; math::Vec3f const & face_normal = face_normals[face_id]; math::Vec3f const face_center = (v1 + v2 + v3) / 3.0f; /* Check visibility and compute quality */ math::Vec3f view_to_face_vec = (face_center - view_pos).normalized(); math::Vec3f face_to_view_vec = (view_pos - face_center).normalized(); /* Backface and basic frustum culling */ float viewing_angle = face_to_view_vec.dot(face_normal); if (viewing_angle < 0.0f || viewing_direction.dot(view_to_face_vec) < 0.0f) continue; if (std::acos(viewing_angle) > MATH_DEG2RAD(75.0f)) continue; /* Projects into the valid part of the TextureView? */ if (!texture_view->inside(v1, v2, v3)) continue; if (settings.geometric_visibility_test) { /* Viewing rays do not collide? */ bool visible = true; math::Vec3f const * samples[] = {&v1, &v2, &v3}; // TODO: random monte carlo samples... for (std::size_t k = 0; k < sizeof(samples) / sizeof(samples[0]); ++k) { BVHTree::Ray ray; ray.origin = *samples[k]; ray.dir = view_pos - ray.origin; ray.tmax = ray.dir.norm(); ray.tmin = ray.tmax * 0.0001f; ray.dir.normalize(); BVHTree::Hit hit; if (bvh_tree.intersect(ray, &hit)) { visible = false; break; } } if (!visible) continue; } FaceProjectionInfo info = {j, 0.0f, math::Vec3f(0.0f, 0.0f, 0.0f)}; /* Calculate quality. */ texture_view->get_face_info(v1, v2, v3, &info, settings); if (info.quality == 0.0) continue; /* Change color space. */ mve::image::color_rgb_to_ycbcr(*(info.mean_color)); std::pair<std::size_t, FaceProjectionInfo> pair(face_id, info); projected_face_view_infos.push_back(pair); } texture_view->release_image(); texture_view->release_validity_mask(); if (settings.data_term == DATA_TERM_GMI) { texture_view->release_gradient_magnitude(); } view_counter.inc(); } //std::sort(projected_face_view_infos.begin(), projected_face_view_infos.end()); #pragma omp critical { for (std::size_t i = projected_face_view_infos.size(); 0 < i; --i) { std::size_t face_id = projected_face_view_infos[i - 1].first; FaceProjectionInfo const & info = projected_face_view_infos[i - 1].second; face_projection_infos->at(face_id).push_back(info); } projected_face_view_infos.clear(); } } }
void from_images_and_camera_files(std::string const & path, std::vector<TextureView> * texture_views) { util::fs::Directory dir(path); std::sort(dir.begin(), dir.end()); std::vector<std::string> files; for (std::size_t i = 0; i < dir.size(); ++i) { util::fs::File const & cam_file = dir[i]; if (cam_file.is_dir) continue; std::string cam_file_ext = util::string::uppercase(util::string::right(cam_file.name, 4)); if (cam_file_ext != ".CAM") continue; std::string prefix = util::string::left(cam_file.name, cam_file.name.size() - 4); if (prefix.empty()) continue; /* Find corresponding image file. */ int step = 1; for (std::size_t j = i + 1; j < dir.size(); j += step) { util::fs::File const & img_file = dir[j]; /* Since the files are sorted we can break - no more files with the same prefix exist. */ if (util::string::left(img_file.name, prefix.size()) != prefix) { if (step == 1) { j = i; step = -1; continue; } else { break; } } /* Image file (based on extension)? */ std::string img_file_ext = util::string::uppercase(util::string::right(img_file.name, 4)); if (img_file_ext != ".PNG" && img_file_ext != ".JPG" && img_file_ext != "TIFF" && img_file_ext != "JPEG") continue; files.push_back(cam_file.get_absolute_name()); files.push_back(img_file.get_absolute_name()); break; } } ProgressCounter view_counter("\tLoading", files.size() / 2); #pragma omp parallel for for (std::size_t i = 0; i < files.size(); i += 2) { view_counter.progress<SIMPLE>(); std::string cam_file = files[i]; std::string img_file = files[i + 1]; mve::ByteImage::Ptr image = mve::image::load_file(img_file); /* Read CAM file. */ std::ifstream infile(cam_file.c_str(), std::ios::binary); if (!infile.good()) throw util::FileException(util::fs::basename(cam_file), std::strerror(errno)); std::string cam_int_str, cam_ext_str; std::getline(infile, cam_ext_str); std::getline(infile, cam_int_str); util::Tokenizer tok_ext, tok_int; tok_ext.split(cam_ext_str); tok_int.split(cam_int_str); #pragma omp critical if (tok_ext.size() != 12 || tok_int.size() < 1) { std::cerr << "Invalid CAM file: " << util::fs::basename(cam_file) << std::endl; std::exit(EXIT_FAILURE); } /* Create cam_info and eventually undistort image. */ mve::CameraInfo cam_info; cam_info.from_ext_string(cam_ext_str); cam_info.from_int_string(cam_int_str); mve::ByteImage::Ptr undist; if (cam_info.dist[0] != 0.0f) { if (cam_info.dist[1] != 0.0f) { undist = mve::image::image_undistort_bundler<uint8_t>(image, cam_info.flen, cam_info.dist[0], cam_info.dist[1]); } else { undist = mve::image::image_undistort_vsfm<uint8_t>(image, cam_info.flen, cam_info.dist[0]); } } else { undist = image; } mve::image::save_png_file(undist, std::string("/tmp/") + util::fs::basename(img_file)); #pragma omp critical texture_views->push_back(TextureView(i / 2, cam_info, undist)); view_counter.inc(); } }