@@ -208,6 +208,17 @@ impl YOLOModel {
208208 )
209209 } ) ;
210210
211+ // Check for dynamic input dimensions
212+ // Dimensions are typically [-1, 3, -1, -1] for dynamic batch/height/width
213+ // ort 2.0 returns Option<i64> (None means dynamic/unknown)
214+ let is_dynamic = input_info. is_some_and ( |i| {
215+ if let ValueType :: Tensor { shape, .. } = i. dtype ( ) {
216+ shape. iter ( ) . any ( |d| * d == -1 || * d == 0 )
217+ } else {
218+ false
219+ }
220+ } ) ;
221+
211222 // Use FP16 input if model tensor type requires it
212223 let fp16_input = model_input_fp16;
213224
@@ -217,14 +228,53 @@ impl YOLOModel {
217228 . map ( |o| o. name ( ) . to_string ( ) )
218229 . collect ( ) ;
219230
220- // Update config with model metadata if not overridden
221- // Sync half flag with model's half metadata (for display purposes)
231+ // Resolve image size
232+ // Priority:
233+ // 1. User config
234+ // 2. Model metadata
235+ // 3. Dynamic default (1024 for OBB, 640 for others)
236+ // 4. Static input shape
237+ // 5. Hard default (640)
238+ let resolved_imgsz = if let Some ( sz) = config. imgsz {
239+ sz
240+ } else if let Some ( sz) = metadata. imgsz {
241+ sz
242+ } else if is_dynamic {
243+ // Dynamic input without metadata -> apply robust defaults
244+ match metadata. task {
245+ Task :: Obb => ( 1024 , 1024 ) ,
246+ _ => ( 640 , 640 ) ,
247+ }
248+ } else {
249+ // Static input without metadata -> try to read from tensor shape
250+ // Typically [1, 3, H, W]
251+ input_info
252+ . and_then ( |i| {
253+ if let ValueType :: Tensor { shape, .. } = i. dtype ( ) {
254+ if shape. len ( ) == 4 && shape[ 2 ] > 0 && shape[ 3 ] > 0 {
255+ #[ allow( clippy:: cast_sign_loss) ]
256+ Some ( ( shape[ 2 ] as usize , shape[ 3 ] as usize ) )
257+ } else {
258+ None
259+ }
260+ } else {
261+ None
262+ }
263+ } )
264+ . unwrap_or ( ( 640 , 640 ) )
265+ } ;
266+
267+ // Update config with resolved values
222268 let config = InferenceConfig {
223- imgsz : config . imgsz . or ( Some ( metadata . imgsz ) ) ,
269+ imgsz : Some ( resolved_imgsz ) ,
224270 half : config. half || metadata. half , // Use half if user requested OR model was exported with half
225271 ..config
226272 } ;
227273
274+ // Ensure metadata reflects the resolved size
275+ let mut metadata = metadata;
276+ metadata. imgsz = Some ( resolved_imgsz) ;
277+
228278 let mut model = Self {
229279 session,
230280 metadata,
@@ -253,7 +303,11 @@ impl YOLOModel {
253303 return Ok ( ( ) ) ;
254304 }
255305
256- let target_size = self . config . imgsz . unwrap_or ( self . metadata . imgsz ) ;
306+ let target_size = self
307+ . config
308+ . imgsz
309+ . or ( self . metadata . imgsz )
310+ . unwrap_or ( ( 640 , 640 ) ) ;
257311
258312 // Sanity check to prevent huge allocations from invalid imgsz
259313 if target_size. 0 > Self :: MAX_IMGSZ || target_size. 1 > Self :: MAX_IMGSZ {
@@ -379,7 +433,11 @@ impl YOLOModel {
379433 /// Vector of Results.
380434 pub fn predict_image ( & mut self , image : & DynamicImage , path : String ) -> Result < Vec < Results > > {
381435 // Get target size from config or metadata
382- let target_size = self . config . imgsz . unwrap_or ( self . metadata . imgsz ) ;
436+ let target_size = self
437+ . config
438+ . imgsz
439+ . or ( self . metadata . imgsz )
440+ . unwrap_or ( ( 640 , 640 ) ) ;
383441
384442 // Preprocess - generate FP16 tensor if model expects FP16 input
385443 let start_preprocess = Instant :: now ( ) ;
@@ -595,8 +653,8 @@ impl YOLOModel {
595653
596654 /// Get the model's input size.
597655 #[ must_use]
598- pub const fn imgsz ( & self ) -> ( usize , usize ) {
599- self . metadata . imgsz
656+ pub fn imgsz ( & self ) -> ( usize , usize ) {
657+ self . metadata . imgsz . unwrap_or ( ( 640 , 640 ) )
600658 }
601659
602660 /// Get the model's stride.
0 commit comments