From a56074e3a3440ad13e597ac78ff02cff89af845b Mon Sep 17 00:00:00 2001 From: Boris Date: Tue, 10 Mar 2026 22:48:06 +0300 Subject: [PATCH 01/31] opencl matching can be slower on server --- tests/test_matching.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_matching.cpp b/tests/test_matching.cpp index 4de5b716..adaac65e 100644 --- a/tests/test_matching.cpp +++ b/tests/test_matching.cpp @@ -560,7 +560,7 @@ TEST (MATCHING, SimpleMatching) { EXPECT_LT(time_my, 1.5 * time_cv); EXPECT_LT(time_my, 0.1 * time_bruteforce); -#if ENABLE_GPU_BRUTEFORCE_MATCHER +#if ENABLE_GPU_BRUTEFORCE_MATCHER && !SERVER_TESTING EXPECT_LT(time_bruteforce_gpu, time_bruteforce); #endif @@ -839,4 +839,4 @@ TEST (STITCHING, Orthophoto) { std::cout << "n stable ortho kpts: : " << score << std::endl; EXPECT_GT(score, 7500); #endif -} \ No newline at end of file +} From 9d8dda19639f2eb36e06b1cbeea9c569ed4834db Mon Sep 17 00:00:00 2001 From: Boris Date: Wed, 11 Mar 2026 11:18:38 +0300 Subject: [PATCH 02/31] Update README for bonus points criteria --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 39c8318b..da3dec48 100755 --- a/README.md +++ b/README.md @@ -56,5 +56,5 @@ 4. Проверьте, что тесты продолжают проходить. Если это не так, постарайтесь понять в чем причина с помощью отладочного вывода (просмотра дебаговых картинок, сравнения количества найденных сопоставлений на разных шагах матчинга с разными дескрипторами и тд.). Если заставить работать не получилось, коммитьте решение с выключенным **ENABLE_MY_DESCRIPTOR** чтобы проходили тесты. Баллы в этом случае не снимаются, но у вас может остаться неприятное чувство неполноценности проекта как самостоятельной единицы. - Если все хорошо, за выполненное задание дается **8 баллов** -- **1 доп. балл** можно получить, если при оценке матрицы гомографии реализовать метод **A contrario RANSAC**, не требующий на вход порога (см. homography.cpp:166) +- **3 доп. балла** можно получить, если при оценке матрицы гомографии реализовать метод **A contrario RANSAC**, не требующий на вход порога (см. homography.cpp:166) - **1 доп. балл** можно получить, если реализовать Brute-force матчер на GPU. Для включения его в тестах см. **ENABLE_GPU_BRUTEFORCE_MATCHER** в ```test/test_matching.cpp``` From ffe7a475e39690f9eeba51d67097fdaafc9c4e19 Mon Sep 17 00:00:00 2001 From: alexander Date: Fri, 27 Feb 2026 17:21:06 +0300 Subject: [PATCH 03/31] mvp --- src/phg/sift/sift.cpp | 186 ++++++++++++++++++++++++------------------ tests/test_sift.cpp | 2 +- 2 files changed, 108 insertions(+), 80 deletions(-) diff --git a/src/phg/sift/sift.cpp b/src/phg/sift/sift.cpp index 72047711..a7ad7cc4 100755 --- a/src/phg/sift/sift.cpp +++ b/src/phg/sift/sift.cpp @@ -108,14 +108,18 @@ std::vector phg::buildOctaves(const cv::Mat& img, const phg:: // можно подумать, как сделать эффективнее - для построения n+1 слоя доблюревать уже поблюренный n-ый слой, так чтобы в итоге получилась такая же сигма // это будет немного быстрее, тк нужно более маленькое ядро свертки на каждый шаг for (int i = 1; i < n_layers; i++) { - // TODO double sigma_layer = sigma0 * корень из двух нужной степени, чтобы при i==s получали удвоение базового блюра; + double sigma_layer = sigma0 * std::pow((double) 2, (double) i / s); + sigma_layer = std::sqrt(sigma_layer * sigma_layer - sigma0 * sigma0); + cv::GaussianBlur(oct.layers[0], oct.layers[i], cv::Size(), sigma_layer, sigma_layer); + // double sigma_layer = sigma0 * корень из двух нужной степени, чтобы при i==s получали удвоение базового блюра; // // вычтем sigma0 чтобы размыть ровно до нужной суммарной сигмы - // TODO sigma_layer = ... (вычитаем как в sigma base); + // sigma_layer = ... (вычитаем как в sigma base); // cv::GaussianBlur(oct.layers[0], oct.layers[i], cv::Size(), sigma_layer, sigma_layer); } // подготавливаем базовый слой для следующей октавы if (o + 1 < n_octaves) { + cv::resize(oct.layers[s], base, cv::Size(), 0.5f, 0.5f, cv::INTER_NEAREST); // используется в opencv, формула для пересчета ключевых точек: pt_upscaled = 2^o * pt_downscaled // TODO cv::resize(даунскейлим текущий слой в два раза, без интерполяции, просто сабсепмлинг); @@ -137,8 +141,10 @@ std::vector phg::buildDoG(const std::vector phg::findScaleSpaceExtrema(const std::vector phg::findScaleSpaceExtrema(const std::vector(yi, xi + 1) + cL.at(yi, xi - 1) - 2.f * resp_center; -// float dyy = TODO; -// float dss = TODO; -// -// float dxy = (cL.at(yi + 1, xi + 1) - cL.at(yi + 1, xi - 1) - cL.at(yi - 1, xi + 1) + cL.at(yi - 1, xi - 1)) * 0.25f; -// float dxs = TODO; -// float dys = TODO; + dxx = cL.at(yi, xi + 1) + cL.at(yi, xi - 1) - 2.f * resp_center; + dyy = cL.at(yi + 1, xi) + cL.at(yi - 1, xi) - 2.f * resp_center; + dss = pL.at(yi, xi) + nL.at(yi, xi) - 2.f * resp_center; + + dxy = (cL.at(yi + 1, xi + 1) - cL.at(yi + 1, xi - 1) - cL.at(yi - 1, xi + 1) + cL.at(yi - 1, xi - 1)) * 0.25f; + dxs = (nL.at(yi, xi + 1) - nL.at(yi, xi - 1) - pL.at(yi, xi + 1) + pL.at(yi, xi - 1)) * 0.25f; + dys = (nL.at(yi + 1, xi) - nL.at(yi - 1, xi) - pL.at(yi + 1, xi) + pL.at(yi - 1, xi)) * 0.25f; cv::Matx33f H(dxx, dxy, dxs, dxy, dyy, dys, dxs, dys, dss); @@ -273,10 +302,10 @@ std::vector phg::findScaleSpaceExtrema(const std::vector phg::findScaleSpaceExtrema(const std::vector ((double) r + 1) * ((double) r + 1) / r) + break; } // скейлим координаты точек обратно до родных размеров картинки @@ -379,39 +408,39 @@ std::vector phg::computeOrientations(const std::vector(py, px + 1) - img.at(py, px - 1); -// float gy = img.at(py + 1, px) - img.at(py - 1, px); -// -// float mag = TODO; -// float angle = std::atan2(TODO); // [-pi, pi] -// -// float angle_deg = angle * 180.f / (float) CV_PI; -// if (angle_deg < 0.f) angle_deg += 360.f; -// -// // гауссово взвешивание голоса точки с затуханием к краям -// float weight = std::exp(-(TODO) / (2.f * sigma_win * sigma_win)); -// if (!params.enable_orientation_gaussian_weighting) { -// weight = 1.f; -// } -// -// // голосуем в гистограмме направлений. находим два ближайших бина и гладко распределяем голос между ними -// // в таком случае, голос попавший близко к границе между бинами, проголосует поровну за оба бина -// float bin = TODO; -// if (bin >= n_bins) bin -= n_bins; -// int bin0 = (int) bin; -// int bin1 = (bin0 + 1) % n_bins; -// -// float frac = bin - bin0; -// if (!params.enable_orientation_bin_interpolation) { -// frac = 0.f; -// } -// -// histogram[bin0] += TODO; -// histogram[bin1] += TODO; + int px = xi + dx; + int py = yi + dy; + + // градиент + float gx = img.at(py, px + 1) - img.at(py, px - 1); + float gy = img.at(py + 1, px) - img.at(py - 1, px); + + float mag = std::sqrt(gx * gx + gy * gy); + float angle = std::atan2(gy, gx); // [-pi, pi] + + float angle_deg = angle * 180.f / (float) CV_PI; + if (angle_deg < 0.f) angle_deg += 360.f; + + // гауссово взвешивание голоса точки с затуханием к краям + float weight = std::exp(-(dx * dx + dy * dy) / (2.f * sigma_win * sigma_win)); + if (!params.enable_orientation_gaussian_weighting) { + weight = 1.f; + } + + // голосуем в гистограмме направлений. находим два ближайших бина и гладко распределяем голос между ними + // в таком случае, голос попавший близко к границе между бинами, проголосует поровну за оба бина + float bin = angle_deg / 360.f * n_bins; + if (bin >= n_bins) bin -= n_bins; + int bin0 = (int) bin; + int bin1 = (bin0 + 1) % n_bins; + + float frac = bin - bin0; + if (!params.enable_orientation_bin_interpolation) { + frac = 0.f; + } + + histogram[bin0] += weight * mag * (1.f - frac); + histogram[bin1] += weight * mag * frac; } } @@ -450,20 +479,20 @@ std::vector phg::computeOrientations(const std::vector a = (left + right - 2 * center) / 2 // f(1) - f(-1) = 2b -> b = (right - left) / 2 -// float offset = TODO; -// if (!params.enable_orientation_subpixel_localization) { -// offset = 0.f; -// } -// -// float bin_real = i + offset; -// if (bin_real < 0.f) bin_real += n_bins; -// if (bin_real >= n_bins) bin_real -= n_bins; -// -// float angle = bin_real * 360.f / n_bins; -// -// cv::KeyPoint new_kp = kp; -// new_kp.angle = angle; -// oriented_kpts.push_back(new_kp); + float offset = (left - right) / (left + right - 2.f * center) / 2.f; + if (!params.enable_orientation_subpixel_localization) { + offset = 0.f; + } + + float bin_real = i + offset; + if (bin_real < 0.f) bin_real += n_bins; + if (bin_real >= n_bins) bin_real -= n_bins; + + float angle = bin_real * 360.f / n_bins; + + cv::KeyPoint new_kp = kp; + new_kp.angle = angle; + oriented_kpts.push_back(new_kp); } } } @@ -574,11 +603,11 @@ std::pair> phg::computeDescriptors(const std: bin_o -= n_orient_bins; // семплы вблизи края патча взвешиваем с меньшим весом -// float weight = std::exp(-(TODO) / (2.f * sigma_desc * sigma_desc)); -// if (!params.enable_descriptor_gaussian_weighting) { -// weight = 1.f; -// } -// float weighted_mag = mag * weight; + float weight = std::exp(-(rot_x * rot_x + rot_y * rot_y) / (2.f * sigma_desc * sigma_desc)); + if (!params.enable_descriptor_gaussian_weighting) { + weight = 1.f; + } + float weighted_mag = mag * weight; if (params.enable_descriptor_bin_interpolation) { // размажем вклад weighted_mag по пространственным бинам и по бинам гистограммок трилинейной интерполяцией @@ -609,8 +638,8 @@ std::pair> phg::computeDescriptors(const std: io += n_orient_bins; float wo = (dio == 0) ? (1.f - fo) : fo; -// int idx = TODO; -// desc[idx] += TODO; + int idx = (iy * n_spatial_bins + ix) * n_orient_bins + io; + desc[idx] += wy * wx * wo * weighted_mag; } } } @@ -620,9 +649,8 @@ std::pair> phg::computeDescriptors(const std: int io_nearest = (int)std::round(bin_o) % n_orient_bins; if (ix_nearest >= 0 && ix_nearest < n_spatial_bins && iy_nearest >= 0 && iy_nearest < n_spatial_bins) { - // TODO uncomment -// int idx = (iy_nearest * n_spatial_bins + ix_nearest) * n_orient_bins + io_nearest; -// desc[idx] += weighted_mag; + int idx = (iy_nearest * n_spatial_bins + ix_nearest) * n_orient_bins + io_nearest; + desc[idx] += weighted_mag; } } } diff --git a/tests/test_sift.cpp b/tests/test_sift.cpp index cf3bd7df..7433f9bb 100755 --- a/tests/test_sift.cpp +++ b/tests/test_sift.cpp @@ -28,7 +28,7 @@ // TODO ENABLE ME // TODO ENABLE ME // TODO ENABLE ME -#define ENABLE_MY_SIFT_TESTING 0 +#define ENABLE_MY_SIFT_TESTING 1 #define DENY_CREATE_REF_DATA 1 From 02077e3a0b1717fe7e27b8731c4ab63cdb540402 Mon Sep 17 00:00:00 2001 From: alexander Date: Sat, 21 Mar 2026 11:31:25 +0300 Subject: [PATCH 04/31] tmp --- src/phg/matching/descriptor_matcher.cpp | 100 ++++++++++++--------- src/phg/matching/flann_matcher.cpp | 12 ++- src/phg/sfm/homography.cpp | 113 +++++++++++++----------- tests/test_matching.cpp | 11 ++- 4 files changed, 137 insertions(+), 99 deletions(-) diff --git a/src/phg/matching/descriptor_matcher.cpp b/src/phg/matching/descriptor_matcher.cpp index f4bcd871..1cf96387 100644 --- a/src/phg/matching/descriptor_matcher.cpp +++ b/src/phg/matching/descriptor_matcher.cpp @@ -7,8 +7,11 @@ void phg::DescriptorMatcher::filterMatchesRatioTest(const std::vector &filtered_matches) { filtered_matches.clear(); - - throw std::runtime_error("not implemented yet"); + for (const auto match: matches) { + if (match.size() > 1 && match[0].distance / match[1].distance < 0.5f) { + filtered_matches.push_back(match[0]); + } + } } @@ -35,42 +38,59 @@ void phg::DescriptorMatcher::filterMatchesClusters(const std::vector points_query.at(i) = keypoints_query[matches[i].queryIdx].pt; points_train.at(i) = keypoints_train[matches[i].trainIdx].pt; } -// -// // размерность всего 2, так что точное KD-дерево -// std::shared_ptr index_params = flannKdTreeIndexParams(TODO); -// std::shared_ptr search_params = flannKsTreeSearchParams(TODO); -// -// std::shared_ptr index_query = flannKdTreeIndex(points_query, index_params); -// std::shared_ptr index_train = flannKdTreeIndex(points_train, index_params); -// -// // для каждой точки найти total neighbors ближайших соседей -// cv::Mat indices_query(n_matches, total_neighbours, CV_32SC1); -// cv::Mat distances2_query(n_matches, total_neighbours, CV_32FC1); -// cv::Mat indices_train(n_matches, total_neighbours, CV_32SC1); -// cv::Mat distances2_train(n_matches, total_neighbours, CV_32FC1); -// -// index_query->knnSearch(points_query, indices_query, distances2_query, total_neighbours, *search_params); -// index_train->knnSearch(points_train, indices_train, distances2_train, total_neighbours, *search_params); -// -// // оценить радиус поиска для каждой картинки -// // NB: radius2_query, radius2_train: квадраты радиуса! -// float radius2_query, radius2_train; -// { -// std::vector max_dists2_query(n_matches); -// std::vector max_dists2_train(n_matches); -// for (int i = 0; i < n_matches; ++i) { -// max_dists2_query[i] = distances2_query.at(i, total_neighbours - 1); -// max_dists2_train[i] = distances2_train.at(i, total_neighbours - 1); -// } -// -// int median_pos = n_matches / 2; -// std::nth_element(max_dists2_query.begin(), max_dists2_query.begin() + median_pos, max_dists2_query.end()); -// std::nth_element(max_dists2_train.begin(), max_dists2_train.begin() + median_pos, max_dists2_train.end()); -// -// radius2_query = max_dists2_query[median_pos] * radius_limit_scale * radius_limit_scale; -// radius2_train = max_dists2_train[median_pos] * radius_limit_scale * radius_limit_scale; -// } -// -// метч остается, если левое и правое множества первых total_neighbors соседей в радиусах поиска(radius2_query, radius2_train) имеют как минимум consistent_matches общих элементов -// // TODO заполнить filtered_matches + + // размерность всего 2, так что точное KD-дерево + std::shared_ptr index_params = flannKdTreeIndexParams(4); // 1 + std::shared_ptr search_params = flannKsTreeSearchParams(32); // n_matches + + std::shared_ptr index_query = flannKdTreeIndex(points_query, index_params); + std::shared_ptr index_train = flannKdTreeIndex(points_train, index_params); + + // для каждой точки найти total neighbors ближайших соседей + cv::Mat indices_query(n_matches, total_neighbours, CV_32SC1); + cv::Mat distances2_query(n_matches, total_neighbours, CV_32FC1); + cv::Mat indices_train(n_matches, total_neighbours, CV_32SC1); + cv::Mat distances2_train(n_matches, total_neighbours, CV_32FC1); + + index_query->knnSearch(points_query, indices_query, distances2_query, total_neighbours, *search_params); + index_train->knnSearch(points_train, indices_train, distances2_train, total_neighbours, *search_params); + + // оценить радиус поиска для каждой картинки + // NB: radius2_query, radius2_train: квадраты радиуса! + float radius2_query, radius2_train; + { + std::vector max_dists2_query(n_matches); + std::vector max_dists2_train(n_matches); + for (int i = 0; i < n_matches; ++i) { + max_dists2_query[i] = distances2_query.at(i, total_neighbours - 1); + max_dists2_train[i] = distances2_train.at(i, total_neighbours - 1); + } + + int median_pos = n_matches / 2; + std::nth_element(max_dists2_query.begin(), max_dists2_query.begin() + median_pos, max_dists2_query.end()); + std::nth_element(max_dists2_train.begin(), max_dists2_train.begin() + median_pos, max_dists2_train.end()); + + radius2_query = max_dists2_query[median_pos] * radius_limit_scale * radius_limit_scale; + radius2_train = max_dists2_train[median_pos] * radius_limit_scale * radius_limit_scale; + } + + // метч остается, если левое и правое множества первых total_neighbors соседей в радиусах поиска(radius2_query, radius2_train) имеют как минимум consistent_matches общих элементов + for (size_t i = 0; i < n_matches; i++) { + std::set set2train; + size_t n_consistent_matches = 0; + for (size_t j = 0; j < total_neighbours; j++) { + if (distances2_train.at(i, j) <= radius2_train) { + set2train.insert(indices_train.at(i, j)); + } + } + for (size_t j = 0; j < total_neighbours; j++) { + if (distances2_query.at(i, j) <= radius2_query && set2train.count(indices_query.at(i, j))) { + n_consistent_matches++; + } + } + + if (n_consistent_matches >= consistent_matches) { + filtered_matches.push_back(matches[i]); + } + } } diff --git a/src/phg/matching/flann_matcher.cpp b/src/phg/matching/flann_matcher.cpp index 9e9f5180..043e3616 100644 --- a/src/phg/matching/flann_matcher.cpp +++ b/src/phg/matching/flann_matcher.cpp @@ -6,8 +6,8 @@ phg::FlannMatcher::FlannMatcher() { // параметры для приближенного поиска -// index_params = flannKdTreeIndexParams(TODO); -// search_params = flannKsTreeSearchParams(TODO); + index_params = flannKdTreeIndexParams(5); + search_params = flannKsTreeSearchParams(50); } void phg::FlannMatcher::train(const cv::Mat &train_desc) @@ -17,5 +17,11 @@ void phg::FlannMatcher::train(const cv::Mat &train_desc) void phg::FlannMatcher::knnMatch(const cv::Mat &query_desc, std::vector> &matches, int k) const { - throw std::runtime_error("not implemented yet"); + for (size_t i = 0; i < query_desc.size().height; i++) { + std::vector outIndices(k); + std::vector outDists(k); + + flann_index->knnSearch(query_desc.row(i), outIndices, outDists, k, *search_params); + matches.push_back({cv::DMatch(i, outIndices[0], std::sqrt(outDists[0])), cv::DMatch(i, outIndices[1], std::sqrt(outDists[1]))}); + } } diff --git a/src/phg/sfm/homography.cpp b/src/phg/sfm/homography.cpp index 5cbc780c..8a5df668 100644 --- a/src/phg/sfm/homography.cpp +++ b/src/phg/sfm/homography.cpp @@ -84,8 +84,11 @@ namespace { double w1 = ws1[i]; // 8 elements of matrix + free term as needed by gauss routine -// A.push_back({TODO}); -// A.push_back({TODO}); + // A.push_back({0, 0, 0, -w1 * x0, -w1 * y0, -w1 * w0, y1 * x0, y1 * y0, y1 * w0}); + // A.push_back({w1 * x0, w1 * y0, w1 * w0, 0, 0, 0, -x1 * x0, -x1 * y0, -x1 * w0}); + + A.push_back({w1 * x0, w1 * y0, w1 * w0, 0, 0, 0, -x1 * x0, -x1 * y0, x1 * w0}); + A.push_back({0, 0, 0, w1 * x0, w1 * y0, w1 * w0, -y1 * x0, -y1 * y0, y1 * w0}); } int res = gauss(A, H); @@ -168,57 +171,57 @@ namespace { // * (простое описание для понимания) // * [3] http://ikrisoft.blogspot.com/2015/01/ransac-with-contrario-approach.html -// const int n_matches = points_lhs.size(); -// -// // https://en.wikipedia.org/wiki/Random_sample_consensus#Parameters -// const int n_trials = TODO; -// -// const int n_samples = TODO; -// uint64_t seed = 1; -// const double reprojection_error_threshold_px = 2; -// -// int best_support = 0; -// cv::Mat best_H; -// -// std::vector sample; -// for (int i_trial = 0; i_trial < n_trials; ++i_trial) { -// randomSample(sample, n_matches, n_samples, &seed); -// -// cv::Mat H = estimateHomography4Points(points_lhs[sample[0]], points_lhs[sample[1]], points_lhs[sample[2]], points_lhs[sample[3]], -// points_rhs[sample[0]], points_rhs[sample[1]], points_rhs[sample[2]], points_rhs[sample[3]]); -// -// int support = 0; -// for (int i_point = 0; i_point < n_matches; ++i_point) { -// try { -// cv::Point2d proj = phg::transformPoint(points_lhs[i_point], H); -// if (cv::norm(proj - cv::Point2d(points_rhs[i_point])) < reprojection_error_threshold_px) { -// ++support; -// } -// } catch (const std::exception &e) -// { -// std::cerr << e.what() << std::endl; -// } -// } -// -// if (support > best_support) { -// best_support = support; -// best_H = H; -// -// std::cout << "estimateHomographyRANSAC : support: " << best_support << "/" << n_matches << std::endl; -// -// if (best_support == n_matches) { -// break; -// } -// } -// } -// -// std::cout << "estimateHomographyRANSAC : best support: " << best_support << "/" << n_matches << std::endl; -// -// if (best_support == 0) { -// throw std::runtime_error("estimateHomographyRANSAC : failed to estimate homography"); -// } -// -// return best_H; + const int n_matches = points_lhs.size(); + + // https://en.wikipedia.org/wiki/Random_sample_consensus#Parameters + const int n_trials = 1000; + + const int n_samples = 10; + uint64_t seed = 1; + const double reprojection_error_threshold_px = 2; + + int best_support = 0; + cv::Mat best_H; + + std::vector sample; + for (int i_trial = 0; i_trial < n_trials; ++i_trial) { + randomSample(sample, n_matches, n_samples, &seed); + + cv::Mat H = estimateHomography4Points(points_lhs[sample[0]], points_lhs[sample[1]], points_lhs[sample[2]], points_lhs[sample[3]], + points_rhs[sample[0]], points_rhs[sample[1]], points_rhs[sample[2]], points_rhs[sample[3]]); + + int support = 0; + for (int i_point = 0; i_point < n_matches; ++i_point) { + try { + cv::Point2d proj = phg::transformPoint(points_lhs[i_point], H); + if (cv::norm(proj - cv::Point2d(points_rhs[i_point])) < reprojection_error_threshold_px) { + ++support; + } + } catch (const std::exception &e) + { + std::cerr << e.what() << std::endl; + } + } + + if (support > best_support) { + best_support = support; + best_H = H; + + std::cout << "estimateHomographyRANSAC : support: " << best_support << "/" << n_matches << std::endl; + + if (best_support == n_matches) { + break; + } + } + } + + std::cout << "estimateHomographyRANSAC : best support: " << best_support << "/" << n_matches << std::endl; + + if (best_support == 0) { + throw std::runtime_error("estimateHomographyRANSAC : failed to estimate homography"); + } + + return best_H; } } @@ -238,7 +241,9 @@ cv::Mat phg::findHomographyCV(const std::vector &points_lhs, const // таким преобразованием внутри занимается функции cv::perspectiveTransform и cv::warpPerspective cv::Point2d phg::transformPoint(const cv::Point2d &pt, const cv::Mat &T) { - throw std::runtime_error("not implemented yet"); + double w = T.at(2, 0) * pt.x + T.at(2, 1) * pt.y + T.at(2, 2); + return {(T.at(0, 0) * pt.x + T.at(0, 1) * pt.y + T.at(0, 2)) / w, + (T.at(1, 0) * pt.x + T.at(1, 1) * pt.y + T.at(1, 2)) / w}; } cv::Point2d phg::transformPointCV(const cv::Point2d &pt, const cv::Mat &T) { diff --git a/tests/test_matching.cpp b/tests/test_matching.cpp index adaac65e..5753ad84 100644 --- a/tests/test_matching.cpp +++ b/tests/test_matching.cpp @@ -19,8 +19,8 @@ // TODO enable both toggles for testing custom detector & matcher -#define ENABLE_MY_DESCRIPTOR 0 -#define ENABLE_MY_MATCHING 0 +#define ENABLE_MY_DESCRIPTOR 1 +#define ENABLE_MY_MATCHING 1 #define ENABLE_GPU_BRUTEFORCE_MATCHER 0 // TODO disable for local testing but do not commit @@ -138,11 +138,14 @@ namespace { #if ENABLE_MY_MATCHING phg::DescriptorMatcher::filterMatchesRatioTest(knn_matches, good_matches); + printf("haha\n"); { std::vector tmp; phg::DescriptorMatcher::filterMatchesClusters(good_matches, keypoints1, keypoints2, tmp); std::swap(tmp, good_matches); } + printf("haho\n"); + #else { std::vector tmp; @@ -156,8 +159,12 @@ namespace { points1.push_back(keypoints1[match.queryIdx].pt); points2.push_back(keypoints2[match.trainIdx].pt); } + printf("huhu\n"); + #if ENABLE_MY_MATCHING cv::Mat H = phg::findHomography(points1, points2); + printf("hihi\n"); + #else cv::Mat H = phg::findHomographyCV(points1, points2); #endif From 917e08bf3ebfcec3f3713bf3a055e25a2d7d61fa Mon Sep 17 00:00:00 2001 From: alexander Date: Sun, 22 Mar 2026 20:07:31 +0300 Subject: [PATCH 05/31] stitching 1st attempt --- src/phg/sfm/panorama_stitcher.cpp | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/phg/sfm/panorama_stitcher.cpp b/src/phg/sfm/panorama_stitcher.cpp index 8d76939b..4b4002b4 100644 --- a/src/phg/sfm/panorama_stitcher.cpp +++ b/src/phg/sfm/panorama_stitcher.cpp @@ -21,9 +21,36 @@ cv::Mat phg::stitchPanorama(const std::vector &imgs, // вектор гомографий, для каждой картинки описывает преобразование до корня std::vector Hs(n_images); { + size_t root_idx = 0; + std::vector visited(n_images, false); // здесь надо посчитать вектор Hs // при этом можно обойтись n_images - 1 вызовами функтора homography_builder - throw std::runtime_error("not implemented yet"); + for (size_t img_num = 0; img_num < n_images; img_num++) { + if (parent[img_num] == -1) { + root_idx = img_num; + } + } + + Hs[root_idx] = cv::Mat::eye(3, 3, CV_64FC1); + visited[root_idx] = true; + + std::function calc_recurse = [&] (size_t cur_idx) { + if (visited[cur_idx]) { + return; + } + const size_t parent_idx = parent[cur_idx]; + if (!visited[parent_idx]) { + calc_recurse(parent_idx); + } + Hs[cur_idx] = homography_builder(imgs[cur_idx], imgs[parent_idx]) * Hs[parent_idx]; + visited[cur_idx] = true; + }; + + for (size_t img_num = 0; img_num < n_images; img_num++) { + if (img_num != root_idx && !visited[img_num]) { + calc_recurse(img_num); + } + } } bbox2 bbox; From e31c21def92edf2a7f0d17441d9d63761a62599b Mon Sep 17 00:00:00 2001 From: alexander Date: Tue, 24 Mar 2026 22:57:10 +0300 Subject: [PATCH 06/31] accelerated --- src/phg/matching/flann_matcher.cpp | 10 +++++----- src/phg/sfm/homography.cpp | 10 ++++++---- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/phg/matching/flann_matcher.cpp b/src/phg/matching/flann_matcher.cpp index 043e3616..e27f54ed 100644 --- a/src/phg/matching/flann_matcher.cpp +++ b/src/phg/matching/flann_matcher.cpp @@ -6,8 +6,8 @@ phg::FlannMatcher::FlannMatcher() { // параметры для приближенного поиска - index_params = flannKdTreeIndexParams(5); - search_params = flannKsTreeSearchParams(50); + index_params = flannKdTreeIndexParams(3); // рекомендуется выставлять 5, но когда включил свой SIFT пришлось уменьшить до 3, чтобы прозоходились тесты + search_params = flannKsTreeSearchParams(30); // в документации OpenCV используют 50, но 50 не очень стабильно проходит тесты по тайм-лимитам } void phg::FlannMatcher::train(const cv::Mat &train_desc) @@ -17,10 +17,10 @@ void phg::FlannMatcher::train(const cv::Mat &train_desc) void phg::FlannMatcher::knnMatch(const cv::Mat &query_desc, std::vector> &matches, int k) const { - for (size_t i = 0; i < query_desc.size().height; i++) { - std::vector outIndices(k); - std::vector outDists(k); + std::vector outIndices(k); + std::vector outDists(k); + for (size_t i = 0; i < query_desc.size().height; i++) { flann_index->knnSearch(query_desc.row(i), outIndices, outDists, k, *search_params); matches.push_back({cv::DMatch(i, outIndices[0], std::sqrt(outDists[0])), cv::DMatch(i, outIndices[1], std::sqrt(outDists[1]))}); } diff --git a/src/phg/sfm/homography.cpp b/src/phg/sfm/homography.cpp index 8a5df668..28658485 100644 --- a/src/phg/sfm/homography.cpp +++ b/src/phg/sfm/homography.cpp @@ -84,11 +84,13 @@ namespace { double w1 = ws1[i]; // 8 elements of matrix + free term as needed by gauss routine - // A.push_back({0, 0, 0, -w1 * x0, -w1 * y0, -w1 * w0, y1 * x0, y1 * y0, y1 * w0}); - // A.push_back({w1 * x0, w1 * y0, w1 * w0, 0, 0, 0, -x1 * x0, -x1 * y0, -x1 * w0}); + // in fact 9 elements + 1 free term (extended matrix form) + // A.push_back({0, 0, 0, -w1 * x0, -w1 * y0, -w1 * w0, y1 * x0, y1 * y0, y1 * w0, 0}); + // A.push_back({w1 * x0, w1 * y0, w1 * w0, 0, 0, 0, -x1 * x0, -x1 * y0, -x1 * w0, 0}); - A.push_back({w1 * x0, w1 * y0, w1 * w0, 0, 0, 0, -x1 * x0, -x1 * y0, x1 * w0}); - A.push_back({0, 0, 0, w1 * x0, w1 * y0, w1 * w0, -y1 * x0, -y1 * y0, y1 * w0}); + // set h_9 equals 1 and move Ae_9 to the free term + A.push_back({0, 0, 0, -w1 * x0, -w1 * y0, -w1 * w0, y1 * x0, y1 * y0, -(y1 * w0)}); + A.push_back({w1 * x0, w1 * y0, w1 * w0, 0, 0, 0, -x1 * x0, -x1 * y0, -(-(x1 * w0))}); } int res = gauss(A, H); From f20034cad6ace4520d869f6b68143b6e2c987d2c Mon Sep 17 00:00:00 2001 From: alexander Date: Wed, 25 Mar 2026 20:52:25 +0300 Subject: [PATCH 07/31] make sense for n_points and n_trials --- src/phg/matching/flann_matcher.cpp | 2 +- src/phg/sfm/homography.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/phg/matching/flann_matcher.cpp b/src/phg/matching/flann_matcher.cpp index e27f54ed..358d2336 100644 --- a/src/phg/matching/flann_matcher.cpp +++ b/src/phg/matching/flann_matcher.cpp @@ -7,7 +7,7 @@ phg::FlannMatcher::FlannMatcher() { // параметры для приближенного поиска index_params = flannKdTreeIndexParams(3); // рекомендуется выставлять 5, но когда включил свой SIFT пришлось уменьшить до 3, чтобы прозоходились тесты - search_params = flannKsTreeSearchParams(30); // в документации OpenCV используют 50, но 50 не очень стабильно проходит тесты по тайм-лимитам + search_params = flannKsTreeSearchParams(35); // в документации OpenCV используют 50, но 50 не очень стабильно проходит тесты по тайм-лимитам } void phg::FlannMatcher::train(const cv::Mat &train_desc) diff --git a/src/phg/sfm/homography.cpp b/src/phg/sfm/homography.cpp index 28658485..af544ead 100644 --- a/src/phg/sfm/homography.cpp +++ b/src/phg/sfm/homography.cpp @@ -174,11 +174,13 @@ namespace { // * [3] http://ikrisoft.blogspot.com/2015/01/ransac-with-contrario-approach.html const int n_matches = points_lhs.size(); + const int n_points = 4; // https://en.wikipedia.org/wiki/Random_sample_consensus#Parameters - const int n_trials = 1000; + const double singlePointInlierProbability = 0.5, successProbability = 0.99; + const int n_trials = (int) (log(1 - successProbability) / log(1 - pow(singlePointInlierProbability, n_points))); - const int n_samples = 10; + const int n_samples = n_points; uint64_t seed = 1; const double reprojection_error_threshold_px = 2; From dee35b4f569929ce9e7c412ee77d376238614761 Mon Sep 17 00:00:00 2001 From: alexander Date: Thu, 26 Mar 2026 01:28:35 +0300 Subject: [PATCH 08/31] answers + removed debug prints --- Q&A2.md | 35 +++++++++++++++++++++++++++++++++++ tests/test_matching.cpp | 5 ----- 2 files changed, 35 insertions(+), 5 deletions(-) create mode 100644 Q&A2.md diff --git a/Q&A2.md b/Q&A2.md new file mode 100644 index 00000000..73ed7f11 --- /dev/null +++ b/Q&A2.md @@ -0,0 +1,35 @@ +# Перечислите идеи и коротко обозначьте мысли которые у вас возникали по мере выполнения задания, в частности попробуйте ответить на вопросы: + +1) Зачем фильтровать матчи, если потом мы запускаем устойчивый к выбросам RANSAC и отфильтровываем шумные сопоставления? \ +\ +Число запусков в алгоритме RANSAC (см homography.cpp:182) зависит от w (переменная singlePointInlierProbability) -- вероятности того, что метч является инлаером. Чем больше эта вероятность, тем меньше нужно итераций RANSAC. Фильтрация метчей перед запускам RANSAC нужна чтобы увеличить эту вероятность. + +2) Cluster filtering довольно хорошо работает и без Ratio test. Однако, если оставить только Cluster filtering, некоторые тесты начнут падать. Почему так происходит? В каких случаях наоборот, не хватает Ratio test и необходима дополнительная фильтрация? +- Cluster filtering слабо себя показывает в случае если на картинке присутсвуют регулярные структуры, за которые цепляется дескриптор => образуются множественные очень близкие друг к другу кластера, которые могут найти метчи из другого кластера. В этом случае cluster filtering такие матчи посчитает верными, что может быть ошибочно. +- Ratio test наоборот не учитывает пространственные окрестности, из-за чего может сметчить цветочки (элементы) из двух разных клумб (окрестностей). +3) С какой проблемой можно столкнуться при приравнивании единице элемента H33 матрицы гомографии? Как ее решить? \ +\ +В случае если матрица полученной системы численно нестабильна (это может произойти если в одной из нормировок H_33~0, остальные значения конечны и не бесконечно малы => при нормировке на H_33 получим огромные значения оставшихся элементов), тогда +- будет проблематично обращать такую матрицу, чтобы получить преобразованные точки +- флотовые вычисления вносят дополнительную ошибку когда складываем числа разного порядка + +4) Какой подвох таится в попытке склеивать большие панорамы и ортофото методом, реализованным в данной домашке? (Для интуиции можно посмотреть на результат склейки, когда за корень взята какая-нибудь другая картинка) \ +\ +Заметно, что чем ближе пара склеенных фоток к корню, тем лучше склейка. Следовательно от выбора корня зависит общая невязка -- лучше выбирать корень таким образом, чтобы корень оказался в наиболее важной части композиции, тогда, согласно наблюдению, в зонах интереса склейка будет менее резкой. + +5) Как можно автоматически построить граф для построения панорамы, чтобы на вход метод принимал только список картинок? \ +(Мысли именно насчет однострочной панорамы) +- провести метчинг для каждой пары картинок +- для каждой пары картинок вычислить MSE заметченных дескрипторов +- для каждой картинки находим по две картинки с минимумом MSE -- это окрестность картинки +- далее находим две картинки с максимальными минимумами -- это краевые картинки +- начиная с любой из этих двух картинок используя минимальный из ее минимумов начинаем собирать граф-путь + +6) Если с вашей реализацией SIFT пройти тесты не получилось, напишите (если пробовали дебажить), где, как вам кажется, проблема и как вы пробовали ее решать. \ +\ +Изначально была проблема с тайм-лимитами, пофиксил поправив настройки FLANN. + +7) Если есть, фидбек по заданию: какая часть больше всего понравилась, где-то слишком сложно/просто (что именно), где-то слишком мало ссылок и тд. +\ +\ +Подбор гиперпарматеров в алгоритме FLANN оказался весьма неприятным -- приходилось искать компромисс между тайм-лимитами и скором, при этом у фейлов низкая воспроизводимость, что усложняло дебаг. \ No newline at end of file diff --git a/tests/test_matching.cpp b/tests/test_matching.cpp index 5753ad84..6a0e4661 100644 --- a/tests/test_matching.cpp +++ b/tests/test_matching.cpp @@ -138,13 +138,11 @@ namespace { #if ENABLE_MY_MATCHING phg::DescriptorMatcher::filterMatchesRatioTest(knn_matches, good_matches); - printf("haha\n"); { std::vector tmp; phg::DescriptorMatcher::filterMatchesClusters(good_matches, keypoints1, keypoints2, tmp); std::swap(tmp, good_matches); } - printf("haho\n"); #else { @@ -159,12 +157,9 @@ namespace { points1.push_back(keypoints1[match.queryIdx].pt); points2.push_back(keypoints2[match.trainIdx].pt); } - printf("huhu\n"); #if ENABLE_MY_MATCHING cv::Mat H = phg::findHomography(points1, points2); - printf("hihi\n"); - #else cv::Mat H = phg::findHomographyCV(points1, points2); #endif From a01f213a9e25d1ccb3fb2d6494a27e4c44732d1e Mon Sep 17 00:00:00 2001 From: alexander Date: Sun, 29 Mar 2026 14:08:43 +0300 Subject: [PATCH 09/31] task3 mvp --- src/phg/sfm/ematrix.cpp | 197 +++++++++++++++--------------- src/phg/sfm/fmatrix.cpp | 224 ++++++++++++++++++++-------------- src/phg/sfm/resection.cpp | 174 +++++++++++++------------- src/phg/sfm/sfm_utils.cpp | 8 +- src/phg/sfm/triangulation.cpp | 26 +++- tests/test_sfm.cpp | 2 +- 6 files changed, 354 insertions(+), 277 deletions(-) diff --git a/src/phg/sfm/ematrix.cpp b/src/phg/sfm/ematrix.cpp index 3bc052b0..5ba79fc6 100644 --- a/src/phg/sfm/ematrix.cpp +++ b/src/phg/sfm/ematrix.cpp @@ -18,8 +18,10 @@ namespace { copy(Ecv, E); Eigen::JacobiSVD svd(E, Eigen::ComputeFullU | Eigen::ComputeFullV); - throw std::runtime_error("not implemented yet"); -// TODO + auto singular_values_vector = svd.singularValues(); + singular_values_vector[2] = double(0.); + singular_values_vector[1] = singular_values_vector[0]; + E = svd.matrixU() * singular_values_vector.asDiagonal() * svd.matrixV().transpose(); copy(E, Ecv); } @@ -28,12 +30,11 @@ namespace { cv::Matx33d phg::fmatrix2ematrix(const cv::Matx33d &F, const phg::Calibration &calib0, const phg::Calibration &calib1) { - throw std::runtime_error("not implemented yet"); -// matrix3d E = TODO; -// -// ensureSpectralProperty(E); -// -// return E; + matrix3d E = calib0.K().t() * F * calib1.K(); + + ensureSpectralProperty(E); + + return E; } namespace { @@ -61,21 +62,22 @@ namespace { bool depthTest(const vector2d &m0, const vector2d &m1, const phg::Calibration &calib0, const phg::Calibration &calib1, const matrix34d &P0, const matrix34d &P1) { - throw std::runtime_error("not implemented yet"); -// // скомпенсировать калибровки камер -// vector3d p0 = TODO; -// vector3d p1 = TODO; -// -// vector3d ps[2] = {p0, p1}; -// matrix34d Ps[2] = {P0, P1}; -// -// vector4d X = phg::triangulatePoint(Ps, ps, 2); -// if (X[3] != 0) { -// X /= X[3]; -// } -// -// // точка должна иметь положительную глубину для обеих камер -// return TODO && TODO; + // скомпенсировать калибровки камер + // vector3d p0 = calib0.K().t() * vector3d(m0[0], m0[1], 1.); + // vector3d p1 = calib1.K().t() * vector3d(m1[0], m1[1], 1.); + vector3d p0 = calib0.unproject(m0); + vector3d p1 = calib1.unproject(m1); + + vector3d ps[2] = {p0, p1}; + matrix34d Ps[2] = {P0, P1}; + + vector4d X = phg::triangulatePoint(Ps, ps, 2); + if (X[3] != 0) { + X /= X[3]; + } + + // точка должна иметь положительную глубину для обеих камер + return (P0 * X)[3] && (P1 * X)[3]; } } @@ -88,80 +90,81 @@ namespace { // первичное разложение существенной матрицы (а из него, взаимное расположение камер) для последующего уточнения методом нелинейной оптимизации void phg::decomposeEMatrix(cv::Matx34d &P0, cv::Matx34d &P1, const cv::Matx33d &Ecv, const std::vector &m0, const std::vector &m1, const Calibration &calib0, const Calibration &calib1) { - throw std::runtime_error("not implemented yet"); -// if (m0.size() != m1.size()) { -// throw std::runtime_error("decomposeEMatrix : m0.size() != m1.size()"); -// } -// -// using mat = Eigen::MatrixXd; -// using vec = Eigen::VectorXd; -// -// mat E; -// copy(Ecv, E); -// -// // (см. Hartley & Zisserman p.258) -// -// Eigen::JacobiSVD svd(E, Eigen::ComputeFullU | Eigen::ComputeFullV); -// -// mat U = svd.matrixU(); -// vec s = svd.singularValues(); -// mat V = svd.matrixV(); -// -// // U, V must be rotation matrices, not just orthogonal -// if (U.determinant() < 0) U = -U; -// if (V.determinant() < 0) V = -V; -// -// std::cout << "U:\n" << U << std::endl; -// std::cout << "s:\n" << s << std::endl; -// std::cout << "V:\n" << V << std::endl; -// -// -// mat R0 = TODO; -// mat R1 = TODO; -// -// std::cout << "R0:\n" << R0 << std::endl; -// std::cout << "R1:\n" << R1 << std::endl; -// -// vec t0 = TODO; -// vec t1 = TODO; -// -// std::cout << "t0:\n" << t0 << std::endl; -// -// P0 = matrix34d::eye(); -// -// // 4 possible solutions -// matrix34d P10 = composeP(R0, t0); -// matrix34d P11 = composeP(R0, t1); -// matrix34d P12 = composeP(R1, t0); -// matrix34d P13 = composeP(R1, t1); -// matrix34d P1s[4] = {P10, P11, P12, P13}; -// -// // need to select best of 4 solutions: 3d points should be in front of cameras (positive depths) -// int best_count = 0; -// int best_idx = -1; -// for (int i = 0; i < 4; ++i) { -// int count = 0; -// for (int j = 0; j < (int) m0.size(); ++j) { -// if (depthTest(m0[j], m1[j], calib0, calib1, P0, P1s[i])) { -// ++count; -// } -// } -// std::cout << "decomposeEMatrix: count: " << count << std::endl; -// if (count > best_count) { -// best_count = count; -// best_idx = i; -// } -// } -// -// if (best_count == 0) { -// throw std::runtime_error("decomposeEMatrix : can't decompose ematrix"); -// } -// -// P1 = P1s[best_idx]; -// -// std::cout << "best idx: " << best_idx << std::endl; -// std::cout << "P0: \n" << P0 << std::endl; -// std::cout << "P1: \n" << P1 << std::endl; + if (m0.size() != m1.size()) { + throw std::runtime_error("decomposeEMatrix : m0.size() != m1.size()"); + } + + using mat = Eigen::MatrixXd; + using vec = Eigen::VectorXd; + + mat E; + copy(Ecv, E); + + // (см. Hartley & Zisserman p.258) + + Eigen::JacobiSVD svd(E, Eigen::ComputeFullU | Eigen::ComputeFullV); + + mat U = svd.matrixU(); + vec s = svd.singularValues(); + mat V = svd.matrixV(); + + // U, V must be rotation matrices, not just orthogonal + if (U.determinant() < 0) U = -U; + if (V.determinant() < 0) V = -V; + + std::cout << "U:\n" << U << std::endl; + std::cout << "s:\n" << s << std::endl; + std::cout << "V:\n" << V << std::endl; + + mat W(3, 3); + W << 0., -1., 0., 1., 0., 0., 0., 0., 1.; + + mat R0 = U * W * V.transpose(); + mat R1 = U * W.transpose() * V.transpose(); + + std::cout << "R0:\n" << R0 << std::endl; + std::cout << "R1:\n" << R1 << std::endl; + + vec t0 = U.col(2); + vec t1 = -U.col(2); + + std::cout << "t0:\n" << t0 << std::endl; + + P0 = matrix34d::eye(); + + // 4 possible solutions + matrix34d P10 = composeP(R0, t0); + matrix34d P11 = composeP(R0, t1); + matrix34d P12 = composeP(R1, t0); + matrix34d P13 = composeP(R1, t1); + matrix34d P1s[4] = {P10, P11, P12, P13}; + + // need to select best of 4 solutions: 3d points should be in front of cameras (positive depths) + int best_count = 0; + int best_idx = -1; + for (int i = 0; i < 4; ++i) { + int count = 0; + for (int j = 0; j < (int) m0.size(); ++j) { + if (depthTest(m0[j], m1[j], calib0, calib1, P0, P1s[i])) { + ++count; + } + } + std::cout << "decomposeEMatrix: count: " << count << std::endl; + if (count > best_count) { + best_count = count; + best_idx = i; + } + } + + if (best_count == 0) { + throw std::runtime_error("decomposeEMatrix : can't decompose ematrix"); + } + + P1 = P1s[best_idx]; + + std::cout << "best idx: " << best_idx << std::endl; + std::cout << "P0: \n" << P0 << std::endl; + std::cout << "P1: \n" << P1 << std::endl; } void phg::decomposeUndistortedPMatrix(cv::Matx33d &R, cv::Vec3d &O, const cv::Matx34d &P) diff --git a/src/phg/sfm/fmatrix.cpp b/src/phg/sfm/fmatrix.cpp index 50127189..7fd0400b 100644 --- a/src/phg/sfm/fmatrix.cpp +++ b/src/phg/sfm/fmatrix.cpp @@ -25,49 +25,85 @@ namespace { // (см. Hartley & Zisserman p.279) cv::Matx33d estimateFMatrixDLT(const cv::Vec2d *m0, const cv::Vec2d *m1, int count) { - throw std::runtime_error("not implemented yet"); -// int a_rows = TODO; -// int a_cols = TODO; -// -// Eigen::MatrixXd A(a_rows, a_cols); -// -// for (int i_pair = 0; i_pair < count; ++i_pair) { -// -// double x0 = m0[i_pair][0]; -// double y0 = m0[i_pair][1]; -// -// double x1 = m1[i_pair][0]; -// double y1 = m1[i_pair][1]; -// -//// std::cout << "(" << x0 << ", " << y0 << "), (" << x1 << ", " << y1 << ")" << std::endl; -// -// TODO -// } -// -// Eigen::JacobiSVD svda(A, Eigen::ComputeFullU | Eigen::ComputeFullV); -// Eigen::VectorXd null_space = TODO -// -// Eigen::MatrixXd F(3, 3); -// F.row(0) << null_space[0], null_space[1], null_space[2]; -// F.row(1) << null_space[3], null_space[4], null_space[5]; -// F.row(2) << null_space[6], null_space[7], null_space[8]; -// -//// Поправить F так, чтобы соблюдалось свойство фундаментальной матрицы (последнее сингулярное значение = 0) -// Eigen::JacobiSVD svdf(F, Eigen::ComputeFullU | Eigen::ComputeFullV); -// -// TODO -// -// cv::Matx33d Fcv; -// copy(F, Fcv); -// -// return Fcv; + int a_rows = count; + int a_cols = 9; + + Eigen::MatrixXd A(a_rows, a_cols); + + double avg_x1 = 0, avg_y1 = 0, avg_x2 = 0, avg_y2 = 0; + double std_x1 = 0, std_y1 = 0, std_x2 = 0, std_y2 = 0; + for (int i_pair = 0; i_pair < count; ++i_pair) { + + double x0 = m0[i_pair][0]; + double y0 = m0[i_pair][1]; + avg_x1 += x0; + avg_y1 += y0; + std_x1 += x0 * x0; + std_y1 += y0 * y0; + + double x1 = m1[i_pair][0]; + double y1 = m1[i_pair][1]; + avg_x2 += x1; + avg_y2 += y1; + std_x2 += x1 * x1; + std_y2 += y1 * y1; + + // std::cout << "(" << x0 << ", " << y0 << "), (" << x1 << ", " << y1 << ")" << std::endl; + + A(i_pair, 0) = x1 * x0; + A(i_pair, 1) = x1 * y0; + A(i_pair, 2) = x1; + + A(i_pair, 3) = y1 * x0; + A(i_pair, 4) = y1 * y0; + A(i_pair, 5) = y1; + + A(i_pair, 6) = x0; + A(i_pair, 7) = y0; + A(i_pair, 8) = 1.; + } + + Eigen::JacobiSVD svda(A, Eigen::ComputeFullU | Eigen::ComputeFullV); + Eigen::VectorXd null_space = svda.matrixV().col(8); + + Eigen::MatrixXd F(3, 3); + F.row(0) << null_space[0], null_space[1], null_space[2]; + F.row(1) << null_space[3], null_space[4], null_space[5]; + F.row(2) << null_space[6], null_space[7], null_space[8]; + + // Поправить F так, чтобы соблюдалось свойство фундаментальной матрицы (последнее сингулярное значение = 0) + Eigen::JacobiSVD svdf(F, Eigen::ComputeFullU | Eigen::ComputeFullV); + + + auto singular_values_vector = svdf.singularValues(); + singular_values_vector[2] = double(0.); + F = svdf.matrixU() * singular_values_vector.asDiagonal() * svdf.matrixV().transpose(); + + cv::Matx33d Fcv; + copy(F, Fcv); + + return Fcv; } // Нужно создать матрицу преобразования, которая сдвинет переданное множество точек так, что центр масс перейдет в ноль, а Root Mean Square расстояние до него станет sqrt(2) // (см. Hartley & Zisserman p.107 Why is normalization essential?) cv::Matx33d getNormalizeTransform(const std::vector &m) { - throw std::runtime_error("not implemented yet"); + cv::Vec2d avg(0, 0); + for (size_t i = 0; i < m.size(); i++) { + avg += m[i]; + } + avg = cv::Vec2d(avg[0] / m.size(), avg[1] / m.size()); + + double rms = 0; + for (size_t i = 0; i < m.size(); i++) { + rms += (m[i][0] - avg[0]) * (m[i][0] - avg[0]) + (m[i][1] - avg[1]) * (m[i][1] - avg[1]); + + } + rms = std::sqrt(rms) / m.size(); + double s = std::sqrt(2) / (rms + 1e-6); + + return {s, 0., -avg[0] * s, 0., s, -avg[1] * s, 0., 0., 1.}; } cv::Vec2d transformPoint(const cv::Vec2d &pt, const cv::Matx33d &T) @@ -101,64 +137,64 @@ namespace { { // Проверьте лог: при повторной нормализации должно найтись почти единичное преобразование - getNormalizeTransform(m0_t); - getNormalizeTransform(m1_t); + // std::cout << getNormalizeTransform(m0_t) << "\n"; + // std::cout << getNormalizeTransform(m1_t) << "\n"; + } + // https://en.wikipedia.org/wiki/Random_sample_consensus#Parameters + // будет отличаться от случая с гомографией + const int n_trials = 100000; // works + + const int n_samples = 8; + uint64_t seed = 1; + + int best_support = 0; + cv::Matx33d best_F; + + std::vector sample; + for (int i_trial = 0; i_trial < n_trials; ++i_trial) { + phg::randomSample(sample, n_matches, n_samples, &seed); + + cv::Vec2d ms0[n_samples]; + cv::Vec2d ms1[n_samples]; + for (int i = 0; i < n_samples; ++i) { + ms0[i] = m0_t[sample[i]]; + ms1[i] = m1_t[sample[i]]; + } + + cv::Matx33d F = estimateFMatrixDLT(ms0, ms1, n_samples); + + // denormalize TODO + F = TN1.t() * F * TN0; + + + int support = 0; + for (int i = 0; i < n_matches; ++i) { + if (phg::epipolarTest(m0[i], m1[i], F, threshold_px) && phg::epipolarTest(m1[i], m0[i], F.t(), threshold_px)) + { + ++support; + } + } + + if (support > best_support) { + best_support = support; + best_F = F; + + std::cout << "estimateFMatrixRANSAC : support: " << best_support << "/" << n_matches << std::endl; + infoF(F); + + if (best_support == n_matches) { + break; + } + } } - throw std::runtime_error("not implemented yet"); -// // https://en.wikipedia.org/wiki/Random_sample_consensus#Parameters -// // будет отличаться от случая с гомографией -// const int n_trials = TODO; -// -// const int n_samples = TODO; -// uint64_t seed = 1; -// -// int best_support = 0; -// cv::Matx33d best_F; -// -// std::vector sample; -// for (int i_trial = 0; i_trial < n_trials; ++i_trial) { -// phg::randomSample(sample, n_matches, n_samples, &seed); -// -// cv::Vec2d ms0[n_samples]; -// cv::Vec2d ms1[n_samples]; -// for (int i = 0; i < n_samples; ++i) { -// ms0[i] = m0_t[sample[i]]; -// ms1[i] = m1_t[sample[i]]; -// } -// -// cv::Matx33d F = estimateFMatrixDLT(ms0, ms1, n_samples); -// -// // denormalize -// F = TODO -// -// int support = 0; -// for (int i = 0; i < n_matches; ++i) { -// if (phg::epipolarTest(m0[i], m1[i], todo, threshold_px) && phg::epipolarTest(m1[i], m0[i], todo, threshold_px)) -// { -// ++support; -// } -// } -// -// if (support > best_support) { -// best_support = support; -// best_F = F; -// -// std::cout << "estimateFMatrixRANSAC : support: " << best_support << "/" << n_matches << std::endl; -// infoF(F); -// -// if (best_support == n_matches) { -// break; -// } -// } -// } -// -// std::cout << "estimateFMatrixRANSAC : best support: " << best_support << "/" << n_matches << std::endl; -// -// if (best_support == 0) { -// throw std::runtime_error("estimateFMatrixRANSAC : failed to estimate fundamental matrix"); -// } -// -// return best_F; + + std::cout << "estimateFMatrixRANSAC : best support: " << best_support << "/" << n_matches << std::endl; + + if (best_support == 0) { + throw std::runtime_error("estimateFMatrixRANSAC : failed to estimate fundamental matrix"); + } + + return best_F; } } diff --git a/src/phg/sfm/resection.cpp b/src/phg/sfm/resection.cpp index d2cf6433..f60cd087 100644 --- a/src/phg/sfm/resection.cpp +++ b/src/phg/sfm/resection.cpp @@ -49,95 +49,103 @@ namespace { // (см. Hartley & Zisserman p.178) cv::Matx34d estimateCameraMatrixDLT(const cv::Vec3d *Xs, const cv::Vec3d *xs, int count) { - throw std::runtime_error("not implemented yet"); -// using mat = Eigen::MatrixXd; -// using vec = Eigen::VectorXd; -// -// mat A(TODO); -// -// for (int i = 0; i < count; ++i) { -// -// double x = xs[i][0]; -// double y = xs[i][1]; -// double w = xs[i][2]; -// -// double X = Xs[i][0]; -// double Y = Xs[i][1]; -// double Z = Xs[i][2]; -// double W = 1.0; -// -// TODO -// } -// -// matrix34d result; -// TODO -// -// return canonicalizeP(result); + using mat = Eigen::MatrixXd; + using vec = Eigen::VectorXd; + + mat A(2 * count, 12); + + for (int i = 0; i < count; ++i) { + + double x = xs[i][0]; + double y = xs[i][1]; + double w = xs[i][2]; + + double X = Xs[i][0]; + double Y = Xs[i][1]; + double Z = Xs[i][2]; + double W = 1.0; + + A.row(i * 2) << 0., 0., 0., 0., -w * X, -w * Y, -w * Z, -w * W, y * X, y * Y, y * Z, y * W; + A.row(i * 2 + 1) << w * X, w * Y, w * Z, w * W, 0., 0., 0., 0., -x * X, -x * Y, -x * Z, -x * W; + } + + matrix34d result; + + Eigen::JacobiSVD svd(A, Eigen::ComputeFullU | Eigen::ComputeFullV); + Eigen::VectorXd null_space = svd.matrixV().col(11); + + result(0, 0) = null_space[0]; result(0, 1) = null_space[1]; result(0, 2) = null_space[2]; result(0, 3) = null_space[3]; + result(1, 0) = null_space[4]; result(1, 1) = null_space[5]; result(1, 2) = null_space[6]; result(1, 3) = null_space[7]; + result(2, 0) = null_space[8]; result(2, 1) = null_space[9]; result(2, 2) = null_space[10]; result(2, 3) = null_space[11]; + + return canonicalizeP(result); } // По трехмерным точкам и их проекциям на изображении определяем положение камеры cv::Matx34d estimateCameraMatrixRANSAC(const phg::Calibration &calib, const std::vector &X, const std::vector &x) { - throw std::runtime_error("not implemented yet"); -// if (X.size() != x.size()) { -// throw std::runtime_error("estimateCameraMatrixRANSAC: X.size() != x.size()"); -// } -// -// const int n_points = X.size(); -// -// // https://en.wikipedia.org/wiki/Random_sample_consensus#Parameters -// // будет отличаться от случая с гомографией -// const int n_trials = TODO; -// -// const double threshold_px = 3; -// -// const int n_samples = TODO; -// uint64_t seed = 1; -// -// int best_support = 0; -// cv::Matx34d best_P; -// -// std::vector sample; -// for (int i_trial = 0; i_trial < n_trials; ++i_trial) { -// phg::randomSample(sample, n_points, n_samples, &seed); -// -// cv::Vec3d ms0[n_samples]; -// cv::Vec3d ms1[n_samples]; -// for (int i = 0; i < n_samples; ++i) { -// ms0[i] = TODO; -// ms1[i] = TODO; -// } -// -// cv::Matx34d P = estimateCameraMatrixDLT(ms0, ms1, n_samples); -// -// int support = 0; -// for (int i = 0; i < n_points; ++i) { -// cv::Vec2d px = TODO спроецировать 3Д точку в пиксель с использованием P и calib; -// if (cv::norm(px - x[i]) < threshold_px) { -// ++support; -// } -// } -// -// if (support > best_support) { -// best_support = support; -// best_P = P; -// -// std::cout << "estimateCameraMatrixRANSAC : support: " << best_support << "/" << n_points << std::endl; -// -// if (best_support == n_points) { -// break; -// } -// } -// } -// -// std::cout << "estimateCameraMatrixRANSAC : best support: " << best_support << "/" << n_points << std::endl; -// -// if (best_support == 0) { -// throw std::runtime_error("estimateCameraMatrixRANSAC : failed to estimate camera matrix"); -// } -// -// return best_P; + if (X.size() != x.size()) { + throw std::runtime_error("estimateCameraMatrixRANSAC: X.size() != x.size()"); + } + + const int n_points = X.size(); + + // https://en.wikipedia.org/wiki/Random_sample_consensus#Parameters + // будет отличаться от случая с гомографией + const int n_points_fit = 6; + const double singlePointInlierProbability = 0.2, successProbability = 0.99; // maybe singlePointInlierProbability should be set to lower value + const int n_trials = (int) (log(1 - successProbability) / log(1 - pow(singlePointInlierProbability, n_points_fit))); + + const double threshold_px = 3; + + const int n_samples = n_points_fit; + uint64_t seed = 1; + + int best_support = 0; + cv::Matx34d best_P; + + std::vector sample; + for (int i_trial = 0; i_trial < n_trials; ++i_trial) { + phg::randomSample(sample, n_points, n_samples, &seed); + + cv::Vec3d ms0[n_samples]; + cv::Vec3d ms1[n_samples]; + for (int i = 0; i < n_samples; ++i) { + ms0[i] = X[sample[i]]; + ms1[i] = calib.unproject(x[sample[i]]); + } + + cv::Matx34d P = estimateCameraMatrixDLT(ms0, ms1, n_samples); + + int support = 0; + for (int i = 0; i < n_points; ++i) { + cv::Vec3d px_uniqform = calib.project(P * cv::Vec4d(X[i][0], X[i][1], X[i][2], 1.)); // спроецировать 3Д точку в пиксель с использованием P и calib; + cv::Vec2d px = {px_uniqform[0] / px_uniqform[2], px_uniqform[1] / px_uniqform[2]}; + if (cv::norm(px - x[i]) < threshold_px) { + ++support; + } + } + + if (support > best_support) { + best_support = support; + best_P = P; + + std::cout << "estimateCameraMatrixRANSAC : support: " << best_support << "/" << n_points << std::endl; + + if (best_support == n_points) { + break; + } + } + } + + std::cout << "estimateCameraMatrixRANSAC : best support: " << best_support << "/" << n_points << std::endl; + + if (best_support == 0) { + throw std::runtime_error("estimateCameraMatrixRANSAC : failed to estimate camera matrix"); + } + + return best_P; } diff --git a/src/phg/sfm/sfm_utils.cpp b/src/phg/sfm/sfm_utils.cpp index d2d2e294..ef7ef53c 100644 --- a/src/phg/sfm/sfm_utils.cpp +++ b/src/phg/sfm/sfm_utils.cpp @@ -41,5 +41,11 @@ void phg::randomSample(std::vector &dst, int max_id, int sample_size, uint6 // проверяет, что расстояние от точки до линии меньше порога bool phg::epipolarTest(const cv::Vec2d &pt0, const cv::Vec2d &pt1, const cv::Matx33d &F, double t) { - throw std::runtime_error("not implemented yet"); + cv::Vec3d pt0ext(pt0[0], pt0[1], 1.), pt1ext(pt1[0], pt1[1], 1.); + + cv::Vec3d epipolarLine = F * pt0ext; + double inner_product = pt1ext.ddot(epipolarLine); + double dist = std::abs(inner_product) / std::sqrt(epipolarLine[0] * epipolarLine[0] + epipolarLine[1] * epipolarLine[1]); + + return dist < t; } diff --git a/src/phg/sfm/triangulation.cpp b/src/phg/sfm/triangulation.cpp index 8dd11e69..d2e327ca 100644 --- a/src/phg/sfm/triangulation.cpp +++ b/src/phg/sfm/triangulation.cpp @@ -12,5 +12,29 @@ cv::Vec4d phg::triangulatePoint(const cv::Matx34d *Ps, const cv::Vec3d *ms, int { // составление однородной системы + SVD // без подвохов - throw std::runtime_error("not implemented yet"); + Eigen::MatrixXd A(4, 4); + A.row(0) << ms[0][0] * Ps[0](2, 0) - Ps[0](0, 0), + ms[0][0] * Ps[0](2, 1) - Ps[0](0, 1), + ms[0][0] * Ps[0](2, 2) - Ps[0](0, 2), + ms[0][0] * Ps[0](2, 3) - Ps[0](0, 3); + + A.row(1) << ms[0][1] * Ps[0](2, 0) - Ps[0](1, 0), + ms[0][1] * Ps[0](2, 1) - Ps[0](1, 1), + ms[0][1] * Ps[0](2, 2) - Ps[0](1, 2), + ms[0][1] * Ps[0](2, 3) - Ps[0](1, 3); + + A.row(2) << ms[1][0] * Ps[1](2, 0) - Ps[1](0, 0), + ms[1][0] * Ps[1](2, 1) - Ps[1](0, 1), + ms[1][0] * Ps[1](2, 2) - Ps[1](0, 2), + ms[1][0] * Ps[1](2, 3) - Ps[1](0, 3); + + A.row(3) << ms[1][1] * Ps[1](2, 0) - Ps[1](1, 0), + ms[1][1] * Ps[1](2, 1) - Ps[1](1, 1), + ms[1][1] * Ps[1](2, 2) - Ps[1](1, 2), + ms[1][1] * Ps[1](2, 3) - Ps[1](1, 3); + + Eigen::JacobiSVD svd(A, Eigen::ComputeFullU | Eigen::ComputeFullV); + auto null_space = svd.matrixV().col(3); + + return {null_space[0], null_space[1], null_space[2], null_space[3]}; } diff --git a/tests/test_sfm.cpp b/tests/test_sfm.cpp index 4229b86b..48cc1588 100644 --- a/tests/test_sfm.cpp +++ b/tests/test_sfm.cpp @@ -18,7 +18,7 @@ #include "utils/test_utils.h" -#define ENABLE_MY_SFM 0 +#define ENABLE_MY_SFM 1 namespace { From e8b66c1f5d1cec89681bba9aed28f3c5e5f3f8ef Mon Sep 17 00:00:00 2001 From: alexander Date: Sun, 29 Mar 2026 14:42:46 +0300 Subject: [PATCH 10/31] more trials resection --- src/phg/sfm/resection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/phg/sfm/resection.cpp b/src/phg/sfm/resection.cpp index f60cd087..8599d021 100644 --- a/src/phg/sfm/resection.cpp +++ b/src/phg/sfm/resection.cpp @@ -95,7 +95,7 @@ namespace { // будет отличаться от случая с гомографией const int n_points_fit = 6; const double singlePointInlierProbability = 0.2, successProbability = 0.99; // maybe singlePointInlierProbability should be set to lower value - const int n_trials = (int) (log(1 - successProbability) / log(1 - pow(singlePointInlierProbability, n_points_fit))); + const int n_trials = 100000; const double threshold_px = 3; From 1c00ce602b86c488c531c9a37fcec8d70dd79e16 Mon Sep 17 00:00:00 2001 From: alexander Date: Sun, 29 Mar 2026 15:35:12 +0300 Subject: [PATCH 11/31] fix for depth test --- src/phg/sfm/ematrix.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/phg/sfm/ematrix.cpp b/src/phg/sfm/ematrix.cpp index 5ba79fc6..15f821d4 100644 --- a/src/phg/sfm/ematrix.cpp +++ b/src/phg/sfm/ematrix.cpp @@ -77,7 +77,7 @@ namespace { } // точка должна иметь положительную глубину для обеих камер - return (P0 * X)[3] && (P1 * X)[3]; + return ((P0 * X)[2] > 0) && ((P1 * X)[2] > 0); } } From b71fc8ff00a9900ed7d2ec70602d2883be0534aa Mon Sep 17 00:00:00 2001 From: alexander Date: Sun, 29 Mar 2026 23:01:20 +0300 Subject: [PATCH 12/31] task3: probabilities in order to get 100000 n_trials + answers --- Q&A3.md | 10 ++++++++++ src/phg/sfm/fmatrix.cpp | 5 ++++- src/phg/sfm/resection.cpp | 3 ++- 3 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 Q&A3.md diff --git a/Q&A3.md b/Q&A3.md new file mode 100644 index 00000000..d625df48 --- /dev/null +++ b/Q&A3.md @@ -0,0 +1,10 @@ +# Перечислите идеи и коротко обозначьте мысли которые у вас возникали по мере выполнения задания, в частности попробуйте ответить на вопросы: + +1) Мы можем получить облако точек и взаимную ориентацию по двум камерам. Почему для выравнивания трёх камер мы использовали резекцию, а не посчитали E матрицу для второй пары камер и не разложили ее? \ + При работе с двумя камерами, мы получаем матрицу E с точностью до масштаба. При добавлении последующих камер масштабы могут не метэчиться. +2) Как реализовать выравнивание если мы все же хотим использовать Е матрицу? +- Фиттить первоначально полученную матрицу P_n таким образом, чтобы 3х-мерные точки, полученные из первых двух камер при триангуляции не перемещались, но описанный процесс сильно похож на резекцию. Наверное потому что без иных вводных и критериев правильности облака точек сложно придумать иную концепцию. +- С другой стороны можно попробовать повторить нахождение матрицы E для следующей пары (одна из камер уже была в наборе, ее берем за основную с единичной P-матрицей), а потом RANSAC-ом связывать два облака, фиттируя преобразование масштаба для P-матрицы новой камеры. Проблема появялется при росте числа камер: если связывать новую пару только с предыдущей -- невязка будет накапливаться, если связывать все облака -- большая стоимость одной итерации RANSAC. + +3) Если есть, фидбек по заданию: какая часть больше всего понравилась, где-то слишком сложно/просто (что именно), где-то слишком мало ссылок и тд. \ +Как и в прошлом задании -- подбор параметров RANSAC для прохождения тестов. Хотелось бы больше интуиции, ведь по сути так как для разных тестов необходимо разное количество итераций RANSAC (причем по порядкам), из формулы числа итераций следует, что вероятности инлаеров сильно отличаются, возможно стоит добавить оценку этих параметров отдельным подзаданием. diff --git a/src/phg/sfm/fmatrix.cpp b/src/phg/sfm/fmatrix.cpp index 7fd0400b..3194b5b3 100644 --- a/src/phg/sfm/fmatrix.cpp +++ b/src/phg/sfm/fmatrix.cpp @@ -142,9 +142,12 @@ namespace { } // https://en.wikipedia.org/wiki/Random_sample_consensus#Parameters // будет отличаться от случая с гомографией + const int n_points_fit = 8; + const double singlePointInlierProbability = 0.287, successProbability = 0.99; // maybe singlePointInlierProbability should be set to lower value + // const int n_trials = (int) (log(1 - successProbability) / log(1 - pow(singlePointInlierProbability, n_points_fit))); const int n_trials = 100000; // works - const int n_samples = 8; + const int n_samples = n_points_fit; uint64_t seed = 1; int best_support = 0; diff --git a/src/phg/sfm/resection.cpp b/src/phg/sfm/resection.cpp index 8599d021..3fe1fcfd 100644 --- a/src/phg/sfm/resection.cpp +++ b/src/phg/sfm/resection.cpp @@ -94,7 +94,8 @@ namespace { // https://en.wikipedia.org/wiki/Random_sample_consensus#Parameters // будет отличаться от случая с гомографией const int n_points_fit = 6; - const double singlePointInlierProbability = 0.2, successProbability = 0.99; // maybe singlePointInlierProbability should be set to lower value + const double singlePointInlierProbability = 0.1893, successProbability = 0.99; // maybe singlePointInlierProbability should be set to lower value + // const int n_trials = (int) (log(1 - successProbability) / log(1 - pow(singlePointInlierProbability, n_points_fit))); const int n_trials = 100000; const double threshold_px = 3; From 63b961379d0726ce2f011af4ee93cabf40f65794 Mon Sep 17 00:00:00 2001 From: alexander Date: Wed, 1 Apr 2026 11:20:31 +0300 Subject: [PATCH 13/31] task03: changed behavior for ensureSpectralProperty -- now it is making a mean value instead of the first --- src/phg/sfm/ematrix.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/phg/sfm/ematrix.cpp b/src/phg/sfm/ematrix.cpp index 15f821d4..2b1b229c 100644 --- a/src/phg/sfm/ematrix.cpp +++ b/src/phg/sfm/ematrix.cpp @@ -19,8 +19,10 @@ namespace { Eigen::JacobiSVD svd(E, Eigen::ComputeFullU | Eigen::ComputeFullV); auto singular_values_vector = svd.singularValues(); + double sigma12 = (singular_values_vector[0] + singular_values_vector[1]) / 2.; + singular_values_vector[0] = sigma12; + singular_values_vector[1] = sigma12; singular_values_vector[2] = double(0.); - singular_values_vector[1] = singular_values_vector[0]; E = svd.matrixU() * singular_values_vector.asDiagonal() * svd.matrixV().transpose(); copy(E, Ecv); From 58419fa1d33732b75683ac17b7b83c90d67a9cec Mon Sep 17 00:00:00 2001 From: alexander Date: Wed, 1 Apr 2026 11:45:54 +0300 Subject: [PATCH 14/31] task03: fixed fmatrix2ematrix camera order, made epipolarTest more computational stable --- src/phg/sfm/ematrix.cpp | 4 ++-- src/phg/sfm/sfm_utils.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/phg/sfm/ematrix.cpp b/src/phg/sfm/ematrix.cpp index 2b1b229c..e12b0cba 100644 --- a/src/phg/sfm/ematrix.cpp +++ b/src/phg/sfm/ematrix.cpp @@ -32,7 +32,7 @@ namespace { cv::Matx33d phg::fmatrix2ematrix(const cv::Matx33d &F, const phg::Calibration &calib0, const phg::Calibration &calib1) { - matrix3d E = calib0.K().t() * F * calib1.K(); + matrix3d E = calib1.K().t() * F * calib0.K(); ensureSpectralProperty(E); @@ -121,7 +121,7 @@ void phg::decomposeEMatrix(cv::Matx34d &P0, cv::Matx34d &P1, const cv::Matx33d & mat W(3, 3); W << 0., -1., 0., 1., 0., 0., 0., 0., 1.; - mat R0 = U * W * V.transpose(); + mat R0 = U * W * V.transpose(); // the same thing as for U and V? => positive determinant : det ALWAYS > 0 mat R1 = U * W.transpose() * V.transpose(); std::cout << "R0:\n" << R0 << std::endl; diff --git a/src/phg/sfm/sfm_utils.cpp b/src/phg/sfm/sfm_utils.cpp index ef7ef53c..bbf65624 100644 --- a/src/phg/sfm/sfm_utils.cpp +++ b/src/phg/sfm/sfm_utils.cpp @@ -45,7 +45,7 @@ bool phg::epipolarTest(const cv::Vec2d &pt0, const cv::Vec2d &pt1, const cv::Mat cv::Vec3d epipolarLine = F * pt0ext; double inner_product = pt1ext.ddot(epipolarLine); - double dist = std::abs(inner_product) / std::sqrt(epipolarLine[0] * epipolarLine[0] + epipolarLine[1] * epipolarLine[1]); + double epipolarLineLength = std::sqrt(epipolarLine[0] * epipolarLine[0] + epipolarLine[1] * epipolarLine[1]); - return dist < t; + return std::abs(inner_product) < t * epipolarLineLength; } From 3fb7d63bbeeec8ea66299c347d814f421961357c Mon Sep 17 00:00:00 2001 From: alexander Date: Wed, 1 Apr 2026 12:19:20 +0300 Subject: [PATCH 15/31] task03: rms eps removed? --- src/phg/sfm/fmatrix.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/phg/sfm/fmatrix.cpp b/src/phg/sfm/fmatrix.cpp index 3194b5b3..fcbba379 100644 --- a/src/phg/sfm/fmatrix.cpp +++ b/src/phg/sfm/fmatrix.cpp @@ -100,8 +100,8 @@ namespace { rms += (m[i][0] - avg[0]) * (m[i][0] - avg[0]) + (m[i][1] - avg[1]) * (m[i][1] - avg[1]); } - rms = std::sqrt(rms) / m.size(); - double s = std::sqrt(2) / (rms + 1e-6); + + double s = std::sqrt(2 * m.size() / (rms + 1e-6)); return {s, 0., -avg[0] * s, 0., s, -avg[1] * s, 0., 0., 1.}; } From 8ce5e85def3f21557ab90ac1d99b4568e2c3d789 Mon Sep 17 00:00:00 2001 From: Nikolai Poliarnyi Date: Mon, 6 Apr 2026 22:49:46 +0300 Subject: [PATCH 16/31] CI: run patch match depth maps binary on windows --- .github/workflows/cmake.yml | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index b697ec35..923c191d 100755 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -112,12 +112,7 @@ jobs: Copy-Item "$vcpkgBin\*.dll" $exeDir -Force } - - name: Run test_ceres_solver (Windows) + - name: Run test_depth_maps_pm (Windows) if: runner.os == 'Windows' shell: pwsh - run: .\build\${{ env.BUILD_TYPE }}\test_ceres_solver.exe - - - name: Run test_sfm_ba (Windows) - if: runner.os == 'Windows' - shell: pwsh - run: .\build\${{ env.BUILD_TYPE }}\test_sfm_ba.exe + run: .\build\${{ env.BUILD_TYPE }}\test_depth_maps_pm.exe From f50c5a357f5d996a950b387d2b898e4f02ab34b3 Mon Sep 17 00:00:00 2001 From: alexander Date: Thu, 23 Apr 2026 13:19:14 +0300 Subject: [PATCH 17/31] task04 -- initial --- Q&A4.md | 38 +++++++++++++++++ herzjesu22.png | Bin 0 -> 70013 bytes saharov32.png | Bin 0 -> 95350 bytes src/phg/core/calibration.cpp | 30 +++++++++++-- src/phg/sfm/resection.cpp | 4 +- tests/test_ceres_solver.cpp | 62 +++++++++++++++++---------- tests/test_sfm_ba.cpp | 79 ++++++++++++++++++++++++++++------- 7 files changed, 170 insertions(+), 43 deletions(-) create mode 100644 Q&A4.md create mode 100644 herzjesu22.png create mode 100644 saharov32.png diff --git a/Q&A4.md b/Q&A4.md new file mode 100644 index 00000000..f4c64d95 --- /dev/null +++ b/Q&A4.md @@ -0,0 +1,38 @@ +# Перечислите идеи и коротко обозначьте мысли которые у вас возникали по мере выполнения задания, в частности попробуйте ответить на вопросы: + +1) test_ceres_solver/FitLine: почему найденная прямая и эталонная - не совпадают? Как это исправить пост-обработкой? Как это исправить формулировкой задачи?\ +\ +Прямые геометрически совпадают (одна прямая задается семейством наборов коэффициентов {a, b, c}, определенных с точностью до масштаба), коэффициенты же могут отличаться масштабом. \ +На постобработке можно исправить, поделив коэффициенты на некий скейл (такой, чтобы c_0==c_ideal, тут можно любой из коэффициентов приравнять, но в решении c имеет наибольший модуль и вычисления получаются более стабильными?)\ +В формулировку задачи можно добавить ограничение на величину одного из коэффициентов или на длину вектора (a, b) + +2) BA: представьте что вы написали преобразование phg::Calibration -> блок параметров и обратное блок параметров -> phg::Calibration. Как проверить простым образом что эти преобразования сделаны корректно? Что должно быть в логе про процент inliers до/после BA если runBA() вызывать всегда два раза пордяд? Иначе говоря - что следует из того что в идеале runBA() должна быть (мне очень нравится это слово) - [идемпотентна](https://ru.wikipedia.org/wiki/%D0%98%D0%B4%D0%B5%D0%BC%D0%BF%D0%BE%D1%82%D0%B5%D0%BD%D1%82%D0%BD%D0%BE%D1%81%D1%82%D1%8C)?\ +\ +Написать темплейт-функцию, считающую, например, проекцию точки в фокальную плоскость и сделать ассерт на равенство проекций. \ +Идемпотентность означает, что BA(BA(X)) = BA(X) => результат (процент inliers после однократного/двухкратного BA) должен совпадать. + + +3) Какое максимальное число кадров у вас получилось хорошо выравнять для каждого из датасетов? (проверьте хотя бы saharov32 и herzjesu25) Не забудьте приложить скриншоты. \ +\ +saharov32 -- 32/32 ![Alt Text](saharov32.png) +herzjesu25 -- 22/25 ![Alt Text](herzjesu22.png) + +4) Если бы вычисления в double были абсолютно точны - можно ли было бы назвать вычисления в Calibration::project/unproject строго зеркальными? \ +\ +Нет, т.к. мы полностью теряем информацию о координате z исходной точки. Кстати, в задании 3 при условии обратимости матрицы K project/unproject были взаимно обратными. Мне кажется стоит в задании 3 функционал проецирования однородных координат также перенести в project. + +5) Почему фокальная длина меняется от того что мы уменьшаем картинку? Почему именно f/downscale? \ +\ +$x_p = x_r \dfrac{f}{z} \Leftrightarrow x_r = \dfrac{x_p}{f} * z$ . \ +При даунсемпле картинки в s раз $x_p^{'} = \dfrac{x_p}{s} \Rightarrow $ \ +$x_r^{'} = \dfrac{x_p^{'}}{f} * z = \dfrac{x_p / s} {f} * z = \dfrac{x_p}{(f^{'} * s)} * z$ \ +Так как $x_r^{'} = x_r \Rightarrow f^{'} * s = f \Rightarrow f^{'} = \dfrac{f}{s}$ + +6) Имеет ли право BA двигать точку отсчета системы координат (т.е. добавить константу ко всем координатам)? Как это повлияет на суммарную Loss? \\ +В целом может, но зачем, это же не изменит координат векторов, не повлияет на Loss. + +7) Каким образом можно гарантировать чтобы при сравнении нескольких последовательно построенных облаков точек одного и того же датасета (созданных по мере добавления фотографии за фотографией) в MeshLab - облака не были хаотично смещены/отмасштабированы/повернуты друг от друга? \\ +Не оптимизировать параметры уже добавленных камер -- использовать систему координат 0-й камеры как якорную. Таким образом при сравнении в качестве осей брать оси 0-й камеры, в качестве масштаба брать среднее расстояние до триангулированных метчей первых двух камер. А еще лучше -- расстояние между первыми двумя камерами + +100) Если есть - фидбек/идеи по улучшению задания. +Сделать более плавный переход от 3 задания к 4-му (как минимум project/unproject). \ No newline at end of file diff --git a/herzjesu22.png b/herzjesu22.png new file mode 100644 index 0000000000000000000000000000000000000000..5c4ee2a43afb6fcbf189ebd3c6c3b3d9f55a9fd4 GIT binary patch literal 70013 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 S92D?8ny8=@B0X<{#FhhN70^X?kgkI5Z< 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
    eQquVk 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 " << cur_x << std::endl; std::cout << "f(x): " << initial_residual << " -> " << final_residual << std::endl; std::cout << "f'(x): " << initial_jacobian << " -> " << final_jacobian << std::endl; - // TODO 1: почему результирующая производная не ноль? мы ведь должны были сойтись в минимуме функции 0.5*(10-x)^2 - + // 1: почему результирующая производная не ноль? мы ведь должны были сойтись в минимуме функции 0.5*(10-x)^2 + // Потому что мы вычисляем функцию в CostFunctor1 не в виде 0.5*(10-x)^2, а в виде 10 - x => f'=-1, а класс jet позволяет вычислять табличные производные, а не разностные. + // Судя по всему ceres выводит якобиан не общего лосса, а конкретно нашей функции потерь: dL/dx = dL/dF * dF/dx, + // где L -- TrivialLoss, F -- CostFunctor1, y = L(F(x, r)) ASSERT_NEAR(cur_x, 10.0, 1e-6); } @@ -132,7 +134,9 @@ class ResidualToParaboloid { // Поэтому например для вычисления квадрата - можно просто перемножить T-переменные, а для вычисления произвольной степени - ceres::pow(x, y) T dx = queryPoint[0] - center[0]; T dy = queryPoint[1] - center[1]; - residual[0] = a*dx*dx + b*dy*dy - center[2]; + T dz = queryPoint[2] - center[2]; + // z = a*dx*dx + b*dy*dy + c0 + residual[0] = ceres::abs(a*dx*dx + b*dy*dy + center[2] - queryPoint[2]); return true; } protected: @@ -158,10 +162,9 @@ TEST (CeresSolver, HelloWorld2) { ceres::CostFunction* paraboloid_cost_function = new ceres::AutoDiffCostFunction (new ResidualToParaboloid(paraboloid_center, paraboloid_a, paraboloid_b)); - return; // TODO 2 удалите эту строку, затем // нарисуйте систему координат на бумажке чтобы найти координаты пересечения прямой и параболоида (параболоид и прямые - простые, поэтому пересечь их довольно просто) // и подставьте найденные координаты эталонного ответа в массив: - const double expected_point_solution[3] = {-1000.0, -1000.0, -1000.0}; + const double expected_point_solution[3] = {10.0, 5.0, 200.0}; { // Проверим что невязка эталонного решения нулевая для обоих функций невязки const double* params[1]; @@ -225,8 +228,8 @@ TEST (CeresSolver, HelloWorld2) { } for (int d = 0; d < 3; ++d) { -// EXPECT_NEAR(point[d], expected_point_solution[d], 1e-4); - // TODO 3: раскомментируйте^, почему он находит не то что ожидалось? + EXPECT_NEAR(point[d], expected_point_solution[d], 1e-4); + // 3: раскомментируйте, почему он находит не то что ожидалось? // либо мы набагали в коде, либо в аналитическом поиске правильного ответа на бумажке (проверьте вычисления на бумажке) // если бага в коде, то первые подозреваемые - две функции невязки (только там есть содержательный код) // заметьте что у найденного ответа ошибка только по одной из осей @@ -234,6 +237,8 @@ TEST (CeresSolver, HelloWorld2) { // отладьте те функции невязки которые по-хорошему не должны соглашаться на такой ответ - поставьте просто точку остановки чуть выше, там где мы проверяли // что невязка найденного решения - нулевая, и найдите где вдруг ваше ожидание большой невязки для этого ответа сталкивается с суровой реальностью баги в коде // которая приводит к нулевой невязке + + // ошибка была в функции невязки параболоида -- по сути исходной функцией невязки мы тянули точку к (x_1, y_1, 0) -- эта точка принадлежит параболоиду, но не принадлежит прямой } // TODO 4: если любопытно и хватит времени - можете попросить ceres-solver посчитать якобианы в некоторых точках подобно тому как это делалось в конце теста HelloWorld1 @@ -258,9 +263,9 @@ class PointObservationError { template bool operator()(const T* const line, T* residual) const { // Блок параметров - line=[a, b, c] - задает прямую вида ax+by+c=0 - // TODO 5 посчитайте единственную невязку - расстояние от нашей точки-замера до текущего состояния прямой (для извлечения корня, помня про T=Jet, нужно использовать ceres::sqrt): + // 5 посчитайте единственную невязку - расстояние от нашей точки-замера до текущего состояния прямой (для извлечения корня, помня про T=Jet, нужно использовать ceres::sqrt): // обратите внимание что расстояние лучше оставить знаковым, т.к. тогда эта невязка будет хорошо дифференцироваться при расстоянии около нуля -// residual[0] = ; + residual[0] = (line[0] * samplePoint[0] + line[1] * samplePoint[1] + line[2]) / ceres::sqrt(line[0] * line[0] + line[1] * line[1]); return true; } protected: @@ -348,7 +353,6 @@ void evaluateLineFitting(double sigma, double &fitted_inliers_fraction, double & 1, // количество невязок (размер искомого residual массива переданного в функтор, т.е. размерность искомой невязки, у нас это просто расстояние до прямой) 3> // число параметров в каждом блоке параметров, у нас один блок параметров (искомая прямая) из трех ее параметров - a, b, c (new PointObservationError(points[i])); - return; // TODO 6 удалите этот return сразу после выполнения TODO 5 ceres::LossFunction* loss; if (use_huber) { @@ -372,29 +376,45 @@ void evaluateLineFitting(double sigma, double &fitted_inliers_fraction, double & double threshold = 1e-4 * std::max(std::abs(ideal_line[0]), std::max(std::abs(ideal_line[1]), std::abs(ideal_line[2]))); if (outliers_fraction > 0.0 && !use_huber) { - threshold *= 10.0; // ослабляем порог если есть выбросы и мы к ним не устойчивы (не робастны за счет loss-функции (функции потерь) Huber-а) + threshold *= 100.0; // ослабляем порог если есть выбросы и мы к ним не устойчивы (не робастны за счет loss-функции (функции потерь) Huber-а) } + double scale = ideal_line[2] / line_params[2]; + double normed_line_params[3] = {line_params[0] * scale, line_params[1] * scale, line_params[2] * scale}; + std::cout << "Normed line: (a=" << normed_line_params[0] << ", b=" << normed_line_params[1] << ", c=" << normed_line_params[2] << ")" << std::endl; + for (int d = 0; d < 3; ++d) { -// ASSERT_NEAR(line_params[d], ideal_line[d], threshold); - // TODO 7 расскоментируйте сверку найденной прямой и эталонной + ASSERT_NEAR(normed_line_params[d], ideal_line[d], threshold); + // ASSERT_NEAR(line_params[d], ideal_line[d], threshold); // почему они расходятся? как это можно решить? придумайте хотя бы два способа: // - пост-обработкой - как-то поправив параметры прямой перед сверкой (при этом не меняя ее положение в пространстве) + // 7 поправьте тест так или иначе (хотя бы пост-процессингом) + + // по сути скейл зашит в отношении param_ideal / param_our, домножаем на это выражение все координаты => но приходится увеличивать трешолд. + // Далее у нас есть степень свободы в выборе коэффициента, на который будем нормировать + // Эмперически лучше всего подошел коэффициент c, что возможно объяснимо тем, что он обладает наибольшим модулем // - формулировкой задачи - можно сформулировать для ceres-solver задчау так чтобы избавиться от неоднозначности убрав степень свободы, т.е. описав прямую как-то иначе, как? - // TODO 7 поправьте тест так или иначе (хотя бы пост-процессингом) + // задание прямой двумя параметрами + // 1) cos(a) * x + sin(a) * y = b -- требует нормировки; + // 2) 0.5 * x + b * y + c = 0 -- не требует нормировки, но необходимо знать один из коэффициентов идеальной прямой. } // Оцениваем качество идеальной прямой double inliers_fraction, mse; evaluateLine(points, ideal_line, sigma, inliers_fraction, mse); -// ASSERT_GT(inliers_fraction, 0.99); // TODO 8 раскоментируйте, почему эта проверка падает? как поправить? -// ASSERT_LT(mse, 1.1 * sigma * sigma); // TODO 9 раскомментируйте, почему проверка падает? на каких тестах она падает, на каких проходит? попробуйте отладить рассчет mse_inliers_distance в evaluateLine - + std::cout << inliers_fraction << outliers_fraction << "\n"; + ASSERT_GT(inliers_fraction, 0.99 * (1. - outliers_fraction)); // 8 раскоментируйте, почему эта проверка падает? как поправить? + // 0.99 * max_possible_inliers_fraction = 0.99 * (1. - outliers_fraction) + ASSERT_LT(mse, 1.1 * sigma * sigma); // 9 раскомментируйте, почему проверка падает? на каких тестах она падает, на каких проходит? попробуйте отладить рассчет mse_inliers_distance в evaluateLine + // abs in evaluateLine + // Оцениваем качество найденной прямой evaluateLine(points, line_params, sigma, inliers_fraction, mse); if (outliers_fraction == 0 || use_huber) { - // TODO 10 раскоментируйте обе проверки, почему они падают? в каких тестах? поправьте (в т.ч. подобно тому как было с ослаблением порога выше) -// ASSERT_GT(inliers_fraction, 0.99); -// ASSERT_LT(mse, 1.1 * sigma * sigma); + // 10 раскоментируйте обе проверки, почему они падают? в каких тестах? поправьте (в т.ч. подобно тому как было с ослаблением порога выше) + ASSERT_GT(inliers_fraction, 0.99 * (1. - outliers_fraction)); + // 0.99 * max_possible_inliers_fraction = 0.99 * (1. - outliers_fraction) + ASSERT_LT(mse, 1.1 * sigma * sigma); + // abs in evaluateLine } } @@ -405,7 +425,7 @@ void evaluateLine(const std::vector &points, const double* line, mse_inliers_distance = 0.0; // mean square error for (size_t i = 0; i < n; ++i) { double dist = calcDistanceToLine2D(points[i][0], points[i][1], line); - if (dist <= 3 * sigma) { + if (std::abs(dist) <= 3 * sigma) { ++inliers; mse_inliers_distance += dist * dist; } diff --git a/tests/test_sfm_ba.cpp b/tests/test_sfm_ba.cpp index 0490c45e..0ec56d45 100644 --- a/tests/test_sfm_ba.cpp +++ b/tests/test_sfm_ba.cpp @@ -21,11 +21,12 @@ #include #include -// TODO включите Bundle Adjustment (но из любопытства посмотрите как ведет себя реконструкция без BA например для saharov32 без BA) -#define ENABLE_BA 0 +// включите Bundle Adjustment (но из любопытства посмотрите как ведет себя реконструкция без BA например для saharov32 без BA) +#define ENABLE_BA 1 -// TODO когда заработает при малом количестве фотографий - увеличьте это ограничение до 100 чтобы попробовать обработать все фотографии (если же успешно будут отрабаывать только N фотографий - отправьте PR выставив здесь это N) -#define NIMGS_LIMIT 10 // сколько фотографий обрабатывать (можно выставить меньше чтобы ускорить экспериментирование, или в случае если весь датасет не выравнивается) +// когда заработает при малом количестве фотографий - увеличьте это ограничение до 100 чтобы попробовать обработать все фотографии (если же успешно будут отрабаывать только N фотографий - отправьте PR выставив здесь это N) +// sakharov OK, herzjesu 22 -- works, 23-fails +#define NIMGS_LIMIT 100 // сколько фотографий обрабатывать (можно выставить меньше чтобы ускорить экспериментирование, или в случае если весь датасет не выравнивается) #define INTRINSICS_CALIBRATION_MIN_IMGS 5 // начиная со скольки камер начинать оптимизировать внутренние параметры камеры (фокальную длину и т.п.) - из соображений что "пока камер мало - наблюдений может быть недостаточно чтобы не сойтись к ложной внутренней модели камеры" #define ENABLE_INSTRINSICS_K1_K2 1 // TODO учитывать ли радиальную дисторсию - коэффициенты k1, k2 попробуйте с ним и и без saharov32, заметна ли разница? @@ -51,8 +52,10 @@ //#define DATASET_DIR "herzjesu25" //#define DATASET_DOWNSCALE 2 // для ускорения SIFT //#define DATASET_F (2761.5 / DATASET_DOWNSCALE) // see herzjesu25/K.txt -// TODO почему фокальная длина меняется от того что мы уменьшаем картинку? почему именно в такой пропорции? может надо домножать? или делить на downscale^2 ? - +// почему фокальная длина меняется от того что мы уменьшаем картинку? почему именно в такой пропорции? может надо домножать? или делить на downscale^2 ? +// x_p = x_r * f / z <=> x_r = x_p / f * z . +// При даунсемпле картинки в s раз x_p1 = x_p / s => x_r1 = x_p1 / f * z = x_p / s / f * z = x_p / (f1 * s) * z +// Так как x_r1 = x_r => f1 * s = f => f1 = f / s // но temple47 - не вышло, я не разобрался в чем с ним проблема, может быть слишком мало точек, может критерии фильтрации выкидышей для него слишком строги //#define DATASET_DIR "temple47" //#define DATASET_DOWNSCALE 1 @@ -382,30 +385,50 @@ class ReprojectionError { const T* camera_intrinsics, // внутренние калибровочные параметры камеры: [5] = {k1, k2, f, cx, cy} (одни и те же для всех кадров, т.к. снято на одну и ту же камеру) const T* point_global, // 3D точка: [3] = {x, y, z} T* residuals) const { // невязка: [2] = {dx, dy} - // TODO реализуйте функцию проекции, все нужно делать в типе T чтобы ceres-solver мог под него подставить как Jet (очень рекомендую посмотреть Jet.h - как класная статья из википедии!), так и double + // реализуйте функцию проекции, все нужно делать в типе T чтобы ceres-solver мог под него подставить как Jet (очень рекомендую посмотреть Jet.h - как класная статья из википедии!), так и double // translation[3] - сдвиг в локальную систему координат камеры + T pt_T[3] = { + point_global[0] - camera_extrinsics[0], + point_global[1] - camera_extrinsics[1], + point_global[2] - camera_extrinsics[2] + }; + T pt_R[3]; // rotation[3] - angle-axis rotation, поворачиваем точку point->p (чтобы перейти в локальную систему координат камеры) + ceres::AngleAxisRotatePoint(camera_extrinsics + 3, pt_T, pt_R); // подробнее см. https://en.wikipedia.org/wiki/Axis%E2%80%93angle_representation // (P.S. у камеры всмысле вращения три степени свободы) // Проецируем точку на фокальную плоскость матрицы (т.е. плоскость Z=фокальная длина) - + // вроде что бы проекция была в фокальной плоскости нужно в этом месте домножать на фокусное расстояние, но это требуется ниже + T pt_P[2] = { + pt_R[0] / pt_R[2], + pt_R[1] / pt_R[2] + }; #if ENABLE_INSTRINSICS_K1_K2 // k1, k2 - коэффициенты радиального искажения (radial distortion) + T r_squared = pt_P[0] * pt_P[0] + pt_P[1] * pt_P[1]; + T r_fourth = r_squared * r_squared; + T radial_coef = (1. + camera_intrinsics[0] * r_squared + camera_intrinsics[1] * r_fourth); + pt_P[0] *= radial_coef; + pt_P[1] *= radial_coef; #endif // Домножаем на f, тем самым переводя в пиксели - + pt_P[0] *= camera_intrinsics[2]; + pt_P[1] *= camera_intrinsics[2]; // Из координат когда точка (0, 0) - центр оптической оси // Переходим в координаты когда точка (0, 0) - левый верхний угол картинки // cx, cy - координаты центра оптической оси (обычно это центр картинки, но часто он чуть смещен) - + pt_P[0] += camera_intrinsics[3]; + pt_P[1] += camera_intrinsics[4]; // Теперь по спроецированным координатам не забудьте посчитать невязку репроекции + residuals[0] = pt_P[0] - observed_x; + residuals[1] = pt_P[1] - observed_y; return true; - // TODO сверьте эту функцию с вашей реализацией проекции в src/phg/core/calibration.cpp (они должны совпадать) + // сверьте эту функцию с вашей реализацией проекции в src/phg/core/calibration.cpp (они должны совпадать) } protected: double observed_x; @@ -435,8 +458,14 @@ void runBA(std::vector &tie_points, ASSERT_NEAR(calib.cy_, 0.0, 0.3 * calib.height()); // внутренние калибровочные параметры камеры: [5] = {k1, k2, f, cx, cy} - // TODO: преобразуйте calib в блок параметров камеры (ее внутренних характеристик) для оптимизации в BA - double camera_intrinsics[5]; + // : преобразуйте calib в блок параметров камеры (ее внутренних характеристик) для оптимизации в BA + double camera_intrinsics[5] = { + calib.k1_, + calib.k2_, + calib.f_, + calib.cx_ + calib.width() * 0.5, + calib.cy_ + calib.height() * 0.5 + }; std::cout << "Before BA "; printCamera(camera_intrinsics); @@ -575,8 +604,13 @@ void runBA(std::vector &tie_points, std::cout << "After BA "; printCamera(camera_intrinsics); - // TODO преобразуйте параметры камеры в обратную сторону, чтобы последующая резекция учла актуальное представление о пространстве: + // преобразуйте параметры камеры в обратную сторону, чтобы последующая резекция учла актуальное представление о пространстве: // calib.* = camera_intrinsics[*]; + calib.k1_ = camera_intrinsics[0]; + calib.k2_ = camera_intrinsics[1]; + calib.f_ = camera_intrinsics[2]; + calib.cx_ = camera_intrinsics[3] - 0.5 * calib.width(); + calib.cy_ = camera_intrinsics[4] - 0.5 * calib.height(); ASSERT_NEAR(calib.f_ , DATASET_F, 0.2 * DATASET_F); ASSERT_NEAR(calib.cx_, 0.0, 0.3 * calib.width()); @@ -649,8 +683,21 @@ void runBA(std::vector &tie_points, } if (ENABLE_OUTLIERS_FILTRATION_COLINEAR && ENABLE_BA) { - // TODO выполните проверку случая когда два луча почти параллельны, чтобы не было странных точек улетающих на бесконечность (например чтобы угол был хотя бы 2.5 градуса) - // should_be_disabled = true; + // выполните проверку случая когда два луча почти параллельны, чтобы не было странных точек улетающих на бесконечность (например чтобы угол был хотя бы 2.5 градуса) + double min_angle_degrees = 2.5; + double min_angle_rad = (min_angle_degrees * CV_PI / 180.0); + double max_cos = std::cos(min_angle_rad); + vector3d track_in_current_camera = cv::normalize(track_point - camera_origin); + + int second_camera_id = track.img_kpt_pairs[ci].second; + double* second_camera_extrinsics = cameras_extrinsics.data() + CAMERA_EXTRINSICS_NPARAMS * second_camera_id; + matrix3d second_R; vector3d second_camera_origin; + phg::decomposeUndistortedPMatrix(second_R, second_camera_origin, cameras[second_camera_id]); + vector3d track_in_second_camera = cv::normalize(track_point - second_camera_origin); + + if (std::abs(track_in_current_camera.ddot(track_in_second_camera)) > max_cos) { + should_be_disabled = true; + } } { From 746a4a5c61d2712ce60d6a2ce3da8cdbef3f9a7a Mon Sep 17 00:00:00 2001 From: alexander Date: Fri, 24 Apr 2026 20:14:48 +0300 Subject: [PATCH 18/31] gitignores --- .gitignore | 9 ++++++++- data/debug/test_matching/.gitignore | 4 ++++ data/debug/test_sfm_ba/.gitignore | 4 ++++ 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100755 data/debug/test_matching/.gitignore create mode 100644 data/debug/test_sfm_ba/.gitignore diff --git a/.gitignore b/.gitignore index 81ef2b99..4865a837 100755 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,12 @@ **/*_cl.h .idea -build +.DS_store +build* cmake-build* data/src/test_sfm/saharov/*.JPG +opencv-4.11.0 +.github/scripts/macos/4.11.0.zip +2.2.0.zip +ceres-solver-2.2.0 +eigen-3.4.0 +eigen-3.4.0.tar.gz \ No newline at end of file diff --git a/data/debug/test_matching/.gitignore b/data/debug/test_matching/.gitignore new file mode 100755 index 00000000..86d0cb27 --- /dev/null +++ b/data/debug/test_matching/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore \ No newline at end of file diff --git a/data/debug/test_sfm_ba/.gitignore b/data/debug/test_sfm_ba/.gitignore new file mode 100644 index 00000000..86d0cb27 --- /dev/null +++ b/data/debug/test_sfm_ba/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore \ No newline at end of file From 065906fdd5271aeb826fe2573058ae409dbe1a21 Mon Sep 17 00:00:00 2001 From: alexander Date: Mon, 27 Apr 2026 22:48:31 +0300 Subject: [PATCH 19/31] baseline --- src/phg/core/calibration.cpp | 18 ++++---- src/phg/mvs/depth_maps/pm_depth_maps.cpp | 52 ++++++++++++++++++------ 2 files changed, 48 insertions(+), 22 deletions(-) diff --git a/src/phg/core/calibration.cpp b/src/phg/core/calibration.cpp index 6ca9cb92..f070ca63 100644 --- a/src/phg/core/calibration.cpp +++ b/src/phg/core/calibration.cpp @@ -36,18 +36,16 @@ cv::Vec3d phg::Calibration::project(const cv::Vec3d &point) const double x = point[0] / point[2]; double y = point[1] / point[2]; -<<<<<<< HEAD double r2 = x * x + y * y; double r4 = r2 * r2; -======= - // 11: добавьте учет радиальных искажений (k1_, k2_) (после деления на Z, но до умножения на f) - double r_squared = x * x + y * y; - double r_fourth = r_squared * r_squared; - double radial_coef = 1. + k1_ * r_squared + k2_ * r_fourth; - - x *= radial_coef; - y *= radial_coef; ->>>>>>> task04 + // from task04 + // // 11: добавьте учет радиальных искажений (k1_, k2_) (после деления на Z, но до умножения на f) + // double r_squared = x * x + y * y; + // double r_fourth = r_squared * r_squared; + // double radial_coef = 1. + k1_ * r_squared + k2_ * r_fourth; + + // x *= radial_coef; + // y *= radial_coef; x = x * (1.0 + k1_ * r2 + k2_ * r4); y = y * (1.0 + k1_ * r2 + k2_ * r4); diff --git a/src/phg/mvs/depth_maps/pm_depth_maps.cpp b/src/phg/mvs/depth_maps/pm_depth_maps.cpp index 7021ddd0..1476696b 100644 --- a/src/phg/mvs/depth_maps/pm_depth_maps.cpp +++ b/src/phg/mvs/depth_maps/pm_depth_maps.cpp @@ -46,14 +46,15 @@ vector3d project(const vector3d& global_point, const phg::Calibration& calibrati return pixel_with_depth; } -// TODO 101 реализуйте unproject (вам поможет тест на идемпотентность project -> unproject в test_depth_maps_pm) +// TODODONE 101 реализуйте unproject (вам поможет тест на идемпотентность project -> unproject в test_depth_maps_pm) vector3d unproject(const vector3d& pixel, const phg::Calibration& calibration, const matrix34d& PtoWorld) { double depth = pixel[2]; // на самом деле это не глубина, это координата по оси +Z (вдоль которой смотрит камера в ее локальной системе координат) - vector3d local_point; // TODO 102 пустите луч pixel из calibration а затем возьмите ан нем точку у которой по оси +Z координата=depth + vector3d local_point = calibration.unproject({pixel[0], pixel[1]}) * depth; // TODODONE 102 пустите луч pixel из calibration а затем возьмите ан нем точку у которой по оси +Z координата=depth - vector3d global_point; // TODO 103 переведите точку из локальной системы в глобальную + vector4d local_point_ext = {local_point[0], local_point[1], local_point[2], 1.0}; + vector3d global_point = PtoWorld * local_point_ext; // TODODONE 103 переведите точку из локальной системы в глобальную return global_point; } @@ -79,7 +80,7 @@ void PMDepthMapsBuilder::buildDepthMap(unsigned int camera_key, cv::Mat& depth_m // в первую очередь нам надо заполнить случайными гипотезами, этим займется refinement refinement(); - + printf("First refinement done!\n"); for (iter = 1; iter <= NITERATIONS; ++iter) { propagation(); refinement(); @@ -112,13 +113,15 @@ void PMDepthMapsBuilder::refinement() n0 = normal_map.at(j, i); // 2) случайной пертурбации текущей гипотезы (мутация и уточнение того что уже смогли найти) - dp = r.nextf(d0 * 0.5f, d0 * 1.5); // TODO 104: сделайте так чтобы отклонение было тем меньше, чем номер итерации ближе к NITERATIONS, улучшило ли это результат? - np = cv::normalize(n0 + randomNormalObservedFromCamera(cameras_RtoWorld[ref_cam], r) * 0.5); // TODO 105: сделайте так чтобы отклонение было тем меньше, чем номер итерации ближе к NITERATIONS, улучшило ли это результат? + dp = r.nextf(d0 * 0.5f, d0 * 1.5); // TODODONE 104: сделайте так чтобы отклонение было тем меньше, чем номер итерации ближе к NITERATIONS, улучшило ли это результат? + np = cv::normalize(n0 + randomNormalObservedFromCamera(cameras_RtoWorld[ref_cam], r) * 0.5); // TODODONE 105: сделайте так чтобы отклонение было тем меньше, чем номер итерации ближе к NITERATIONS, улучшило ли это результат? dp = std::max(ref_depth_min, std::min(ref_depth_max, dp)); // 3) новой случайной гипотезы из фрустума поиска (новые идеи, вечный поиск во всем пространстве) - // TODO 106: создайте случайную гипотезу dr+nr, вам поможет: + // TODODONE 106: создайте случайную гипотезу dr+nr, вам поможет: + dr = r.nextf(ref_depth_min, ref_depth_max); + nr = cv::normalize(randomNormalObservedFromCamera(cameras_RtoWorld[ref_cam], r)); // - r.nextf(...) // - ref_depth_min, ref_depth_max // - randomNormalObservedFromCamera - поможет создать нормаль которая гарантированно смотрит на нас @@ -352,14 +355,17 @@ float PMDepthMapsBuilder::estimateCost(ptrdiff_t i, ptrdiff_t j, double d, const ptrdiff_t u = x; ptrdiff_t v = y; - // TODO 108: добавьте проверку "попали ли мы в камеру номер neighb_cam?" если не попали - возвращаем NO_COST + // TODODONE 108: добавьте проверку "попали ли мы в камеру номер neighb_cam?" если не попали - возвращаем NO_COST + if (u < 0 || u > calibration.width() || v < 0 || v > calibration.height()) { + return NO_COST; + } float intensity = cameras_imgs_grey[neighb_cam].at(v, u) / 255.0f; patch1.push_back(intensity); } } - // TODO 109: реализуйте ZNCC https://en.wikipedia.org/wiki/Cross-correlation#Zero-normalized_cross-correlation_(ZNCC) + // TODODONE 109: реализуйте ZNCC https://en.wikipedia.org/wiki/Cross-correlation#Zero-normalized_cross-correlation_(ZNCC) // или слайд #25 в лекции 5 про SGM и Cost-функции - https://my.compscicenter.ru/attachments/classes/slides_w2n8WNLY/photogrammetry_lecture_090321.pdf rassert(patch0.size() == patch1.size(), 12489185129326); size_t n = patch0.size(); @@ -376,7 +382,22 @@ float PMDepthMapsBuilder::estimateCost(ptrdiff_t i, ptrdiff_t j, double d, const mean0 /= n; mean1 /= n; // ... - float zncc = 0.0f; + + float nom = 0.0, denom1 = 0.0, denom2 = 0.0; + for (size_t k = 0; k < n; ++k) { + float a = patch0[k]; + float b = patch1[k]; + + nom += (a - mean0) * (b - mean1); + denom1 += (a - mean0) * (a - mean0); + denom2 += (b - mean1) * (b - mean1); + } + + + float zncc = 0; + if (std::abs(nom) > 0. && std::abs(denom1) > 0. && std::abs(denom2) > 0.) { + zncc = nom / std::sqrt(denom1 * denom2); + } // ZNCC в диапазоне [-1; 1], 1: идеальное совпадение, -1: ничего общего rassert(zncc == zncc, 23141241210380); // проверяем что не nan @@ -403,8 +424,15 @@ float PMDepthMapsBuilder::avgCost(std::vector& costs) float cost_sum = best_cost; float cost_w = 1.0f; - // TODO 110 реализуйте какое-то "усреднение cost-ов по всем соседям", с ограничением что участвуют только COSTS_BEST_K_LIMIT лучших - // TODO 111 добавьте к этому усреднению еще одно ограничение: если cost больше чем best_cost*COSTS_K_RATIO - то такой cost подозрительно плохой и мы его не хотим учитывать (вероятно occlusion) + // TODODONE 110 реализуйте какое-то "усреднение cost-ов по всем соседям", с ограничением что участвуют только COSTS_BEST_K_LIMIT лучших + for (size_t i = 1; i < COSTS_BEST_K_LIMIT; i++) { + // TODODONE 111 добавьте к этому усреднению еще одно ограничение: если cost больше чем best_cost*COSTS_K_RATIO - то такой cost подозрительно плохой и мы его не хотим учитывать (вероятно occlusion) + if (costs[i] > best_cost * COSTS_K_RATIO) { + break; + } + cost_sum += costs[i]; + cost_w += 1; + } // TODO 112 а что если в пикселе occlusion, но best_cost - большой и поэтому отсечение по best_cost*COSTS_K_RATIO не срабатывает? можно ли это отсечение как-то выправить для такого случая? // TODO 207 а что если добавить какой-нибудь бонус в случае если больше чем Х камер засчиталось? улучшается/ухудшается ли от этого что-то на herzjezu25? а при большем числе фотографий From c0d33d202fef0c8175a9e9b04efdeca46c8f17d1 Mon Sep 17 00:00:00 2001 From: alexander Date: Mon, 27 Apr 2026 23:30:57 +0300 Subject: [PATCH 20/31] fixed calibration --- src/phg/core/calibration.cpp | 41 ++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/src/phg/core/calibration.cpp b/src/phg/core/calibration.cpp index f070ca63..37fdf73c 100644 --- a/src/phg/core/calibration.cpp +++ b/src/phg/core/calibration.cpp @@ -68,30 +68,31 @@ cv::Vec3d phg::Calibration::unproject(const cv::Vec2d &pixel) const x /= f_; y /= f_; - double r2 = x * x + y * y; - double r4 = r2 * r2; + // from task05 -- probably wrong + // double r2 = x * x + y * y; + // double r4 = r2 * r2; - x = x / (1.0 + k1_ * r2 + k2_ * r4); - y = y / (1.0 + k1_ * r2 + k2_ * r4); + // x = x / (1.0 + k1_ * r2 + k2_ * r4); + // y = y / (1.0 + k1_ * r2 + k2_ * r4); - return cv::Vec3d(x, y, 1.0); + // return cv::Vec3d(x, y, 1.0); // from task04 - // // 12: добавьте учет радиальных искажений, когда реализуете - подумайте: почему строго говоря это - не симметричная формула формуле из project? (но лишь приближение) - // // потому что мы имеем дело с функцией 4 степени относительно x и y. - // double x_u = x, y_u = y; - // // while (1) { - // for (size_t i = 0; i < 1000; i++) { - // double r_squared = x_u * x_u + y_u * y_u; - // double r_fourth = r_squared * r_squared; - // double dr = 1 + k1_ * r_squared + k2_ * r_fourth; - // x_u = x / dr; - // y_u = y / dr; + // 12: добавьте учет радиальных искажений, когда реализуете - подумайте: почему строго говоря это - не симметричная формула формуле из project? (но лишь приближение) + // потому что мы имеем дело с функцией 4 степени относительно x и y. + double x_u = x, y_u = y; + // while (1) { + for (size_t i = 0; i < 1000; i++) { + double r_squared = x_u * x_u + y_u * y_u; + double r_fourth = r_squared * r_squared; + double dr = 1 + k1_ * r_squared + k2_ * r_fourth; + x_u = x / dr; + y_u = y / dr; - // if (std::abs(dr * x_u - x) + std::abs(dr * y_u - y) < 1e-10) { - // break; - // } - // } + if (std::abs(dr * x_u - x) + std::abs(dr * y_u - y) < 1e-10) { + break; + } + } - // return cv::Vec3d(x_u, y_u, 1.0); + return cv::Vec3d(x_u, y_u, 1.0); } From b14af3bf3ea3801bad222e21ae78f9f11a6e2e51 Mon Sep 17 00:00:00 2001 From: alexander Date: Tue, 28 Apr 2026 12:25:12 +0300 Subject: [PATCH 21/31] fixed costAvg --- src/phg/mvs/depth_maps/pm_depth_maps.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/phg/mvs/depth_maps/pm_depth_maps.cpp b/src/phg/mvs/depth_maps/pm_depth_maps.cpp index 1476696b..723cd09b 100644 --- a/src/phg/mvs/depth_maps/pm_depth_maps.cpp +++ b/src/phg/mvs/depth_maps/pm_depth_maps.cpp @@ -425,7 +425,7 @@ float PMDepthMapsBuilder::avgCost(std::vector& costs) float cost_w = 1.0f; // TODODONE 110 реализуйте какое-то "усреднение cost-ов по всем соседям", с ограничением что участвуют только COSTS_BEST_K_LIMIT лучших - for (size_t i = 1; i < COSTS_BEST_K_LIMIT; i++) { + for (size_t i = 1; i < COSTS_BEST_K_LIMIT && i < costs.size(); i++) { // TODODONE 111 добавьте к этому усреднению еще одно ограничение: если cost больше чем best_cost*COSTS_K_RATIO - то такой cost подозрительно плохой и мы его не хотим учитывать (вероятно occlusion) if (costs[i] > best_cost * COSTS_K_RATIO) { break; From 38dd832b2b85c62be8fe7b38fadbb9c1db8eb9d6 Mon Sep 17 00:00:00 2001 From: alexander Date: Tue, 28 Apr 2026 21:13:18 +0300 Subject: [PATCH 22/31] ACMH --- src/phg/mvs/depth_maps/pm_depth_maps.cpp | 164 +++++++++++++++++++---- 1 file changed, 139 insertions(+), 25 deletions(-) diff --git a/src/phg/mvs/depth_maps/pm_depth_maps.cpp b/src/phg/mvs/depth_maps/pm_depth_maps.cpp index 723cd09b..c624b268 100644 --- a/src/phg/mvs/depth_maps/pm_depth_maps.cpp +++ b/src/phg/mvs/depth_maps/pm_depth_maps.cpp @@ -113,8 +113,8 @@ void PMDepthMapsBuilder::refinement() n0 = normal_map.at(j, i); // 2) случайной пертурбации текущей гипотезы (мутация и уточнение того что уже смогли найти) - dp = r.nextf(d0 * 0.5f, d0 * 1.5); // TODODONE 104: сделайте так чтобы отклонение было тем меньше, чем номер итерации ближе к NITERATIONS, улучшило ли это результат? - np = cv::normalize(n0 + randomNormalObservedFromCamera(cameras_RtoWorld[ref_cam], r) * 0.5); // TODODONE 105: сделайте так чтобы отклонение было тем меньше, чем номер итерации ближе к NITERATIONS, улучшило ли это результат? + dp = r.nextf(d0 * (0.5f + 0.5f * iter / (NITERATIONS + 1.f)), d0 * (1.5f - 0.5f * iter / (NITERATIONS + 1.f))); // TODODONE 104: сделайте так чтобы отклонение было тем меньше, чем номер итерации ближе к NITERATIONS, улучшило ли это результат? + np = cv::normalize(n0 + randomNormalObservedFromCamera(cameras_RtoWorld[ref_cam], r) * 0.5 * (1.f - iter / (NITERATIONS + 1.f))); // TODODONE 105: сделайте так чтобы отклонение было тем меньше, чем номер итерации ближе к NITERATIONS, улучшило ли это результат? dp = std::max(ref_depth_min, std::min(ref_depth_max, dp)); @@ -205,6 +205,69 @@ void PMDepthMapsBuilder::tryToPropagateDonor(ptrdiff_t ni, ptrdiff_t nj, int che hypos_cost.push_back(cost); } + +void PMDepthMapsBuilder::tryToPropagateDonor3dots(ptrdiff_t ni0, ptrdiff_t nj0, + ptrdiff_t ni1, ptrdiff_t nj1, + ptrdiff_t ni2, ptrdiff_t nj2, + int chessboard_pattern_step, std::vector& hypos_depth, std::vector& hypos_normal, std::vector& hypos_cost) +{ + // rassert-ы или любой другой способ явной фиксации инвариантов со встроенной их проверкой в runtime - + // это очень приятный способ ускорить отладку и гарантировать что ожидания в голове сойдутся с реальностью в коде, + // а если разойдутся - то узнать об этом в самом первом сломавшемся предположении + // (в данном случае мы явно проверяем что нигде не промахнулись и все соседи - другого шахматного цвета) + // пусть лучше эта проверка упадет, мы сразу это заметим и отладим, чем бага будет тихо портить результаты + // а мы это может быть даже не заметим + // rassert((ni0 + nj0) % 2 != chessboard_pattern_step, 2391249129510120); + // rassert((ni1 + nj1) % 2 != chessboard_pattern_step, 2391249129510121); + // rassert((ni2 + nj2) % 2 != chessboard_pattern_step, 2391249129510122); + + std::vector depths; + std::vector costs; + std::vector> costs_indexed; + std::vector ns; + size_t cur_idx = 0; + if (!(ni0 < 0 || ni0 >= width || nj0 < 0 || nj0 >= height)) { + depths.push_back(depth_map.at(nj0, ni0)); + costs.push_back(cost_map.at(nj0, ni0)); + costs_indexed.push_back(std::make_pair(cost_map.at(nj0, ni0), cur_idx)); + ns.push_back(normal_map.at(nj0, ni0)); + cur_idx++; + } + + if (!(ni1 < 0 || ni1 >= width || nj1 < 0 || nj1 >= height)) { + depths.push_back(depth_map.at(nj1, ni1)); + costs.push_back(cost_map.at(nj1, ni1)); + costs_indexed.push_back(std::make_pair(cost_map.at(nj1, ni1), cur_idx)); + ns.push_back(normal_map.at(nj1, ni1)); + cur_idx++; + } + + + if (!(ni2 < 0 || ni2 >= width || nj2 < 0 || nj2 >= height)) { + depths.push_back(depth_map.at(nj2, ni2)); + costs.push_back(cost_map.at(nj2, ni2)); + costs_indexed.push_back(std::make_pair(cost_map.at(nj2, ni2), cur_idx)); + ns.push_back(normal_map.at(nj2, ni2)); + cur_idx++; + } + + std::sort(costs_indexed.begin(), costs_indexed.end()); + + if (costs_indexed.size() == 0) { + return; + } + size_t best_idx = costs_indexed[0].second; + if (depths[best_idx] == NO_DEPTH) { + return; + } + + hypos_depth.push_back(depths[best_idx]); + hypos_normal.push_back(ns[best_idx]); + hypos_cost.push_back(costs[best_idx]); + +} + + void PMDepthMapsBuilder::propagation() { timer t; @@ -235,29 +298,80 @@ void PMDepthMapsBuilder::propagation() * o o o o o o o o o o o * o o o o o C o o o o o */ - tryToPropagateDonor(i - 1, j + 0, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); - tryToPropagateDonor(i + 0, j - 1, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); - tryToPropagateDonor(i + 1, j + 0, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); - tryToPropagateDonor(i + 0, j + 1, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); - - tryToPropagateDonor(i - 2, j - 1, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); - tryToPropagateDonor(i - 1, j - 2, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); - tryToPropagateDonor(i + 1, j - 2, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); - tryToPropagateDonor(i + 2, j - 1, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); - tryToPropagateDonor(i + 2, j + 1, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); - tryToPropagateDonor(i + 1, j + 2, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); - tryToPropagateDonor(i - 1, j + 2, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); - tryToPropagateDonor(i - 2, j + 1, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); - - // в таких случаях очень приятно использовать множественный курсор (чтобы скопировав четыре строки выше, затем просто колесиком мышки сделать четыре каретки для того чтобы дважды вставить *PROPAGATION_STEP): - tryToPropagateDonor(i - 1 * PROPAGATION_STEP, j + 0 * PROPAGATION_STEP, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); - tryToPropagateDonor(i + 0 * PROPAGATION_STEP, j - 1 * PROPAGATION_STEP, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); - tryToPropagateDonor(i + 1 * PROPAGATION_STEP, j + 0 * PROPAGATION_STEP, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); - tryToPropagateDonor(i + 0 * PROPAGATION_STEP, j + 1 * PROPAGATION_STEP, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); - - // TODO 201 переделайте чтобы было как в ACMH: - // TODO 202 - паттерн донорства - // TODO 203 - логика про "берем 8 лучших по их личной оценке - по их личному cost" и только их примеряем уже на себя для рассчета cost в нашей точке + // tryToPropagateDonor(i - 1, j + 0, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); + // tryToPropagateDonor(i + 0, j - 1, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); + // tryToPropagateDonor(i + 1, j + 0, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); + // tryToPropagateDonor(i + 0, j + 1, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); + + // tryToPropagateDonor(i - 2, j - 1, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); + // tryToPropagateDonor(i - 1, j - 2, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); + // tryToPropagateDonor(i + 1, j - 2, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); + // tryToPropagateDonor(i + 2, j - 1, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); + // tryToPropagateDonor(i + 2, j + 1, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); + // tryToPropagateDonor(i + 1, j + 2, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); + // tryToPropagateDonor(i - 1, j + 2, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); + // tryToPropagateDonor(i - 2, j + 1, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); + + // // в таких случаях очень приятно использовать множественный курсор (чтобы скопировав четыре строки выше, затем просто колесиком мышки сделать четыре каретки для того чтобы дважды вставить *PROPAGATION_STEP): + // tryToPropagateDonor(i - 1 * PROPAGATION_STEP, j + 0 * PROPAGATION_STEP, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); + // tryToPropagateDonor(i + 0 * PROPAGATION_STEP, j - 1 * PROPAGATION_STEP, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); + // tryToPropagateDonor(i + 1 * PROPAGATION_STEP, j + 0 * PROPAGATION_STEP, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); + // tryToPropagateDonor(i + 0 * PROPAGATION_STEP, j + 1 * PROPAGATION_STEP, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); + + // TODODONE 201 переделайте чтобы было как в ACMH: + // TODODONE 202 - паттерн донорства + tryToPropagateDonor3dots( + i + 1, j + 0, + i + 2, j + 1, + i + 2, j - 1, + chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost + ); + tryToPropagateDonor3dots( + i - 1, j + 0, + i - 2, j + 1, + i - 2, j - 1, + chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost + ); + tryToPropagateDonor3dots( + i + 0, j + 1, + i + 1, j + 2, + i - 1, j + 2, + chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost + ); + tryToPropagateDonor3dots( + i + 0, j - 1, + i + 1, j - 2, + i - 1, j - 2, + chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost + ); + + + + tryToPropagateDonor3dots( + i - 1 * PROPAGATION_STEP, j + 0 * PROPAGATION_STEP, + i - 1 * (PROPAGATION_STEP - 1), j + 0 * (PROPAGATION_STEP - 1), + i - 1 * (PROPAGATION_STEP - 2), j + 0 * (PROPAGATION_STEP - 2), + chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); + tryToPropagateDonor3dots( + i + 0 * PROPAGATION_STEP, j - 1 * PROPAGATION_STEP, + i + 0 * (PROPAGATION_STEP - 1), j - 1 * (PROPAGATION_STEP - 1), + i + 0 * (PROPAGATION_STEP - 2), j - 1 * (PROPAGATION_STEP - 2), + chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); + tryToPropagateDonor3dots( + i + 1 * PROPAGATION_STEP, j + 0 * PROPAGATION_STEP, + i + 1 * (PROPAGATION_STEP - 1), j + 0 * (PROPAGATION_STEP - 1), + i + 1 * (PROPAGATION_STEP - 2), j + 0 * (PROPAGATION_STEP - 2), + chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); + tryToPropagateDonor3dots( + i + 0 * PROPAGATION_STEP, j + 1 * PROPAGATION_STEP, + i + 0 * (PROPAGATION_STEP - 1), j + 1 * (PROPAGATION_STEP - 1), + i + 0 * (PROPAGATION_STEP - 2), j + 1 * (PROPAGATION_STEP - 2), + chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); + + + + // TODODONE 203 - логика про "берем 8 лучших по их личной оценке - по их личному cost" и только их примеряем уже на себя для рассчета cost в нашей точке + // вроде же и так делаем именно такой подход // TODO 301 - сделайте вместо наивного переноса depth+normal в наш пиксель - логику про "пересекли луч из нашего пикселя с плоскостью которую задает донор-сосед" и оценку cost в нашей точке тогда можно провести для более // релевантной точки-пересечения From c3cef19bd89a2013ed853599eae303820e6aa114 Mon Sep 17 00:00:00 2001 From: alexander Date: Fri, 1 May 2026 16:03:40 +0300 Subject: [PATCH 23/31] refactored propagation + implemented bilinear interpolation in estimateCost --- src/phg/mvs/depth_maps/pm_depth_maps.cpp | 218 ++++++++++-------- .../mvs/depth_maps/pm_depth_maps_defines.h | 2 + 2 files changed, 125 insertions(+), 95 deletions(-) diff --git a/src/phg/mvs/depth_maps/pm_depth_maps.cpp b/src/phg/mvs/depth_maps/pm_depth_maps.cpp index c624b268..1c9c1547 100644 --- a/src/phg/mvs/depth_maps/pm_depth_maps.cpp +++ b/src/phg/mvs/depth_maps/pm_depth_maps.cpp @@ -281,97 +281,101 @@ void PMDepthMapsBuilder::propagation() std::vector hypos_normal; std::vector hypos_cost; - /* 4 прямых соседа A, 8 соседей B через диагональ, 4 соседа C вдалеке (условный рисунок для PROPAGATION_STEP=5): - * (удобно подсвечивать через Ctrl+F) - * center - * | - * v - * o o o o o C o o o o o - * o o o o o o o o o o o - * o o o o o o o v o o o - * o o o o B o B o v o o - * o o o B o A o B o o o - * C o o o A . A o o o C <- center - * o o o B o A o B o o o - * o o o o B o B o v o o - * o o o o o o o v o o o - * o o o o o o o o o o o - * o o o o o C o o o o o - */ - // tryToPropagateDonor(i - 1, j + 0, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); - // tryToPropagateDonor(i + 0, j - 1, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); - // tryToPropagateDonor(i + 1, j + 0, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); - // tryToPropagateDonor(i + 0, j + 1, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); - - // tryToPropagateDonor(i - 2, j - 1, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); - // tryToPropagateDonor(i - 1, j - 2, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); - // tryToPropagateDonor(i + 1, j - 2, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); - // tryToPropagateDonor(i + 2, j - 1, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); - // tryToPropagateDonor(i + 2, j + 1, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); - // tryToPropagateDonor(i + 1, j + 2, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); - // tryToPropagateDonor(i - 1, j + 2, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); - // tryToPropagateDonor(i - 2, j + 1, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); - - // // в таких случаях очень приятно использовать множественный курсор (чтобы скопировав четыре строки выше, затем просто колесиком мышки сделать четыре каретки для того чтобы дважды вставить *PROPAGATION_STEP): - // tryToPropagateDonor(i - 1 * PROPAGATION_STEP, j + 0 * PROPAGATION_STEP, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); - // tryToPropagateDonor(i + 0 * PROPAGATION_STEP, j - 1 * PROPAGATION_STEP, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); - // tryToPropagateDonor(i + 1 * PROPAGATION_STEP, j + 0 * PROPAGATION_STEP, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); - // tryToPropagateDonor(i + 0 * PROPAGATION_STEP, j + 1 * PROPAGATION_STEP, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); - - // TODODONE 201 переделайте чтобы было как в ACMH: - // TODODONE 202 - паттерн донорства - tryToPropagateDonor3dots( - i + 1, j + 0, - i + 2, j + 1, - i + 2, j - 1, - chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost - ); - tryToPropagateDonor3dots( - i - 1, j + 0, - i - 2, j + 1, - i - 2, j - 1, - chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost - ); - tryToPropagateDonor3dots( - i + 0, j + 1, - i + 1, j + 2, - i - 1, j + 2, - chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost - ); - tryToPropagateDonor3dots( - i + 0, j - 1, - i + 1, j - 2, - i - 1, j - 2, - chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost - ); + if (USE_ACMH_POPAGATION_SCHEME) { + // TODODONE 201 переделайте чтобы было как в ACMH: + // TODODONE 202 - паттерн донорства + tryToPropagateDonor3dots( + i + 1, j + 0, + i + 2, j + 1, + i + 2, j - 1, + chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost + ); + tryToPropagateDonor3dots( + i - 1, j + 0, + i - 2, j + 1, + i - 2, j - 1, + chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost + ); + tryToPropagateDonor3dots( + i + 0, j + 1, + i + 1, j + 2, + i - 1, j + 2, + chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost + ); + tryToPropagateDonor3dots( + i + 0, j - 1, + i + 1, j - 2, + i - 1, j - 2, + chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost + ); + + + + tryToPropagateDonor3dots( + i - 1 * PROPAGATION_STEP, j + 0 * PROPAGATION_STEP, + i - 1 * (PROPAGATION_STEP - 1), j + 0 * (PROPAGATION_STEP - 1), + i - 1 * (PROPAGATION_STEP - 2), j + 0 * (PROPAGATION_STEP - 2), + chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost + ); + tryToPropagateDonor3dots( + i + 0 * PROPAGATION_STEP, j - 1 * PROPAGATION_STEP, + i + 0 * (PROPAGATION_STEP - 1), j - 1 * (PROPAGATION_STEP - 1), + i + 0 * (PROPAGATION_STEP - 2), j - 1 * (PROPAGATION_STEP - 2), + chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost + ); + tryToPropagateDonor3dots( + i + 1 * PROPAGATION_STEP, j + 0 * PROPAGATION_STEP, + i + 1 * (PROPAGATION_STEP - 1), j + 0 * (PROPAGATION_STEP - 1), + i + 1 * (PROPAGATION_STEP - 2), j + 0 * (PROPAGATION_STEP - 2), + chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost + ); + tryToPropagateDonor3dots( + i + 0 * PROPAGATION_STEP, j + 1 * PROPAGATION_STEP, + i + 0 * (PROPAGATION_STEP - 1), j + 1 * (PROPAGATION_STEP - 1), + i + 0 * (PROPAGATION_STEP - 2), j + 1 * (PROPAGATION_STEP - 2), + chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost + ); + } else { + /* 4 прямых соседа A, 8 соседей B через диагональ, 4 соседа C вдалеке (условный рисунок для PROPAGATION_STEP=5): + * (удобно подсвечивать через Ctrl+F) + * center + * | + * v + * o o o o o C o o o o o + * o o o o o o o o o o o + * o o o o o o o v o o o + * o o o o B o B o v o o + * o o o B o A o B o o o + * C o o o A . A o o o C <- center + * o o o B o A o B o o o + * o o o o B o B o v o o + * o o o o o o o v o o o + * o o o o o o o o o o o + * o o o o o C o o o o o + */ + tryToPropagateDonor(i - 1, j + 0, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); + tryToPropagateDonor(i + 0, j - 1, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); + tryToPropagateDonor(i + 1, j + 0, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); + tryToPropagateDonor(i + 0, j + 1, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); + + tryToPropagateDonor(i - 2, j - 1, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); + tryToPropagateDonor(i - 1, j - 2, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); + tryToPropagateDonor(i + 1, j - 2, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); + tryToPropagateDonor(i + 2, j - 1, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); + tryToPropagateDonor(i + 2, j + 1, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); + tryToPropagateDonor(i + 1, j + 2, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); + tryToPropagateDonor(i - 1, j + 2, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); + tryToPropagateDonor(i - 2, j + 1, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); + + // в таких случаях очень приятно использовать множественный курсор (чтобы скопировав четыре строки выше, затем просто колесиком мышки сделать четыре каретки для того чтобы дважды вставить *PROPAGATION_STEP): + tryToPropagateDonor(i - 1 * PROPAGATION_STEP, j + 0 * PROPAGATION_STEP, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); + tryToPropagateDonor(i + 0 * PROPAGATION_STEP, j - 1 * PROPAGATION_STEP, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); + tryToPropagateDonor(i + 1 * PROPAGATION_STEP, j + 0 * PROPAGATION_STEP, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); + tryToPropagateDonor(i + 0 * PROPAGATION_STEP, j + 1 * PROPAGATION_STEP, chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); + } - tryToPropagateDonor3dots( - i - 1 * PROPAGATION_STEP, j + 0 * PROPAGATION_STEP, - i - 1 * (PROPAGATION_STEP - 1), j + 0 * (PROPAGATION_STEP - 1), - i - 1 * (PROPAGATION_STEP - 2), j + 0 * (PROPAGATION_STEP - 2), - chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); - tryToPropagateDonor3dots( - i + 0 * PROPAGATION_STEP, j - 1 * PROPAGATION_STEP, - i + 0 * (PROPAGATION_STEP - 1), j - 1 * (PROPAGATION_STEP - 1), - i + 0 * (PROPAGATION_STEP - 2), j - 1 * (PROPAGATION_STEP - 2), - chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); - tryToPropagateDonor3dots( - i + 1 * PROPAGATION_STEP, j + 0 * PROPAGATION_STEP, - i + 1 * (PROPAGATION_STEP - 1), j + 0 * (PROPAGATION_STEP - 1), - i + 1 * (PROPAGATION_STEP - 2), j + 0 * (PROPAGATION_STEP - 2), - chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); - tryToPropagateDonor3dots( - i + 0 * PROPAGATION_STEP, j + 1 * PROPAGATION_STEP, - i + 0 * (PROPAGATION_STEP - 1), j + 1 * (PROPAGATION_STEP - 1), - i + 0 * (PROPAGATION_STEP - 2), j + 1 * (PROPAGATION_STEP - 2), - chessboard_pattern_step, hypos_depth, hypos_normal, hypos_cost); - - - - // TODODONE 203 - логика про "берем 8 лучших по их личной оценке - по их личному cost" и только их примеряем уже на себя для рассчета cost в нашей точке - // вроде же и так делаем именно такой подход // TODO 301 - сделайте вместо наивного переноса depth+normal в наш пиксель - логику про "пересекли луч из нашего пикселя с плоскостью которую задает донор-сосед" и оценку cost в нашей точке тогда можно провести для более // релевантной точки-пересечения @@ -465,17 +469,41 @@ float PMDepthMapsBuilder::estimateCost(ptrdiff_t i, ptrdiff_t j, double d, const double x = neighb_proj[0]; double y = neighb_proj[1]; - // TODO 205: замените этот наивный вариант nearest neighbor сэмплирования текстуры на билинейную интерполяцию (учтите что центр пикселя - .5 после запятой) - ptrdiff_t u = x; - ptrdiff_t v = y; - // TODODONE 108: добавьте проверку "попали ли мы в камеру номер neighb_cam?" если не попали - возвращаем NO_COST - if (u < 0 || u > calibration.width() || v < 0 || v > calibration.height()) { + if (x < 0 || x > calibration.width() || y < 0 || y > calibration.height()) { // не height - 1 и width - 1, тк пиксели в данной нотации имеют ширину return NO_COST; } - float intensity = cameras_imgs_grey[neighb_cam].at(v, u) / 255.0f; - patch1.push_back(intensity); + // TODODONE 205: замените этот наивный вариант nearest neighbor сэмплирования текстуры на билинейную интерполяцию (учтите что центр пикселя - .5 после запятой) + // тк центры в (p.x + 0.5, p.y + 0.5) + if (USE_BILINEAR_INTERPOLATION) { + x -= 0.5; // смещаем для того чтобы проще округлять к центрам пикселей + y -= 0.5; + + ptrdiff_t u0 = std::floor(x) < 0 ? std::floor(x) + 1 : std::floor(x); + ptrdiff_t v0 = std::floor(y) < 0 ? std::floor(y) + 1 : std::floor(y); + ptrdiff_t ud = u0 < (width - 1) ? 1 : 0; + ptrdiff_t vd = v0 < (height - 1) ? 1 : 0; + float du_lambda0 = 1.f - (x - u0); + float dv_lambda0 = 1.f - (y - v0); + float du_lambda1 = 1. - du_lambda0; + float dv_lambda1 = 1. - dv_lambda0; + + float intensity = dv_lambda0 * ( + du_lambda0 * cameras_imgs_grey[neighb_cam].at(v0, u0) + + du_lambda1 * cameras_imgs_grey[neighb_cam].at(v0, u0 + ud) + ) + dv_lambda1 * ( + du_lambda0 * cameras_imgs_grey[neighb_cam].at(v0 + vd, u0) + + du_lambda1 * cameras_imgs_grey[neighb_cam].at(v0 + vd, u0 + ud) + ); + intensity /= 255.; + patch1.push_back(intensity); + } else { + ptrdiff_t u = x; + ptrdiff_t v = y; + float intensity = cameras_imgs_grey[neighb_cam].at(v, u) / 255.0f; + patch1.push_back(intensity); + } } } diff --git a/src/phg/mvs/depth_maps/pm_depth_maps_defines.h b/src/phg/mvs/depth_maps/pm_depth_maps_defines.h index 87f62399..f5fda40a 100644 --- a/src/phg/mvs/depth_maps/pm_depth_maps_defines.h +++ b/src/phg/mvs/depth_maps/pm_depth_maps_defines.h @@ -4,6 +4,8 @@ #define NO_DEPTH 0.0f #define NO_COST 1.0f #define GOOD_COST 0.2f +#define USE_BILINEAR_INTERPOLATION 1 +#define USE_ACMH_POPAGATION_SCHEME 1 #define NITERATIONS 5 From 8a106b4cf109bea37efd95a13f39b34bb4f4fdec Mon Sep 17 00:00:00 2001 From: alexander Date: Sat, 2 May 2026 10:13:39 +0300 Subject: [PATCH 24/31] uncertanty + big cost filtering --- src/phg/mvs/depth_maps/pm_depth_maps.cpp | 34 +++++++++++++++++-- .../mvs/depth_maps/pm_depth_maps_defines.h | 2 ++ 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/phg/mvs/depth_maps/pm_depth_maps.cpp b/src/phg/mvs/depth_maps/pm_depth_maps.cpp index 1c9c1547..1c476b21 100644 --- a/src/phg/mvs/depth_maps/pm_depth_maps.cpp +++ b/src/phg/mvs/depth_maps/pm_depth_maps.cpp @@ -537,8 +537,20 @@ float PMDepthMapsBuilder::estimateCost(ptrdiff_t i, ptrdiff_t j, double d, const float zncc = 0; - if (std::abs(nom) > 0. && std::abs(denom1) > 0. && std::abs(denom2) > 0.) { - zncc = nom / std::sqrt(denom1 * denom2); + if (USE_ADVANCED_UNCERTANTY) { + float denom = std::sqrt(denom1 * denom2); + if (denom < 1e-9) { // в scipy.stats.pearsonr в случае если одна из выборок близка к среднему выдают ворнинги + if (std::abs(nom) < 1e-6) { + return 0.f; + } else { + return NO_COST; + } + } + zncc = nom / denom; + } else { + if (std::abs(nom) > 0. && std::abs(denom1) > 0. && std::abs(denom2) > 0.) { + zncc = nom / std::sqrt(denom1 * denom2); + } } // ZNCC в диапазоне [-1; 1], 1: идеальное совпадение, -1: ничего общего @@ -565,6 +577,13 @@ float PMDepthMapsBuilder::avgCost(std::vector& costs) float cost_sum = best_cost; float cost_w = 1.0f; + if (USE_BIG_COST_FILTERING) { + // TODODONE 112 а что если в пикселе occlusion, но best_cost - большой и поэтому отсечение по best_cost*COSTS_K_RATIO не срабатывает? можно ли это отсечение как-то выправить для такого случая? + // не дает улучшений + if (best_cost > GOOD_COST) { + return NO_COST; + } + } // TODODONE 110 реализуйте какое-то "усреднение cost-ов по всем соседям", с ограничением что участвуют только COSTS_BEST_K_LIMIT лучших for (size_t i = 1; i < COSTS_BEST_K_LIMIT && i < costs.size(); i++) { @@ -572,10 +591,19 @@ float PMDepthMapsBuilder::avgCost(std::vector& costs) if (costs[i] > best_cost * COSTS_K_RATIO) { break; } + if (USE_BIG_COST_FILTERING) { + // TODODONE 112 а что если в пикселе occlusion, но best_cost - большой и поэтому отсечение по best_cost*COSTS_K_RATIO не срабатывает? можно ли это отсечение как-то выправить для такого случая? + // не дает улучшений + if (costs[i] > GOOD_COST) { + break; + } + } + if (costs[i] < 0) { + printf("SHIT %lf\n", costs[i]); + } cost_sum += costs[i]; cost_w += 1; } - // TODO 112 а что если в пикселе occlusion, но best_cost - большой и поэтому отсечение по best_cost*COSTS_K_RATIO не срабатывает? можно ли это отсечение как-то выправить для такого случая? // TODO 207 а что если добавить какой-нибудь бонус в случае если больше чем Х камер засчиталось? улучшается/ухудшается ли от этого что-то на herzjezu25? а при большем числе фотографий float avg_cost = cost_sum / cost_w; diff --git a/src/phg/mvs/depth_maps/pm_depth_maps_defines.h b/src/phg/mvs/depth_maps/pm_depth_maps_defines.h index f5fda40a..6cd22184 100644 --- a/src/phg/mvs/depth_maps/pm_depth_maps_defines.h +++ b/src/phg/mvs/depth_maps/pm_depth_maps_defines.h @@ -6,6 +6,8 @@ #define GOOD_COST 0.2f #define USE_BILINEAR_INTERPOLATION 1 #define USE_ACMH_POPAGATION_SCHEME 1 +#define USE_ADVANCED_UNCERTANTY 1 +#define USE_BIG_COST_FILTERING 1 #define NITERATIONS 5 From 6a91cf327311a4b41484c41d13fef33dda3e6396 Mon Sep 17 00:00:00 2001 From: alexander Date: Sun, 3 May 2026 12:01:50 +0300 Subject: [PATCH 25/31] self-cost evaluation --- src/phg/mvs/depth_maps/pm_depth_maps.cpp | 28 +++++++++++++++++++ src/phg/mvs/depth_maps/pm_depth_maps.h | 4 +++ .../mvs/depth_maps/pm_depth_maps_defines.h | 1 + 3 files changed, 33 insertions(+) diff --git a/src/phg/mvs/depth_maps/pm_depth_maps.cpp b/src/phg/mvs/depth_maps/pm_depth_maps.cpp index 1c476b21..e14253c4 100644 --- a/src/phg/mvs/depth_maps/pm_depth_maps.cpp +++ b/src/phg/mvs/depth_maps/pm_depth_maps.cpp @@ -386,6 +386,34 @@ void PMDepthMapsBuilder::propagation() best_cost = NO_COST; } + if (ESTIMATE_BEST_SELF_COST_N) { + // TODODONE 203 - логика про "берем 8 лучших по их личной оценке - по их личному cost" и только их примеряем уже на себя для рассчета cost в нашей точке + // rassert(hypos_cost.size() >= ESTIMATE_BEST_SELF_COST_N, 126731264127481); + if (hypos_cost.size() > ESTIMATE_BEST_SELF_COST_N) { + printf("%lu\n", hypos_cost.size()); + } + std::vector> costs_indexed; + for (size_t i = 0; i < hypos_cost.size(); i++) { + costs_indexed.push_back(std::make_pair(hypos_cost[i], i)); + } + std::sort(costs_indexed.begin(), costs_indexed.end()); + std::vector hypos_depth_tmp; + std::vector hypos_normal_tmp; + std::vector hypos_cost_tmp; + + for (size_t i = 0; i < std::min(ESTIMATE_BEST_SELF_COST_N, costs_indexed.size()); i++) { + size_t cur_best_idx = costs_indexed[i].second; + + hypos_depth_tmp.push_back(hypos_depth[cur_best_idx]); + hypos_cost_tmp.push_back(hypos_cost[cur_best_idx]); + hypos_normal_tmp.push_back(hypos_normal[cur_best_idx]); + + hypos_depth = hypos_depth_tmp; + hypos_cost = hypos_cost_tmp; + hypos_normal = hypos_normal_tmp; + } + } + for (size_t hi = 0; hi < hypos_depth.size(); ++hi) { // эту гипотезу мы сейчас рассматриваем как очередного кандидата float d = hypos_depth[hi]; diff --git a/src/phg/mvs/depth_maps/pm_depth_maps.h b/src/phg/mvs/depth_maps/pm_depth_maps.h index 0f53e80b..bc22ea49 100644 --- a/src/phg/mvs/depth_maps/pm_depth_maps.h +++ b/src/phg/mvs/depth_maps/pm_depth_maps.h @@ -70,6 +70,10 @@ class PMDepthMapsBuilder { float estimateCost(ptrdiff_t i, ptrdiff_t j, double d, const vector3d& global_normal, size_t neighb_cam); float avgCost(std::vector& costs); void tryToPropagateDonor(ptrdiff_t ni, ptrdiff_t nj, int chessboard_pattern_step, std::vector& hypos_depth, std::vector& hypos_normal, std::vector& hypos_cost); + void tryToPropagateDonor3dots(ptrdiff_t ni0, ptrdiff_t nj0, + ptrdiff_t ni1, ptrdiff_t nj1, + ptrdiff_t ni2, ptrdiff_t nj2, + int chessboard_pattern_step, std::vector& hypos_depth, std::vector& hypos_normal, std::vector& hypos_cost); void printCurrentStats(); void debugCurrentPoints(const std::string& label); diff --git a/src/phg/mvs/depth_maps/pm_depth_maps_defines.h b/src/phg/mvs/depth_maps/pm_depth_maps_defines.h index 6cd22184..db084ddd 100644 --- a/src/phg/mvs/depth_maps/pm_depth_maps_defines.h +++ b/src/phg/mvs/depth_maps/pm_depth_maps_defines.h @@ -6,6 +6,7 @@ #define GOOD_COST 0.2f #define USE_BILINEAR_INTERPOLATION 1 #define USE_ACMH_POPAGATION_SCHEME 1 +#define ESTIMATE_BEST_SELF_COST_N 0ul #define USE_ADVANCED_UNCERTANTY 1 #define USE_BIG_COST_FILTERING 1 From 9d4764875578e84f314ce5265edbec64c94ad7ab Mon Sep 17 00:00:00 2001 From: alexander Date: Mon, 4 May 2026 21:33:42 +0300 Subject: [PATCH 26/31] some photos --- .../Saharov_all_cameras00.png | Bin 0 -> 1915856 bytes .../Saharov_all_cameras01.png | Bin 0 -> 2344389 bytes .../Saharov_two_cameras00.png | Bin 0 -> 288553 bytes .../herzjesu_all_cameras00.png | Bin 0 -> 921796 bytes 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 data/highlighted_results/test_depth_maps_pm/Saharov_all_cameras00.png create mode 100644 data/highlighted_results/test_depth_maps_pm/Saharov_all_cameras01.png create mode 100644 data/highlighted_results/test_depth_maps_pm/Saharov_two_cameras00.png create mode 100644 data/highlighted_results/test_depth_maps_pm/herzjesu_all_cameras00.png diff --git a/data/highlighted_results/test_depth_maps_pm/Saharov_all_cameras00.png b/data/highlighted_results/test_depth_maps_pm/Saharov_all_cameras00.png new file mode 100644 index 0000000000000000000000000000000000000000..f96a9ecca4292e4707a600d3843dddeea52b17ef GIT binary patch literal 1915856 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

    ^-P0lF)(rimP%_*uyMZmN3NX2?JnR& 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