use color_eyre::Result;
use object_detector::{DetectedObject, ObjectBBox, PromptFreeDetector};
use serde::Serialize;
use std::collections::BTreeMap;
use std::fs;
use std::path::Path;
#[derive(Serialize)]
struct SerializableDetection {
tag: String,
score: f32,
bbox: ObjectBBox,
mask_stats: Option<MaskStats>,
}
#[derive(Serialize)]
struct MaskStats {
width: u32,
height: u32,
active_pixels: usize,
}
impl From<DetectedObject> for SerializableDetection {
fn from(det: DetectedObject) -> Self {
let mask_stats = det.mask.as_ref().map(|m| MaskStats {
width: m.width,
height: m.height,
active_pixels: m.data.iter().map(|&b| b.count_ones() as usize).sum(),
});
Self {
tag: det.tag,
score: det.score,
bbox: det.bbox,
mask_stats,
}
}
}
#[tokio::main]
async fn main() -> Result<()> {
color_eyre::install()?;
let predictor = PromptFreeDetector::from_hf().build().await?;
let img_dir = Path::new("assets/img");
let mut all_results = BTreeMap::new();
for entry in fs::read_dir(img_dir)? {
let path = entry?.path();
let file_name = path.file_name().unwrap().to_string_lossy().into_owned();
println!("Processing {file_name}...");
let img = image::open(&path)?;
let results = predictor.predict(&img).call()?;
let serializable: Vec<SerializableDetection> = results
.into_iter()
.map(SerializableDetection::from)
.collect();
all_results.insert(file_name, serializable);
}
let output_path = "assets/expected_outputs.json";
fs::write(output_path, serde_json::to_string_pretty(&all_results)?)?;
println!("✅ Successfully exported results to {output_path}");
Ok(())
}