first commit
This commit is contained in:
commit
a52d0029b4
10 files changed
+1640
No files matched your search
@@ -0,0 +1,68 @@
|
||||
#include <opencv2/opencv.hpp>
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc != 3) { std::cerr << "usage: measure_overlap IMAGE_A IMAGE_B\n"; return 2; }
|
||||
cv::Mat a = cv::imread(argv[1], cv::IMREAD_GRAYSCALE);
|
||||
cv::Mat b = cv::imread(argv[2], cv::IMREAD_GRAYSCALE);
|
||||
if (a.empty() || b.empty()) { std::cerr << "cannot read input image\n"; return 3; }
|
||||
if (a.size() != b.size()) cv::resize(b, b, a.size());
|
||||
|
||||
const double scale = std::min(1.0, 960.0 / a.cols);
|
||||
if (scale < 1.0) {
|
||||
cv::resize(a, a, {}, scale, scale, cv::INTER_AREA);
|
||||
cv::resize(b, b, {}, scale, scale, cv::INTER_AREA);
|
||||
}
|
||||
auto orb = cv::ORB::create(2500, 1.2f, 8, 31, 0, 2, cv::ORB::HARRIS_SCORE, 31, 8);
|
||||
std::vector<cv::KeyPoint> ka, kb; cv::Mat da, db;
|
||||
orb->detectAndCompute(a, {}, ka, da);
|
||||
orb->detectAndCompute(b, {}, kb, db);
|
||||
if (da.empty() || db.empty()) {
|
||||
std::cout << "{\"valid\":false,\"reason\":\"not_enough_features\",\"overlap\":0}\n";
|
||||
return 0;
|
||||
}
|
||||
std::vector<std::vector<cv::DMatch>> knn;
|
||||
cv::BFMatcher(cv::NORM_HAMMING).knnMatch(da, db, knn, 2);
|
||||
std::vector<cv::DMatch> good;
|
||||
for (const auto& pair : knn)
|
||||
if (pair.size() == 2 && pair[0].distance < 0.75f * pair[1].distance) good.push_back(pair[0]);
|
||||
if (good.size() < 8) {
|
||||
std::cout << "{\"valid\":false,\"reason\":\"not_enough_matches\",\"good_matches\":"
|
||||
<< good.size() << ",\"overlap\":0}\n";
|
||||
return 0;
|
||||
}
|
||||
std::vector<cv::Point2f> pa, pb;
|
||||
for (const auto& m : good) { pa.push_back(ka[m.queryIdx].pt); pb.push_back(kb[m.trainIdx].pt); }
|
||||
cv::Mat mask;
|
||||
cv::Mat h = cv::findHomography(pa, pb, cv::RANSAC, 4.0, mask, 3000, 0.995);
|
||||
const int inliers = mask.empty() ? 0 : cv::countNonZero(mask);
|
||||
const double inlier_ratio = good.empty() ? 0.0 : inliers / (double)good.size();
|
||||
if (h.empty() || inliers < 50 || inlier_ratio < 0.45) {
|
||||
std::cout << "{\"valid\":false,\"reason\":\"homography_failed\",\"good_matches\":"
|
||||
<< good.size() << ",\"inliers\":" << inliers
|
||||
<< ",\"inlier_ratio\":" << inlier_ratio << ",\"overlap\":0}\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<cv::Point2f> corners{{0,0},{(float)a.cols,0},{(float)a.cols,(float)a.rows},{0,(float)a.rows}};
|
||||
std::vector<cv::Point2f> warped;
|
||||
cv::perspectiveTransform(corners, warped, h);
|
||||
std::vector<cv::Point2f> frame{{0,0},{(float)b.cols,0},{(float)b.cols,(float)b.rows},{0,(float)b.rows}};
|
||||
std::vector<cv::Point2f> intersection;
|
||||
const float area = cv::intersectConvexConvex(warped, frame, intersection, true);
|
||||
const double overlap = std::clamp(area / (double)(b.cols * b.rows), 0.0, 1.0);
|
||||
std::vector<cv::Point2f> center{{a.cols * .5f, a.rows * .5f}}, moved_center;
|
||||
cv::perspectiveTransform(center, moved_center, h);
|
||||
const double dx = (moved_center[0].x - center[0].x) / a.cols;
|
||||
const double dy = (moved_center[0].y - center[0].y) / a.rows;
|
||||
std::cout << std::fixed << std::setprecision(4)
|
||||
<< "{\"valid\":true,\"overlap\":" << overlap
|
||||
<< ",\"good_matches\":" << good.size()
|
||||
<< ",\"inliers\":" << inliers
|
||||
<< ",\"inlier_ratio\":" << inlier_ratio
|
||||
<< ",\"center_dx\":" << dx << ",\"center_dy\":" << dy << "}\n";
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user