Skip to content

Commit 75cc0ea

Browse files
authored
Support unknown thresholds and add debug mode (#13)
1 parent 19755be commit 75cc0ea

File tree

6 files changed

+135
-19
lines changed

6 files changed

+135
-19
lines changed

Cargo.lock

Lines changed: 62 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ edition = "2021"
55
description = "GStreamer plugin to run AI/ML inference via Edge Impulse machine learning models"
66
authors = ["Fernando Jiménez Moreno <[email protected]>"]
77
license = "BSD-3-Clause-Clear"
8+
rust-version = "1.75" # Minimum Rust version that supports edition 2024 features
89

910
[lib]
1011
name = "gstedgeimpulse"

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ This plugin depends on:
110110
* GStreamer 1.20 or newer
111111
* [edge-impulse-runner-rs](https://github.com/edgeimpulse/edge-impulse-runner-rs) - Rust bindings for Edge Impulse Linux SDK
112112
* A trained Edge Impulse model file (.eim)
113-
* Rust toolchain (via rustup)
113+
* Rust nightly toolchain (via rustup) - required for edition 2024 support
114114

115115
## Installation
116116

@@ -124,6 +124,12 @@ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
124124

125125
Follow the prompts to complete the installation. After installation, restart your terminal to ensure the Rust tools are in your PATH.
126126

127+
**Note:** This plugin requires Rust nightly due to the `edge-impulse-runner` dependency using edition 2024. Switch to nightly after installation:
128+
129+
```bash
130+
rustup override set nightly
131+
```
132+
127133
### 2. Install GStreamer
128134
Download and install GStreamer from the official binaries:
129135

examples/video_inference.rs

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,12 @@ fn create_pipeline(args: &VideoClassifyParams) -> Result<gst::Pipeline, Box<dyn
160160
.build()
161161
.expect("Could not create queue element.");
162162

163-
let mut classifier_factory =
164-
gst::ElementFactory::make("edgeimpulsevideoinfer").property("model-path", &args.model);
163+
let mut classifier_factory = if args.debug {
164+
gst::ElementFactory::make("edgeimpulsevideoinfer")
165+
.property("model-path-with-debug", &args.model)
166+
} else {
167+
gst::ElementFactory::make("edgeimpulsevideoinfer").property("model-path", &args.model)
168+
};
165169

166170
// Set thresholds if provided
167171
for threshold in &args.threshold {
@@ -327,15 +331,21 @@ fn example_main() -> Result<(), Box<dyn Error>> {
327331
let y = cell["y"].as_u64().unwrap_or(0);
328332
let width = cell["width"].as_u64().unwrap_or(0);
329333
let height = cell["height"].as_u64().unwrap_or(0);
330-
let score = cell["score"].as_f64().unwrap_or(0.0);
331-
println!(
332-
" Cell at ({}, {}) size {}x{}: score {:.2}%",
333-
x,
334-
y,
335-
width,
336-
height,
337-
score * 100.0
338-
);
334+
let score = cell
335+
.get("score")
336+
.and_then(|v| v.as_f64())
337+
.or_else(|| cell.get("value").and_then(|v| v.as_f64()));
338+
if let Some(score) = score {
339+
println!(
340+
" Cell at ({}, {}) size {}x{}: score {:.2}%",
341+
x, y, width, height, score
342+
);
343+
} else {
344+
println!(
345+
" Cell at ({}, {}) size {}x{}: score N/A",
346+
x, y, width, height
347+
);
348+
}
339349
}
340350
}
341351
}

src/common.rs

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ pub fn create_common_properties() -> Vec<glib::ParamSpec> {
2929
.nick("Model Path")
3030
.blurb("Path to Edge Impulse model file")
3131
.build(),
32+
glib::ParamSpecString::builder("model-path-with-debug")
33+
.nick("Model Path With Debug")
34+
.blurb("Path to Edge Impulse model file (debug mode enabled)")
35+
.build(),
3236
glib::ParamSpecString::builder("threshold")
3337
.nick("Model Block Threshold")
3438
.blurb("Threshold value for model blocks in format 'blockId.type=value'. Examples: '5.min_score=0.6' for object detection blocks, '4.min_anomaly_score=0.35' for anomaly detection blocks. Multiple thresholds can be set by calling the property multiple times.")
@@ -50,15 +54,35 @@ pub fn set_common_property<T>(
5054
"model-path" => {
5155
let mut state = state.lock().unwrap();
5256
let model_path: Option<String> = value.get().expect("type checked upstream");
53-
54-
// Initialize the model when the path is set
5557
if let Some(model_path) = model_path {
56-
match edge_impulse_runner::EimModel::new(&model_path) {
58+
let model_result = edge_impulse_runner::EimModel::new(&model_path);
59+
match model_result {
60+
Ok(model) => {
61+
gst::debug!(
62+
cat,
63+
obj = obj,
64+
"Successfully loaded model from {} (debug=false)",
65+
model_path
66+
);
67+
*state.as_mut() = Some(model);
68+
}
69+
Err(err) => {
70+
gst::error!(cat, obj = obj, "Failed to load model: {}", err);
71+
}
72+
}
73+
}
74+
}
75+
"model-path-with-debug" => {
76+
let mut state = state.lock().unwrap();
77+
let model_path: Option<String> = value.get().expect("type checked upstream");
78+
if let Some(model_path) = model_path {
79+
let model_result = edge_impulse_runner::EimModel::new_with_debug(&model_path, true);
80+
match model_result {
5781
Ok(model) => {
5882
gst::debug!(
5983
cat,
6084
obj = obj,
61-
"Successfully loaded model from {}",
85+
"Successfully loaded model from {} (debug=true)",
6286
model_path
6387
);
6488
*state.as_mut() = Some(model);
@@ -171,6 +195,7 @@ where
171195
None::<String>.to_value()
172196
}
173197
}
198+
"model-path-with-debug" => None::<String>.to_value(),
174199
"threshold" => {
175200
let state = state.lock().unwrap();
176201
if let Some(ref model) = *state.as_ref() {
@@ -200,6 +225,9 @@ where
200225
} => {
201226
format!("{}.threshold={}", id, threshold)
202227
}
228+
edge_impulse_runner::types::ModelThreshold::Unknown { id, unknown } => {
229+
format!("{}.unknown={}", id, unknown)
230+
}
203231
})
204232
.collect();
205233

src/video/imp.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,8 +258,18 @@ impl ObjectSubclass for EdgeImpulseVideoInfer {
258258

259259
impl ObjectImpl for EdgeImpulseVideoInfer {
260260
fn properties() -> &'static [glib::ParamSpec] {
261-
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> =
262-
Lazy::new(crate::common::create_common_properties);
261+
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
262+
let mut props = crate::common::create_common_properties();
263+
if !props.iter().any(|p| p.name() == "model-path-with-debug") {
264+
props.push(
265+
glib::ParamSpecString::builder("model-path-with-debug")
266+
.nick("Model Path With Debug")
267+
.blurb("Path to Edge Impulse model file (debug mode enabled)")
268+
.build(),
269+
);
270+
}
271+
props
272+
});
263273
PROPERTIES.as_ref()
264274
}
265275

0 commit comments

Comments
 (0)