use anyhow::Result;
use argh::FromArgs;
use darknet::{BBox, Image, Network};
use image::RgbImage;
use std::{
convert::TryFrom,
fs::{self},
path::PathBuf,
};
#[derive(Debug, Clone, FromArgs)]
struct Args {
#[argh(option)]
label_file: PathBuf,
#[argh(option)]
model_cfg: PathBuf,
#[argh(option)]
weights: PathBuf,
#[argh(option, default = "PathBuf::from(\"./output\")")]
output_dir: PathBuf,
#[argh(option, default = "0.9")]
objectness_threshold: f32,
#[argh(option, default = "0.9")]
class_prob_threshold: f32,
#[argh(positional)]
input_images: Vec<PathBuf>,
}
fn main() -> Result<()> {
let Args {
label_file,
model_cfg,
weights,
output_dir,
objectness_threshold,
class_prob_threshold,
input_images,
} = argh::from_env();
let object_labels = std::fs::read_to_string(label_file)?
.lines()
.map(ToOwned::to_owned)
.collect::<Vec<_>>();
let mut net = Network::load(model_cfg, Some(weights), false)?;
for image_path in input_images {
let image = Image::open(&image_path)?;
let image_file_name = image_path
.file_name()
.expect(&format!("{} is not a valid file", image_path.display()));
let curr_output_dir = output_dir.join(image_file_name);
fs::create_dir_all(&curr_output_dir)?;
let detections = net.predict(&image, 0.25, 0.5, 0.45, true);
println!("# {}", image_path.display());
detections
.iter()
.filter(|det| det.objectness() > objectness_threshold)
.flat_map(|det| {
det.best_class(Some(class_prob_threshold))
.map(|(class_index, prob)| (det, prob, &object_labels[class_index]))
})
.enumerate()
.for_each(|(index, (det, prob, label))| {
let bbox = det.bbox();
let BBox { x, y, w, h } = bbox;
let image_path =
curr_output_dir.join(format!("{}-{}-{:2.2}.jpg", index, label, prob * 100.0));
RgbImage::try_from(image.crop_bbox(bbox))
.unwrap()
.save(image_path)
.unwrap();
println!(
"{}\t{:.2}%\tx: {}\ty: {}\tw: {}\th: {}",
label,
prob * 100.0,
x,
y,
w,
h
);
});
}
Ok(())
}