Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ cargo run -r -F openvino -F ort-load-dynamic --example yolo -- --device openvino
| [YOLOE-v8/11-Prompt-Free](https://github.com/THU-MIG/yoloe) | Open-Set Detection And Segmentation | [demo](./examples/image-segmentation/yoloe_prompt_free) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| [YOLOE-26-Prompt-Free](https://github.com/ultralytics/ultralytics) | Open-Set Detection And Segmentation | [demo](./examples/image-segmentation/yoloe_prompt_free) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| [FastSAM](https://github.com/CASIA-IVA-Lab/FastSAM) | Instance Segmentation | [demo](./examples/image-segmentation) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| [EdgeCrafter (ECDetSeg)](https://github.com/Intellindust-AI-Lab/EdgeCrafter) | Instance Segmentation | [demo](./examples/image-segmentation) | ❓ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
| [SAM2](https://github.com/facebookresearch/segment-anything-2) | Segment Anything | [demo](./examples/image-segmentation) | ✅ | ❓ | ✅ | ❌ | ❌ | ❌ | ❌ |
| [SAM3-Tracker](https://github.com/facebookresearch/segment-anything-3) | Segment Anything | [demo](./examples/image-segmentation) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| [BiRefNet - COD](https://github.com/ZhengPeng7/BiRefNet) | Camouflaged Object Detection | [demo](./examples/birefnet) | ✅ | ❓ | ✅ | ✅ | ✅ | ✅ | ✅ |
Expand Down
62 changes: 62 additions & 0 deletions examples/image-segmentation/ecdetseg.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use anyhow::Result;
use clap::Args;
use usls::{Config, DType, Device, Scale};

#[derive(Args, Debug)]
pub struct EcdetsegArgs {
/// Scale: s, m, l, x
#[arg(long, global = true, default_value = "m")]
pub scale: Scale,

/// Optional local ONNX model path (overrides the released asset)
#[arg(long)]
pub model: Option<String>,

/// Dtype: fp32, fp16
#[arg(long, default_value = "fp16")]
pub dtype: DType,

/// Device: cpu, cuda:0, tensorrt:0, trt-rtx:0, coreml, etc.
#[arg(long, global = true, default_value = "cpu")]
pub device: Device,

/// Processor device (for pre/post processing)
#[arg(long, global = true, default_value = "cpu")]
pub processor_device: Device,

/// Batch size
#[arg(long, global = true, default_value_t = 1)]
pub batch: usize,

/// Min batch size (TensorRT)
#[arg(long, global = true, default_value_t = 1)]
pub min_batch: usize,

/// Max batch size (TensorRT)
#[arg(long, global = true, default_value_t = 4)]
pub max_batch: usize,

/// num dry run
#[arg(long, global = true, default_value_t = 3)]
pub num_dry_run: usize,
}

pub fn config(args: &EcdetsegArgs) -> Result<Config> {
let config = match &args.model {
Some(path) => Config::ecdetseg().with_model_file(path),
None => match args.scale {
Scale::S => Config::ecdetseg_s(),
Scale::M => Config::ecdetseg_m(),
Scale::L => Config::ecdetseg_l(),
Scale::X => Config::ecdetseg_x(),
_ => anyhow::bail!("Unsupported scale: {}. Try s, m, l, x.", args.scale),
},
}
.with_model_dtype(args.dtype)
.with_model_device(args.device)
.with_batch_size_min_opt_max_all(args.min_batch, args.batch, args.max_batch)
.with_num_dry_run_all(args.num_dry_run)
.with_image_processor_device(args.processor_device);

Ok(config)
}
11 changes: 10 additions & 1 deletion examples/image-segmentation/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ use anyhow::Result;
use clap::{Parser, Subcommand};
use usls::{
models::{
FastSAM, Sam3Prompt, Sam3Tracker, SamPrompt, YOLOEPromptFree, YOLOPv2, RFDETR, SAM, SAM2,
ECDetSeg, FastSAM, Sam3Prompt, Sam3Tracker, SamPrompt, YOLOEPromptFree, YOLOPv2, RFDETR,
SAM, SAM2,
},
Annotator, Config, DataLoader, Model, Source,
};

mod ecdetseg;
mod fastsam;
mod rfdetr;
mod sam;
Expand Down Expand Up @@ -36,6 +38,7 @@ struct Cli {
#[derive(Subcommand)]
enum Commands {
Rfdetr(rfdetr::RfdetrArgs),
Ecdetseg(ecdetseg::EcdetsegArgs),
YoloePromptFree(yoloe_prompt_free::YoloePromptFreeArgs),
Sam(sam::SamArgs),
Sam2(sam2::Sam2Args),
Expand Down Expand Up @@ -89,6 +92,12 @@ fn main() -> Result<()> {
.commit()?;
run::<RFDETR>(config, &cli.source, &annotator)
}
Commands::Ecdetseg(args) => {
let config = ecdetseg::config(args)?
.with_class_confs(&cli.confs)
.commit()?;
run::<ECDetSeg>(config, &cli.source, &annotator)
}
Commands::YoloePromptFree(args) => {
let config = yoloe_prompt_free::config(args)?
.with_class_confs(&cli.confs)
Expand Down
8 changes: 5 additions & 3 deletions src/dataloader/hub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -485,9 +485,11 @@ impl Hub {
pb = pb.with_message(msg);
}

// Create temporary file in system temp directory (more secure and reliable)
let mut temp_file = NamedTempFile::new()
.context("Failed to create temporary download file in system temp directory")?;
let parent_dir = dst_path
.parent()
.context("Invalid download destination: no parent directory found")?;
let mut temp_file = NamedTempFile::new_in(parent_dir)
.context("Failed to create temporary download file next to destination")?;

let mut reader = resp.into_body().into_reader();
const BUFFER_SIZE: usize = 64 * 1024;
Expand Down
71 changes: 71 additions & 0 deletions src/models/vision/ecdetseg/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
use crate::Task;

const ECDETSEG_RELEASE: &str = "https://github.com/wep21/assets/releases/download/ecdetseg";

///
/// > # ECDetSeg: EdgeCrafter Instance Segmentation
/// >
/// > Compact ViT-based real-time instance segmentation from EdgeCrafter, built on the
/// > RT-DETR / D-FINE detection family with an additional mask head.
/// >
/// > # Paper & Code
/// >
/// > - **GitHub**: [Intellindust-AI-Lab/EdgeCrafter](https://github.com/Intellindust-AI-Lab/EdgeCrafter)
/// > - **arXiv**: <https://arxiv.org/abs/2603.18739>
/// >
/// > # Model Variants
/// >
/// > - **ecdetseg-s**: Small model for 80-class COCO instance segmentation
/// > - **ecdetseg-m**: Medium model for 80-class COCO instance segmentation
/// > - **ecdetseg-l**: Large model for 80-class COCO instance segmentation
/// > - **ecdetseg-x**: Extra large model for 80-class COCO instance segmentation
/// >
/// > # Implemented Features / Tasks
/// >
/// > - [X] **Instance Segmentation**: 80-class COCO instance segmentation
/// >
/// > # Precision / File naming
/// >
/// > Assets are hosted on the `wep21/assets` GitHub releases (tag `ecdetseg`).
/// > FP32 weights use `ecdetseg-{scale}.onnx`; FP16 weights follow the `-fp16.onnx`
/// > convention (`ecdetseg-{scale}-fp16.onnx`) and are selected automatically via
/// > [`crate::Config::with_model_dtype(DType::Fp16)`](crate::Config::with_model_dtype).
///
/// Model configuration for `ECDetSeg`
///
impl crate::Config {
/// Base configuration for ECDetSeg models.
///
/// ECDetSeg shares the RT-DETR / D-FINE detection front-end (same `images` +
/// `orig_target_sizes` inputs and `labels`, `boxes`, `scores` outputs) and adds a
/// fourth `masks` output for instance segmentation.
pub fn ecdetseg() -> Self {
Self::rtdetr()
.with_name("ecdetseg")
.with_task(Task::InstanceSegmentation)
// EdgeCrafter eval stretches to the model size (letterbox degrades small models)
.with_resize_mode_type(crate::ResizeModeType::FitExact)
.with_image_mean([0.485, 0.456, 0.406])
.with_image_std([0.229, 0.224, 0.225])
}

/// Small model for 80-class COCO instance segmentation.
pub fn ecdetseg_s() -> Self {
Self::ecdetseg().with_model_file(format!("{ECDETSEG_RELEASE}/ecdetseg-s.onnx"))
}

/// Medium model for 80-class COCO instance segmentation.
pub fn ecdetseg_m() -> Self {
Self::ecdetseg().with_model_file(format!("{ECDETSEG_RELEASE}/ecdetseg-m.onnx"))
}

/// Large model for 80-class COCO instance segmentation.
pub fn ecdetseg_l() -> Self {
Self::ecdetseg().with_model_file(format!("{ECDETSEG_RELEASE}/ecdetseg-l.onnx"))
}

/// Extra large model for 80-class COCO instance segmentation.
pub fn ecdetseg_x() -> Self {
Self::ecdetseg().with_model_file(format!("{ECDETSEG_RELEASE}/ecdetseg-x.onnx"))
}
}
Loading
Loading