- 
          
 - 
                Notifications
    
You must be signed in to change notification settings  - Fork 1.9k
 
refactor #2167
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
refactor #2167
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR refactors the BoxMOT detector interface by introducing a standardized, modular architecture with a unified Detector base class. The changes replace model-specific "strategy" classes with dedicated detector implementations that follow a consistent preprocess → process → postprocess pipeline.
- Introduces a new 
Detectorbase class providing a unified interface across all detector types - Migrates YOLOX, Ultralytics, and RF-DETR to the new architecture with standalone detector classes
 - Maintains backward compatibility through legacy interface functions while deprecating the old strategy pattern
 
Reviewed Changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description | 
|---|---|
| boxmot/engine/detectors/base.py | New base class implementing the detector interface with resolve_image utility | 
| boxmot/engine/detectors/yolox_detector.py | New YOLOX detector implementation replacing YoloXStrategy | 
| boxmot/engine/detectors/ultralytics_detector.py | New Ultralytics detector implementation replacing UltralyticsStrategy | 
| boxmot/engine/detectors/rfdetr_detector.py | New RF-DETR detector implementation replacing RFDETRStrategy | 
| boxmot/engine/detectors/init.py | Updated to export new detector classes while maintaining legacy interface | 
| boxmot/engine/detectors/yolox.py | Removed old YoloXStrategy implementation | 
| boxmot/engine/detectors/rfdetr.py | Removed old RFDETRStrategy implementation | 
| boxmot/engine/detectors/yolo_interface.py | Removed old YoloInterface abstract base class | 
| boxmot/engine/detectors/README.md | Comprehensive documentation for the new interface | 
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| """Determine YOLOX model type from filename.""" | ||
| for key in YOLOX_ZOO.keys(): | ||
| if Path(key).stem in str(path.name): | ||
| return str(Path(key).with_suffix("")) | 
    
      
    
      Copilot
AI
    
    
    
      Oct 30, 2025 
    
  
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The call to Path(key).with_suffix('') is redundant. Since key already has .pt extension and we're extracting the stem, this can be simplified to return Path(key).stem which is clearer and more direct.
| return str(Path(key).with_suffix("")) | |
| return Path(key).stem | 
| self.imgsz = [imgsz, imgsz] | ||
| else: | ||
| vals = imgsz if isinstance(imgsz, (list, tuple)) else (imgsz,) | ||
| w, h = (vals * 2)[:2] | 
    
      
    
      Copilot
AI
    
    
    
      Oct 30, 2025 
    
  
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When imgsz is already a list/tuple with 2 elements, the expression (vals * 2)[:2] will unnecessarily duplicate and then slice. For example, if vals = [640, 480], this produces [640, 480, 640, 480][:2] = [640, 480]. While the result is correct, if vals has only 1 element like (640,), the result is [640, 640]. Consider using w, h = (list(vals) + list(vals))[:2] or better yet, check the length explicitly for clarity: w, h = (vals[0], vals[1]) if len(vals) >= 2 else (vals[0], vals[0]).
| w, h = (vals * 2)[:2] | |
| w, h = (vals[0], vals[1]) if len(vals) >= 2 else (vals[0], vals[0]) | 
| self.imgsz = imgsz | ||
| else: | ||
| vals = imgsz if isinstance(imgsz, (list, tuple)) else (imgsz,) | ||
| self.imgsz = vals[0] # Ultralytics uses single value | 
    
      
    
      Copilot
AI
    
    
    
      Oct 30, 2025 
    
  
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code will raise an IndexError if imgsz is an empty list or tuple. Add a check: self.imgsz = vals[0] if vals else 640 or validate that vals is non-empty before accessing vals[0].
| self.imgsz = vals[0] # Ultralytics uses single value | |
| self.imgsz = vals[0] if vals else 640 # Ultralytics uses single value, default to 640 if empty | 
| def _get_model_type(self, path: Path): | ||
| """Determine YOLOX model type from filename.""" | ||
| for key in YOLOX_ZOO.keys(): | ||
| if Path(key).stem in str(path.name): | 
    
      
    
      Copilot
AI
    
    
    
      Oct 30, 2025 
    
  
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Converting path.name to string is unnecessary since path.name is already a string. Simplify to if Path(key).stem in path.name:.
| if Path(key).stem in str(path.name): | |
| if Path(key).stem in path.name: | 
| 
               | 
          ||
| ## Examples | ||
| 
               | 
          ||
| See `examples/detector_usage_example.py` for complete working examples including: | 
    
      
    
      Copilot
AI
    
    
    
      Oct 30, 2025 
    
  
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The documentation references examples/detector_usage_example.py but this file is not included in the PR changes. Verify that this example file exists or will be added, otherwise users following the documentation may encounter a broken reference.
        
          
                boxmot/engine/detectors/rfdetr.py
              
                Outdated
          
        
      | from typing import Union | ||
| 
               | 
          
    
      
    
      Copilot
AI
    
    
    
      Oct 30, 2025 
    
  
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Import of 'Union' is not used.
| from typing import Union | 
        
          
                boxmot/engine/detectors/rfdetr.py
              
                Outdated
          
        
      | from rfdetr.util.coco_classes import COCO_CLASSES | ||
| RFDETR_AVAILABLE = True | ||
| except ImportError: | ||
| RFDETR_AVAILABLE = False | ||
| COCO_CLASSES = {} | 
    
      
    
      Copilot
AI
    
    
    
      Oct 30, 2025 
    
  
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Import of 'COCO_CLASSES' is not used.
| from rfdetr.util.coco_classes import COCO_CLASSES | |
| RFDETR_AVAILABLE = True | |
| except ImportError: | |
| RFDETR_AVAILABLE = False | |
| COCO_CLASSES = {} | |
| RFDETR_AVAILABLE = True | |
| except ImportError: | |
| RFDETR_AVAILABLE = False | 
No description provided.