Skip to content

Commit

Permalink
???
Browse files Browse the repository at this point in the history
  • Loading branch information
jamjamjon committed Sep 13, 2024
1 parent 5720ed6 commit 35be2df
Show file tree
Hide file tree
Showing 7 changed files with 266 additions and 141 deletions.
20 changes: 8 additions & 12 deletions examples/dl/main.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
#![allow(unused)]
use usls::{models::YOLO, Annotator, DataLoader, Options, Vision, YOLOTask, YOLOVersion};

fn main() -> anyhow::Result<()> {
let options = Options::default()
let options = Options::new()
.with_cuda(0)
.with_model("yolo/v8-m-dyn.onnx")?
.with_yolo_version(YOLOVersion::V8)
Expand All @@ -14,34 +13,31 @@ fn main() -> anyhow::Result<()> {
let mut model = YOLO::new(options)?;

// build dataloader
// let image = DataLoader::try_read("images/car.jpg")?;
let dl = DataLoader::new(
// "rtsp://admin:[email protected]:554/h265/ch1/",
// "rtsp://admin:[email protected]:554/h264/ch1/",
// "../hall.mp4",
// "./assets/bus.jpg",
"./assets/bus.jpg",
// "images/car.jpg",
// "../set-negs",
// "/home/qweasd/Desktop/coco/val2017/images/test",
"/home/qweasd/Desktop/SourceVideos/3.mp4",
// "/home/qweasd/Desktop/SourceVideos/3.mp4",
// "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4",
)?
.with_batch(1)
.build()?;

// build annotator
let annotator = Annotator::default()
.with_bboxes_thickness(4)
.with_saveout("YOLO-DataLoader");
// // build annotator
let annotator = Annotator::new().with_saveout("YOLO-DataLoader");

for (xs, _paths) in dl {
println!("xs: {:?} | {:?}", xs.len(), _paths);
// run
for (xs, _) in dl {
let ys = model.forward(&xs, false)?;
annotator.annotate(&xs, &ys);
}

// images -> video
// DataLoader::new("runs/YOLO-DataLoader")?.to_video(30)?;
DataLoader::is2v("runs/YOLO-DataLoader", &["runs", "is2v"], 24)?;

Ok(())
}
2 changes: 1 addition & 1 deletion examples/yolo/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ pub struct Args {
#[arg(long)]
pub model: Option<String>,

#[arg(long, default_value_t = String::from("images/bus.jpg"))]
#[arg(long, default_value_t = String::from("./assets/bus.jpg"))]
pub source: String,

#[arg(long, value_enum, default_value_t = YOLOTask::Detect)]
Expand Down
21 changes: 14 additions & 7 deletions src/core/annotator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,10 @@ impl Default for Annotator {
fn default() -> Self {
Self {
verbose: true,
font: Self::load_font(None).unwrap(),
font: match Self::load_font(None) {
Ok(x) => x,
Err(err) => panic!("Failed to load font: {}", err),
},
_scale: 6.666667,
scale_dy: 28.,
polygons_alpha: 179,
Expand Down Expand Up @@ -108,6 +111,10 @@ impl Default for Annotator {
}

impl Annotator {
pub fn new() -> Self {
Default::default()
}

pub fn with_decimal_places(mut self, x: usize) -> Self {
self.decimal_places = x;
self
Expand Down Expand Up @@ -318,9 +325,9 @@ impl Annotator {
self
}

pub fn with_font(mut self, path: &str) -> Self {
self.font = Self::load_font(Some(path)).unwrap();
self
pub fn with_font(mut self, path: &str) -> Result<Self> {
self.font = Self::load_font(Some(path))?;
Ok(self)
}

/// Create folders for saving annotated results. e.g., `./runs/xxx`
Expand Down Expand Up @@ -386,7 +393,7 @@ impl Annotator {
self.plot_probs(&mut img_rgba, xs);
}

// TODO: logger
// save
let saveout = self.saveout()?.join(format!("{}.png", string_now("-")));
match img_rgba.save(&saveout) {
Err(err) => println!("{} Saving failed: {:?}", CROSS_MARK, err),
Expand All @@ -404,8 +411,8 @@ impl Annotator {

/// Plot bounding bboxes and labels
pub fn plot_bboxes(&self, img: &mut RgbaImage, bboxes: &[Bbox]) {
// bbox
for bbox in bboxes.iter() {
// bbox
let short_side_threshold =
bbox.width().min(bbox.height()) * self.bboxes_thickness_threshold;
let thickness = self.bboxes_thickness.min(short_side_threshold as usize);
Expand Down Expand Up @@ -749,7 +756,7 @@ impl Annotator {
Some(p) => p.into(),
};
let buffer = std::fs::read(path_font)?;
Ok(FontVec::try_from_vec(buffer.to_owned()).unwrap())
Ok(FontVec::try_from_vec(buffer.to_owned())?)
}

/// Pick color from pallette
Expand Down
142 changes: 83 additions & 59 deletions src/core/dataloader.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use anyhow::{anyhow, Result};
use image::DynamicImage;
use indicatif::{ProgressBar, ProgressStyle};
use std::collections::VecDeque;
use std::path::{Path, PathBuf};
use std::sync::mpsc;
Expand All @@ -13,7 +14,6 @@ use crate::{string_now, Dir, Hub, Location, MediaType, CHECK_MARK, CROSS_MARK};

type TempReturnType = (Vec<DynamicImage>, Vec<PathBuf>);

// Use IntoIterator trait
impl IntoIterator for DataLoader {
type Item = TempReturnType;
type IntoIter = DataLoaderIterator;
Expand Down Expand Up @@ -80,29 +80,9 @@ impl DataLoader {
Some(MediaType::from_path(source_path)),
)
} else if source_path.is_dir() {
let mut entries: Vec<PathBuf> = std::fs::read_dir(source_path)?
.filter_map(|entry| entry.ok())
.filter_map(|entry| {
let path = entry.path();
if path.is_file() {
Some(path)
} else {
None
}
})
.collect();

entries.sort_by(|a, b| {
let a_name = a.file_name().and_then(|s| s.to_str());
let b_name = b.file_name().and_then(|s| s.to_str());

match (a_name, b_name) {
(Some(a_str), Some(b_str)) => natord::compare(a_str, b_str),
_ => std::cmp::Ordering::Equal,
}
});
let paths_sorted = Self::load_from_folder(source_path)?;
(
Some(VecDeque::from(entries)),
Some(VecDeque::from(paths_sorted)),
Some(MediaType::Image(Location::Local)),
)
} else {
Expand All @@ -111,6 +91,10 @@ impl DataLoader {
}
};

if let Some(MediaType::Unknown) = media_type {
anyhow::bail!("Could not locate the source path: {:?}", source_path);
}

// mpsc
let (sender, receiver) = mpsc::channel::<TempReturnType>();

Expand Down Expand Up @@ -236,6 +220,32 @@ impl DataLoader {
self
}

pub fn load_from_folder<P: AsRef<std::path::Path>>(path: P) -> Result<Vec<std::path::PathBuf>> {
let mut paths: Vec<PathBuf> = std::fs::read_dir(path)?
.filter_map(|entry| entry.ok())
.filter_map(|entry| {
let path = entry.path();
if path.is_file() {
Some(path)
} else {
None
}
})
.collect();

paths.sort_by(|a, b| {
let a_name = a.file_name().and_then(|s| s.to_str());
let b_name = b.file_name().and_then(|s| s.to_str());

match (a_name, b_name) {
(Some(a_str), Some(b_str)) => natord::compare(a_str, b_str),
_ => std::cmp::Ordering::Equal,
}
});

Ok(paths)
}

pub fn try_read<P: AsRef<Path>>(path: P) -> Result<DynamicImage> {
let mut path = path.as_ref().to_path_buf();

Expand All @@ -244,11 +254,11 @@ impl DataLoader {
let p = Hub::new()?.fetch(path.to_str().unwrap())?.commit()?;
path = PathBuf::from(&p);
}
let img = Self::load_into_rgb8(path)?;
let img = Self::read_into_rgb8(path)?;
Ok(DynamicImage::from(img))
}

fn load_into_rgb8<P: AsRef<Path>>(path: P) -> Result<image::RgbImage> {
fn read_into_rgb8<P: AsRef<Path>>(path: P) -> Result<image::RgbImage> {
let path = path.as_ref();
let img = image::ImageReader::open(path)
.map_err(|err| {
Expand Down Expand Up @@ -278,44 +288,50 @@ impl DataLoader {
Ok(img)
}

pub fn to_video(&self, fps: usize) -> Result<()> {
/// Convert images into a video
pub fn is2v<P: AsRef<Path>>(source: P, subs: &[&str], fps: usize) -> Result<()> {
let paths = Self::load_from_folder(source.as_ref())?;
if paths.is_empty() {
anyhow::bail!("No images found.");
}
let mut encoder = None;
let mut position = Time::zero();
let saveout = Dir::Currnet
.raw_path_with_subs(subs)?
.join(format!("{}.mp4", string_now("-")));

// pb
let pb = ProgressBar::new(paths.len() as u64);
pb.set_style(
ProgressStyle::with_template(
"{prefix:.cyan.bold} {msg} |{bar}| ({percent_precise}%, {human_pos}/{human_len}, {per_sec})",
)?
.progress_chars("██ "),
);
pb.set_prefix(" Converting");
pb.set_message(saveout.to_str().unwrap_or_default().to_string());

// loop
for path in paths {
pb.inc(1);
let img = Self::read_into_rgb8(path)?;
let (w, h) = img.dimensions();

// build encoder at the 1st time
if encoder.is_none() {
let settings = Settings::preset_h264_yuv420p(w as _, h as _, false);
encoder = Some(Encoder::new(saveout.clone(), settings)?);
}

match &self.paths {
None => anyhow::bail!("No images found"),
Some(paths) => {
for path in paths {
let img = Self::load_into_rgb8(path)?;
let (w, h) = img.dimensions();

// build it at the 1st time
if encoder.is_none() {
// setting
let settings = Settings::preset_h264_yuv420p(w as _, h as _, false);

// saveout
let saveout = Dir::Currnet
.raw_path_with_subs(&["runs", "is2v"])?
.join(&format!("{}.mp4", string_now("-")));

// build encoder
encoder = Some(Encoder::new(saveout, settings)?);
}

// write video
if let Some(encoder) = encoder.as_mut() {
let raw_data = img.into_raw();
let frame =
ndarray::Array3::from_shape_vec((h as usize, w as usize, 3), raw_data)
.expect("Failed to create ndarray from raw image data");

encoder.encode(&frame, position)?;
// write video
if let Some(encoder) = encoder.as_mut() {
let raw_data = img.into_raw();
let frame = ndarray::Array3::from_shape_vec((h as usize, w as usize, 3), raw_data)
.expect("Failed to create ndarray from raw image data");

// update position
position = position.aligned_with(Time::from_nth_of_a_second(fps)).add();
}
}
// encode and update
encoder.encode(&frame, position)?;
position = position.aligned_with(Time::from_nth_of_a_second(fps)).add();
}
}

Expand All @@ -324,6 +340,14 @@ impl DataLoader {
None => anyhow::bail!("Found no video encoder."),
}

// update
pb.set_prefix(" Downloaded");
pb.set_prefix(" Converted");
pb.set_style(ProgressStyle::with_template(
"{prefix:.green.bold} {msg} in {elapsed}",
)?);
pb.finish();

Ok(())
}
}
14 changes: 7 additions & 7 deletions src/core/hub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ impl Hub {
releases.iter().map(|x| x.tag_name.as_str()).collect();
if !tags.contains(&tag) {
anyhow::bail!(
"Tag '{}' not found in releases. Available tags: {:?}",
"Hub tag '{}' not found in releases. Available tags: {:?}",
tag,
tags
);
Expand All @@ -187,7 +187,7 @@ impl Hub {
release.assets.iter().map(|x| x.name.as_str()).collect();
if !files.contains(&file_name) {
anyhow::bail!(
"File '{}' not found in tag '{}'. Available files: {:?}",
"Hub file '{}' not found in tag '{}'. Available files: {:?}",
file_name,
tag,
files
Expand Down Expand Up @@ -376,11 +376,11 @@ impl Hub {

let pb = ProgressBar::new(ntotal);
pb.set_style(
ProgressStyle::with_template(
"{prefix:.cyan.bold} {msg} |{bar}| ({percent_precise}%, {binary_bytes}/{binary_total_bytes}, {binary_bytes_per_sec})",
)?
.progress_chars("██ "),
);
ProgressStyle::with_template(
"{prefix:.cyan.bold} {msg} |{bar}| ({percent_precise}%, {binary_bytes}/{binary_total_bytes}, {binary_bytes_per_sec})",
)?
.progress_chars("██ "),
);
pb.set_prefix(if i_try == 0 {
" Fetching"
} else {
Expand Down
12 changes: 8 additions & 4 deletions src/core/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ pub struct Options {
pub device: Device,
pub profile: bool,
pub num_dry_run: usize,
pub i00: Option<MinOptMax>, // 1st input, axis 0, batch usually
pub i01: Option<MinOptMax>, // 1st input, axis 1
pub i00: Option<MinOptMax>, // the 1st input, axis 0, batch usually
pub i01: Option<MinOptMax>, // the 1st input, axis 1
pub i02: Option<MinOptMax>,
pub i03: Option<MinOptMax>,
pub i04: Option<MinOptMax>,
pub i05: Option<MinOptMax>,
pub i10: Option<MinOptMax>, // 2nd input, axis 0
pub i11: Option<MinOptMax>, // 2nd input, axis 1
pub i10: Option<MinOptMax>, // the 2nd input, axis 0
pub i11: Option<MinOptMax>, // the 2nd input, axis 1
pub i12: Option<MinOptMax>,
pub i13: Option<MinOptMax>,
pub i14: Option<MinOptMax>,
Expand Down Expand Up @@ -181,6 +181,10 @@ impl Default for Options {
}

impl Options {
pub fn new() -> Self {
Default::default()
}

pub fn with_model(mut self, onnx_path: &str) -> Result<Self> {
self.onnx_path = Hub::new()?.fetch(onnx_path)?.commit()?;
Ok(self)
Expand Down
Loading

0 comments on commit 35be2df

Please sign in to comment.