1#![warn(missing_docs)]
55#![allow(clippy::module_name_repetitions)]
56#![allow(clippy::similar_names)]
57#![allow(clippy::cast_possible_truncation)]
58#![allow(clippy::cast_sign_loss)]
59#![allow(clippy::cast_precision_loss)]
60#![allow(clippy::cast_lossless)]
61#![allow(clippy::cast_possible_wrap)]
62#![allow(clippy::many_single_char_names)]
63#![allow(clippy::too_many_lines)]
64#![allow(clippy::needless_range_loop)]
65#![allow(clippy::missing_panics_doc)]
66#![allow(clippy::unused_self)]
67#![allow(clippy::items_after_statements)]
68#![allow(clippy::manual_memcpy)]
69#![allow(clippy::unnecessary_wraps)]
70#![allow(clippy::trivially_copy_pass_by_ref)]
71#![allow(clippy::single_match_else)]
72#![allow(clippy::must_use_candidate)]
73#![allow(clippy::missing_errors_doc)]
74#![allow(clippy::manual_swap)]
75#![allow(clippy::doc_markdown)]
76#![allow(dead_code)]
77
78pub mod action_beat;
79pub mod activity;
80pub mod adaptive_scene;
81pub mod aesthetic;
82pub mod audio_visual_correlation;
83#[path = "camera_motion/mod.rs"]
84pub mod camera_motion;
85pub mod classification;
86pub mod classify;
87pub mod color_temperature;
88pub mod complexity_detector;
89pub mod composition;
90pub mod content_moderation;
91pub mod continuity_check;
92pub mod crowd_density;
93pub mod depth_of_field;
94pub mod detect;
95pub mod emotion_recognition;
96pub mod error;
97pub mod event;
98pub mod face_landmark;
99pub mod features;
100pub mod lighting_analysis;
101pub mod location;
102#[cfg(feature = "onnx")]
103pub mod ml;
104pub mod mood;
105pub mod motion_energy;
106pub mod object_tracker;
107pub mod pacing;
108pub mod saliency;
109pub mod scene_boundary;
110pub mod scene_captioning;
111pub mod scene_graph;
112pub mod scene_metadata;
113pub mod scene_score;
114pub mod scene_stats;
115pub mod scene_tags;
116pub mod segment;
117pub mod segmentation;
118pub mod shot_type;
119pub mod storyboard;
120pub mod summarization;
121pub mod temporal_graph;
122pub mod text_detect;
123pub mod thumbnail_selector;
124pub mod transition;
125pub mod visual_quality_map;
126pub mod visual_rhythm;
127
128pub use error::{SceneError, SceneResult};
130
131#[cfg(feature = "onnx")]
132pub use ml::MlSceneEnricher;
133
134pub mod common {
136 use serde::{Deserialize, Serialize};
137
138 #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
140 pub struct Point {
141 pub x: f32,
143 pub y: f32,
145 }
146
147 impl Point {
148 #[must_use]
150 pub const fn new(x: f32, y: f32) -> Self {
151 Self { x, y }
152 }
153
154 #[must_use]
156 pub fn distance(&self, other: &Self) -> f32 {
157 let dx = self.x - other.x;
158 let dy = self.y - other.y;
159 (dx * dx + dy * dy).sqrt()
160 }
161 }
162
163 #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
165 pub struct Rect {
166 pub x: f32,
168 pub y: f32,
170 pub width: f32,
172 pub height: f32,
174 }
175
176 impl Rect {
177 #[must_use]
179 pub const fn new(x: f32, y: f32, width: f32, height: f32) -> Self {
180 Self {
181 x,
182 y,
183 width,
184 height,
185 }
186 }
187
188 #[must_use]
190 pub const fn area(&self) -> f32 {
191 self.width * self.height
192 }
193
194 #[must_use]
196 pub const fn center(&self) -> Point {
197 Point {
198 x: self.x + self.width / 2.0,
199 y: self.y + self.height / 2.0,
200 }
201 }
202
203 #[must_use]
205 pub const fn contains(&self, point: &Point) -> bool {
206 point.x >= self.x
207 && point.x <= self.x + self.width
208 && point.y >= self.y
209 && point.y <= self.y + self.height
210 }
211
212 #[must_use]
214 pub fn iou(&self, other: &Self) -> f32 {
215 let x1 = self.x.max(other.x);
216 let y1 = self.y.max(other.y);
217 let x2 = (self.x + self.width).min(other.x + other.width);
218 let y2 = (self.y + self.height).min(other.y + other.height);
219
220 if x2 <= x1 || y2 <= y1 {
221 return 0.0;
222 }
223
224 let intersection = (x2 - x1) * (y2 - y1);
225 let union = self.area() + other.area() - intersection;
226
227 if union == 0.0 {
228 0.0
229 } else {
230 intersection / union
231 }
232 }
233 }
234
235 #[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Serialize, Deserialize)]
237 pub struct Confidence(f32);
238
239 impl Confidence {
240 #[must_use]
242 pub fn new(value: f32) -> Self {
243 Self(value.clamp(0.0, 1.0))
244 }
245
246 #[must_use]
248 pub const fn value(&self) -> f32 {
249 self.0
250 }
251
252 #[must_use]
254 pub const fn meets_threshold(&self, threshold: f32) -> bool {
255 self.0 >= threshold
256 }
257 }
258
259 impl From<f32> for Confidence {
260 fn from(value: f32) -> Self {
261 Self::new(value)
262 }
263 }
264
265 impl From<Confidence> for f32 {
266 fn from(conf: Confidence) -> Self {
267 conf.0
268 }
269 }
270}
271
272#[cfg(test)]
273mod tests {
274 use super::common::*;
275
276 #[test]
277 fn test_point_distance() {
278 let p1 = Point::new(0.0, 0.0);
279 let p2 = Point::new(3.0, 4.0);
280 assert!((p1.distance(&p2) - 5.0).abs() < f32::EPSILON);
281 }
282
283 #[test]
284 fn test_rect_area() {
285 let rect = Rect::new(0.0, 0.0, 10.0, 20.0);
286 assert!((rect.area() - 200.0).abs() < f32::EPSILON);
287 }
288
289 #[test]
290 fn test_rect_center() {
291 let rect = Rect::new(0.0, 0.0, 10.0, 20.0);
292 let center = rect.center();
293 assert!((center.x - 5.0).abs() < f32::EPSILON);
294 assert!((center.y - 10.0).abs() < f32::EPSILON);
295 }
296
297 #[test]
298 fn test_rect_contains() {
299 let rect = Rect::new(0.0, 0.0, 10.0, 20.0);
300 assert!(rect.contains(&Point::new(5.0, 10.0)));
301 assert!(!rect.contains(&Point::new(15.0, 10.0)));
302 }
303
304 #[test]
305 fn test_rect_iou() {
306 let rect1 = Rect::new(0.0, 0.0, 10.0, 10.0);
307 let rect2 = Rect::new(5.0, 5.0, 10.0, 10.0);
308 let iou = rect1.iou(&rect2);
309 assert!((iou - 0.1428571).abs() < 0.001);
313 }
314
315 #[test]
316 fn test_confidence() {
317 let conf = Confidence::new(0.75);
318 assert!((conf.value() - 0.75).abs() < f32::EPSILON);
319 assert!(conf.meets_threshold(0.5));
320 assert!(!conf.meets_threshold(0.8));
321
322 let conf_high = Confidence::new(1.5);
324 assert!((conf_high.value() - 1.0).abs() < f32::EPSILON);
325
326 let conf_low = Confidence::new(-0.5);
327 assert!((conf_low.value() - 0.0).abs() < f32::EPSILON);
328 }
329}