Commit:
87f70e8Parent:
e0b7b06Include image dimensions in the sample-match diagnostic dump
The previous coordinate dump had no way to verify in/out-of-bounds without a separate cross-check against feature_extractor output for a possibly-different image -- feature_extractor's denormalization was just confirmed correct for one image, but the matcher's diagnostic picks whichever pair has the most raw matches, which could well be a different pair of images entirely. Make the dump self-contained: print each image's actual stored dimensions and flag any coordinate that falls outside them explicitly. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
src/exhaustive_matcher.rs
+25
-7
diff --git a/src/exhaustive_matcher.rs b/src/exhaustive_matcher.rs
index af7fa7c..4a8f74a 100644
@@ -26,6 +26,8 @@ const UNCALIBRATED_CONFIG: i64 = 3;
struct ImageFeatures {
image_id: i64,
name: String,
width: u32,
height: u32,
/// Original pixel-space [x, y, scale, orientation], as stored in the database.
keypoints: Vec<[f32; 4]>,
/// Flat n*2 keypoints re-normalized to [-1, 1], matching ALIKED's own convention
@@ -47,8 +49,8 @@ fn load_features(conn: &rusqlite::Connection, image_id: i64, name: String) -> Re
);
}
let (w, h) = database::image_dimensions(conn, image_id)?;
let max_dim = w.max(h) as f32;
let (width, height) = database::image_dimensions(conn, image_id)?;
let max_dim = width.max(height) as f32;
let kpts_norm: Vec<f32> = keypoints
.iter()
.flat_map(|k| [2.0 * k[0] / max_dim - 1.0, 2.0 * k[1] / max_dim - 1.0])
@@ -57,6 +59,8 @@ fn load_features(conn: &rusqlite::Connection, image_id: i64, name: String) -> Re
Ok(ImageFeatures {
image_id,
name,
width,
height,
keypoints,
kpts_norm,
descriptors,
@@ -116,6 +120,8 @@ struct PendingPair {
pair_id: i64,
name_lo: String,
name_hi: String,
size_lo: (u32, u32),
size_hi: (u32, u32),
matched: Vec<(usize, usize)>,
pts0: Vec<(f32, f32)>,
pts1: Vec<(f32, f32)>,
@@ -184,6 +190,8 @@ pub fn run(cfg: ExhaustiveMatcherConfig) -> Result<()> {
pair_id,
name_lo: lo.name.clone(),
name_hi: hi.name.clone(),
size_lo: (lo.width, lo.height),
size_hi: (hi.width, hi.height),
matched: ordered_matched,
pts0,
pts1,
@@ -198,16 +206,26 @@ pub fn run(cfg: ExhaustiveMatcherConfig) -> Result<()> {
// physical point in both photos?
if let Some(sample) = pending.iter().max_by_key(|p| p.matched.len()) {
eprintln!(
"[diag] sample matches for {} <-> {} ({} raw matches):",
"[diag] sample matches for {} ({}x{}) <-> {} ({}x{}) ({} raw matches):",
sample.name_lo,
sample.size_lo.0,
sample.size_lo.1,
sample.name_hi,
sample.size_hi.0,
sample.size_hi.1,
sample.matched.len()
);
for k in (0..sample.pts0.len()).step_by((sample.pts0.len() / 10).max(1)) {
eprintln!(
"[diag] {} @ ({:.1}, {:.1}) <-> {} @ ({:.1}, {:.1})",
sample.name_lo, sample.pts0[k].0, sample.pts0[k].1, sample.name_hi, sample.pts1[k].0, sample.pts1[k].1
);
let (x0, y0) = sample.pts0[k];
let (x1, y1) = sample.pts1[k];
let in_bounds0 = x0 >= 0.0 && x0 <= sample.size_lo.0 as f32 && y0 >= 0.0 && y0 <= sample.size_lo.1 as f32;
let in_bounds1 = x1 >= 0.0 && x1 <= sample.size_hi.0 as f32 && y1 >= 0.0 && y1 <= sample.size_hi.1 as f32;
let flag = if in_bounds0 && in_bounds1 {
""
} else {
" <-- OUT OF BOUNDS"
};
eprintln!("[diag] ({x0:.1}, {y0:.1}) <-> ({x1:.1}, {y1:.1}){flag}");
}
}