@@ -69,6 +69,9 @@ pub struct InferenceConfig {
6969 /// Whether to use minimal padding (rectangular inference).
7070 /// Defaults to `true` to match Ultralytics Python.
7171 pub rect : bool ,
72+ /// Class IDs to filter predictions. If `None`, all classes are returned.
73+ /// Useful for focusing on specific objects in multi-class detection tasks.
74+ pub classes : Option < Vec < usize > > ,
7275}
7376
7477impl Default for InferenceConfig {
@@ -85,6 +88,7 @@ impl Default for InferenceConfig {
8588 save : Self :: DEFAULT_SAVE ,
8689 save_frames : Self :: DEFAULT_SAVE_FRAMES ,
8790 rect : Self :: DEFAULT_RECT ,
91+ classes : None ,
8892 }
8993 }
9094}
@@ -302,6 +306,47 @@ impl InferenceConfig {
302306 self . rect = rect;
303307 self
304308 }
309+
310+ /// Set the class IDs to filter predictions.
311+ ///
312+ /// Only detections belonging to the specified classes will be returned.
313+ ///
314+ /// # Arguments
315+ ///
316+ /// * `classes` - A vector of class IDs to keep.
317+ ///
318+ /// # Example
319+ ///
320+ /// ```rust
321+ /// use ultralytics_inference::InferenceConfig;
322+ ///
323+ /// // Only detect persons (class 0) and cars (class 2)
324+ /// let config = InferenceConfig::new()
325+ /// .with_classes(vec![0, 2]);
326+ /// ```
327+ ///
328+ /// # Returns
329+ ///
330+ /// * The modified `InferenceConfig`.
331+ #[ must_use]
332+ pub fn with_classes ( mut self , classes : Vec < usize > ) -> Self {
333+ self . classes = Some ( classes) ;
334+ self
335+ }
336+ /// Check if a class should be included in the results.
337+ ///
338+ /// # Arguments
339+ ///
340+ /// * `class_id` - The class index to check.
341+ ///
342+ /// # Returns
343+ ///
344+ /// * `true` if the class should be kept.
345+ /// * `false` if the class should be filtered out.
346+ #[ must_use]
347+ pub fn keep_class ( & self , class_id : usize ) -> bool {
348+ self . classes . as_ref ( ) . is_none_or ( |c| c. contains ( & class_id) )
349+ }
305350}
306351
307352#[ cfg( test) ]
@@ -331,4 +376,22 @@ mod tests {
331376 assert_eq ! ( config. imgsz, Some ( ( 640 , 640 ) ) ) ;
332377 assert_eq ! ( config. num_threads, 8 ) ;
333378 }
379+
380+ #[ test]
381+ fn test_keep_class ( ) {
382+ let config = InferenceConfig :: default ( ) ;
383+ // Default: no filtering -> keep all
384+ assert ! ( config. keep_class( 0 ) ) ;
385+ assert ! ( config. keep_class( 100 ) ) ;
386+
387+ let config_filtered = InferenceConfig :: new ( ) . with_classes ( vec ! [ 1 , 3 ] ) ;
388+ // Class 1 is in list -> keep
389+ assert ! ( config_filtered. keep_class( 1 ) ) ;
390+ // Class 3 is in list -> keep
391+ assert ! ( config_filtered. keep_class( 3 ) ) ;
392+ // Class 0 is NOT in list -> filter out (keep = false)
393+ assert ! ( !config_filtered. keep_class( 0 ) ) ;
394+ // Class 2 is NOT in list -> filter out (keep = false)
395+ assert ! ( !config_filtered. keep_class( 2 ) ) ;
396+ }
334397}
0 commit comments