mirror of
https://github.com/mii443/usls.git
synced 2025-08-22 15:45:41 +00:00
Enhance Annotator with mask-cutout functionality (#101)
Co-authored-by: jamjamjon <zhangjian@zhuofansoft.com>
This commit is contained in:
@ -32,7 +32,6 @@ natord = "1.0.9"
|
|||||||
geo = "0.30.0"
|
geo = "0.30.0"
|
||||||
chrono = "0.4.40"
|
chrono = "0.4.40"
|
||||||
regex = "1.11.1"
|
regex = "1.11.1"
|
||||||
sha2 = "0.10.8"
|
|
||||||
tempfile = "3.19.1"
|
tempfile = "3.19.1"
|
||||||
video-rs = { version = "0.10.3", features = ["ndarray"], optional = true }
|
video-rs = { version = "0.10.3", features = ["ndarray"], optional = true }
|
||||||
fast_image_resize = { version = "5.1.2", features = ["image"] }
|
fast_image_resize = { version = "5.1.2", features = ["image"] }
|
||||||
|
@ -43,7 +43,8 @@ fn main() -> anyhow::Result<()> {
|
|||||||
let ys = model.forward(&xs)?;
|
let ys = model.forward(&xs)?;
|
||||||
|
|
||||||
// annotate
|
// annotate
|
||||||
let annotator = Annotator::default();
|
let annotator =
|
||||||
|
Annotator::default().with_mask_style(usls::Style::mask().with_mask_cutout(true));
|
||||||
for (x, y) in xs.iter().zip(ys.iter()) {
|
for (x, y) in xs.iter().zip(ys.iter()) {
|
||||||
annotator.annotate(x, y)?.save(format!(
|
annotator.annotate(x, y)?.save(format!(
|
||||||
"{}.jpg",
|
"{}.jpg",
|
||||||
|
@ -2,7 +2,6 @@ use anyhow::{Context, Result};
|
|||||||
use indicatif::ProgressStyle;
|
use indicatif::ProgressStyle;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sha2::{Digest, Sha256};
|
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
@ -461,9 +460,9 @@ impl Hub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn cache_file(owner: &str, repo: &str) -> String {
|
fn cache_file(owner: &str, repo: &str) -> String {
|
||||||
let mut hasher = Sha256::new();
|
let safe_owner = owner.replace(|c: char| !c.is_ascii_alphanumeric(), "_");
|
||||||
hasher.update(format!("{}-{}", owner, repo));
|
let safe_repo = repo.replace(|c: char| !c.is_ascii_alphanumeric(), "_");
|
||||||
format!(".{:x}", hasher.finalize())
|
format!(".releases_{}_{}.json", safe_owner, safe_repo)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_releases(owner: &str, repo: &str, to: &Dir, ttl: &Duration) -> Result<Vec<Release>> {
|
fn get_releases(owner: &str, repo: &str, to: &Dir, ttl: &Duration) -> Result<Vec<Release>> {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use crate::Drawable;
|
use crate::Drawable;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use image::{DynamicImage, RgbaImage};
|
use image::{DynamicImage, Rgba, RgbaImage};
|
||||||
|
|
||||||
use crate::{ColorMap256, DrawContext, Mask, Style};
|
use crate::{Color, ColorMap256, DrawContext, Mask, Style};
|
||||||
|
|
||||||
fn render_mask(mask: &Mask, colormap256: Option<&ColorMap256>) -> DynamicImage {
|
fn render_mask(mask: &Mask, colormap256: Option<&ColorMap256>) -> DynamicImage {
|
||||||
if let Some(colormap256) = colormap256 {
|
if let Some(colormap256) = colormap256 {
|
||||||
@ -10,12 +10,26 @@ fn render_mask(mask: &Mask, colormap256: Option<&ColorMap256>) -> DynamicImage {
|
|||||||
let idx = p[0];
|
let idx = p[0];
|
||||||
image::Rgb(colormap256.data()[idx as usize].rgb().into())
|
image::Rgb(colormap256.data()[idx as usize].rgb().into())
|
||||||
});
|
});
|
||||||
DynamicImage::from(luma)
|
luma.into()
|
||||||
} else {
|
} else {
|
||||||
DynamicImage::from(mask.mask().clone())
|
mask.mask().clone().into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn apply_mask(origin: &RgbaImage, mask: &Mask, background_color: Option<Color>) -> DynamicImage {
|
||||||
|
let bg = background_color.unwrap_or(Color::green());
|
||||||
|
imageproc::map::map_colors2(origin, mask.mask(), |src, mask| {
|
||||||
|
let [r, g, b, _] = src.0;
|
||||||
|
let mask_alpha = mask.0[0];
|
||||||
|
if mask_alpha == 0 {
|
||||||
|
Rgba(bg.into())
|
||||||
|
} else {
|
||||||
|
Rgba([r, g, b, mask_alpha])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
fn best_grid(n: usize) -> (usize, usize) {
|
fn best_grid(n: usize) -> (usize, usize) {
|
||||||
let mut best_rows = 1;
|
let mut best_rows = 1;
|
||||||
let mut best_cols = n;
|
let mut best_cols = n;
|
||||||
@ -38,6 +52,8 @@ fn draw_masks(
|
|||||||
masks: &[&Mask],
|
masks: &[&Mask],
|
||||||
colormap256: Option<&ColorMap256>,
|
colormap256: Option<&ColorMap256>,
|
||||||
canvas: &mut RgbaImage,
|
canvas: &mut RgbaImage,
|
||||||
|
mask_cutout: bool,
|
||||||
|
mask_background_color: Option<Color>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let (w, h) = canvas.dimensions();
|
let (w, h) = canvas.dimensions();
|
||||||
let n = masks.len() + 1; // +1 for original
|
let n = masks.len() + 1; // +1 for original
|
||||||
@ -58,7 +74,11 @@ fn draw_masks(
|
|||||||
let x = ((w as i32 - mw as i32) / 2).max(0) as u32;
|
let x = ((w as i32 - mw as i32) / 2).max(0) as u32;
|
||||||
let y = ((h as i32 - mh as i32) / 2).max(0) as u32;
|
let y = ((h as i32 - mh as i32) / 2).max(0) as u32;
|
||||||
|
|
||||||
let mask_dyn = render_mask(mask, colormap256);
|
let mask_dyn = if mask_cutout {
|
||||||
|
apply_mask(canvas, mask, mask_background_color)
|
||||||
|
} else {
|
||||||
|
render_mask(mask, colormap256)
|
||||||
|
};
|
||||||
image::imageops::overlay(&mut mask_img, &mask_dyn, x as i64, y as i64);
|
image::imageops::overlay(&mut mask_img, &mask_dyn, x as i64, y as i64);
|
||||||
|
|
||||||
let out_x = (col as u32 * w) as i64;
|
let out_x = (col as u32 * w) as i64;
|
||||||
@ -122,7 +142,14 @@ impl Drawable for [Mask] {
|
|||||||
self.get_global_style(ctx),
|
self.get_global_style(ctx),
|
||||||
self.get_id(),
|
self.get_id(),
|
||||||
);
|
);
|
||||||
draw_masks(&masks_visible, style.colormap256(), canvas)
|
|
||||||
|
draw_masks(
|
||||||
|
&masks_visible,
|
||||||
|
style.colormap256(),
|
||||||
|
canvas,
|
||||||
|
style.mask_cutout(),
|
||||||
|
style.mask_background_color().copied(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,7 +202,11 @@ impl Drawable for Mask {
|
|||||||
|
|
||||||
if style.visible() {
|
if style.visible() {
|
||||||
let (w, h) = canvas.dimensions();
|
let (w, h) = canvas.dimensions();
|
||||||
let mask_dyn = render_mask(self, style.colormap256());
|
let mask_dyn = if style.mask_cutout() {
|
||||||
|
apply_mask(canvas, self, style.mask_background_color().copied())
|
||||||
|
} else {
|
||||||
|
render_mask(self, style.colormap256())
|
||||||
|
};
|
||||||
|
|
||||||
let (mut out, mask_x, mask_y) = if w <= h {
|
let (mut out, mask_x, mask_y) = if w <= h {
|
||||||
(RgbaImage::new(w * 2, h), w as i64, 0)
|
(RgbaImage::new(w * 2, h), w as i64, 0)
|
||||||
|
@ -60,8 +60,8 @@ pub trait Drawable {
|
|||||||
|
|
||||||
impl Drawable for Y {
|
impl Drawable for Y {
|
||||||
fn draw(&self, ctx: &DrawContext, canvas: &mut image::RgbaImage) -> anyhow::Result<()> {
|
fn draw(&self, ctx: &DrawContext, canvas: &mut image::RgbaImage) -> anyhow::Result<()> {
|
||||||
if let Some(probs) = self.probs() {
|
if let Some(masks) = self.masks() {
|
||||||
probs.draw(ctx, canvas)?;
|
masks.draw(ctx, canvas)?;
|
||||||
}
|
}
|
||||||
if let Some(polygons) = self.polygons() {
|
if let Some(polygons) = self.polygons() {
|
||||||
polygons.draw(ctx, canvas)?;
|
polygons.draw(ctx, canvas)?;
|
||||||
@ -78,8 +78,8 @@ impl Drawable for Y {
|
|||||||
if let Some(keypointss) = self.keypointss() {
|
if let Some(keypointss) = self.keypointss() {
|
||||||
keypointss.draw(ctx, canvas)?;
|
keypointss.draw(ctx, canvas)?;
|
||||||
}
|
}
|
||||||
if let Some(masks) = self.masks() {
|
if let Some(probs) = self.probs() {
|
||||||
masks.draw(ctx, canvas)?;
|
probs.draw(ctx, canvas)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -4,25 +4,27 @@ use crate::{Color, ColorMap256, Skeleton};
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Builder, PartialEq)]
|
#[derive(Debug, Clone, Builder, PartialEq)]
|
||||||
pub struct Style {
|
pub struct Style {
|
||||||
visible: bool, // For ALL
|
visible: bool, // For ALL
|
||||||
text_visible: bool, // For ALL
|
text_visible: bool, // For ALL
|
||||||
draw_fill: bool, // For ALL
|
draw_fill: bool, // For ALL
|
||||||
draw_outline: bool, // For ALL
|
draw_outline: bool, // For ALL
|
||||||
color_fill_alpha: Option<u8>, // Alpha for fill
|
color_fill_alpha: Option<u8>, // Alpha for fill
|
||||||
radius: usize, // For Keypoint
|
radius: usize, // For Keypoint
|
||||||
text_x_pos: f32, // For Probs
|
text_x_pos: f32, // For Probs
|
||||||
text_y_pos: f32, // For Probs
|
text_y_pos: f32, // For Probs
|
||||||
thickness: usize, // For Hbb
|
thickness: usize, // For Hbb
|
||||||
thickness_threshold: f32, // For Hbb
|
thickness_threshold: f32, // For Hbb
|
||||||
draw_mask_polygons: bool, // For Masks
|
draw_mask_polygons: bool, // For Masks
|
||||||
draw_mask_polygon_largest: bool, // For Masks
|
draw_mask_polygon_largest: bool, // For Masks
|
||||||
draw_mask_hbbs: bool, // For Masks
|
draw_mask_hbbs: bool, // For Masks
|
||||||
draw_mask_obbs: bool, // For Masks
|
draw_mask_obbs: bool, // For Masks
|
||||||
text_loc: TextLoc, // For ALL
|
mask_cutout: bool, // For Masks
|
||||||
color: StyleColors, // For ALL
|
mask_background_color: Option<Color>, // For Masks
|
||||||
palette: Vec<Color>, // For ALL
|
text_loc: TextLoc, // For ALL
|
||||||
skeleton: Option<Skeleton>, // For Keypoints
|
color: StyleColors, // For ALL
|
||||||
colormap256: Option<ColorMap256>, // For Masks
|
palette: Vec<Color>, // For ALL
|
||||||
|
skeleton: Option<Skeleton>, // For Keypoints
|
||||||
|
colormap256: Option<ColorMap256>, // For Masks
|
||||||
decimal_places: usize,
|
decimal_places: usize,
|
||||||
#[args(set_pre = "show")]
|
#[args(set_pre = "show")]
|
||||||
confidence: bool,
|
confidence: bool,
|
||||||
@ -45,6 +47,8 @@ impl Default for Style {
|
|||||||
draw_mask_polygon_largest: false,
|
draw_mask_polygon_largest: false,
|
||||||
draw_mask_hbbs: false,
|
draw_mask_hbbs: false,
|
||||||
draw_mask_obbs: false,
|
draw_mask_obbs: false,
|
||||||
|
mask_cutout: false,
|
||||||
|
mask_background_color: None,
|
||||||
radius: 3,
|
radius: 3,
|
||||||
text_x_pos: 0.05,
|
text_x_pos: 0.05,
|
||||||
text_y_pos: 0.05,
|
text_y_pos: 0.05,
|
||||||
|
Reference in New Issue
Block a user