| 234 | } |
| 235 | |
| 236 | std::vector<std::map<int, float>> Model::ComputeTriangulationAngles( |
| 237 | const float percentile) const { |
| 238 | std::vector<Eigen::Vector3d> proj_centers(images.size()); |
| 239 | for (size_t image_idx = 0; image_idx < images.size(); ++image_idx) { |
| 240 | const auto& image = images[image_idx]; |
| 241 | Eigen::Vector3f C; |
| 242 | ComputeProjectionCenter(image.GetR(), image.GetT(), C.data()); |
| 243 | proj_centers[image_idx] = C.cast<double>(); |
| 244 | } |
| 245 | |
| 246 | std::vector<std::map<int, std::vector<float>>> all_triangulation_angles( |
| 247 | images.size()); |
| 248 | for (const auto& point : points) { |
| 249 | for (size_t i = 0; i < point.track.size(); ++i) { |
| 250 | const int image_idx1 = point.track[i]; |
| 251 | for (size_t j = 0; j < i; ++j) { |
| 252 | const int image_idx2 = point.track[j]; |
| 253 | if (image_idx1 != image_idx2) { |
| 254 | const float angle = CalculateTriangulationAngle( |
| 255 | proj_centers.at(image_idx1), |
| 256 | proj_centers.at(image_idx2), |
| 257 | Eigen::Vector3d(point.x, point.y, point.z)); |
| 258 | all_triangulation_angles.at(image_idx1)[image_idx2].push_back(angle); |
| 259 | all_triangulation_angles.at(image_idx2)[image_idx1].push_back(angle); |
| 260 | } |
| 261 | } |
| 262 | } |
| 263 | } |
| 264 | |
| 265 | std::vector<std::map<int, float>> triangulation_angles(images.size()); |
| 266 | for (size_t image_idx = 0; image_idx < all_triangulation_angles.size(); |
| 267 | ++image_idx) { |
| 268 | auto& overlapping_images = all_triangulation_angles[image_idx]; |
| 269 | for (auto& [other_image_idx, angles] : overlapping_images) { |
| 270 | triangulation_angles[image_idx].emplace(other_image_idx, |
| 271 | Percentile(angles, percentile)); |
| 272 | } |
| 273 | } |
| 274 | |
| 275 | return triangulation_angles; |
| 276 | } |
| 277 | |
| 278 | bool Model::ReadFromBundlerPMVS(const std::filesystem::path& path) { |
| 279 | const auto bundle_file_path = path / "bundle.rd.out"; |