45 auto format_lower_case =
format;
47 if (format_lower_case ==
"colmap") {
49 }
else if (format_lower_case ==
"pmvs") {
52 LOG(FATAL) <<
"Invalid input format";
57 const std::string& sparse_path,
58 const std::string& images_path) {
63 std::unordered_map<image_t, size_t> image_id_to_idx;
64 for (
size_t i = 0; i < reconstruction.
NumRegImages(); ++i) {
65 const auto image_id = reconstruction.
RegImageIds()[i];
66 const auto&
image = reconstruction.
Image(image_id);
67 const auto& camera = reconstruction.
Camera(
image.CameraId());
70 const Eigen::Matrix<float, 3, 3, Eigen::RowMajor> K =
71 camera.CalibrationMatrix().cast<
float>();
72 const Eigen::Matrix<float, 3, 3, Eigen::RowMajor> R =
74 const Eigen::Vector3f T =
image.Tvec().cast<
float>();
76 images.emplace_back(image_path, camera.Width(), camera.Height(), K.data(),
78 image_id_to_idx.emplace(image_id, i);
79 image_names_.push_back(
image.Name());
80 image_name_to_idx_.emplace(
image.Name(), i);
84 for (
const auto& point3D : reconstruction.
Points3D()) {
86 point.
x = point3D.second.X();
87 point.
y = point3D.second.Y();
88 point.
z = point3D.second.Z();
89 point.
track.reserve(point3D.second.Track().Length());
90 for (
const auto& track_el : point3D.second.Track().Elements()) {
91 point.
track.push_back(image_id_to_idx.at(track_el.image_id));
118 if (ReadFromBundlerPMVS(
path)) {
120 }
else if (ReadFromRawPMVS(
path)) {
123 LOG(FATAL) <<
"Invalid PMVS format";
128 CHECK_GT(image_name_to_idx_.count(
name), 0)
129 <<
"Image with name `" <<
name <<
"` does not exist";
130 return image_name_to_idx_.at(
name);
134 CHECK_GE(image_idx, 0);
135 CHECK_LT(image_idx, image_names_.size());
136 return image_names_.at(image_idx);
140 const size_t num_images,
const double min_triangulation_angle)
const {
141 std::vector<std::vector<int>> overlapping_images(
images.size());
143 const float min_triangulation_angle_rad =
DegToRad(min_triangulation_angle);
147 const float kTriangulationAnglePercentile = 75;
148 const auto triangulation_angles =
151 for (
size_t image_idx = 0; image_idx <
images.size(); ++image_idx) {
152 const auto& shared_images = shared_num_points.at(image_idx);
153 const auto& overlapping_triangulation_angles =
154 triangulation_angles.at(image_idx);
156 std::vector<std::pair<int, int>> ordered_images;
157 ordered_images.reserve(shared_images.size());
158 for (
const auto&
image : shared_images) {
159 if (overlapping_triangulation_angles.at(
image.first) >=
160 min_triangulation_angle_rad) {
161 ordered_images.emplace_back(
image.first,
image.second);
165 const size_t eff_num_images = std::min(ordered_images.size(), num_images);
166 if (eff_num_images < shared_images.size()) {
167 std::partial_sort(ordered_images.begin(),
168 ordered_images.begin() + eff_num_images,
169 ordered_images.end(),
170 [](
const std::pair<int, int> image1,
171 const std::pair<int, int> image2) {
172 return image1.second > image2.second;
175 std::sort(ordered_images.begin(), ordered_images.end(),
176 [](
const std::pair<int, int> image1,
177 const std::pair<int, int> image2) {
178 return image1.second > image2.second;
182 overlapping_images[image_idx].reserve(eff_num_images);
183 for (
size_t i = 0; i < eff_num_images; ++i) {
184 overlapping_images[image_idx].push_back(ordered_images[i].first);
188 return overlapping_images;
193 return pmvs_vis_dat_;
197 std::vector<std::vector<float>> depths(
images.size());
198 for (
const auto& point :
points) {
199 const Eigen::Vector3f
X(point.x, point.y, point.z);
200 for (
const auto& image_idx : point.track) {
203 Eigen::Map<const Eigen::Vector3f>(&
image.GetR()[6]).dot(
X) +
206 depths[image_idx].push_back(depth);
211 std::vector<std::pair<float, float>> depth_ranges(depths.size());
212 for (
size_t image_idx = 0; image_idx < depth_ranges.size(); ++image_idx) {
213 auto& depth_range = depth_ranges[image_idx];
215 auto& image_depths = depths[image_idx];
217 if (image_depths.empty()) {
218 depth_range.first = -1.0f;
219 depth_range.second = -1.0f;
223 std::sort(image_depths.begin(), image_depths.end());
225 const float kMinPercentile = 0.01f;
226 const float kMaxPercentile = 0.99f;
227 depth_range.first = image_depths[image_depths.size() * kMinPercentile];
228 depth_range.second = image_depths[image_depths.size() * kMaxPercentile];
230 const float kStretchRatio = 0.25f;
231 depth_range.first *= (1.0f - kStretchRatio);
232 depth_range.second *= (1.0f + kStretchRatio);
239 std::vector<std::map<int, int>> shared_points(
images.size());
240 for (
const auto& point :
points) {
241 for (
size_t i = 0; i < point.track.size(); ++i) {
242 const int image_idx1 = point.track[i];
243 for (
size_t j = 0; j < i; ++j) {
244 const int image_idx2 = point.track[j];
245 if (image_idx1 != image_idx2) {
246 shared_points.at(image_idx1)[image_idx2] += 1;
247 shared_points.at(image_idx2)[image_idx1] += 1;
252 return shared_points;
256 const float percentile)
const {
257 std::vector<Eigen::Vector3d> proj_centers(
images.size());
258 for (
size_t image_idx = 0; image_idx <
images.size(); ++image_idx) {
262 proj_centers[image_idx] = C.cast<
double>();
265 std::vector<std::map<int, std::vector<float>>> all_triangulation_angles(
267 for (
const auto& point :
points) {
268 for (
size_t i = 0; i < point.track.size(); ++i) {
269 const int image_idx1 = point.track[i];
270 for (
size_t j = 0; j < i; ++j) {
271 const int image_idx2 = point.track[j];
272 if (image_idx1 != image_idx2) {
274 proj_centers.at(image_idx1), proj_centers.at(image_idx2),
275 Eigen::Vector3d(point.x, point.y, point.z));
276 all_triangulation_angles.at(image_idx1)[image_idx2].push_back(angle);
277 all_triangulation_angles.at(image_idx2)[image_idx1].push_back(angle);
283 std::vector<std::map<int, float>> triangulation_angles(
images.size());
284 for (
size_t image_idx = 0; image_idx < all_triangulation_angles.size();
286 const auto& overlapping_images = all_triangulation_angles[image_idx];
287 for (
const auto&
image : overlapping_images) {
288 triangulation_angles[image_idx].emplace(
293 return triangulation_angles;
296 bool Model::ReadFromBundlerPMVS(
const std::string&
path) {
297 const std::string bundle_file_path =
JoinPaths(
path,
"bundle.rd.out");
303 std::ifstream file(bundle_file_path);
304 CHECK(file.is_open()) << bundle_file_path;
308 std::getline(file, header);
310 int num_images, num_points;
311 file >> num_images >> num_points;
313 images.reserve(num_images);
314 for (
int image_idx = 0; image_idx < num_images; ++image_idx) {
315 const std::string image_name =
StringPrintf(
"%08d.jpg", image_idx);
316 const std::string image_path =
JoinPaths(
path,
"visualize", image_name);
318 float K[9] = {1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f};
323 CHECK(bitmap.Read(image_path));
324 K[2] = bitmap.Width() / 2.0f;
325 K[5] = bitmap.Height() / 2.0f;
333 for (
size_t i = 0; i < 9; ++i) {
336 for (
size_t i = 3; i < 9; ++i) {
341 file >> T[0] >> T[1] >> T[2];
345 images.emplace_back(image_path, bitmap.Width(), bitmap.Height(), K, R, T);
346 image_names_.push_back(image_name);
347 image_name_to_idx_.emplace(image_name, image_idx);
350 points.resize(num_points);
351 for (
int point_id = 0; point_id < num_points; ++point_id) {
352 auto& point =
points[point_id];
354 file >> point.x >> point.y >> point.z;
361 point.track.resize(track_len);
363 for (
int i = 0; i < track_len; ++i) {
366 file >> point.track[i] >> feature_idx >> imx >> imy;
367 CHECK_LT(point.track[i],
images.size());
374 bool Model::ReadFromRawPMVS(
const std::string&
path) {
380 for (
int image_idx = 0;; ++image_idx) {
381 const std::string image_name =
StringPrintf(
"%08d.jpg", image_idx);
382 const std::string image_path =
JoinPaths(
path,
"visualize", image_name);
389 CHECK(bitmap.Read(image_path));
391 const std::string proj_matrix_path =
394 std::ifstream proj_matrix_file(proj_matrix_path);
395 CHECK(proj_matrix_file.is_open()) << proj_matrix_path;
398 proj_matrix_file >> contour;
399 CHECK_EQ(contour,
"CONTOUR");
402 for (
int i = 0; i < 3; ++i) {
403 proj_matrix_file >> P(i, 0) >> P(i, 1) >> P(i, 2) >> P(i, 3);
418 const Eigen::Matrix<float, 3, 3, Eigen::RowMajor> K_float = K.cast<
float>();
419 const Eigen::Matrix<float, 3, 3, Eigen::RowMajor> R_float = R.cast<
float>();
420 const Eigen::Vector3f T_float = T.cast<
float>();
422 images.emplace_back(image_path, bitmap.Width(), bitmap.Height(),
423 K_float.data(), R_float.data(), T_float.data());
424 image_names_.push_back(image_name);
425 image_name_to_idx_.emplace(image_name, image_idx);
428 std::ifstream vis_dat_file(vis_dat_path);
429 CHECK(vis_dat_file.is_open()) << vis_dat_path;
432 vis_dat_file >> visdata;
433 CHECK_EQ(visdata,
"VISDATA");
436 vis_dat_file >> num_images;
437 CHECK_GE(num_images, 0);
438 CHECK_EQ(num_images,
images.size());
440 pmvs_vis_dat_.resize(num_images);
441 for (
int i = 0; i < num_images; ++i) {
443 vis_dat_file >> image_idx;
444 CHECK_GE(image_idx, 0);
445 CHECK_LT(image_idx, num_images);
447 int num_visible_images;
448 vis_dat_file >> num_visible_images;
450 auto& visible_image_idxs = pmvs_vis_dat_[image_idx];
451 visible_image_idxs.reserve(num_visible_images);
453 for (
int j = 0; j < num_visible_images; ++j) {
454 int visible_image_idx;
455 vis_dat_file >> visible_image_idx;
456 CHECK_GE(visible_image_idx, 0);
457 CHECK_LT(visible_image_idx, num_images);
458 if (visible_image_idx != image_idx) {
459 visible_image_idxs.push_back(visible_image_idx);
std::shared_ptr< core::Tensor > image
filament::Texture::InternalFormat format
size_t NumRegImages() const
void DeleteAllPoints2DAndPoints3D()
const class Image & Image(const image_t image_id) const
size_t NumPoints3D() const
const class Camera & Camera(const camera_t camera_id) const
const std::unordered_map< point3D_t, class Point3D > & Points3D() const
const std::vector< image_t > & RegImageIds() const
void Read(const std::string &path)
Matrix< double, 3, 4 > Matrix3x4d
static const std::string path
void ComputeProjectionCenter(const float R[9], const float T[3], float C[3])
void StringToLower(std::string *str)
bool DecomposeProjectionMatrix(const Eigen::Matrix3x4d &P, Eigen::Matrix3d *K, Eigen::Matrix3d *R, Eigen::Vector3d *T)
bool ExistsFile(const std::string &path)
std::string JoinPaths(T const &... paths)
std::string StringPrintf(const char *format,...)
double CalculateTriangulationAngle(const Eigen::Vector3d &proj_center1, const Eigen::Vector3d &proj_center2, const Eigen::Vector3d &point3D)
float DegToRad(const float deg)
T Percentile(const std::vector< T > &elems, const double p)
Eigen::Matrix3d QuaternionToRotationMatrix(const Eigen::Vector4d &qvec)
std::vector< Point > points
std::string GetImageName(const int image_idx) const
int GetImageIdx(const std::string &name) const
std::vector< std::pair< float, float > > ComputeDepthRanges() const
void ReadFromCOLMAP(const std::string &path, const std::string &sparse_path="sparse", const std::string &images_path="images")
std::vector< Image > images
std::vector< std::vector< int > > GetMaxOverlappingImages(const size_t num_images, const double min_triangulation_angle) const
std::vector< std::map< int, float > > ComputeTriangulationAngles(const float percentile=50) const
void Read(const std::string &path, const std::string &format)
void ReadFromPMVS(const std::string &path)
const std::vector< std::vector< int > > & GetMaxOverlappingImagesFromPMVS() const
std::vector< std::map< int, int > > ComputeSharedPoints() const