
    {i                    8   d Z ddlZddlZddlZddlmZmZmZ ddl	Z	ddl
Z
ddlZddlmZ ddlmZ ddlZddlZddlZddlZddlmZ ddlmZ ddlZddlmZmZ ddlZddl	Z		 ddlmZ d	Z G d d      Zddedede de!de"f
dZ#ddede de!fdZ$y# e$ r d
ZY .w xY w)u0   
PyCV基础类 - 图像处理功能的基础类
    N)DictAnyOptional)Path)datetime)ImageThreadPoolExecutoras_completedYOLOTFc                   d   e Zd ZdZddedefdZdefdZddedefd	Zd
ede	eef   fdZ
d
edefdZd
edefdZd
edefdZdedefdZd Zd Zd ZdedefdZddedefdZdedefdZdd
ededefdZdefdZd ZdedefdZddefdZd Zd
edefd Zdd
ed!edefd"Zdedefd#Zd$ Z d% Z!de"ee#f   fd&Z$dd'e%jL                  d(ede%jL                  fd)Z'd'e%jL                  de#fd*Z(d'e%jL                  de#fd+Z)d'e%jL                  d,e*d-ede#fd.Z+d'e%jL                  d,e*fd/Z,d'e%jL                  d,e*fd0Z-dd'e%jL                  d(ede%jL                  fd1Z.d2 Z/d3 Z0d4 Z1dd5Z2d6 Z3d7 Z4d8edefd9Z5dd:e%jL                  d;ede6fd<Z7d=edefd>Z8d?e6defd@Z9d?e6defdAZ:de*fdBZ;dC Z<defdDZ=dedefdEZ>defdFZ?dGedefdHZ@defdIZAdefdJZBdefdKZCdefdLZDdefdMZEdNede*fdOZFddNedPe6defdQZGdRedPe6defdSZHdTe*dUe*de6fdVZIdWede*fdXZJddNedPe6de	eef   fdYZKd'e%jL                  dZede%jL                  fd[ZLd'e%jL                  dZefd\ZMdd]e*d^edefd_ZNd]e*d`e*de*fdaZOddbe%jL                  dce*dde*d^edee%jL                  de*fdfZPdd'e%jL                  d]e*dgedhe6ddf
diZQdGede*fdjZRdke	dledmede	fdnZSdoe*de*fdpZTd'e%jL                  dqedre*fdsZUdd'e%jL                  dqedre*dte6fduZVd'e%jL                  dqedre*fdvZWd'e%jL                  dqedre*fdwZXd'e%jL                  dqedre*fdxZYdd'e%jL                  dqedre*dte6fdyZZdd'e%jL                  dqedre*dte6fdzZ[doe*de*fd{ZTd'e%jL                  d|e	d}e	d~e	def
dZ\d'e%jL                  d]e*dre*fdZ]d'e%jL                  dede	dre*fdZ^dde*de*dede*fdZ_y)yolo_model_loderu:   YOLO模型加载器类，使用纯ONNX Runtime进行推理Ndeviceverbosec                 0   d| _         d| _        d| _        | j                  |      | _        d| _        d| _        d| _        d| _        d| _	        ddi| _
        d| _        d| _        d| _        g | _        d| _        d| _        d| _        d| _        i | _        y)	u   
        初始化模型加载器
        Args:
            device: 设备选择，可选 'cpu', 'cuda', 'auto'。默认为自动选择
            verbose: 是否显示详细日志信息，默认为True
        NFdetectonnx  r   Class0      ?)sessionmodel
model_path_select_devicer   is_model_loadedmodel_load_error
model_typemodel_format
input_sizeclass_namesr   usr_class_name
input_nameoutput_namesinput_shapeis_warmed_upuse_independent_confglobal_confclass_conf_thresholds)selfr   r   s      *   D:\pyccd\极耳翻折\utils\model_utils.py__init__zyolo_model_loder.__init__=   s     
))&1$ $""x=" ! %*!%'"    messagec                 4    | j                   rt        |       yy)uZ   
        内部日志输出方法
        Args:
            message: 日志消息
        N)r   print)r*   r.   s     r+   _logzyolo_model_loder._log\   s     <<'N r-   returnc                     |dk(  ry|r|j                  d      r|S |r|j                         rd| S t        j                  j	                         ryy)u   
        自动选择设备
        Args:
            device: 指定设备，可选 'cpu', 'cuda', 'auto' 或具体的GPU编号如 '0', '1'
        Returns:
            选择的设备字符串
        cpucudacuda:cuda:0)
startswithisdigittorchr5   is_available)r*   r   s     r+   r   zyolo_model_loder._select_devicee   sT     U?))&1M(6(## zz&&(r-   r   c                     |syt        |      }|j                         sdd| fS h d}|j                  j                         |vrdd|j                   d| fS y)u   
        验证模型路径和格式
        Args:
            model_path: 模型文件路径
        Returns:
            (是否有效, 错误信息)
        )Fu   模型路径不能为空Fu   模型文件不存在: >   .engine.torchscript.pt.onnx   不支持的模型格式: u   ，支持的格式: )T )r   existssuffixlower)r*   r   supported_formatss      r+   _validate_model_pathz%yolo_model_loder._validate_model_pathz   sz     4*%
  "3J<@@@ H""$,==6z7H7H6II]^o]pqqqr-   c                    	 | j                  |      \  }}|s|| _        y| j                  r-| j                  t	        |      k(  r| j                  d|        y| j                          t        |      j                  j                         }| j                  d|        | j                  d|        |dk(  r | j                  |fi |S |dk(  r | j                  |fi |S d| d	| _        | j                  | j                         y# t        $ rF}d
t	        |       | _        | j                  | j                         d| _        d| _        Y d}~yd}~ww xY w)ub  
        从路径加载YOLO模型，根据文件后缀选择加载方式
        - .onnx 文件使用 onnxruntime 直接加载
        - .pt 文件使用 ultralytics YOLO 加载
        Args:
            model_path: 模型文件路径
            **kwargs: 其他参数，如 imgsz, conf, iou 等
        Returns:
            是否加载成功
        Fu    模型已加载，路径相同: T   正在加载模型:    检测到文件格式: r@   r?   rA      ，仅支持 .onnx 和 .pt   模型加载失败: N)rG   r   r   r   strr1   unload_modelr   rD   rE   _load_onnx_model_load_pytorch_model	Exceptionr   )r*   r   kwargsis_valid	error_msgfile_extes          r+   load_from_pathzyolo_model_loder.load_from_path   s[   #	"&";";J"GHi(1% $$3z?2		<ZLIJ J'..446HII,ZL9:II/z:; 7",t,,ZB6BBU"/t//
EfEE*DXJNh(i%		$//0 	&:3q6($CD!IId++,DL#(D 	s/   D 8D A2D D $&D 	E<EEc                    	 ddl }| j                  d       | j                  | j                        }t	        j                         }|j                  ||      | _        t	        j                         |z
  }| j                          t        |      | _	        d| _
        d| _        d| _        | j                  d|dd	       | j                  d
| j                          | j                  d| j                          | j                  dt        | j                                 | j#                          y# t$        $ rM}dt        |       | _        | j                  | j                         d| _        d| _        d| _	        Y d}~yd}~ww xY w)u(   使用ONNX Runtime直接加载ONNX模型r   Nu3   🔄 ONNX模型：使用ONNX Runtime直接加载...)	providersr   Tu%   ✅ ONNX模型加载完成，耗时: .2f   秒u     输入名称: u     输入形状: u     输出数量: u   ONNX模型加载失败: F)onnxruntimer1   _get_onnx_providersr   timeInferenceSessionr   _extract_onnx_model_inforM   r   r   r   r   r#   r%   lenr$   _warmup_onnx_modelrQ   )r*   r   rR   ortrY   
start_time	load_timerV   s           r+   rO   z!yolo_model_loder._load_onnx_model   s_   '	%IIKL 00=I J//
i/PDL		j0I ))+ "*oDO &D#'D $(D!II=i_CPQII((9:;II()9)9(:;<II(T->->)?(@AB ##% 	&>s1vh$GD!IId++,DL#(D "DO	s   D1D4 4	F
=AFF
c                    	 t         sd| _        y| j                  d       ddlm} t        j
                         } ||d      | _        t        j
                         |z
  }t        | j                  d      r%| j                  j                  | j                         t        |      | _        d	| _        	 | j                          d| _        d| _        | j                  d|dd       | j                  d| j                          | j                  d| j                           | j                  d| j"                  rt'        | j"                        nd        y# t        $ r5}| j                  d
|        d| _        d| _        ddi| _        Y d}~d}~ww xY w# t        $ r8}dt        |       | _        | j                  | j                         Y d}~yd}~ww xY w)u)   使用ultralytics YOLO加载PyTorch模型<   ultralytics库未安装，请安装: pip install ultralyticsFu4   🔄 PyTorch模型：使用ultralytics YOLO加载...r   r   r   )tasktoptu:   ⚠️ 提取PyTorch模型信息失败，使用默认值: r   r   NTu(   ✅ PyTorch模型加载完成，耗时: rZ   r[   u
     类型: u     输入尺寸: u     类别数: Unknownu   PyTorch模型加载失败: )ULTRALYTICS_AVAILABLEr   r1   ultralyticsr   r^   r   hasattrri   r   rM   r   r   _extract_pytorch_model_inforQ   r   r    r!   r   ra   )r*   r   rR   r   rd   re   rV   s          r+   rP   z$yolo_model_loder._load_pytorch_model   s   ,	((f%IILM )Jjx8DJ		j0I tzz4(

dkk* "*oDO $D1002 $(D $(D!II@3sSTII
4??"345II((9:;IIt?O?Oc$*:*:&;U^%_`a  1		VWXVYZ["*"%$%x=  	1   	&A#a&$JD!IId++,	sH   F B#F 4E BF 	F#+FF FF 	G$.GGtarget_devicec                 6   	 |dk(  rddddfg}| j                  d       |S t        j                  j                         s"| j                  d       | j	                  d      S d}d	|v r	 t        |j                  d	      d
         }|t        j                  j                         k\  r| j                  d| d       d}|dddd}d|fdg}| j                  d|        t        j                  j                         rdt        j                  j                  |      }t        j                  j                  |      j                  dz  }| j                  d| d|dd       |S #  d}Y xY w# t        $ r#}| j                  d|        di fgcY d}~S d}~ww xY w)u'   获取ONNX Runtime执行提供者配置r4   CPUExecutionProvider      intra_op_num_threadsinter_op_num_threadsu"   🔧 配置ONNX CPU执行提供者#   ⚠️ CUDA不可用，回退到CPUr   :      ⚠️ GPU     不存在，使用GPU 0kSameAsRequested	HEURISTICT	device_idarena_extend_strategycudnn_conv_algo_searchdo_copy_in_default_streamCUDAExecutionProvideru)   🔧 配置ONNX CUDA执行提供者: GPU=   @u      GPU设备:  (.1fGB)u.   ⚠️ 配置ONNX提供者失败，使用CPU: N)r1   r:   r5   r;   r]   intsplitdevice_countget_device_nameget_device_propertiestotal_memoryrQ   )r*   rp   rY   gpu_idcuda_provider_optionsgpu_name
gpu_memoryrV   s           r+   r]   z$yolo_model_loder._get_onnx_providers  s   4	2%4,-,-7  	 		>?T M zz..0IICD33E:: -'#!$]%8%8%=a%@!A
 UZZ4466IIF83KLMF "(-?.915	)% -.CD*	
 		EfXNO ::**,$zz99&AH!&!A!A&!I!V!VZa!bJIIxj:c:J#NO;#!"<  	2IIFqcJK+R011	2sA   E, ?E, "E, )E# CE, #E)'E, ,	F5FFFc                    | j                   sy| j                   j                         d   }|j                  | _        |j                  | _        | j
                  r,t        | j
                        dk\  r| j
                  d   | _        | j                   j                         D cg c]  }|j                   c}| _	        ddi| _
        d| _        yc c}w )u   提取ONNX模型信息Nr   rs   r   r   )r   
get_inputsnamer#   shaper%   ra   r    get_outputsr$   r!   r   )r*   
input_infooutputs      r+   r`   z)yolo_model_loder._extract_onnx_model_infoS  s    || \\,,.q1
$//%++ D$4$4 5 :"..r2DO 8<||7O7O7QR7QVV[[7QR x="	 Ss   !Cc                    | j                   syt        | j                   d      rt        | j                   j                   d      r1t        | j                   j                   j                  dd      | _        nft        | j                   j                   d      rF| j                   j                   j
                  }t        |t              rd|v r|d   | _        nd| _        t        | j                   d      r#| j                   j                  | _	        d| _
        yt        | j                   d      rEt        | j                   j                   d      r%| j                   j                   j                  | _	        d| _
        y)	u   提取PyTorch模型信息Nr   argsimgszr   yamlnamesr   )r   rn   getattrr   r    r   
isinstancedictr   r!   r   )r*   	yaml_dicts     r+   ro   z,yolo_model_loder._extract_pytorch_model_infoh  s
   zz 4::w'tzz''0")$***:*:*?*?#"N))62 JJ,,11	i.7i3G&/&8DO&)DO 4::w'#zz//D # TZZ)gdjj6F6F.P#zz//55D"r-   c                 .   | j                   r| j                  ry	 | j                  rg }| j                  D ]:  }t        |t              s|dk(  r|j                  d       *|j                  |       < t        j                  j                  | j                  t        j                        }| j                   j                  d| j                  |i       d| _        | j                  d       yy# t        $ r}| j                  d|        Y d}~yd}~ww xY w)u   预热ONNX模型Nr   rz   Tu   🔥 ONNX模型预热完成   ⚠️ ONNX模型预热失败: r   r&   r%   r   rM   appendnprandomrandastypefloat32runr#   r1   rQ   r*   r   dimdummy_inputrV   s        r+   rb   z#yolo_model_loder._warmup_onnx_model      ||t00	=++C!#s+sbyQS)	 , !iinne4;;BJJG   'EF$(!		78    	=II7s;<<	=   CC- -	D6DDc                    	 ddl }|dk(  r#ddd}d|fg}| j                  rt        d       |S t        j                  j                         s(| j                  rt        d	       | j                  d      S d}d
|v r	 t        |j                  d
      d         }|t        j                  j                         k\  r| j                  rt        d| d       d}|dddd}d|fdg}| j                  rt        d|        t        d|        t        j                  j                         r^t        j                  j                  |      }t        j                  j                  |      j                  dz  }t        d| d|dd       |S #  d}Y xY w# t        $ r | j                  rt        d       Y yt        $ r-}	| j                  rt        dt        |	              Y d}	~	yd}	~	ww xY w)uW   为指定设备优化ONNX Runtime执行提供者配置 - 按测试程序的可靠模式r   Nr4   rs   rt   ru   rr   u"   🚀 配置ONNX CPU执行提供者rx   ry   rz   r{   r|   kNextPowerOfTwo
EXHAUSTIVETr   r   u)   🚀 配置ONNX CUDA执行提供者: GPU=u      CUDA提供者device_id: r   u      GPU信息: r   r   r   3   ⚠️ 无法导入onnxruntime，使用默认配置u(   ⚠️ 配置ONNX执行提供者失败: )r\   r   r0   r:   r5   r;   #_optimize_onnx_providers_for_devicer   r   r   r   r   r   ImportErrorrQ   rM   )
r*   rp   rc   cpu_provider_optionsrY   r   r   r   r   rV   s
             r+   r   z4yolo_model_loder._optimize_onnx_providers_for_device  s   D	%% -.,-($
 56JKL	<<>@\ U zz..0||CDCCEJJ -'#!$]%8%8%=a%@!A
 UZZ4466||F83KLMF "(->.:15	)% -.CD*	
 <<EfXNO7x@A zz..0#(::#=#=f#E%*ZZ%E%Ef%M%Z%Z^e%f
xj:c:J#NOA#!"B  	||KL 	||@QIJ	sB   +F AF 4F ;F	 C0F 	FF  G)4G)<#G$$G)warmup_runsc                    	 | j                   rDt        | j                   d      r,| j                  rt        d| d       t        j
                  j                  dddt        j                        }g }t        |      D ]  }t        j                         }| j                   j                  |ddd	|
      }t        j                         |z
  }|j                  |       |dk(  se| j                  srt        d|dd        t        |      dkD  r9t        |dd       t        |dd       z  }	| j                  rt        d|	dd       d| _        yyy# t         $ r)}
| j                  rt        d|
        Y d}
~
yY d}
~
yd}
~
ww xY w)u"   在指定设备上预热ONNX模型predictu   🔥 在设备 u    上预热ONNX模型...r         r      dtypeF      ?r   saveconfr         首次预热: .3fr[   rz   Nu%   ✅ ONNX预热完成，平均时间: Tr   )r   rn   r   r0   r   r   randintuint8ranger^   perf_counterr   r   ra   sumr&   rQ   )r*   rp   r   r   warmup_timesird   _warmup_timeavg_warmup_timerV   s              r+   _warmup_onnx_model_on_devicez-yolo_model_loder._warmup_onnx_model_on_device  sz   %	=zzgdjj)<<<OM?:QRS !ii//3RXX/V!{+A!%!2!2!4J 

**# %" , + A #'"3"3"5
"BK ''4Av<<!$5k#5Fc"JK# ,& |$q(&),qr*:&;c,qrBR>S&SO|| EoVYEZZ]^_$(!A =zD  	=||7s;<< 	=s%   C!E $E 1A E 	FFFexpected_devicec           	         	 | j                   dk(  r| j                  sy| j                   dk7  rt        | d      syt        j                  j                  dddt        j                        }t        j                         }| j                   dk(  r| j                  ||d      }n| j                  j                  ||dd	      }t        j                         |z
  }|d
u}| j                  r)|dk(  rdnd| d}|rdnd}t        d| d| d|dd       |S # t        $ r-}	| j                  rt        dt        |	              Y d
}	~	yd
}	~	ww xY w)u.   验证ONNX模型是否在期望设备上运行r   Fr   r   r   r   r   )r   r   )r   r   r   Nr4   CPUzGPU ()u   ✅ 运行正常u   ❌ 运行异常u   🔍 ONNX设备验证:  - u
   , 耗时: r   r[   u   ❌ ONNX设备验证失败: )r   r   rn   r   r   r   r   r^   r   	predictExr   r   r   r0   rQ   rM   )
r*   r   
test_inputrd   resultinference_timesuccessdevice_typestatusrV   s
             r+   _verify_onnx_device_usagez*yolo_model_loder._verify_onnx_device_usage  sX   (	  F*4<<""f,WT75K **1c=*QJ**,J   F*
?TYZ ++*!	 ,  "..0:=N D(G||'6%'?eu_L]]^E_/6+<N/}CxzR`adQeehijN 	||4SVH=>	s"   D D CD 	E
#EE
force_devicec                    	 t         sd| _        y| j                  |      \  }}|s|| _        y| j                  }| j                  }||j	                         dk(  rd}| j                  d       no|j	                         dk(  rHt        j                  j                         rd}| j                  d       n)| j                  d	       d}n|j	                         j                  d
      r|j                  d      d   }t        j                  j                         r]t        |      t        j                  j                         k  r3|j	                         }| j                  d|        t        d|        nf| j                  d| d       d}nN|j	                         dk(  r&| j                  d      }| j                  d|        n| j                  d| d       || _        | j                  r{| j                   t#        |      k(  rc| j                  |k(  rTt%        | d      xr | j&                  duxs t%        | d      xr | j(                  du}	|	r| j                  d| d|        y| j+                          | j                  d|        | j                  d|        t-        |      j.                  j	                         }
| j                  d|
        |
dk(  r | j0                  |fi |}n@|
dk(  r | j2                  |fi |}n'd|
 d| _        | j                  | j                         y|s|| _        y| j                  d        | j                  d!| j                           | j                  d"| j                          | j                  d#| j4                          | j                  d$| j6                          | j                  d%| j8                          | j                  d&| j:                  rt=        | j:                        nd'        y# t>        $ rB}| _        d(t#        |       | _        | j                  d)| j                          Y d}~yd}~ww xY w)*u(  
        从路径加载YOLO模型，支持强制指定设备
        Args:
            model_path: 模型文件路径
            force_device: 强制指定设备，可选值：
                - 'cpu': 强制使用CPU
                - 'cuda': 使用第一个GPU
                - 'cuda:0', 'cuda:1': 指定具体GPU
                - 'auto': 自动选择（默认行为）
                - None: 使用初始化时的设备设置
            **kwargs: 其他参数，如 imgsz, conf, iou 等
        Returns:
            是否加载成功
        rg   FNr4   u   🔧 强制使用CPU设备r5   r7   u   🔧 强制使用GPU: cuda:0rx   r6   ry   rz   u   🔧 强制使用GPU: r{   u    不可用，回退到CPUautou   🔧 自动选择设备: u   ⚠️ 无效的设备参数 'u   '，使用默认设备r   r   u)   模型已加载，路径和设备相同:  -> TrI   u   目标设备: rJ   r@   r?   rA   rK   u   ✅ 模型加载成功:u      路径: u      设备: u      类型: u      格式: u      输入尺寸: u      类别数: rk   rL      ❌ ) rl   r   rG   r   rE   r1   r:   r5   r;   r8   r   r   r   r0   r   r   r   rM   rn   r   r   rN   r   rD   rO   rP   r   r   r    r!   ra   rQ   )r*   r   r   rR   rS   rT   original_devicerp   r   model_existsrU   r   rV   s                r+   load_from_path_with_devicez+yolo_model_loder.load_from_path_with_device7  s   a	((f% #'";";J"GHi(1% #kkO KKM'%%'50$)MII :<!'')V3zz..0(0		$@B		$GI(-!'')44W=)//4Q7Fzz..0S[5::CZCZC\5\(4(:(:(<		$:=/"JK 6}oFG		K~=V"WX(-!'')V3$($7$7$?MII 9-IJII >|nLbcd (DK $$3z?2}, 'g 6 Q4::T;Q  V&tY7TDLLPT<T II I*UYZgYhij  II,ZL9:II}o67 J'..446HII/z:; 7"/$//
EfEU"2$22:HH*DXJNh(i%		$//0-II/1IIDOO#456IIDKK=12IIDOO#456IID$5$5#678II)$//):;<II@P@Ps4+;+;'<V_&`ab 	)DK&:3q6($CD!IIT22345	s6   P P H?P .CP 6	P  CP 	Q(&8Q##Q(c                 `   	 | j                   rt        | j                   d      rt        | j                   j                   j                               j                  }|dk(  r6|j
                  dk(  r| j                  d       y| j                  d|        yd|v rt        |j                  d      d         nd}|j
                  dk(  r$|j                  |k(  r| j                  d	|        y| j                  d
| d|        yyy# t        $ r}| j                  d|        Y d}~yd}~ww xY w)u}   
        验证模型是否正确放置在指定设备上
        Args:
            expected_device: 期望的设备
        r   r4   u   ✅ 模型已正确放置在CPUu   ⚠️ 预期CPU但模型在 ry   rz   r   r5   u   ✅ 模型已正确放置在 u   ⚠️ 预期 u    但模型在 u!   ⚠️ 无法验证设备放置: N)r   rn   next
parametersr   typer1   r   r   indexrQ   )r*   r   model_deviceexpected_cuda_idrV   s        r+   _verify_device_placementz)yolo_model_loder._verify_device_placement  s   	?zzgdjj':#DJJ$4$4$?$?$ABII"e+#((E1		$CE		$A,"PQMPTcMcs?+@+@+Ea+H'Iij$#((F2|7I7IM]7]		$A/AR"ST		N?2C>R^Q_"`a ;z   	?II9!=>>	?s+   A>D D AD ,D 	D-D((D-c                 d   	 ddl }d|j                  d<   d|j                  d<   d|j                  d<   d|j                  d<   d|j                  d	<   d|j                  d
<   d|j                  d<   | j                  d       d| _        y# t        $ r}| j                  d|        Y d}~yd}~ww xY w)u   设置ONNX Runtime优化选项r   N0ORT_DISABLE_ALL_OPTIMIZATION1ORT_ENABLE_BASIC_OPTIMIZATION ORT_ENABLE_EXTENDED_OPTIMIZATIONCUDA_LAUNCH_BLOCKINGCUDA_CACHE_DISABLEORT_CUDA_GRAPH_CAPTURE3ORT_LOG_SEVERITY_LEVELu%   ✅ ONNX Runtime优化选项已设置Tu%   ⚠️ 设置ONNX优化选项失败: )osenvironr1   onnx_optimizedrQ   )r*   r   rV   s      r+   _set_onnx_optimization_optionsz/yolo_model_loder._set_onnx_optimization_options  s    	C :=BJJ56:=BJJ67=@BJJ9: 25BJJ-./2BJJ+, 47BJJ/0 47BJJ/0II=>"&D 	CII=aSABB	Cs   BB 	B/B**B/c                 \   	 ddl }|dk7  rft        j                  j                         rHd|v rt	        |j                  d      d         nddddd	d
}d|fdg}| j                  d|d           |S ddd}d|fg}| j                  d       |S # t        $ r | j                  d       Y yw xY w)u'   优化ONNX Runtime执行提供者配置r   Nr4   ry   rz   r   l        r   T)r   r   gpu_mem_limitr   r   r   rr   u$   🚀 配置CUDA执行提供者: GPU=r   rs   rt   ru   u   🚀 配置CPU执行提供者r   )r\   r:   r5   r;   r   r   r1   r   )r*   rp   rc   r   rY   r   s         r+   _optimize_onnx_providersz)yolo_model_loder._optimize_onnx_providers  s    $	%%%***A*A*C FIMEY]%8%8%=a%@!A_`->%;.:15)% -.CD*	
 		@AVWbAc@def  -.,-($ ,-AB	 		9; 	IIKL	s   A.B 1B B+*B+c                 4   	 t        | d      rC| j                  r6t        | j                  d      r| j                  d| d       t        j                  j                  dddt        j                        }g }t        |      D ]  }t        j                         }| j                  j                  |d	d	d
| j                        }t        j                         |z
  }|j                  |       |dk(  so| j                  d|dd        t        |dd       t        dt        |      dz
        z  }| j                  d|dd       d| _        y| j"                  r| j%                          yy# t&        $ r}	| j                  d|	        Y d}	~	yd}	~	ww xY w)uP   预热ONNX模型以提高后续推理速度 - 保留用于PyTorch模型的预热r   r   u    🔥 开始预热PyTorch模型 (u   次)r   r   r   r   Fr   r   r   r   r[   rz   Nu1   ✅ PyTorch预热完成，优化后平均时间: Tu   ⚠️ 模型预热失败: )rn   r   r1   r   r   r   r   r   r^   r   r   r   r   r   maxra   r&   r   _warmup_onnx_sessionrQ   )
r*   r   r   r   r   rd   r   r   r   rV   s
             r+   _warmup_onnx_model_legacyz*yolo_model_loder._warmup_onnx_model_legacy  s~   "	9tW%$**Y9W		<[MNO !ii//3RXX/V!{+A!%!2!2!4J 

**# %" #{{ + A #'"3"3"5
"BK ''4Av		$5k#5Fc"JK! ,$ #&l12&6"7#a\ARUVAV:W"W		Mo^aMbbefg$(!))+   	9II3A3788	9s%   C2E0 5AE0 E0 0	F9FFc                 .   | j                   r| j                  ry	 | j                  rg }| j                  D ]:  }t        |t              s|dk(  r|j                  d       *|j                  |       < t        j                  j                  | j                  t        j                        }| j                   j                  d| j                  |i       d| _        | j                  d       yy# t        $ r}| j                  d|        Y d}~yd}~ww xY w)u   专门为ONNX会话进行预热Nr   rz   Tu   🔥 ONNX会话预热完成u   ⚠️ ONNX会话预热失败: r   r   s        r+   r  z%yolo_model_loder._warmup_onnx_session+  r   r   c                 ,     | j                   |fddi|S )u   
        强制加载模型到CPU的便捷方法
        Args:
            model_path: 模型文件路径
            **kwargs: 其他参数
        Returns:
            是否加载成功
        r   r4   r   )r*   r   rR   s      r+   load_cpuzyolo_model_loder.load_cpuD  s"     /t..zXXQWXXr-   r   c                 2     | j                   |fdd| i|S )u   
        强制加载模型到指定GPU的便捷方法
        Args:
            model_path: 模型文件路径
            gpu_id: GPU编号，默认为0
            **kwargs: 其他参数
        Returns:
            是否加载成功
        r   r6   r	  )r*   r   r   rR   s       r+   load_gpuzyolo_model_loder.load_gpuO  s*     /t..zc%PVxHXc\bccr-   c                     | j                   r| j                  sd| _        y| j                  d|        | j	                  | j                  |      S )u   
        将已加载的模型重新加载到指定设备
        Args:
            target_device: 目标设备 ('cpu', 'cuda:0', 'cuda:1', 等)
        Returns:
            是否重新加载成功
        u*   没有已加载的模型可以重新加载Fu"   🔄 重新加载模型到设备: )r   )r   r   r   r1   r   )r*   rp   s     r+   reload_to_devicez!yolo_model_loder.reload_to_device[  sL     ##4??$PD!		6}oFG..t].[[r-   c                    	 | j                   dk(  rt        | d      r| j                  sd| _        t        | d      r| j                  sd| _        t        | d      r| j                  s	ddi| _        | j                  d	| j                   d
| j                          yt        | d      r| j                  rt        | j                  d      r| j                  j                  | _        nd| _        t        | j                  d      r| j                  j                  | _        nd| _        t        | j                  d      r| j                  j                  | _        nd| _        | j                  d| j                   d
| j                          yd| _        d| _        ddi| _        | j                  d| j                   d
| j                          y# t        $ r5}| j                  d|        d| _        d| _        ddi| _        Y d}~yd}~ww xY w)u>   提取模型信息，安全版本，兼容ONNX和PyTorch模型r   r   r   r    r   r!   r   r   u   ONNX模型信息确认: 类型=u	   , 尺寸=r   rh   r   r   Nu(   PyTorch模型信息提取成功: 类型=u!   使用默认模型信息: 类型=u   提取模型信息时出错: )r   rn   r   r    r!   r1   r   rh   r   r   rQ   r*   rV   s     r+   _extract_model_infoz$yolo_model_loder._extract_model_infoj  s   .	-  F* t\2$//&.DOt\2$//&)DOt]34;K;K()8}D$		;DOO;LIVZVeVeUfghw'DJJ 4::v.&*jjooDO&.DO 4::w/&*jj&6&6DO&)DO 4::w/'+zz'7'7D$'+D$		DT__DUU^_c_n_n^opq #+"%$%x= 		=doo=NiX\XgXgWhij 	-II5aS9:&DO!DO !8}D	-s&   BG C.G AG 	H+HHc                    	 t        | d      r&| j                  | `d| _        | j                  d       t        | d      rW| j                  Kt        | j                  d      r| j                  j	                          | `d| _        | j                  d       nt        | d      sd| _        t
        j                  j                         rt
        j                  j                          d| _	        d| _
        d| _        | j                  d       d| _        t        | d      rd| _        d| _	        d| _
        d| _        d| _        d| _        d| _        y# t        $ r}| j                  d	|        Y d}~gd}~ww xY w# d| _        t        | d      rd| _        d| _	        d| _
        d| _        d| _        d| _        d| _        w xY w)
u   卸载当前模型r   Nu   ONNX会话已卸载r   r4   u   PyTorch模型已卸载Fu   模型卸载完成u   卸载模型时出错: )rn   r   r1   r   r4   r:   r5   r;   empty_cacher   r   r&   rQ   r   r   r    r!   r  s     r+   rN   zyolo_model_loder.unload_model  s   )	$tY'DLL,DL#		/0 tW%$***@4::u-JJNN$J!
		23T7+!
 zz&&(

&&( $)D "DO %DII*+
  DLtW%!
#(D "DO"DO $D"DO#D  	5II/s344	5  DLtW%!
#(D "DO"DO $D"DO#Ds+   D
E 	E8E3.E; 3E88E; ;AGc           	          | j                   | j                  | j                  | j                  | j                  | j
                  | j                  | j                  dS )u]   
        获取模型信息
        Returns:
            包含模型信息的字典
        )	is_loadedr   r   r   r    r!   r   error)r   r   r   r   r    r!   r   r   r*   s    r+   get_model_infozyolo_model_loder.get_model_info  sN     --//// --//++kk**	
 		
r-   imagetarget_sizec                 .   | j                   st        d      || j                  r| j                  nd}t        |j                        dk(  r%t        j                  |t
        j                        }n|}|j                  dd \  }}t        ||z  ||z        }t        ||z        t        ||z        }}t        j                  |||f      }	t        j                  ||dfdt        j                        }
||z
  dz  }||z
  dz  }|	|
|||z   |||z   f<   |
S )u   
        图像预处理
        Args:
            image: 输入图像 (BGR格式)
            target_size: 目标尺寸，如果为None则使用模型默认尺寸
        Returns:
            预处理后的图像
           模型未加载Nr   r   rt   r   r   )r   RuntimeErrorr    ra   r   cv2cvtColorCOLOR_BGR2RGBminr   resizer   fullr   )r*   r  r  	image_rgbhwscalenew_hnew_wresizedpaddedy_offsetx_offsets                r+   preprocess_imagez!yolo_model_loder.preprocess_image  s    ##011-1__$//#K u{{q UC,=,=>II r"1K!O[1_51u9~s1u9~u **Y7 +{A6288L%'A-%'A-CJx&%(??@r-   c           	      B   | j                   st        d      | j                         }|dk7  r|j                         nd}| j                  r| j                  j                         nd}t        d| d|        	 t        j                         }| j                  dk(  rd|v rt        |j                  d      d	         nd
}|j                         }|dk7  rd| nd|d<   d|d<   d|d<   d|d<   d|d<   d|vrd|d<   d|d<    | j                  j                  |fi |}	nd|vr||d<    | j                  |fi |}	t        j                         |z
  }
t        d|
dd       |	S # t        $ r2}d| d| dt        |       }t        d|        t        |      d}~ww xY w)u  
        优化的预测方法，特别针对ONNX模型，每次推理都显示模型信息
        Args:
            image: 输入图像 (BGR格式)
            **kwargs: 预测参数，如 conf, iou, save 等
        Returns:
            预测结果
        r  r4   r   UNKNOWN   🚀 推理信息:    模型 | 设备: r   ry   rz   r   r6   r   Fbatchr   save_txt	save_cropr   r   r      ⚡ 推理耗时: .4fr[   u   预测失败 (/): r   N)r   r  _get_actual_model_deviceupperr   r0   r^   r   r   r   copyr   r   rQ   rM   )r*   r  rR   actual_devicedevice_displaymodel_type_displayrd   r   onnx_kwargsresultsr   rV   rT   s                r+   r   zyolo_model_loder.predict  s    ##011 5572?52H,,.e:>:K:KT..446QZ#$6#77HHXYZ,	***,J   F*=@M=Q]005a89WX %kkm =JU<R%x(8X]H% (-G$ ',F#*/J'+0K( +-+.K( */I&,$**,,UBkB 6)'4F8$$$**U5f5!..0:=N&~c&:#>?N 	*();(<An=MSQTUVQWPXYID$%y))	*s   9C)E# #	F,-FFc           	         | j                   st        d      |j                  d| j                               }|dk7  r|j	                         nd}| j
                  r| j
                  j	                         nd}	 t        j                         }|j                         }d|v r |d= | j                  r| j                  d       ||d<   d|d	<   | j                  r.| j                  r!t        d
| d| d       | j                  rh| j                  d       | j                  d| j                          | j                  j                         D ]  \  }}	| j                  d| d|	         t!        | j                  | j                  r#t!        | j                  j#                               n| j                        }
|
|d<   | j                  r| j                  d|
        | j%                  |||      }|rp| j'                  |      }n^t        d
| d| d       | j                  |d<   | j                  r| j                  d| j                          | j%                  |||      }t        j                         |z
  }t        d|dd       |S # t(        $ r2}d| d| dt+        |       }t        d|        t        |      d}~ww xY w)u  
        增强预测方法，自动处理独立置信度设置，移除外部conf参数依赖
        
        Args:
            image: 输入图像 (BGR格式)
            **kwargs: 预测参数，如 iou, imgsz, device, save, verbose 等
                     注意：conf参数会被自动处理，外部传入的conf参数会被忽略
            
        Returns:
            预测结果
        r  r   r4   r   r1  r   u7   已移除外部conf参数，使用内部置信度管理Fr   r2  r3  u    | 独立置信度模式u   独立置信度设置:u     全局置信度: z  : u#   使用最低置信度进行预测: u    | 全局置信度模式u   使用全局置信度: r7  r8  r[   u   predictEx失败 (r9  r:  r   N)r   r  getr;  r<  r   r^   r   r=  r   r1   r'   r)   r0   r(   itemsr"  values_execute_prediction'_apply_independent_confidence_filteringrQ   rM   )r*   r  rR   rp   r?  r@  rd   predict_kwargs	class_keyconf_valmin_confrB  r   rV   rT   s                  r+   r   zyolo_model_loder.predictEx?  s    ##011 

8T-J-J-LM2?52H,,.e:>:K:KT..446QZ:	***,J $[[]N'"6*<<IIWX (5N8$(-N9% ((T-G-G+,>+??PQ_P``xyz<<II67II 3D4D4D3EFG/3/I/I/O/O/Q+	8		BykH:">? 0R t//]a]w]wT5O5O5V5V5X1Y  ~B  ~N  ~N  O)1v&<<II CH:NO 225.J\] "JJ7SG +,>+??PQ_P``xyz)-)9)9v&<<II 78H8H7IJK 225.J\]!..0:=N&~c&:#>?N 	*+,>+?q@PPSTWXYTZS[\ID$%y))	*s   8HJ 	K-KKrJ  r@  c                     	 | j                   dk(  r| j                  ||      S | j                  ||      S # t        $ r}t	        dt        |             d}~ww xY w)u*  
        执行实际的预测操作，根据模型格式选择推理方式
        
        Args:
            image: 输入图像
            predict_kwargs: 预测参数字典
            model_type_display: 模型类型显示名称
            
        Returns:
            预测结果
        r   u   执行预测失败: N)r   _onnx_predict_pytorch_predictrQ   r  rM   )r*   r  rJ  r@  rV   s        r+   rH  z$yolo_model_loder._execute_prediction  sg    		@  F*))%@@ ,,UNCC 	@!5c!fX>??	@s    5 5 	AAAc                    | j                   sg }|j                  d       |j                  d| j                          |j                  d| j                          |j                  d| j                          |j                  d| j
                          ddj                  |      z   }| j                  d|        t        |      | j                  st        d	      | j                  r| j                  n|j                  d
d      }| j                  rt        d|        | j                  ||      }t        j                         }| j                   j!                  d| j                  |i      }t        j                         |z
  }	| j#                  ||j$                  |      }
| j                  rt        d|	dd       |
S )u!   使用纯ONNX Runtime进行推理u   ONNX会话未初始化u   模型加载状态: u   模型路径: u   模型格式: u   加载错误: u   ONNX推理失败 -  | r   u   ONNX输入名称未设置r   r   u!   🔧 ONNX预处理: 目标尺寸=Nu   🔥 ONNX纯推理耗时: r8  r[   )r   r   r   r   r   r   joinr1   r  r#   r    rE  r   r0   _preprocess_for_onnxr^   r   _postprocess_onnx_outputsr   )r*   r  rJ  error_details
full_errorr  processed_imagerd   outputsr   rB  s              r+   rO  zyolo_model_loder._onnx_predict  s    ||M  #9;  #78L8L7M!NO  >$//1B!CD  >$2C2C1D!EF  >$2G2G1H!IJ.M1JJJIIZL)*z**:;; *.doon>P>PQXZ]>^<<5k]CD33E;G YY[
,,""4$//?)KLz1 00%++~V<<.~c.B#FGr-   c                     t        | d      r| j                  t        d       | j                  j                  |fi |S )u$   使用ultralytics进行PyTorch推理r   u   PyTorch模型未加载)rn   r   r  r   )r*   r  rJ  s      r+   rP  z!yolo_model_loder._pytorch_predict  s=    tW%);788!tzz!!%:>::r-   c                    t        |j                        dk(  r7|j                  d   dk(  r%t        j                  |t        j                        }n|}|j                  dd \  }}t        ||z  ||z        }t        ||z        t        ||z        }}t        j                  |||f      }	t        j                  ||dfdt        j                        }
||z
  dz  }||z
  dz  }|	|
|||z   |||z   f<   |
j                  t        j                        dz  }|j                  ddd      }t        j                  |d      }|S )	u   为ONNX推理预处理图像r   rt   Nr  r   g     o@r   rz   )ra   r   r  r   r!  r"  r   r#  r   r$  r   r   r   	transposeexpand_dims)r*   r  r  r%  r&  r'  r(  r)  r*  r+  r,  r-  r.  
normalized
transposedbatcheds                   r+   rT  z%yolo_model_loder._preprocess_for_onnx  s8    u{{q U[[^q%8UC,=,=>II r"1K!O[1_51u9~s1u9~u **Y7 +{A6288L%'A-%'A-CJx&%(??@ ]]2::.6
))!Q2
..Q/r-   c                     	 | j                  |||      S # t        $ r7}| j                  rt        d|        | j	                  |||      cY d}~S d}~ww xY w)u6   将ONNX输出后处理为与ultralytics兼容的格式u;   ⚠️ ultralytics后处理失败，使用简化后处理: N)_postprocess_with_ultralyticsrQ   r   r0   _postprocess_simple)r*   rY  original_shaperJ  rV   s        r+   rU  z*yolo_model_loder._postprocess_onnx_outputs  s]    	U55g~~^^ 	U||STUSVWX++G^^TT		Us    	A,A
AAc           	         	 ddl }	 ddlm}m} ddlm}  |j                  |d         }|j                  dd      }	|j                  dd	      }
 |||	|
d
      }g }t        |      D ]  \  }}t        |      r3|j                  dd      } |||f|ddddf   |dd       |ddddf<    |t!        j"                  |t         j$                        d| j&                  t        |      r|j)                         j+                         nd      }|j-                  |        |S # t        $ r1 	 ddlm}m} ddl	m} n# t        $ r ddl
m}m} ddlm} Y nw xY wY Fw xY w# t.        $ r}t        d|       d}~ww xY w)u#   使用ultralytics的后处理方法r   N)non_max_suppressionscale_boxes)Results)rf  scale_coordsr   r   iou?i,  )
conf_thres	iou_thresmax_detr   r   rs   rt   r   )orig_imgpathr   boxesu   ultralytics后处理失败: )r:   ultralytics.utils.opsrf  rg  ultralytics.engine.resultsrh  r   ultralytics.yolo.utilsri  ultralytics.yolo.engine.resultsultralytics.utils&ultralytics.models.yolo.detect.predict
from_numpyrE  	enumeratera   r   zerosr   r!   r4   numpyr   rQ   )r*   rY  rd  rJ  r:   rf  rg  rh  predictionsconf_thresholdiou_threshold
detectionsrB  r   detr  r   rV   s                     r+   rb  z.yolo_model_loder._postprocess_with_ultralytics  s   4	BOR> +%**71:6K ,//=N*..ud;M,)'	J G#J/3s8"0"4"4Wc"BK!,k;-GQPRQRPRUUcdfefUg!hC2A2J !XXnBHHE**/23x#'')//+T	 v& 0 NS  OOgG" ORNOOV  	B <QC@AA	Bs^   E D" DE "	E,D;:E;EEEEE EE 	E;(E66E;c           	         	 ddl }|d   }| j                  rRt        d       t        dt        |              t        d|j                          t        d|j
                           |j                  |      }t        |j                        dk(  r|j                  d      }nt        |j                        dk(  rnn| j                  rt        d	|j                   d
       |j                         }|dz  dk(  r|dz  }|j                  d|d      }nt        d|j                         |j                  dd      }	| j                  r&t        d|j                          t        d|	        g }
t        |j                  d         D ]u  }||   }|j                  d   dk(  rT| j                  rt        d|j                           G d d      }|
j                   ||j                                      o|j                  d   dk  r! G d d      }|
j                   |              |ddddf   }|dddf   }|ddddf   }|j                  d   dkD  r |j                  |d      \  }}||z  }n-|} |j                   |j                  d   |j"                        }||	kD  }|j%                         dkD  r ||   }||   }||   }| j'                  |||j                  dd            }t        |      dkD  r||   }||   }||   } |j(                  ||j                  d      |j                  d      j+                         gd      }|j                  dd      }|d   |z  }|d   |z  }|ddddgfxx   |z  cc<   |ddddgfxx   |z  cc<    G d  d      }|
j                   ||             4 G d! d      }|
j                   |              V G d" d      }|
j                   |              x |
S # t,        $ r7}| j                  rt        d#|         G d$ d      } ||      gcY d}~S d}~ww xY w)%u>   简化的后处理方法，不依赖ultralytics的具体实现r   Nu   🔍 ONNX输出调试:u      输出数量: u      第一个输出形状: u       第一个输出数据类型: rt   r   u   ⚠️ 非标准输出形状: u   ，尝试自适应处理U   rz   u   无法处理的输出形状: r   r   u      处理后形状: u      置信度阈值: i   u$      检测到特殊YOLO输出格式: c                       e Zd Zd Zd Zy):yolo_model_loder._postprocess_simple.<locals>.SimpleResultc                 T    || _         t        j                  g       | _        d | _        y N)raw_outputsr   arrayr  rq  )r*   raw_datas     r+   r,   zCyolo_model_loder._postprocess_simple.<locals>.SimpleResult.__init__o  s     /7D,.0hhrlDO)-DJr-   c                 4    d| j                   j                   S )NzONNX Raw Result: shape=)r  r   r  s    r+   __str__zByolo_model_loder._postprocess_simple.<locals>.SimpleResult.__str__t  s    %<T=M=M=S=S<T#UUr-   N)__name__
__module____qualname__r,   r   r-   r+   SimpleResultr  n  s    .
Vr-   r  c                       e Zd Zd Zy)r  c                 F    t        j                  g       | _        d | _        y r  r   r  r  rq  r  s    r+   r,   zCyolo_model_loder._postprocess_simple.<locals>.SimpleResult.__init__}      .0hhrlDO)-DJr-   Nr  r  r  r,   r  r-   r+   r  z:yolo_model_loder._postprocess_simple.<locals>.SimpleResult|      .r-   rs      r   r   rj  rk  )r~  r   r   c                       e Zd Zd Zy)r  c                     |j                         j                         | _        t        | j                        dkD  r| j                  | _        y d | _        y )Nr   )r4   r{  r  ra   rq  )r*   r  s     r+   r,   zCyolo_model_loder._postprocess_simple.<locals>.SimpleResult.__init__  s<    2<..2B2H2H2J@CDOO@TWX@XT__
^b
r-   Nr  r  r-   r+   r  z:yolo_model_loder._postprocess_simple.<locals>.SimpleResult  s    cr-   c                       e Zd Zd Zy)r  c                 F    t        j                  g       | _        d | _        y r  r  r  s    r+   r,   zCyolo_model_loder._postprocess_simple.<locals>.SimpleResult.__init__  s    24((2,-1
r-   Nr  r  r-   r+   r  z:yolo_model_loder._postprocess_simple.<locals>.SimpleResult  s    2r-   c                       e Zd Zd Zy)r  c                 F    t        j                  g       | _        d | _        y r  r  r  s    r+   r,   zCyolo_model_loder._postprocess_simple.<locals>.SimpleResult.__init__  r  r-   Nr  r  r-   r+   r  z:yolo_model_loder._postprocess_simple.<locals>.SimpleResult  r  r-   u6   ⚠️ 简化后处理也失败，返回原始输出: c                       e Zd Zd Zy)r  c                      || _         d | _        y r  )r  rq  )r*   r  s     r+   r,   zCyolo_model_loder._postprocess_simple.<locals>.SimpleResult.__init__  s    '2D$!%DJr-   Nr  r  r-   r+   r  z:yolo_model_loder._postprocess_simple.<locals>.SimpleResult  s    &r-   )r:   r   r0   ra   r   r   rx  	unsqueezenumelreshape
ValueErrorrE  r   r   r{  r  rz  longr   _simple_nmscatfloatrQ   ) r*   rY  rd  rJ  r:   raw_predictionsr|  total_elementsnum_detectionsr}  rB  	batch_idx
batch_predr  rq  confidencesclass_probsclass_confs	class_idsfinal_confs	keep_maskfiltered_boxesfiltered_confsfiltered_classeskeep_indicesfinal_boxesfinal_classesdetection_resultsr  scale_xscale_yrV   s                                    r+   rc  z$yolo_model_loder._postprocess_simple3  s   _	+ &ajO||.0)#g,892?3H3H2IJK89N9N8OPQ +%**?;K ;$$%*)33A6[&&'1, <<:;;L;L:MMefg!,!2!2!4!B&!+%3r%9N"-"5"5a"LK$'D[EVEVDW%XYY ,//=N||,[->->,?@A,^,<=>G";#4#4Q#78	(3
 ##A&$. || DZEUEUDVWXV V NN<
0@0@0B#CD%%a(2-. . NN<>2 #1bqb5)(A.(AB/ $$Q'!+-6UYY{-J*K"-";K #.K +K,=,=a,@

 SI (.8	==?Q&%*9%5N%0%;N'0';$ $(#3#3NN@N@R@RSXZ^@_ $4 $aL <(1,&4\&B&4\&B(8(F -6EII''11!4)33A6<<>7  !	-") '5&8&8#&F"0"3k"A"0"3k"A)!aV)4?4)!aV)4?4c c
  |4E'FG2 2  |~6. . NN<>2O 9R N 
	+||NqcRS& &
 !)**
	+s   PP 	Q,Q :Q Qc           	         	 ddl }t        |      dk(  rg S |j                  d      \  }}g }t        |      dkD  ra|d   }|j                  |       t        |      dk(  r	 |S | j	                  |||dz    ||dd          }	|	|k  }
|dd |
   }t        |      dkD  ra|S # t
        $ r<  j                  |t        t        |      d            \  }}|j                         cY S w xY w)u   简单的NMS实现r   NT)
descendingrz   d   )	r:   ra   sortr   _calculate_iourQ   topkr"  tolist)r*   rq  scoresr~  r:   r   orderkeepr   iousr  indicess               r+   r  zyolo_model_loder._simple_nms  s    	$5zQ	 {{d{3HAuDe*q.!HAu:? K **51Q3<uQRy9IJ !=0	ab	), e*q. K 	$#FCFS,ABJAw>>##	$s$   B AB "9B B AC#"C#c                 t   	 ddl } |j                  |ddddf   |ddddf   j                               } |j                  |ddddf   |ddddf   j                               } |j                  |ddddf   |ddddf   j                               } |j                  |ddddf   |ddddf   j                               } |j                  ||z
  d       |j                  ||z
  d      z  }|dddf   |dddf   z
  |dddf   |dddf   z
  z  }	|dddf   |dddf   z
  |dddf   |dddf   z
  z  }
|	dddf   |
dddf   z   |z
  }| |j                  |d      z  }|j                         S # t        $ r" ddl } |j                  t        |            cY S w xY w)	u	   计算IoUr   Nrz   rt   r   rs   r"  gư>)	r:   r  tr"  clampflattenrQ   rz  ra   )r*   box1boxes2r:   x1y1x2y2intersectionarea1area2unionrj  s                r+   r  zyolo_model_loder._calculate_iou  s   	,
 41Q3<1Q3)9)9);<B41Q3<1Q3)9)9);<B41Q3<1Q3)9)9);<B41Q3<1Q3)9)9);<B&5;;rBwA6R"WRS9TTL!Q$Z$q!t*,add1a4j1HIEAqD\F1a4L0VAqD\F1a4L5PQE!T'NU47^3lBEU!==C;;=  	,5;;s6{++	,s   F	F (F76F7c                    	 |rt        |      dk(  r|S g }| j                  rDt        d       t        dt        | j                                t        d| j
                          i }| j                  dk(  r3| j                  r| j                  }| j                  rt        d|        ntt        | d      rh| j                  r\t        | j                  d      rF| j                  j                  r0| j                  j                  }| j                  rt        d	|        |s| j                  rt        d
       |D ]S  }t        |d      r2|j                  %|j                  }t        |      dk(  r|j                  |       J|j                  j                         j                         }|j                   j                         j                         }g }t#        t        |            D ]  }	t%        ||	         }
t'        ||	         }| j
                  }d}d}|
| j                  v r| j                  |
   }d|
 d}|
}n.|
|v r*||
   }|| j                  v r| j                  |   }d| d}|}|| j                  j)                         D ]  t+        t,              sd|
 d|
 t-        |
      j/                         j1                         g}|
|v r5||
   }|j3                  ||j/                         |j1                         g       |v st5        fd|D              s| j                     }d d}} n ||k\  }|j                  |       | j                  sv|
|v rd|j7                  |
d       dnd}t        d|
 | d|dd| d|dd| d|rdnd         t5        |      rddl} |j:                  ||j<                         }ddl}|j?                  |      }|jA                  |j                        |_        |j                  jB                  |   |j                  _!        |j                  |       t        |      }tE        |      }| j                  s)t        d!| d"| d#       =ddl}ddl}|j?                  |      }|jA                  |j                        |_         |jF                  dt        |j                  jB                  jH                        d$kD  r#|j                  jB                  jH                  d$   nd%f      }|jK                  |j                  jB                  jL                        |j                  _!        |j                  |       | j                  s6t        d&       C|j                  |       V | j                  rt        d'       |S # tN        $ rF}t        d(|        | j                  r ddl(}t        d)|jS                                 |cY d}~S d}~ww xY w)*u   
        应用独立置信度过滤
        
        Args:
            results: 原始预测结果
            
        Returns:
            过滤后的预测结果
        r   u*          🔍 开始独立置信度过滤...u)          📋 当前独立置信度设置: u          📋 全局置信度: r   u'          🏷️ ONNX模型类别映射: r   r   u*          🏷️ PyTorch模型类别映射: u2          ⚠️ 无可用的模型类别名称信息rq  Nu   全局u	   独立ID(r   u
   独立名(classClassc              3   (   K   | ]	  }|k(    y wr  r  ).0matchset_class_names     r+   	<genexpr>zKyolo_model_loder._apply_independent_confidence_filtering.<locals>.<genexpr>z  s(       QH  wGmrQ_chQh  wGs   u   独立匹配((u   未知rB   u            🎯 类别ID=u   , 置信度=r   z, u   阈值=u   , 匹配键=u	   ✅保留u	   ❌过滤r   u            📊 过滤结果: r   u    个检测框rz      u:            ❌ 所有检测框都被独立置信度过滤掉u&          ✅ 独立置信度过滤完成u(          ❌ 独立置信度过滤失败: u          📍 错误详情: )*ra   r   r0   r   r)   r(   r   r!   rn   r   r   rq  r   r   r4   r{  clsr   r   r  keysr   rM   rE   r<  extendanyrE  r:   tensorboolr=  deepcopydatar   emptyr   ri   r   rQ   	traceback
format_exc)r*   rB  filtered_resultsmodel_namesr   rq  r  r  r  r   class_id
confidenceclass_thresholdthreshold_source	match_keymodel_class_namepossible_matches
model_namer  model_name_infor:   r  r=  filtered_resultoriginal_countfiltered_countempty_tensor_2drV   r  r  s                                @r+   rI  z8yolo_model_loder._apply_independent_confidence_filtering  s   b	c'la/! ||BDA$tGaGaBbAcde5d6F6F5GHI K   F*##"&"2"2K|| G}UVw'DJJ74::w;W\`\f\f\l\l"jj..<<F{mTU4<<JL!67+0H"LLE5zQ(//7  #(**.."2"8"8":K %		 5 5 7I !#I"3u:.#&y|#4%*;q>%:
 +/*:*:+3($(	 $t'A'AA.2.H.H.RO1:8*A/F,(0I &4/:8/D,/43M3MM262L2LM]2^5?@P?QQR3S 0,<	 %,262L2L2Q2Q2S#-nc#B +0z(:*/z(:(+H(6(<(<(>(6(<(<(>8&$4 (0;'>5@5J
(8(?(?,6,6,<,<,>,6,<,<,>A* )+ (69I'IS  QH  wG  QH  NH:>:T:TUc:d=J>JZZ[;\(84B	(-1 3T6  *_<!((.  <<\dhs\s+//(H2U1VVW.Xy{O!$;H:oEVVbcmnqbrrt%5$6goc=R S//8k4KU`;a#c dw /@ 9~$'3u||IUZZ'P $*.))F*; 15fll0K- 6<\\5F5F|5T--2(//@),Y),Y<<!$@@PPTUcTddq"rs $$*.))F*; 15fll0K- +6%++qX[\b\h\h\m\m\s\sXtwxXx&,,:K:K:Q:QRS:T~  7A  +B5D5G5GHYHYH`H`5a--2(//@<<!$^` %++F3o "r ||>@## 	<QC@A|| 293G3G3I2JKLN	sD   V* JV* BV* "<V*  DV* #DV* 09V* *	W93;W4.W94W9imagesc           	         | j                   st        d      	 g }t        |      D ]X  \  }}| j                  r#| j	                  d|dz    dt        |               | j                  |fi |}|j                  |       Z |S # t        $ r;}dt        |       }| j                  r| j	                  |       t        |      d}~ww xY w)u   
        批量预测
        Args:
            images: 图像列表
            **kwargs: 预测参数
        Returns:
            预测结果列表
        r  u   处理图像 rz   r9  u   批量预测失败: N)
r   r  ry  r   r1   ra   r   r   rQ   rM   )	r*   r  rR   rB  r   r  r   rV   rT   s	            r+   predict_batchzyolo_model_loder.predict_batch  s     ##011	*G%f-5<<IIacU!CK=AB%e6v6v&	 .
 N 	*.s1vh7I||		)$y))		*s   A)B 	C6CC
test_imagerunsc                    | j                   st        d       y| j                         }|dk7  r|j                         nd}| j                  r| j                  j                         nd}t        d| d| d|        g }t        |      D ]  }t        j                         }	 | j                  d	k(  r!| j                  j                  |d
ddd      }	n| j                  |d
dd      }	t        j                         |z
  }|j                  |       |dk(  st        d|dd        |st        d       yt        |      t        |      z  }t        |      }t        |      }t        d| d| d       t        d|dd       t        d|dd       t        d|dd       |S # t        $ r}
t        d|dz    d|
        Y d}
~
?d}
~
ww xY w)u   
        对比模型性能
        Args:
            test_image: 测试图像
            runs: 测试轮数
        Returns:
            平均推理时间
        u.   ❌ 模型未加载，无法进行性能测试        r4   r   r1  u   📊 开始性能测试: r3  u    | 测试轮数: r   g?rk  F)r   rj  r   r   )r   rj  r   u   ⚠️ 测试轮次 rz   	    失败: Nr   u      首次推理: r8  r[   u"   ❌ 所有测试轮次都失败了u   📈 性能测试结果 (r9  z):u      平均时间: u      最快时间: u      最慢时间: )r   r0   r;  r<  r   r   r^   r   r   r   rQ   r   r   ra   r"  r  )r*   r  r   r>  r?  r@  timesr   rd   rB  rV   r   avg_timemin_timemax_times                  r+   benchmark_modelz yolo_model_loder.benchmark_model  s    ##BC 5572?52H,,.e:>:K:KT..446QZ)*<)==N~N^^optouvwtA**,J$$."jj00#4Y^ej0kG"jj#4QVjWG
 "..0:=NLL(Av).)=SAB! $ 67u:E
*u:u:)*<)=Q~>NbQR!(3s34!(3s34!(3s34/  ,QqSE1#>?s   !AF%%	G.GGenabledc                     	 || _         |rdnd}| j                  r| j                  d|        y# t        $ r*}| j                  r| j                  d|        Y d}~yd}~ww xY w)u   
        开启或关闭分类独立置信度功能
        
        Args:
            enabled: True启用分类独立置信度, False使用全局置信度
            
        Returns:
            bool: 设置是否成功
           启用   禁用u   分类独立置信度功能已Tu)   设置分类独立置信度功能失败: NF)r'   r   r1   rQ   )r*   r	  r   rV   s       r+   set_independent_conf_enabledz-yolo_model_loder.set_independent_conf_enabled  sd    		(/D%!(XhF||		:6(CD 	||		EaSIJ	s   -0 	A# AA#r}  c                    	 d|cxk  rdk  s#n | j                   r| j                  d|        y|| _        | j                   r| j                  d|        y# t        $ r*}| j                   r| j                  d|        Y d}~yd}~ww xY w)	u   
        设置全局置信度阈值
        
        Args:
            conf_threshold: 置信度阈值 (0.0 - 1.0)
            
        Returns:
            bool: 设置是否成功
        r        ?u3   置信度阈值必须在0.0-1.0之间，当前值: Fu#   全局置信度阈值已设置为: Tu   设置全局置信度失败: N)r   r1   r(   rQ   )r*   r}  rV   s      r+   set_global_confidencez&yolo_model_loder.set_global_confidence'  s    	./C/<<II STbScde-D||		??OPQ 	||		9!=>	s   -A 'A 	B! BBc                 V   	 d|cxk  rdk  s#n | j                   r| j                  d|        yt        |t              r|}|}ntt        |t              r:|dk  r!| j                   r| j                  d|        y|}| j                  |      }n*| j                   r| j                  dt        |              y|| j                  |<   | j                   r| j                  d| d	|        y
# t        $ r3}| j                   r| j                  dt        |              Y d}~yd}~ww xY w)u>  
        设置单个分类的置信度阈值（支持类别ID或类型名）
        
        Args:
            class_identifier: 类别标识符，可以是int(类别ID)或str(类型名)
            conf_threshold: 置信度阈值 (0.0-1.0)
            
        Returns:
            bool: 设置是否成功
        r  r  u*   置信度阈值必须在0.0-1.0范围内: Fr   u+   类别ID必须是非负整数，当前值: u#   不支持的类别标识符类型: u   类别 u    置信度阈值已设置为: Tu   设置分类置信度失败: N)	r   r1   r   rM   r   get_class_namer   r)   rQ   )r*   class_identifierr}  rK  display_namerV   s         r+   set_class_confidencez%yolo_model_loder.set_class_confidence@  s#   $	>0S0<<II J>JZ[\ *C0,	/,c2#a'||		$OP`Oa"bc ,	#223CD<<II CDIYDZC[\] 5CD&&y1||		GL>1OP^O_`a 	||		9#a&BC	s)   -C, A
C, ;=C, 92C, ,	D(5)D##D(c                    | j                   | j                  t        | j                        t	        | j                        d}| j                  rmt        | j                  j                               }t        | j                  j                               }|dd|d|d<   t        | j                  |      |d<   |S d|d<   | j                  |d<   |S )u{   
        获取独立置信度设置状态
        
        Returns:
            dict: 独立置信度状态信息
        )u   独立置信度启用u   全局置信度u   类别置信度设置数量u   类别置信度详情r   r   u   类别置信度范围u   推荐预测置信度u	   未设置)r'   r(   ra   r)   r   r"  rG  r  )r*   r   rM  max_confs       r+   !get_independent_confidence_statusz2yolo_model_loder.get_independent_confidence_statusq  s     &*%>%>#//+.t/I/I+J%)$*D*D%E	
 %%455<<>?H455<<>?H19#c(3.PF*+.1$2B2BH.MF*+
  /:F*+.2.>.>F*+r-   c                 j    d| _         d| _        i | _        | j                  r| j	                  d       yy)u9   
        重置所有置信度设置为默认值
        Fr   u$   置信度设置已重置为默认值N)r'   r(   r)   r   r1   r  s    r+   reset_confidence_settingsz*yolo_model_loder.reset_confidence_settings  s5     %*!%'"<<II<= r-   c                 z   	 | j                   sy| j                  dk(  r| j                  r	 | j                  j                         }d|v rt        j
                  j                  dd      }|U|dk7  rP|j                  d      D cg c],  }|j                         j                         s"t        |      . }}|rd|d	    S t        | d
      rd| j                  v r| j                  S yy| j                  dv rNt        | d      rA	 t        | j                   d      rt        | j                   j                   d      rtt#        | j                   j                   j%                         d      }|D|j                  }|j&                  dk(  r|j(                  d|j(                   S dS |j&                  S t        | j                   d
      r!t+        | j                   j                        }|S t        | j                   d      rIt        | j                   j                   d
      r)t+        | j                   j                   j                        S | j                  r| j                  d       | j                  r| j                  S dS c c}w # t        $ r*}| j                  r| j                  d|        Y d}~jd}~ww xY w# t        $ r*}| j                  r| j                  d|        Y d}~d}~ww xY w# t        $ rD}| j                  r| j                  d|        | j                  r| j                  ndcY d}~S d}~ww xY w)u   
        获取模型实际运行的设备
        
        Returns:
            str: 实际设备名称，如 'cpu', 'cuda:0', 'cuda:1' 等
        unknownr   r   CUDA_VISIBLE_DEVICESNrB   ,r6   r   r   r7   r4   u(   ⚠️ 检查ONNX会话提供者失败: )rj   pthtorchscriptr   r   r5   u(   ⚠️ 检查PyTorch模型设备失败: u=   ⚠️ 无法获取模型实际设备，使用设置的设备u*   ⚠️ 获取模型实际设备时出错: )r   r   r   get_providersr   r   rE  r   stripr9   r   rn   r   rQ   r   r1   r   r   r   r   r   rM   )	r*   rY   cuda_visiblexgpu_idsrV   first_paramparam_devicer   s	            r+   r;  z)yolo_model_loder._get_actual_model_device  s   =	9''    F*t||R $ : : <I.);')zz~~6Ld'S'38J7C7I7I#7N&f7N!RSRYRYR[RcRcRes1v7NG&f&).wqzl'; ; #42w$++7M#';;.'$ ""&BBwtU\G]Rtzz73

@P@PR^8_&*4::+;+;+F+F+H$&O&2+6+=+=L+00F:GSGYGYGe|/A/A.B'C sks s'3'8'8 8 tzz84'*4::+<+<'=++ tzz73

@P@PRZ8["4::#3#3#:#:;; ||		YZ"&++4;;858Y 'g ! R||		$LQC"PQR4 ! R||		$LQC"PQR  	9||		FqcJK"&++4;;58	9s   K- K- AJ #I<'I<4J  %J (K- BJ7 !J7 #J7 /6J7 &AJ7 4K- :K- <J 	J4
 J/*K- /J44K- 7	K*  K% K- %K**K- -	L:69L5/L:5L:c                 p   	 | j                  |      }| j                  r1t        | j                  d      r| j                  j	                  |       || _        | j                  r| j                  d| j
                          y# t        $ r*}| j                  r| j                  d|        Y d}~yd}~ww xY w)u   
        设置计算设备
        Args:
            device: 设备名称
        Returns:
            是否设置成功
        ri   u   设备已切换到: Tu   设备切换失败: NF)	r   r   rn   r   ri   r   r   r1   rQ   )r*   r   
new_devicerV   s       r+   
set_devicezyolo_model_loder.set_device  s    	,,V4J##

D(A

j)$DK||		0>? 	||		045	s   A?B 	B5 B00B5c                     || _         y r  )r"   )r*   r!   s     r+   set_class_namesz yolo_model_loder.set_class_names  s
    )r-   r  c                    | j                   ?|| j                   v r| j                   |   S d| }|| j                   v r| j                   |   S t        | d      r+| j                  | j                  j                  |d|       S d| S )u   
        根据类别ID获取类别名称（可以根据实际模型自定义）
        
        Args:
            class_id: 类别ID
            
        Returns:
            str: 类别名称
        r  r!   r  )r"   rn   r!   rE  )r*   r  rK  s      r+   r  zyolo_model_loder.get_class_name  s     *4...**844z*ID///**955 4'D,<,<,H##''E(2DEE xj!!r-   c                 \   g }	 |rt        |      dk(  r| j                  r| j                  d       |S |d   }| j                  |      }|r| j	                  |      S | j                  |      S # t        $ r5}| j                  r| j                  dt        |              |cY d}~S d}~ww xY w)u  
        从模型推理结果中提取检测框信息为结构化列表
        自动识别YOLO格式和ONNX格式的输出
        
        Args:
            model_results: 模型推理结果 (支持YOLO Results对象或ONNX原始输出)
            
        Returns:
            list: 检测框信息列表，每个元素包含：
                {
                    "类型编号": int,           # 类别ID
                    "类型字符": str,           # 类别名称
                    "AOI位置": {              # 边界框坐标
                        "x1": int,
                        "y1": int, 
                        "x2": int,
                        "y2": int,
                        "center_x": int,
                        "center_y": int,
                        "width": int,
                        "height": int
                    },
                    "检测置信度": float,       # 原始检测置信度
                    "分类置信度": float,       # 分类置信度（如果可用）
                    "综合置信度": float,       # 综合置信度分数
                    "面积": int,              # 检测框面积
                    "索引": int               # 检测结果索引
                }
        r   u   ⚠️ 无检测结果可提取u   ❌ 提取检测结果失败: N)ra   r   r1   _detect_result_format_extract_from_yolo_format_extract_from_onnx_formatrQ   rM   )r*   model_resultsdetection_listr   is_yolo_formatrV   s         r+   extract_detection_listz'yolo_model_loder.extract_detection_list  s    < 	" C$6!$;<<II?@%%"1%F "77?N55f== 55f== 	"||		:3q6(CD!!	"s(   .A- (A- A- -	B+6*B& B+&B+c                     	 t        |d      rt        |d      ryt        |d      r9|j                  -t        |j                  d      rt        |j                  d      ryy# t        $ r Y yw xY w)u   检测结果格式类型rq  r   Txyxyr   F)rn   rq  rQ   )r*   r   s     r+   r/  z&yolo_model_loder._detect_result_formatE  sg    	vw'GFG,D vw'FLL,D6<<0WV\\65R  		s   A! AA! !	A-,A-c                 P   g }	 |j                   t        |j                         dk(  r| j                  r| j                  d       |S |j                   j                  j                         j                         }|j                   j                  j                         j                         }|j                   j                  j                         j                         }| j                  r| j                  dt        |       d       t        t        |            D ]  }||   j                  t              \  }}}	}
t        ||         }t        ||         }t        ||	z   dz        }t        ||
z   dz        }t        |	|z
        }t        |
|z
        }||z  }| j                  |      }|}|}|}t        |j                   d      rG	 t        |j                   j                  |   j                         j                               }||z   dz  }||t        |      t        |      t        |	      t        |
      ||||dt!        |d	      t!        |d	      t!        |d	      ||d
}|j#                  |       | j                  si| j                  d| d| d| d|dd| d| d|	 d|
 d|         | j                  r| j                  dt        |       d       |S #  Y xY w# t$        $ r5}| j                  r| j                  dt'        |              |cY d}~S d}~ww xY w)u(   从YOLO格式结果中提取检测信息Nr   u   ⚠️ 未检测到任何目标   📋 开始提取 u    个YOLO检测结果rt   cls_confr  r  r  r  center_xcenter_ywidthheightrs      类型编号   类型字符	   AOI位置   检测置信度u   分类置信度u   综合置信度   面积   索引
     - 检测rD  (ID:   ), 置信度:r   
   , 位置:[r  
   ], 面积:   ✅ 成功提取 u   ❌ YOLO格式提取失败: )rq  ra   r   r1   r7  r4   r{  r   r  r   r   r   r  r  rn   r:  roundr   rQ   rM   )r*   r   r3  rq  r  r  r   r  r  r  r  r  r  r<  r=  r>  r?  area
class_namedetection_confidenceclassification_confidencecombined_confidencedetection_inforV   s                           r+   r0  z*yolo_model_loder._extract_from_yolo_formatW  s   N	"||#s6<<'8A'=<<II?@%% LL%%))+113E ,,++//1779K((,,.446I||		.s5zl:NOP 3u:&!&q!5BB";q>2
y|, R1}-R1}-BGR"Wv~ "00:
 (2$,6)&0# 6<<449&,,:O:OPQ:R:V:V:X:^:^:`4a1/CF_/_cd.d+ %-$.!"g!"g!"g!"g$,$,!&"(	" (--A1'E',-F'J',-@!'D"#"( %%n5<<II
1#R
|4zWabeVf g%%'D"Qrd!B4z$I Ji 'n ||		-c..A-BBVWX!!AB  	"||		8QAB!!	"sF   AK' FK' 	AK A3K' AK'  K$"K' '	L%0*L L% L%c                 ~   g }	 d}t        |d      r|j                  t        | d      xr | j                  du}|r|j                  }| j                  r| j	                  d|j
                          t        |j
                        dk(  r#|j
                  d   dk\  r| j                  |      S | j                  r| j	                  d       |S | j                  r| j	                  d	       t        |d
      rP|j                  Dt        |j                        dk(  r| j                  r| j	                  d       |S |j                  }n| j                  r| j	                  d       |S | j                  r| j	                  dt        |       d       t        |      D ]5  \  }}|dd j                  t              \  }}	}
}t        |d         }t        |d         }t        ||
z   dz        }t        |	|z   dz        }t        |
|z
        }t        ||	z
        }||z  }| j                  |      }||t        |      t        |	      t        |
      t        |      ||||dt        |d      t        |d      t        |d      ||d}|j                  |       | j                  s	| j	                  d| d| d| d|dd| d|	 d|
 d| d|        8 | j                  r| j	                  dt        |       d       |S # t         $ r5}| j                  r| j	                  dt#        |              |cY d}~S d}~ww xY w)u(   从ONNX格式结果中提取检测信息Nr  r   u,   🔧 ONNX模式检测到特殊输出格式: rt   r   r  u)   ⚠️ 未识别的ONNX原始输出格式u2   🔄 非ONNX模式，跳过raw_outputs特殊处理r  u    ⚠️ ONNX结果无检测数据u#   ⚠️ 未识别的ONNX结果格式r9  u    个ONNX检测结果rs   r;  r@  rG  rD  rH  rI  r   rJ  r  rK  rL  u   ❌ ONNX格式提取失败: )rn   r  r   r   r1   r   ra   _process_special_onnx_formatr  ry  r   r   r  r  rM  r   rQ   rM   )r*   r   r3  detections_datais_onnx_moder  r   	detectionr  r  r  r  r  r  r<  r=  r>  r?  rN  rO  rS  rV   s                         r+   r1  z*yolo_model_loder._extract_from_onnx_format  sC   ^	""O v}-&2D2D2P&tY7TDLLPT<T"("4"4K||		$PQ\QbQbPc"de ;,,-2{7H7H7Kq7P#@@MM<< II&QR-- ||		"VWv|,1B1B1Nv(()Q.||		"DE))"("3"3 <<IICD%% ||		.s?/C.DDXYZ )/ :9!*2A!5!5c!:BB"9Q<0
y|, R1}-R1}-BGR"Wv~ "00:
 %-$.!"g!"g!"g!"g$,$,!&"(	" (-Z';',Z';',Z';"#"( %%n5<<II
1#R
|4zWabeVf g%%'D"Qrd!B4z$I JO !;T ||		-c..A-BBVWX!! 	"||		8QAB!!	"s?   B(K> -K> A+K> 8+K> $D<K> "AK> >	L<*L71L<7L<c                  	   g }	 | j                   r| j                  d|j                          |j                  d   }|dz
  }|dk  r%| j                   r| j                  d| d|        |S | j                   r| j                  d| d|        |d   }|d   }|d	   }|d
   }|dd|z    }	t        j                  |	d      }
t        j
                  |	d      }| j                  r| j                  rt        j                  || j                        }t        |      D ]  }| j                  |      }| j                  }|| j                  v r| j                  |   }nA|| j                  v r| j                  |   }n#d| | j                  v r| j                  d|    }|||<    ||
   }||k\  }n|| j                  k\  }t        j                  |      d   }t        |      dk(  r| j                   r| j                  d       |S ||   }||   }||   }||   }|
|   }||   }|dkD  |dkD  z  }||   }||   }||   }||   }||   }||   }||d	z  z
  j                  t              }||d	z  z
  j                  t              }||d	z  z   j                  t              }||d	z  z   j                  t              }||k  ||k  z  }t        j                   |      }|dk(  r| j                   r| j                  d       |S ||   }||   }||   }||   }||   }||   }||   }||   }||   }||   }t        t        |            D ]  } t        ||          }t#        ||          }!||    ||    ||    ||    f\  }"}#}$}%t        ||          t        ||          }'}&t        ||          t        ||          })}(| j                  |      }|(|)z  }*|||"|#|$|%|&|'|(|)dt%        |!d      t%        |!d      t%        |!d      |*| d}+|j'                  |+        | j                   r*| j                  dt        |       dt        |       d       |S # t(        $ r5},| j                   r| j                  dt+        |,              |cY d},~,S d},~,ww xY w)u   
        处理特殊的ONNX输出格式 (动态类别数量)
        前4行是边界框坐标 (x, y, w, h)
        后N行是类别置信度 (N个类别)
        u   🔧 处理特殊ONNX格式: r   rs   u+   ❌ 无效的ONNX输出格式，总行数: u   , 类别数: u   🔍 检测到 u    个类别，总行数: rz   rt   r   axisr  u.   ⚠️ 没有检测结果满足置信度要求u   ⚠️ 没有有效的检测框r;  r@  u   ✅ 向量化优化提取 u    个检测结果 (从u   个候选中筛选)u"   ❌ 特殊ONNX格式处理失败: N)r   r1   r   r   argmaxr  r'   r)   r$  r(   r   r  wherera   r   r   r   r  rM  r   rQ   rM   )-r*   r  r3  
total_rowsnum_classesx_coordsy_coordsw_coordsh_coordsclass_confidencesmax_class_idsmax_confidencesclass_thresholdsr  rO  	thresholdrequired_thresholds
valid_maskvalid_indicesvalid_xvalid_yvalid_wvalid_hvalid_class_idsvalid_confidences	size_maskx1_arrayy1_arrayx2_arrayy2_array	bbox_maskfinal_countr   r  r  r  r  r  r<  r=  r>  r?  rN  rS  rV   s-                                                r+   rU  z-yolo_model_loder._process_special_onnx_format	  sQ    S	"||		9+:K:K9LMN %**1-J$q.Ka<<II KJ<Wdepdqrs%%||		OK=8PQ[P\]^ #1~H"1~H"1~H"1~H !,Aam < II&7a@M ff%6Q?O ((T-G-G#%77;8H8H#I  %k 2H!%!4!4X!>J $ 0 0I4#=#==$($>$>x$H	#t'A'AA$($>$>z$J	 
+t/I/II$($>$>xj?Q$R	1:$X. !3 '7}&E#,0CC
 -0@0@@
 HHZ03M=!Q&<<IINO%% }-G}-G}-G}-G+M:O / > !115Ii(Gi(Gi(Gi(G-i8O 1) <  'A+-55c:H'A+-55c:H'A+-55c:H'A+-55c:H "H,H1DEI&&+Ka<<II?@%%  	*H	*H	*H	*Hi(Gi(Gi(Gi(G-i8O 1) < 3w<(q12"#4Q#78
!)!hqk8A;QR!SBB%(_c'!*o( #GAJWQZv!00:
v~ %-$.    $,$,!&"(	" (-Z';',Z';',Z';"#"( %%n5= )@ ||		6s>7J6KK`aderas`t  uH  I  J!! 	"||		>s1vhGH!!	"s3   A'P? ,FP? C6P? 8EP? ?	Q=*Q82Q=8Q=r3  c           
         |sdi i i dS i }g }g }|D ]G  }|d   }|j                  |d      dz   ||<   |j                  |d          |j                  |d          I ddl}t        |      |t	        t        |      d      t	        t        |      d      t	         |j                  |      d      t	         |j                  |      d      d	t        |      t        |      t	         |j                  |      d
      t        |      dd}|S )u   
        获取检测结果的统计摘要
        
        Args:
            detection_list: 检测结果列表
            
        Returns:
            dict: 统计摘要信息
        r   )   总数   类别统计   置信度统计u   面积统计rB  rz   rD  rE  Nrs   )u	   最小值u	   最大值	   平均值u	   中位数rt   )u   最小面积u   最大面积u   平均面积u	   总面积)
rE  r   r{  ra   rM  r"  r  meanmedianr   )	r*   r3  class_countr  areasrX  rO  r   summarys	            r+   get_detection_summaryz&yolo_model_loder.get_detection_summary	  s     "#% "	  'I">2J&1ooj!&Dq&HK
#y):;<LL8,-	 ( 	 .)'"3{#3Q7"3{#3Q7"7277;#7;"9299[#91=	  !$E
 #E
 %gbggena 8 Z	
" r-   overlap_thresholdc                 V   	 |rt        |      dk  r|S | j                  r2| j                  d|d       | j                  dt        |              i }|D ]$  }|d   }||vrg ||<   ||   j                  |       & g }d}|j	                         D ]  \  }}|r|d   d   nd| }	| j                  r$| j                  d	|	 d
| dt        |       d       t        |      dk(  r|j                  |       e| j                  ||      }
t        |      t        |
      z
  }||z  }| j                  r!| j                  d| dt        |
       d       |j                  |
        t        |      D ]
  \  }}||d<    | j                  r`| j                  d       | j                  dt        |              | j                  dt        |              | j                  d| d       |S # t        $ r5}| j                  r| j                  dt        |              |cY d}~S d}~ww xY w)u+  
        合并同类别的重叠检测框
        
        Args:
            detection_list: 检测结果列表
            overlap_threshold: 重叠度阈值 (0.0-1.0)，高于此阈值的同类框将被合并
            
        Returns:
            list: 合并后的检测结果列表
        rz   u+   🔄 开始合并同类框，重叠阈值: rZ   u      原始检测框数量: rA  r   rB  r  u      处理类别 z (ID:u   )，共 u    个框u        合并了 u    个框，剩余 u    个rF  u   ✅ 合并完成:u      原始框数: u      合并后框数: u      总共合并: u   ❌ 合并同类框失败: N)
ra   r   r1   r   rF  r  _merge_boxes_in_classry  rQ   rM   )r*   r3  r  class_groupsrX  r  merged_listtotal_mergedr  rO  merged_class_boxesmerged_countr   rV   s                 r+   merge_same_class_boxesz'yolo_model_loder.merge_same_class_boxes	  sO   6	"!S%8A%=%%||		GHYZ]G^_`		6s>7J6KLM L+	$^4</-/L*X&--i8	 , KL )5(:(:(<$*>HZ]>:PUV^U_N`
<<II 0E(8TWXbTcSddklmz?a'&&z2 &*%?%?
L]%^"":5G1HH,<<II~=NsSeOfNggklm""#56# )=( !*+ 69&'	(# !7 ||		-/		-c..A-BCD		0[1A0BCD		-l^7CD 	"||		7Ax@A!!	"s#   G* GG* *	H(3*H#H(#H(r  c                 F   t        |      dk  r|S g }t               }t        |      D ]  \  }}||v r|g}|h}t        |      D ]I  \  }	}
||	k(  s|	|v r| j                  ||
      }||kD  s(|j	                  |
       |j                  |	       K t        |      dkD  r_| j                  |      }|j	                  |       |j                  |       | j                  s| j                  dt        |       d       |j	                  |       |j                  |        |S )u  
        合并同一类别中的重叠框
        
        Args:
            detections: 同一类别的检测结果列表
            overlap_threshold: 重叠度阈值
            
        Returns:
            list: 合并后的检测结果列表
        rz   u          合并 u    个重叠框)
ra   setry  _calculate_overlap_ratior   add_merge_multiple_boxesupdater   r1   )r*   r  r  merged_boxesused_indicesr   detection_ioverlapping_boxesoverlapping_indicesjdetection_joverlap_ratio
merged_boxs                r+   r  z&yolo_model_loder._merge_boxes_in_class!
  s7    z?au'
3NA{L  "-#$#"+J"7;6Q,. !% = =k; W #44%,,[9'++A. #8 $%)!778IJ
##J/##$78<<IIs3D/E.FmTU ##K0  #= 4@ r-   
detection1
detection2c                    	 |d   }|d   }|d   |d   |d   |d   f\  }}}}|d   |d   |d   |d   f\  }	}
}}t        ||	      }t        ||
      }t        ||      }t        ||      }||k\  s||k\  ry||z
  ||z
  z  }|d   }|d   }t        ||      }|dkD  r||z  }|S d}|S # t        $ r3}| j                  r| j	                  d	t        |              Y d
}~yd
}~ww xY w)u  
        计算两个检测框的重叠度 (重叠面积 / 较小框面积)
        
        Args:
            detection1: 第一个检测框
            detection2: 第二个检测框
            
        Returns:
            float: 重叠度比例 (0.0-1.0)
        rC  r  r  r  r  r  rE  r   u   ⚠️ 计算重叠度失败: N)r  r"  rQ   r   r1   rM   )r*   r  r  aoi1aoi2x1_1y1_1x2_1y2_1x1_2y1_2x2_2y2_2
overlap_x1
overlap_y1
overlap_x2
overlap_y2overlap_arear  r  smaller_arear  rV   s                          r+   r  z)yolo_model_loder._calculate_overlap_ratioT
  s=   !	k*Dk*D%)$ZdT$Zd%S"D$d%)$ZdT$Zd%S"D$d T4JT4JT4JT4J Z':+C '3
Z8OPL x(Ex(E ue,L;G!;KL<7M   RUM   	||		:3q6(CD	s$   A2B& 5,B& "B& &	C"/)CC"rq  c                    t        |      dk(  r|d   S t        |d       }t        d |D              }t        d |D              }t        d |D              }t        d |D              }t        ||z   d	z        }t        ||z   d	z        }t        ||z
        }	t        ||z
        }
|	|
z  }|D cg c]  }|d
   	 }}t        |      }|d   |d   t        |      t        |      t        |      t        |      |||	|
dt	        |d      t	        |d      t	        |d      ||d   d}| j
                  r| j                  d|dd|	 d|
 d|        |S c c}w )u   
        合并多个检测框为一个
        
        Args:
            boxes: 要合并的检测框列表
            
        Returns:
            dict: 合并后的检测框
        rz   r   c                     | d   S )NrD  r  r$  s    r+   <lambda>z8yolo_model_loder._merge_multiple_boxes.<locals>.<lambda>
  s
    A.?,@r-   )keyc              3   ,   K   | ]  }|d    d     yw)rC  r  Nr  r  boxs     r+   r  z9yolo_model_loder._merge_multiple_boxes.<locals>.<genexpr>
       =uS%d+u   c              3   ,   K   | ]  }|d    d     yw)rC  r  Nr  r  s     r+   r  z9yolo_model_loder._merge_multiple_boxes.<locals>.<genexpr>
  r  r  c              3   ,   K   | ]  }|d    d     yw)rC  r  Nr  r  s     r+   r  z9yolo_model_loder._merge_multiple_boxes.<locals>.<genexpr>
  r  r  c              3   ,   K   | ]  }|d    d     yw)rC  r  Nr  r  s     r+   r  z9yolo_model_loder._merge_multiple_boxes.<locals>.<genexpr>
  r  r  rt   rD  rA  rB  r;  rs   rF  r@  u            合并框: 置信度r   u   , 尺寸r$  u   , 面积)ra   r  r"  r   rM  r   r1   )r*   rq  best_boxx1_miny1_minx2_maxy2_maxr<  r=  r>  r?  rN  r  r  max_confidencer  s                   r+   r  z&yolo_model_loder._merge_multiple_boxes
  s    u:?8O u"@A =u===u===u===u== 1,-1,-FVO$Vf_%v~ :??#s,-?[) %^4$^4&k&k&k&k$$ 	  %^Q7$^Q7$^Q7x(#

( <<II5nS5IRWQXXYZ`Yaaijniopq7 @s   1Ec                 l   	 t        |      }|dk  rdS | j                  ||      }|j                          |j                  |       |t        |      z
  }d| dt        |       d| d}d|fS # t        $ r<}dt        |       }| j                  r| j                  d|        d	|fcY d
}~S d
}~ww xY w)u7  
        就地合并重叠的同类检测框（直接修改原列表）
        
        Args:
            detection_list: 检测结果列表（会被直接修改）
            overlap_threshold: 重叠度阈值
            
        Returns:
            tuple[bool, str]: (是否成功, 操作信息)
        rz   Tu   合并完成: 原始u   个框 → 合并后u   个框 (合并了u   个)u   合并检测框失败: r   FN)Tu#   检测框数量 <= 1，无需合并)ra   r  clearr  rQ   rM   r   r1   )	r*   r3  r  r  r  r  
result_msgrV   rT   s	            r+   $merge_overlapping_detections_inplacez5yolo_model_loder.merge_overlapping_detections_inplace
  s    	$ 0N"CC 55nFWXK   "!!+.)C,??L//??STWXfTgShhy  {G  zH  HL  MJ## 	$1#a&:I||		D,-)##		$s#   A. AA. .	B371B.(B3.B3deleted_listc                    	 |t        |      dk(  r| j                  r| j                  d       |S |j                         }| j                  r| j                  dt        |       d       dddd	d
dd}g d}|D ]  }	 d|v r
|d   }|d   }|d   }	|d   }
|d   }|d   }|	d   }|	d   }|	d   }|	d   }||v r||   }n||t        |      z     }t	        j
                  |||f||f|d       | d|
ddg}t        j                  }d}d}d}d}g }|D ]@  }t	        j                  ||||      \  \  }}}t        ||      }|j                  ||z          B t        |      |z  d z   }|}||z
  }|dk  r||z   }||z   |j                  d   kD  r|j                  d   |z
  d!z
  }|j                         } t	        j
                  | |d z
  |d z
  f||z   d z   ||z   f|d"       t	        j                  | d#|d$d|       t        |      D ]-  \  }!}||!dz   |z  z   }"t	        j                  ||||"f||d%|       / |	d&   }#|	d'   }$| j                  r(| j                  d(| d)| d*|
dd+| d,| d,| d,| d-        | j                  r| j                  d0       |S # t        $ r+}%| j                  r| j                  d.|%        Y d}%~%Id}%~%wt        $ r4}&| j                  r| j                  d/t!        |&              Y d}&~&d}&~&ww xY w# t        $ r5}'| j                  r| j                  d1t!        |'              |cY d}'~'S d}'~'ww xY w)2u,  
        根据检测结果列表在图像上标注检测框
        
        Args:
            image: 输入图像 (numpy.ndarray)
            deleted_list: 检测结果列表，每个元素包含完整的检测信息
            
        Returns:
            np.ndarray: 标注后的图像
        Nr   u(   ⚠️ 检测列表为空，无需标注u   🎯 开始标注 u    个检测结果r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   rz   rt   r   rs   r  ))   r   r  )r      r   )r   r  r   )r  r   r   u	   不显示rA  rB  rC  rD  rE  rF  r  r  r  r  rt   z :r    r   rz      r  
   r   皙?皙?r   r   r   r<  r=  u     ✅ 标注完成 - 索引:u	   , 类别:u   , 置信度:u
   , 坐标:[r  ]u/     ❌ 检测数据格式错误，缺少字段: u&     ❌ 标注单个检测结果失败: u"   ✅ 所有检测结果标注完成u   ❌ 标注检测结果失败: )ra   r   r1   r=  r  	rectangleFONT_HERSHEY_SIMPLEXgetTextSizer  r   r   addWeightedry  putTextKeyErrorrQ   rM   )(r*   r  r  annotated_imageclass_colorsdefault_colorsrX  r  rO  aoi_positionr  rN  r   r  r  r  r  colorlabel_partsfont
font_scale	thicknessline_heightmax_text_widthtext_heights
label_part
text_widthtext_heightbaselinetotal_heightlabel_xlabel_yoverlayr   text_yr<  r=  kederV   s(                                           r+   draw_detections_from_listz*yolo_model_loder.draw_detections_from_list
  s   ^	#s<'8A'=<<IIHI#jjlO||		.s</@.AAQRS    LN *	s"i/ (8H!*>!:J#,[#9L!*+<!=J$X.D%h/E &d+B%d+B%d+B%d+B  </ ,X 6 .x#n:M/M N MM/B8b"XuaP &,bC(8:#K 33D!$J !I"$K &'N#%L&1
>Aoo&j)?;1[8 *-^Z)H$++K(,BC '2 $'{#3k#AA#EL !G </G {"${"2 //2G2G2JJ"1"7"7":^"Kb"P .224GMM'!(1gk :!(>!9A!=w?U V %r+ OOGS/3?[ *3;)?:!(AE[+@!@OZ!(& 1 $j /< *@  ,J7H+J7H  ||		$@yQ[P\ ]))3C(8
2$at1RDPQRTQUUV#X YU *r ||		>@""   ||		$STVSW"XY  ||		$J3r7)"TU  	||		:3q6(CDL	sl   .L AL ?JL G.J2!L 	L K=L L)K>8L >LL 	M*L?9M?Mc           
         	 |sy| j                  |      }|d   }|d   }|d   d   }d| }dj                  |j                         D 	cg c]  \  }}	| d|	  c}	}      }
d	|d
}t        j                  }d}d}||
|g}d}d}|D ]7  }t        j
                  ||||      \  \  }}}t        ||      }|||z   dz   z  }9 t        j                  |d|dz   |dz   fdd       t        j                  |d|dz   |dz   fdd       d}|D ]$  }t        j                  ||d|f||d|       |dz  }& yc c}	}w # t        $ r8}| j                  r"| j                  dt        |              Y d}~yY d}~yd}~ww xY w)u   
        在图像顶部绘制检测统计摘要
        
        Args:
            image: 要绘制的图像
            deleted_list: 检测结果列表
        Nrz  r{  r|  r}  ztotal_count : rR  ry   zavg_confidence: r   g333333?rt   r   r  )r  r  r  r   r   r   r   r           u!   ⚠️ 绘制统计摘要失败: )r  rS  rF  r  r  r  r  r  r  rQ   r   r1   rM   )r*   r  r  r  total_countclass_statsavg_confidencesummary_textr  count
class_textconfidence_textr  r  r  texts	max_widthr  textr  r  r  r-  rV   s                           r+   draw_detection_summaryz'yolo_model_loder.draw_detection_summary  s   1	H 00>G "(+K!.1K$%67DN ,K=9LHYHYH[$\H[*#uuAeW%5H[$\]J 00DEO ++DJI ":?EIL69oo$
I73)[8  	:6	h 6 ::  MM%INL2<M+N!2'MM%INL2<M+N', HE4"hj/9FB 9 %]B  	H||		=c!fXFGG 	Hs0   D7 AD7 D1
CD7 1D7 7	E8 )E33E8deleted_itemscale_masksc           
         	 t        |t              s| j                  r| j                  d       y|j	                  dd      }|j	                  di       }|j	                  dd      }| j                  ||      }| j                  rj| j                  d|        |r<| j                  d	|d
   dd|d   d       | j                  d|d    d|d           | j                  d|rdnd        g |d<   d|d<   d|d<   d|d<   d|d<   |s#d|d<   | j                  r| j                  d       y|j	                  d d      s6d!|d<   | j                  r$| j                  d"|j	                  d#d$              y|j	                  d%d      }|dk(  r#d&|d<   | j                  r| j                  d'       y| j                  r| j                  d(| d)       g }t        |d*         D ]M  \  }	}
	 |
d+   }| j                  r4| j                  d,|	 d-|
j	                  d.d/       d0|j                          t        |j                        d1kD  r;|j                  d   d2k(  r|d   }n#|j                  d1   d2k(  r|d   n|dddddf   }|j                  t        j                  t        j                  fv r&|d3kD  j                  t        j                        d4z  }n%|dkD  j                  t        j                        d4z  }t        j                  |      dk(  r#| j                  r| j                  d5|	 d6       R| j!                  |||||j	                  d7            }|r|j	                  d8      r|d8   D ]A  }|
j	                  d9|	      |d:<   |
j	                  d.d      |d;<   |
j	                  d<d      |d=<   C |j#                  |d8          | j                  r\| j                  d>t        |d8          d?       n:| j                  r.| j                  d5|	 d@t        j                  |dkD         dA       P |r|j-                  dE dFG       t        |      D ]  \  }}||dH<   |dk(  |dI<    ||d<   t        |      |d<   d|d<   d |d<   |j	                  dJd      }|t        |d*         k  r |d*   |   d+   |d<   |d   j                  |d<   | j                  r8| j                  dKt        |       d?       | j                  dL|d   dM           yFdN|d<   | j                  r| j                  dO| dP       y# t$        $ r]}| j                  rF| j                  dB|	 dCt'        |              ddl}| j                  dD|j+                                 Y d}~d}~ww xY w# t$        $ ra}| j                  r| j                  dQt'        |              t        |t              rg |d<   d|d<   d|d<   d#|d<   d|d<   d|d<   Y d}~yd}~ww xY w)Ru[  
        从单个deleted字典中提取轮廓信息，直接使用其内部的sam_result
        
        Args:
            deleted_item: 单个检测结果字典，包含sam_result字段
            scale_masks: bool, 是否将掩码数组也缩放到原始图像尺寸
                - True: 缩放掩码到原始尺寸（消耗更多内存，但坐标一致）
                - False: 保持掩码为推理尺寸，只缩放坐标点（默认，效率更高）
            
        Returns:
            bool: 是否成功提取轮廓
            
        该方法会在deleted_item中添加以下字段：
            "轮廓列表": [轮廓信息列表]
            "轮廓总数": int
            "主要轮廓索引": int  
            "轮廓处理状态": str
            "原始完整掩码": np.ndarray
            "掩码形状": tuple
        u   ❌ 输入不是字典格式FrB  rk   rC  
sam_resultNu"   🔍 提取单个检测项轮廓: u     📐 缩放信息: scale_x=r  r   
, scale_y=r  u        推理尺寸: inference_sizeu   , 原始尺寸: original_sizeu     🎯 掩码缩放模式: r  r     轮廓列表r      轮廓总数r      主要轮廓索引u   原始完整掩码r   r      掩码形状no_sam_result   轮廓处理状态u     ❌ 无sam_result数据r   
sam_failedu     ❌ SAM处理失败: r  u   未知错误
mask_countno_masksu     ❌ SAM结果中无掩码u     📊 处理 u    个SAM掩码masks
mask_arrayu       处理掩码 	   : 面积=	mask_areazN/Au	   , 形状=rt   rz   r   r   u         ⚠️ 掩码 u    为空掩码，跳过r  contour_list
mask_indexu   来源掩码索引u   来源掩码面积
is_largestu   是否来自最大掩码u         ✅ 提取到 
    个轮廓u,    未提取到轮廓 (掩码非零像素数: r   u         ❌ 处理掩码     时出错: u           详细错误: c                     | d   S )N   轮廓面积r  r  s    r+   r  zByolo_model_loder.extract_single_deleted_contours.<locals>.<lambda>I  s	    Q~5Fr-   T)r  reverse   轮廓索引   是否主要轮廓largest_mask_indexu     ✅ 成功提取 u        主要轮廓面积: r!  no_contours_foundu
     ❌ 从 u%    个掩码中未提取到任何轮廓u%   ❌ 提取单个deleted轮廓失败: )r   r   r   r1   rE  _calculate_scale_infory  r   ra   r   r   r   float64r   r   r   _extract_contours_from_maskr  rQ   rM   r  r  r  )r*   r  r  rO  aoi_infor	  
scale_infor  all_contours_infomask_idx	mask_infor  binary_maskcontours_infocontourmask_er  idxr%  rV   s                       r+   extract_single_deleted_contoursz0yolo_model_loder.extract_single_deleted_contours  s   *Y	lD1<<II<= &)).)DJ#''R8H%)),=J 33L*MJ||		>zlKLII =j>STW=XXbcmnwcxy|b}~II 3J?O4P3QQablm|b}a~  A		7KU]7^_` ,.L(+,L(13L-.15L-.+1L( 5D12<<II9:>>)U35A12<<II 7
wP^8_7`ab#a8JQ5?12<<II;<||		N:,mDE !#'0G1D'E#)1!*<!8J||		$5hZyWbdiIjHkktu  vF  vF  uG  #H  I :++,q0%++A.!3)3AJ:D:J:J1:MQR:RAXbcdefghchXiJ "''BJJ

+CC'1C'7&?&?&IC&O'1A~&=&=bhh&G#&M vvk*a/<< II(<XJF\&]^  %)$D$D[RZ\fhs  vB  vF  vF  GN  vO  %PM$):):>)J'4^'DG<EMM,X`<aG$89<EMM+WX<YG$89BK--P\^cBdG$>? (E
 *00~1NO<< II(<S~A^=_<``j&kl<< II(<XJFrsusysy  {F  IJ  {J  tK  sL  LM  'N  OW (Fj !!&&+FPT&U %..?$@LC.1GN+58AXG01 %A
 0A^,/23D/E^,56125>12 &0^^4H!%L"%Jw,?(@@9CG9LM_9`am9nL!563?@T3U3[3[L0<<II 3C8I4J3K:VWII 9:KA:N~:^9_`a 6I12<<II
:,6[\]O ! ||		$;H:\RUV\R]Q^"_`(		$:9;O;O;Q:R"STR  	||		A#a&JK ,-/1^,/0^,57125<125912/5^,	sq   -V C;V ,AV 49V .8V 'ET2/V 1C<T2-CV &V 2	V;AVV VV 	X$AX  Xr	  c                    	 |j                  d      }|| j                  r| j                  d       yt        |d      r|j                  dd \  }}n| j                  r| j                  d       yd}d\  }}|rq|j                  d      }	|	r)|	\  }}||f}| j                  r| j                  d	|        |s3|j                  d
      }
|
r | j                  r| j                  d|
        |s|r~d|v rz|d   ru|d   d   }|j                  d      }|Zt        |d      rNt        |j                        dk\  r6|j                  dd \  }}||f}| j                  r| j                  d|        |s'd}|\  }}| j                  r| j                  d|        ||z  }||z  }|||||f||||d|r|j                  d      rdndd
}| j                  ro| j                  d       | j                  d| d|        | j                  d| d|        | j                  d|dd|d       | j                  d|d           |S # t        $ r3}| j                  r| j                  dt        |              Y d}~yd}~ww xY w) u  
        计算从SAM推理尺寸到原始图像尺寸的缩放信息（支持动态推理尺寸）
        
        Args:
            deleted_item: 检测结果字典，包含原始图像信息
            sam_result: SAM推理结果，包含推理参数和实际推理尺寸
            
        Returns:
            dict: 缩放信息字典，如果无法计算则返回None
        r  Nu&       ❌ 无法获取原始图像信息r   rt   u#       ❌ 原始图像格式不支持NNinference_actual_sizeu0       📐 从sam_result获取实际推理尺寸: r  u'       📐 sam_result中的原始尺寸: r  r   r  u,       📐 从掩码数组获取推理尺寸: )r   r   u:       ⚠️ 无法获取实际推理尺寸，使用默认: Tdynamicfallback)
r  r  r  r  inference_widthinference_heightoriginal_widthoriginal_heightis_dynamic_inferenceinference_methodu0       ✅ 计算缩放信息成功 (动态推理):u          原始尺寸: r$  u          推理尺寸: u          缩放比例: X=r   , Y=u          推理方法: r?  u"       ❌ 计算缩放信息失败: )rE  r   r1   rn   r   ra   rQ   rM   )r*   r  r	  original_imager=  r<  r  r;  r:  actual_sizeoriginal_size_from_sam
first_maskr  r  r  r+  rV   s                    r+   r'  z&yolo_model_loder._calculate_scale_infox  s   Z	)--g6N%<<IIFG ~w/2@2F2Fr2J/<<IICD "N0:-o (nn-DE8C5$o&6%HN||		$TUcTd"ef &-7^^O-L*-<< II(OPfOg&hi "jW
5JzZaOb'03
'^^L9
)gj'.J:++,1<F<L<LRa<P9(/*:O)L<< II(TUcTd&ef "!+4B1 /<<II Z[iZjkl %6G%(88G #""0"1>!B#2$4"0#2(,1;
Of@gImwJ ||		LN		1.1A?BSTU		1/1B!DTCUVW		3GC=WSMRS		1*=O2P1QRS 	||		>s1vhGH	s#   0I  <I  0GI   	I<	)I77I<seg_maskr*  r+  rA  c                 *   ddl }ddl}	 t        ||j                        s |j                  |      }|j
                  |j                  k(  r |j                  |dk(  |dk(  z        r|}n|j
                  |j                  |j                  fv rY |j                  |      dk  r"|dkD  j                  |j                        dz  }n|dkD  j                  |j                        dz  }n^|j
                  |j                  k(  r"|dkD  j                  |j                        dz  }n#|j                  |j                        }|dkD  dz  }| j                  r6 |j                  |dkD        }	| j                  d|j                   d|	         |j                   ||j"                  |j$                        \  }
}|
s| j                  r| j                  d	       y| j                  r| j                  d
t'        |
       d       |j)                  dd      }|j)                  dd      }g }g }t+        |
      D ]  \  }}	  |j,                  |      } |j.                  |d      }|dk  r$| j                  r| j                  d| d|        V|j1                  |        |j2                  |      \  }}}} |j4                  |      }|d   dk7  r)t7        |d   |d   z        }t7        |d   |d   z        }n||dz  z   ||dz  z   }} |j8                  |      } |j,                  |      }|dkD  r||z  nd}|dkD  rd|j:                  z  |z  ||z  z  nd}||z  }|dkD  r||z  nd} d}!t'        |      dk\  ri	  |j<                  |      }"|"d   }#|#d   dkD  rI|#d   dkD  rAt        |#      dz  }$t?        |#      dz  }%|$dkD  r |j@                  d|%|%z  |$|$z  z  z
        nd}!|r|j)                  dd      }&|j)                  dd      }'t7        ||&z        }t7        ||'z        }t7        ||&z        }t7        ||'z        }t7        ||&z        }t7        ||'z        }t7        ||&z  |'z        }|t        |&|'      z  }| j                  r| j                  d|&dd|'d       |dkD  r||z  nd}(i })|%t'        |j                        dk(  r	  |jB                  |j                  |j                        }* |jD                  |*|gd       |j                  dd \  }+}, |jF                  |*|,|+f|jH                        }-|-dkD  }	 |jJ                  |	      rS||	   }.t'        |.      dkD  r |jL                  |.d       }/ |jN                  |.d       }0tQ        tS        |/d         d      tQ        tS        |/d         d      tQ        tS        |/d         d      d!tQ        tS        |0d         d      tQ        tS        |0d         d      tQ        tS        |0d         d      d!t7        t'        |.            d"})| j                  r| j                  d#| d$t'        |.       d%|/d   d&d'|/d   d&d'|/d   d&d(       n_dddd!dddd!dd"})| j                  rE| j                  d#| d)       n/dddd!dddd!dd"})| j                  r| j                  d#| d*       n1dddd!dddd!dd"})| j                  r|| j                  d#| d-       t'        |      t7        |      tQ        |d      ||||d.||z   ||z   ||z   |z   ||z   |z   d/||d0||z   ||z   d0tQ        |d      tQ        |d      tQ        | d      tQ        |!d      tQ        |(d      |)j)                  d1dddd!      |)j)                  d2dddd!      |)j)                  d3d      d4t'        |      d5d5dddd|j                  |jY                  d6d      j[                         d7d8}2|j1                  |2       | j                  r0| j                  d#| dt7        |       d9|d:d;t'        |               |syt+        |      D ]u  \  }4}2	 |
|4   }|r|r|j)                  dd      }&|j)                  dd      }'|j)                  d>|j                  dd       }5|5\  }6}7 |j8                  |      }8| |j                  |&|'g      z  j                  |j\                        }9|8 |j                  |&|'g      z  j                  |j\                        }: |jB                  |6|7f|j                        }* |jD                  |*|9gd        |jB                  |6|7f|j                        }; |j^                  |;|9gd6dt7        t        |&|'            ?       |9jY                  d6d      j[                         |2d@   dA<   |:jY                  d6d      j[                         |2d@   dB<   d>|2d@   dC<   | j                  r| j                  dD|4 dE|7 dF|6        | j                  dG|&ddH|'d       n |j`                  ||j                        }* |jD                  |*|gd        |j`                  ||j                        }; |j^                  |;|gd6dd?        |j8                  |      }8|jY                  d6d      j[                         }<|8jY                  d6d      j[                         }=|r|j)                  dd      }&|j)                  dd      }'|j)                  d>|j                        }5|<D >cg c]$  }>t7        |>d   |&z        t7        |>d   |'z        g& }?}>|=D >cg c]$  }>t7        |>d   |&z        t7        |>d   |'z        g& }@}>|?|2d@   dA<   |@|2d@   dB<   d>|2d@   dC<   | j                  rG| j                  dD|4 dI       | j                  dG|&ddH|'d       n|<|2d@   dA<   |=|2d@   dB<   d>|2d@   dC<   |rc|j)                  dd      |j)                  dd      |j)                  dJ|j                        |j)                  d>|j                        |dK|2d@   dL<   nd|2d@   dL<   |*|2d@   dM<   |;|2d@   dN<   | j                  rD |j                  |*dkD        }	 |j                  |;dkD        }A| j                  dD|4 dO|	 dP|A        x |r) |jb                  |      }C|Ct'        |      k  rd|C   dS<   nd6}C|t'        |      C||j                  dTS #  d}!Y 	JxY w# tT        $ rE}1| j                  r | j                  d+| d,tW        |1              dddd!dddd!dd"})Y d}1~1pd}1~1ww xY w# tT        $ r7}3| j                  r | j                  d<| d=tW        |3              Y d}3~3d}3~3ww xY wc c}>w c c}>w # tT        $ r}B| j                  r | j                  dQ|4 dRtW        B               |j`                  ||j                        |2d@   dM<    |j`                  ||j                        |2d@   dN<   g |2d@   dB<   Y d}B~Bd}B~Bww xY w# tT        $ r3}D| j                  r| j                  dUtW        D              Y d}D~Dyd}D~Dww xY w)Vu  
        从分割掩码中提取轮廓信息
        
        Args:
            seg_mask: 分割掩码数组
            aoi_info: AOI位置信息
            scale_info: 缩放信息字典，包含从推理尺寸到原始图像的缩放参数
                {
                    "scale_x": float,           # x方向缩放因子
                    "scale_y": float,           # y方向缩放因子
                    "inference_size": tuple,    # SAM推理尺寸
                    "original_size": tuple      # 原始图像尺寸
                }
            scale_masks: bool, 是否将掩码数组也缩放到原始图像尺寸
                - True: 缩放掩码到原始尺寸（消耗更多内存，但坐标一致）
                - False: 保持掩码为推理尺寸，只缩放坐标点（默认，效率更高）
            original_image: 原始图像数据，用于计算轮廓内像素的RGB统计信息
            
        Returns:
            dict: 轮廓信息字典，包含轮廓列表和统计信息
        r   Nr   r  r      u           掩码处理: 形状=u   , 非零像素=u           未找到任何轮廓u           找到 r  r  r  Tr  u             跳过过小轮廓 r  m00m10m01rt   rs   rz   r  r  u&             应用坐标缩放: scale_x=r   r
  r   r   )interpolationrZ  )RGB)	   RGB均值	   RGB中值   像素数量u             轮廓 u    RGB统计: 像素数=u   , RGB均值=(r   r  r   u'    RGB统计: 掩码区域无有效像素u    RGB统计: 掩码为空u             ⚠️ 计算轮廓 u    RGB统计时出错: u1    RGB统计: 原始图像不是3通道彩色图像r$  yr>  r?  )r  r  r  r  )r$  rS  rO  rP  rQ  )u   凸性u	   圆形度u	   矩形度u	   离心率u	   紧密度rO  rP  rQ  Fr   )   单独轮廓掩码   轮廓边界掩码   轮廓点坐标   轮廓凸包点r  u   原始轮廓点)r#  r!  u   轮廓长度	   边界框   绝对边界框u   轮廓中心   绝对中心u   轮廓特征u   轮廓点数r$  filter   轮廓掩码数据u	   , 周长=rZ   u	   , 点数=u       ⚠️ 处理轮廓 r  r  )r  r\  rV  rW     掩码坐标系u       轮廓 u!   : 掩码已缩放到原始尺寸 r$  u            缩放因子: X=r@  u,   : 坐标已缩放，掩码保持推理尺寸r  )r  r  r  r  masks_scaled   缩放信息rT  rU  u   : 掩码像素=u   , 边界像素=u       ⚠️ 生成轮廓 u    掩码数据时出错: r$  )r  r  main_contour_indexu   原始掩码r  u$   ⚠️ 从掩码提取轮廓失败: )2r  r{  r   ndarrayr  r   r   allr   r(  r  r   r   r   r1   r   findContoursRETR_EXTERNALCHAIN_APPROX_SIMPLEra   rE  ry  contourArea	arcLengthr   boundingRectmomentsr   
convexHullpi
fitEllipser"  sqrtrz  fillPolyr#  INTER_NEARESTr  r~  r  rM  r  rQ   rM   r  r  int32drawContours
zeros_liker\  )Er*   rE  r*  r+  r  rA  r  r   r/  mask_pixelscontoursr   aoi_x1aoi_y1r  contour_areasr3  r1  rN  	perimeterr$  rS  r'  r&  Mcxcyhull	hull_area	convexitycircularity	rect_arearectangularityeccentricityellipseaxesabr  r  compactness	rgb_statssingle_contour_mask
roi_height	roi_widthroi_maskmasked_pixelsrgb_mean
rgb_medianrgb_econtour_info	contour_er   r  target_heighttarget_widthcurrent_hullscaled_contourscaled_hullcontour_boundary_maskcontour_pointshull_pointsrj   scaled_contour_pointsscaled_hull_pointsboundary_pixelsr2  main_contour_idxrV   sE                                                                        r+   r)  z,yolo_model_loder._extract_contours_from_mask  sX   , 	i	h

3#288H- ~~)fbffh!mTW5X.Y& >>bjj"**%==rvvh'3.'/#~&=&=bhh&G#&M'/#~&=&=bhh&G#&M^^rxx/#+c>"9"9"(("Cc"IK"*//"((";K#.#4";K||$bff[1_5		9+:K:K9LO\g[hij +#**;8I8I3KbKbcKHa<<II =?||		OCM?*EF \\$*F\\$*FLM )( 3Wx*3??73D -gt <I ax<< II(EcU)TXSY&Z[ !((. "2!1!1'!:JAq!Q $G,Ax1} 5AeH!45 5AeH!45!"QT1q!t8B *3>>'2D / 5I4=My 0qI S\^_R_1ruu9t#3	I8M"NefK !"AI9BQTI%5AN $%L7|q(	-&4cnnW&=G#*1:D#Aw{tAw{$'IM$'IMKLq5wrwwqAaC!A#;/GVW
 "",..C"@",..C"@  G,G,G,G, g. g.  #4'>G#;<$-GW0E$E	<< II(NwWZm[efmnqer&st 7@!m$"2K !#I%1c.:N:N6OST6T0J2:"((;;L;LTVT\T\2]/(CLL)<wiM 5C4H4H!4L1J	'1szz2E	S]G^nqnn  (AH +3Q,K%rvvk20>{0K#&}#5#9/6rww}1/MH1:=q1QJ 27uXa[7I11M16uXa[7I11M16uXa[7I11M6* 27uZ]7KQ1O16uZ]7KQ1O16uZ]7KQ1O6*
 9<C<N8O1&I (,||(,		4EcUJ`aderas`t  uB  CK  LM  CN  OR  BS  ST  U]  ^_  U`  ad  Te  ef  go  pq  gr  sv  fw  wx  3y  )zDEATU>Vklst{|e}  PQ  1RI'+||(,		4EcUJq2r(s@APQ:Rghopwxay  LM  -N	#'<<$(II0A#F^._$` 9:2J_`ghopYq  DE  %F	<<N,F II(9#>o&pq ),L(9(+D	(-i(;!"%&!&
 #)1*"(1*"(1*q."(1*q.	, "$") "("!'")
 ',Iq&9).{A)>).~q)A).|Q)?).{A)>)2{!RSZ[D\)])2{!RSZ[D\)],5MM.!,L	) ),G.3"'2626/3/3,7,=,=/6r1/E/L/L/N/E*$LX !''5||		$5cU)CI;iXabeWffopst{p|o}"~i !4v   $-\#:<iO&qkG "k",..C"@",..C"@(2HYHYZ\[\H](^ 7D3| (6s~~g'> +2HBHHgw=O4P*P)X)XY[YaYa)b'3hbhh?Q6R'R&Z&Z[][c[c&d /7bhh|7T\^\d\d.e+$%8>:JCP08-9V^`^f^f0g-((()>@PRTVYehilmtv}i~e  A Q_PfPfgiklPmPtPtPv%9:;LMP[PcPcdfhiPjPqPqPs%9:;LMP_%9:;LM<< IIA36WXdWeefgtfu&vw II(A'#dSZ[^R_&`a
 /<bmmKrxx.X+$%87)SI 1>kQSQYQY0Z-((()>	2s^_` (6s~~g'> *1Q)?)F)F)H&2&:&:2q&A&H&H&J%&0nnY&DG&0nnY&DG,6NN?KL]L],^M m{4{lzfhc"Q%'/6JCPRSTPUX_P_L`5alz14{it1uitce3r!uw3GRPQUU\_I]2^it.1uTiL)=>?PQTfL)=>?PQTcL)=>?PQ#|| $		Ks:f*g h $		,Egc]RVW^_bVc*d e UcL)=>?PQT_L)=>?PQTcL)=>?PQ "'1~~i'E'1~~i'E.8nn=M{O`O`.a-7^^O[M^M^-_,7N%9:>J NR%9:>J PcL!567KLOdL!567KL||&,bff-@1-D&E*0"&&1F1J*K		Ks/+o^m]n"opE $;Z #,299]#; #c,&77KOL!123GH#%  !-"<0&6 + + 1 1 E-+,LR  ) J#|| $		,J3%Odehineodp*q r<=AA6Ncdklst]u  HI  )JIJv ! ||		$<SEcR[nM]"^_P 5|1uH ! O||		$<QC?WX[\bXcWd"efO\r}}]hprpxpxOyL!567KLO\r}}]hprpxpxOyL!567KLLNL!567HIO0  	||		@QIJ	s   Gy A$y 6Au6y C+u60A(tC)u6H
t%E=u6	y y "Kw>)v9'w-)v>D:wA
y t"u6%	u3.:u.(u6.u33u66	v6?,v1+y 1v66y 9
w	yA<yy yy 	z)zz	draw_type
mask_alphac           
         	 t        |t              s| j                  r| j                  d       y|j	                  d      dk7  r1| j                  r$| j                  d|j	                  dd              y|j	                  dg       }|s| j                  r| j                  d       y|j	                  d	d
      }|j	                  dd      }| j                  r#| j                  d| d| dt        |              | j                  |      }|dk(  r| j                  |||       n|dk(  r| j                  ||||       n|dk(  r| j                  |||       n|dk(  r| j                  |||       n|dk(  r| j                  |||       nn|dk(  r| j                  ||||dz         nQ|dk(  r| j                  ||||dz         n4| j                  r| j                  d| d       | j                  |||       | j                  |||       | j                  r| j                  d|        yy# t        $ r3}	| j                  r| j                  dt!        |	              Y d}	~	yd}	~	ww xY w)u:  
        在图像上绘制检测项的轮廓掩码 (直接修改输入图像)
        
        Args:
            image: 输入图像 (BGR格式) - 将被直接修改
            deleted_item: 检测结果字典，包含轮廓信息
            draw_type: 绘制类型，可选值：
                - "contour": 绘制轮廓线条（默认）
                - "mask": 绘制半透明填充掩码
                - "hull": 绘制凸包
                - "boundary": 绘制边界线
                - "points": 绘制轮廓点
                - "combined": 组合绘制（轮廓+凸包+中心点）
                - "all": 绘制所有类型
            mask_alpha: 掩码透明度，范围0-1（仅在draw_type为"mask"时使用）
        
        Returns:
            None: 直接修改输入图像，无返回值
        u"   ❌ deleted_item不是字典格式Nr  r   u!   ⚠️ 轮廓处理状态异常: r  r  u   ⚠️ 轮廓列表为空rB  rk   rA  r   u   🎨 绘制轮廓: u
   , 类型: u   , 轮廓数: r1  maskr|  boundarypointscombinedgffffff?rb  u   ⚠️ 未知的绘制类型: u   ，使用默认轮廓线条u   ✅ 轮廓绘制完成: u   ❌ 绘制轮廓失败: )r   r   r   r1   rE  ra   _get_draw_colors_draw_contour_lines_draw_filled_masks_draw_convex_hulls_draw_boundaries_draw_contour_points_draw_combined_draw_all_types_add_contour_labelsrQ   rM   )
r*   r  r  r  r  r  rO  r  colorsrV   s
             r+   draw_deleted_maskz"yolo_model_loder.draw_deleted_maske  s`   (:	lD1<<IIBC  45B<<II A,BRBRSgirBsAtuv'++NB?L<<II9: &)).)DJ#'':H||		/
|:i[P]^abn^o]pqr **84F I%((fEf$''|VZPf$''|VDj(%%e\6Bh&))%vFj(##E<cAQRe#$$UL&*sBRS<<II >ykIdef((fE $$UL&A||		4ZLAB   	||		4SVH=>	s*   -H, AH, 51H, 'FH, ,	I(5)I##I(c           	          ddddddd}|j                  |d      }|g |d	t        d
 |D              t        d |D              dddddS )u   获取绘制颜色方案r  r  r  r  r  r  r  )r  r  r  r  c              3   :   K   | ]  }t        d |dz           yw)r   2   Nr  r  cs     r+   r  z4yolo_model_loder._get_draw_colors.<locals>.<genexpr>  s     ?Jq#c1r6*J   c              3   :   K   | ]  }t        d |dz
          yw)r   r  N)r  r  s     r+   r  z4yolo_model_loder._get_draw_colors.<locals>.<genexpr>  s     Ajc!QVnjr  r  r  )r1  r  r|  r  r  centerr  
background)rE  tuple)r*   r  r  
base_colors       r+   r  z!yolo_model_loder._get_draw_colors  su     
 "%%h@
 "&j&#&?J??AjAA%!##	
 		
r-   r  contour_indextotal_contoursc           	      F   |dk  r|S |t        d|dz
        z  }ddl}ddl} |j                  |gg      } |j                  ||j
                        }|d   \  }	}
}t        |dz        }|	|z   dz  }t        |dz  dz
        }t        |dz  dz
        }t        dt        d	t        |
      |z               }t        d
t        d	t        |      |z               } |j                  |||ggg      } |j                  ||j                        }t        d |d   D              }|S )u  
        为单个轮廓生成色移颜色
        
        Args:
            base_color: 基础颜色 (B, G, R)
            contour_index: 轮廓索引
            total_contours: 总轮廓数
            
        Returns:
            tuple: 色移后的颜色 (B, G, R)
        rz   r   Nr  <      r  r  r   P   c           
   3   Z   K   | ]#  }t        d t        dt        |                   % ywr   r   Nr  r"  r   )r  r$  s     r+   r  z6yolo_model_loder._get_contour_color.<locals>.<genexpr>  s#     M}!SCSV$45}   )+)
r  r  r{  r   r   COLOR_BGR2HSVr   r"  COLOR_HSV2BGRr  )r*   r  r  r  shift_ratior  r   	bgr_array	hsv_arrayr&  sv	hue_shiftr)  	sat_shift	val_shiftnew_snew_vnew_hsvnew_bgrresult_colors                        r+   _get_contour_colorz#yolo_model_loder._get_contour_color  sE    Q $c!^a-?&@@ 	 BHHzl^,	 CLLC,=,=>	D/1a b()	Y#% b(2-.	b(2-.	 BCQ)!345BCQ)!345 "((eUE2345#,,w(9(9: Mwt}MMr-   r  c                 ~    |j                  di       }|r%|j                  dd      |j                  dd      dS dddS )u   
        获取AOI偏移信息
        
        Args:
            contour_info: 轮廓信息字典
            
        Returns:
            dict: 包含x_offset, y_offset的偏移信息
        rY  r  r   r  r.  r-  rE  )r*   r  abs_bboxs      r+   _get_aoi_offsetz yolo_model_loder._get_aoi_offset  sO      ##$5r: %LLq1$LLq1  !"q11r-   r  r  c           	         |d   }t        |      }t        |      D ]  \  }}|j                  dd      s"| j                  r| j	                  d| d       ;|j                  di       }|j                  dg       }	|	sbt        |	      dkD  sq	 t        j                  |	t
        j                  	      }
|j                  d
d      }|dk(  r9| j                  |      }|
dddfxx   |d   z  cc<   |
dddfxx   |d   z  cc<   t        |
j                        dk(  r|
j                  d   dk(  r|
j                  d      }| j                  |||      }t        d |D              }|j                  dd      }|rdnd}t        j                  ||gd||       | j                  r#| j	                  dt        |
       d| d|         y# t        $ r4}| j                  r| j	                  dt!        |              Y d}~d}~ww xY w)uW   绘制轮廓线条，直接修改输入图像，每个轮廓使用不同的色移颜色r1  r[  Fu         轮廓    : 跳过绘制 (filter=false)r\  rV  r   r   r]  r  r  Nr.  rz   r-  rt   r   rz   rt   c           
   3   Z   K   | ]#  }t        d t        dt        |                   % ywr  r  r  s     r+   r  z7yolo_model_loder._draw_contour_lines.<locals>.<genexpr>;  s#     *[]3q#c3q62B+C]r  r$  r   r   u         绘制轮廓线条: u    个点, 颜色: u
   , 厚度: u'         ⚠️ 绘制轮廓线条失败: )ra   ry  rE  r   r1   r   r  rp  r  r   r  r  r  r  rq  rQ   rM   )r*   r  r  r  r  r  r  r  contour_datar  r  coord_systemr*  r1  contour_color
safe_coloris_mainr  rV   s                      r+   r  z$yolo_model_loder._draw_contour_lines  s   I&
\*+4\+B'M<##He4<<IIm_<YZ['++,@"EL)--.?DN#n"5"9$XXnBHHEF $0#3#34E#WL#'77#'#7#7#Eq!t(<<q!t(<< 6<<(A-&,,q/Q2F"(.."< )-(?(?
M[i(j &+*[]*[%[
 #/"2"23G"O)0Aa	((	2z9U<< II(B3v;-O`ak`llv  xA  wB  'C  DU ,CX ! ||		$KCPQF8"TUs   D6G	H)H  Halphac           
         |syt        |d         dkD  r|d   dd n|d   }t        |      }| j                  r| j                  d| d|        t        |      D ]  \  }}|j	                  dd      s"| j                  r| j                  d	| d
       ;|j	                  di       }	| j                  |||      }
t        d |
D              }|	j	                  dg       }|rt        |      dkD  rp	 t        j                  |t        j                        }|	j	                  dd      }|dk(  r9| j                  |      }|dddfxx   |d   z  cc<   |dddfxx   |d   z  cc<   t        j                  |j                  dd t        j                        }|j                  d      }t        j                   ||gd       |dkD  }t        j"                  |      rHt%        d      D ]:  }|||f   d|z
  z  ||   |z  z   j'                  t        j                        |||f<   < | j                  r/t        j(                  |      }| j                  d	| d| d|        |	j	                  d      }|	 |	j	                  dd      }|	j	                  d      }|dk(  r|r|j	                  dd       }|j	                  d!d       }t/        |j                  d   |z        }t/        |j                  d   |z        }t        j0                  |||f      }| j                  |      }|d   |d   }}|j                  \  }} |||z   }"}!||| z   }$}#t3        d|!      t5        |j                  d   |"      }"}!t3        d|#      t5        |j                  d   |$      }$}#|"|!kD  rC|$|#kD  r=|"|!z
  |$|#z
  }&}%|%|k7  s|&| k7  rt        j0                  ||&|%f      }'n|}'|'dkD  }t        j"                  |      rS||!|"|#|$f   }(t%        d      D ]:  }|(||f   d|z
  z  ||   |z  z   j'                  t        j                        |(||f<   < | j                  rt        j(                  |      }| j                  d	| d| d"|        nc| j                  |      }|d   |d   }}|j                  \  }} |||z   }"}!||| z   }$}#t3        d|!      t5        |j                  d   |"      }"}!t3        d|#      t5        |j                  d   |$      }$}#|"|!kD  r|$|#kD  r|"|!z
  |$|#z
  }&}%|%|k7  s|&| k7  rt        j0                  ||&|%f      })n|})|)dkD  }t        j"                  |      rS||!|"|#|$f   }(t%        d      D ]:  }|(||f   d|z
  z  ||   |z  z   j'                  t        j                        |(||f<   < | j                  r/t        j(                  |      }| j                  d	| d| d#|         | j                  r| j                  d%       yy# t*        $ r7}| j                  r | j                  d| dt-        |              Y d}~d}~ww xY w# t*        $ r7}| j                  r | j                  d$| dt-        |              Y d}~%d}~ww xY w)&u`   绘制半透明填充掩码，直接修改输入图像，每个轮廓使用不同的色移颜色Nr  r   r1  u         开始绘制 u    个填充掩码，透明度: r[  Fu           轮廓 r  r\  c           
   3   Z   K   | ]#  }t        d t        dt        |                   % ywr  r  r  s     r+   r  z6yolo_model_loder._draw_filled_masks.<locals>.<genexpr>a  s#     OAs1c#s1v&67r  rV  r   r   r]  r  r  r.  rz   r-  rt   r  r   u	   : 绘制 u    个像素，颜色 u           ⚠️ 绘制轮廓 r  rT  r_  r  r  r  u#    个像素 (缩放掩码)，颜色 u#    个像素 (原始掩码)，颜色 u"           ⚠️ 绘制轮廓掩码 u(         ✅ 完成所有填充掩码绘制)ra   r   r1   ry  rE  r  r  r   r  rp  r  rz  r   r   r  r  rn  r  r   r   r   rQ   rM   r   r#  r  r"  )*r*   r  r  r  r  r  r  r  r  r  r  r  r  r  r  r*  r  r1  	mask_boolr  pixels_drawnrV   single_maskr+  r  r  
original_h
original_wscaled_maskr.  r-  mask_hmask_wr  r  r  r  target_htarget_w
final_maskregionresized_masks*                                             r+   r  z#yolo_model_loder._draw_filled_masksJ  s   +.vf~+>+BVF^BQ'yHY
\*<<II+N+;;YZ_Y`ab ,5\+B'M<##He4<<II>[\]'++,@"EL !33J~^MOOOJ *--.?DN#n"5"9 XXnBHHEF $0#3#34E#WL#'77#'#7#7#Eq!t(<<q!t(<< 88EKKO288DD$nnZ8GLLy#6 !%qIvvi(!&qA %il 3q5y A *1 5!6$fRXX. ")Q,/ "* ||')vvi'8		OM?)L>Ymnxmy"z{ +../CD*V!'3'7'78I?'[%1%5%5n%E
'+;;
&0nnY&DG&0nnY&DG *-[->->q-AG-K)LJ),[->->q-AG-K)LJ*-**[:zBZ*[K (,';';L'IH19*1ExPZG[hH .9->->NFF%-x&/@B%-x&/@B &)BZU[[^R1HB%(BZU[[^R1HB!Bw2757"Wb2g(#+v#5V9K14K(T\I]1^J1<J,6N	#%66)#4-22b5"R%<-@F-21X,29a<,@AI,N,6qME,A-B*0&*: )/y!|(< .6 $(<<3566)3DL$(IIiXdWe  fI  JT  IU  /V  %W (,';';L'IH19*1ExPZG[hH-8->->NFF%-x&/@B%-x&/@B &)BZU[[^R1HB%(BZU[[^R1HB!Bw2757"Wb2g(#+v#5V9K36::kHV^K_3`L3>L,81,<	#%66)#4-22b5"R%<-@F-21X,29a<,@AI,N,6qME,A-B*0&*: )/y!|(< .6 $(<<3566)3DL$(IIiXdWe  fI  JT  IU  /V  %WQ ,C^ <<II@B C ! ||		$@yY\]^Y_X`"abx % !<< II(J=/Ybcfghcibj&kl !s2   2E-X7M)Y	Y,X==Y	Z,Z  Zc                 (   |d   }t        |      }t        |      D ]  \  }}|j                  dd      s|j                  di       }|j                  dg       }	|	s@t        j                  |	t        j
                        }
| j                  |      }|
dddfxx   |d	   z  cc<   |
ddd
fxx   |d   z  cc<   | j                  |||      }t        d |D              }|j                  dd      }|rdnd
}t        j                  ||
gd||        y)uQ   绘制凸包，直接修改输入图像，每个轮廓使用不同的色移颜色r|  r[  Fr\  rW  r   Nr   r.  rz   r-  c           
   3   Z   K   | ]#  }t        d t        dt        |                   % ywr  r  r  s     r+   r  z6yolo_model_loder._draw_convex_hulls.<locals>.<genexpr>   #     "S]3q#c3q6*:#;]r  r$  rt   r   )ra   ry  rE  r   r  rp  r  r  r  r  rq  )r*   r  r  r  r  r  r  r  	hull_datar  r  r*  r  r  r  r  s                   r+   r  z#yolo_model_loder._draw_convex_hulls  s   F^
\*+4\+B'M<##He4$(()=rBI#--(92>K+RXX>//=q!t 44q!t 44 !% 7 7
MSa b #"S]"SS
 '**+?G!(Aa	  "j)L1 ,Cr-   c                    |d   }t        |      }t        |      D ]2  \  }}|j                  dd      s|j                  di       }|j                  d      }	|	@| j                  |      }
|
d   |
d   }}|	j                  \  }}|||z   }}|||z   }}t        d	|      t        |j                  d	   |      }}t        d	|      t        |j                  d
   |      }}||kD  s||kD  s||z
  ||z
  }}||k7  s||k7  rt        j                  |	||f      }n|	}| j                  |||      }t        d |D              }||||||f   |d	kD  <   5 y)uT   绘制边界线，直接修改输入图像，每个轮廓使用不同的色移颜色r  r[  Fr\  rU  Nr.  r-  r   rz   c           
   3   Z   K   | ]#  }t        d t        dt        |                   % ywr  r  r  s     r+   r  z4yolo_model_loder._draw_boundaries.<locals>.<genexpr>.  s#     &WAs1c#s1v.>'?r  )ra   ry  rE  r  r   r  r"  r  r#  r  r  )r*   r  r  r  r  r  r  r  	mask_databoundary_maskr*  r.  r-  r  r  r  r  r  r  r  r  r  r  r  s                           r+   r  z!yolo_model_loder._draw_boundaries  s   J'
\*+4\+B'M<##He4$(()=rBI%MM*>?M(//=%-j%98J;O( "/!4!4!8f#4B!8f#4B QSQ%<BQSQ%<B7rBw)+b"r'hH6)X-?'*zz-(HAU'V'4 %)$;$;JWe$fM "'&W&W!WJ =GE"R%B,'q(89K ,Cr-   c           	         |d   }t        |      }t        |      D ]  \  }}|j                  dd      s|j                  di       }|j                  dg       }	|	s@| j                  |      }
| j	                  |||      }t        d |D              }t        dt        |	      dz        }t        d	t        |	      |      D ]8  }|	|   }|d	   |
d
   z   }|d   |
d   z   }t        j                  |||fd|d       :  y)uT   绘制轮廓点，直接修改输入图像，每个轮廓使用不同的色移颜色r  r[  Fr\  rV  c           
   3   Z   K   | ]#  }t        d t        dt        |                   % ywr  r  r  s     r+   r  z8yolo_model_loder._draw_contour_points.<locals>.<genexpr>G  r  r  rz   r  r   r.  r-  rt   r   N)
ra   ry  rE  r  r  r  r  r   r  circle)r*   r  r  r  r  r  r  r  r  r  r*  r  r  stepr   pointr$  rS  s                     r+   r  z%yolo_model_loder._draw_contour_points3  s   H%
\*+4\+B'M<##He4'++,@"EL)--.?DN//= !% 7 7
MSa b #"S]"SS
 1c.1R78q#n"5t<A*1-Ea8J#77Aa8J#77AJJuq!faR@	 =' ,Cr-   c           	         | j                  ||||       | j                  |||       |D ]  }|j                  dd      s|j                  di       }|j                  dg       }|s>t        |      dkD  sMt	        j
                  |t        j                        }| j                  |      }	|dddfxx   |	d	   z  cc<   |ddd
fxx   |	d   z  cc<   t        t        |            D ]E  }
t        ||
         }t        ||
d
z   t        |      z           }| j                  ||||d   d
       G 	 |D ]  }|j                  dd      s|j                  di       }|s+|j                  dd      |j                  dd      }}|j                  dd      }|rdnd}t        j                  |||f||d   d       t        j                  |||f|d
z   |d   d
        y)uD   组合绘制（轮廓+凸包+中心点），直接修改输入图像r[  Fr\  rW  rt   r   Nr   r.  rz   r-  r|  rZ  r$  rS  r$  r  r   r  r   r  )r  r  rE  ra   r   r  rp  r  r   r  _draw_dashed_liner  r  )r*   r  r  r  r  r  r  r  r  r*  r   start_point	end_pointr  rz  r{  r  radiuss                     r+   r  zyolo_model_loder._draw_combinedQ  s    	|VUC 	  f= )L##He4$(()=rBI#--(92>Ks;/!3+RXX>//=q!t 44q!t 44 s6{+A"'q	"2K %fa!es6{-B&C DI**5+y&QW.Z[\ , )* )L##He4!%%nb9FC+VZZQ-?B&**+?G%1

52r(FF84DbI

52r(FQJvJ )r-   c                    | j                  ||||       | j                  |||       | j                  |||       | j                  |||       | j	                  |||       |D ]  }|j                  dd      s|j                  di       }|s+|j                  dd      |j                  dd      }}t        j                  |||fd|d   d	       t        j                  |||fd
|d   d        y)u-   绘制所有类型，直接修改输入图像r[  FrZ  r$  r   rS  rs   r  r   r  r  rz   N)r  r  r  r  r  rE  r  r  )	r*   r  r  r  r  r  r  rz  r{  s	            r+   r  z yolo_model_loder._draw_all_types|  s     	|VUCe\6:|V<  f=!!%v> )L##He4!%%nb9FC+VZZQ-?B

52r(Avh/?D

52r(Avf~qA )r-   c                     |j                  di       }|j                  di       }|rM|rK|j                  dd      |j                  dd      z
  }|j                  dd      |j                  dd      z
  }nd\  }}||d	S )
u   获取AOI偏移量rY  rX  r  r   r$  r  rS  r  r  r  )r*   r  r  rel_bboxr.  r-  s         r+   r  z yolo_model_loder._get_aoi_offset  s      ##$5r:##K4||D!,x||C/CCH||D!,x||C/CCH!%Hh$(;;r-   pt1pt2r  r  c                 @   ddl }|j                  |d   |d   z
  dz  |d   |d   z
  dz  z         }d}d}	||k  rt        j                  |||||       yt	        |||	z   z        }
t        |
      D ]  }|||	z   z  |z  }|||	z   z  |z   |z  }t	        |d   |d   |d   z
  |z  z         }t	        |d   |d   |d   z
  |z  z         }t	        |d   |d   |d   z
  |z  z         }t	        |d   |d   |d   z
  |z  z         }t        j                  |||f||f||        y)u   绘制虚线r   Nrt   rz   r  r   )mathrm  r  liner   r   )r*   r  r	  r
  r  r  r  distdash_length
gap_length
num_dashesr   start_ratio	end_ratiostart_xstart_yend_xend_ys                     r+   r  z"yolo_model_loder._draw_dashed_line  s`   yy#a&3q6/A-Q#a&10DDE
+HHUCeY7+
":;<
z"A{Z784?KkJ67+EMI#a&CFSVO{#BBCG#a&CFSVO{#BBCGA#a&3q6/Y!>>?EA#a&3q6/Y!>>?EHHUWg.yQ #r-   c                 .   	 |j                  dd      }|j                  dd      }|j                  dd      }|dk\  r|j                  dg       }|t        |      k  rw||   }|j                  di       }	|	r]|	j                  d	d      |	j                  d
d      }}
| d| d|j                  dd       g}| j                  |||
dz   |dz
  f|       yyyy# t        $ r5}| j                  r| j                  dt        |              |cY d}~S d}~ww xY w)u3   添加轮廓标签信息，直接修改输入图像rB  rk   r  r   r  r   r  rZ  r$  rS  z
Contours: zArea: r!  r  r  u   ⚠️ 添加标签失败: N)rE  ra   _draw_multi_line_textrQ   r   r1   rM   )r*   r  r  r  rO  contour_countmain_idxr  main_contourr  rz  r{  labelsrV   s                 r+   r  z$yolo_model_loder._add_contour_labels  s>   	%)).)DJ(,,^Q?M $''(<bAH1}+//Cc,//#/#9L)--nbAF!'C!3VZZQ5GB  *l(8$\%5%5na%H$IJ" 225&27BQSGBTV\] 	 0 &  	||		7Ax@AL	s   CC 	D*D	DDr  positionc           
         t         j                  }d}d}d}|\  }	}
d}|D ],  }t        j                  ||||      \  \  }}}t        ||      }. t	        |      |z  dz   }t        j
                  ||	dz
  |
dz
  f|	|z   dz   |
|z   f|d   d       t        j
                  ||	dz
  |
dz
  f|	|z   dz   |
|z   f|d	   d       t        |      D ]0  \  }}|
|dz   |z  z   }t        j                  |||	|f|||d	   |       2 y
)u   绘制多行文本r   rz   r  r   r  r  r  r   r  N)r  r  r  r  ra   r  ry  r  )r*   r  r  r  r  r  r  r  r  r$  rS  r  r  r  r  r   r  r   r  s                      r+   r  z&yolo_model_loder._draw_multi_line_text  s6   ''
	1 	D+.??4zS\+](%ZqIz2I  5zK/"4 	ea!eQU^a)ma.?\AQ-RL)2	/ea!eQU^a)ma.?\AQ-RF^Q	( !'GAt!a%;..FKKta[$
F6NT]^ (r-   main_aoisub_aoi	tolerancec                 .   	 t        fddD              rt        fddD              sddiS d   d   z  }d   d   z  }d   d   d	z  z   d
   d   d	z  z   g}d   d   d	z  z   d
   d   d	z  z   g}d   dkD  rd   d   z  n
t        d      }d   dkD  rd   d   z  n
t        d      }	d   d
   }}
|
d   z   |d   z   }}d   d
   }}|d   z   |d   z   }}|d   |d   z
  }|d   |d   z
  }t        j                  |d	z  |d	z  z         }ddl}|j                  |j                  ||            }|dk  r|dz  }t        |      |k  rt        |      |k  rd}n*t        |      t        |      kD  r
|dkD  rdnd}n	|dkD  rdnd}t        dt        |
|z
  ||z
              }t        dt        ||z
  ||z
              }|j                  |d	z  |d	z  z         }t        t        |
|z
        t        ||z
              }t        t        ||z
        t        ||z
              }|j                  |d	z  |d	z  z         }t        |
|      }t        ||      }t        ||      } t        ||      }!|| k  xr ||!k  }"|"rt        d| |z
        t        d|!|z
        z  nd}#|#dk(  r|dk(  rd}$n"d}$n|#|k(  r|#|k(  rd}$n|#|k(  rd}$n
|#|k(  rd}$nd}$||z   |#z
  }%|%dkD  r|#|%z  nd}&|dkD  r||z  n
t        d      }'d   dkD  rd   d   z  n
t        d      }(d   dkD  rd   d   z  n
t        d      })t        ||	z
        }*t        |'dz
        dk  rd}+n
|'dkD  rd}+nd}+t        |
|z
        |k  },t        ||z
        |k  }-t        ||z
        |k  }.t        ||z
        |k  }/t        |d   |d   z
        |k  }0t        |d   |d   z
        |k  }1||
z
  }2||z
  }3||z
  }4||z
  }5t        |
|      }6t        ||      }7t        ||      }8t        ||      }9|6|7|8|6z
  |9|7z
  d}:|"st        |
|z
  ||z
        n%t        |t        |
|      z
  t        ||      | z
        };|"st        ||z
  ||z
        n%t        |t        ||      z
  t        ||      |!z
        }<||k  }=||k  xs ||k   }>||k  xs ||
k   }?||kD  r	|| k  rd }@n\|| k  r	|| k  rd!}@nM|| k  r||kD  rd"}@n?||kD  r||kD  rd#}@n2t        |      |k  rt        |      |k  rd$}@nt        |      |k  rd%}@nd&}@|$dk(  rd}An
|$dk(  rd}And'}A|'d(kD  rd)}Bn
|'d*k  rd+}Bnd,}B|t        d      k(  s|	t        d      k(  rd-}Cn,t        ||	z
        }Dt        ||	      }Edt        d|D|Ez        z
  }Cd   d
   d   d   ||t        |d.      d/d   d
   d   d   ||t        |	d.      d/d0|t        |d	      ||t        |d	      t        |d	      t        |d      d1|"|$|#t        |dkD  r|#|z  ndd.      t        |dkD  r|#|z  ndd.      |%t        |&d.      d2t        |'d.      t        |(d.      t        |)d.      t        |*d.      |+d3|,|-|.|/|0|1||2|3|4|5d4|:|;|<|=|>|?d5@ABt        Cd.      d6d7}F| j                  r| j                  d8       | j                  d9d    d:d
    d;d    dd           | j                  d<d    d:d
    d;d    dd           | j                  d=| d>|d?d@|$        | j                  dA|2 dB|3 dC|4 dD|5        FS # t        $ rC}G| j                  r| j                  dEt        G              ddFt        G       icY d}G~GS d}G~Gww xY w)Gux  
        计算两个AOI框的各类数学关系
        
        Args:
            main_aoi: 主框 {'x': int, 'y': int, 'width': int, 'height': int}
            sub_aoi: 副框 {'x': int, 'y': int, 'width': int, 'height': int}
            tolerance: 对齐判断的容差（像素）
            
        Returns:
            dict: 包含各类数学关系的字典
        c              3   &   K   | ]  }|v  
 y wr  r  )r  r  r   s     r+   r  z?yolo_model_loder.calculate_aoi_relationships.<locals>.<genexpr>  s     P2O3sh2O   rR  c              3   &   K   | ]  }|v  
 y wr  r  )r  r  r!  s     r+   r  z?yolo_model_loder.calculate_aoi_relationships.<locals>.<genexpr>  s     L.KsC7N.Kr%  u   错误u   AOI数据格式不完整r>  r?  r$  rt   rS  r   infrz   Nih  u   居中u   右侧u   左侧u   下方u   上方u   相切u   分离u   完全重合u   主框包含副框u   副框包含主框u   部分重叠r  g?u   尺寸相近u   主框更大u   副框更大u   第一象限u   第二象限u   第三象限u   第四象限u   原点u   Y轴u   X轴u	   无包含g?u   主框大于副框g?u   副框大于主框u   大小相等r  r   )r$  rS  r>  r?  rE  u	   中心点u	   长宽比)u   主框u   副框)u   相对位置u   中心距离u   水平距离u   垂直距离u   最近边距离u   最远边距离u   连线角度)u   是否重叠u   重叠类型u   重叠面积u   重叠占主框比例u   重叠占副框比例u   并集面积u	   交并比)u   面积比例u   宽度比例u   高度比例u   长宽比差异u   尺寸关系)u   左边缘对齐u   右边缘对齐u   顶边缘对齐u   底边缘对齐u   水平中心线对齐u   垂直中心线对齐u   对齐容差u   左边距离u   右边距离u   上边距离u   下边距离)u   最小外接矩形u   最小水平间隙u   最小垂直间隙u   是否相邻u   是否同行u   是否同列)u   象限关系u   包含关系u   相对大小u   形状相似度)u   基础信息u   位置关系u   重叠关系u   尺寸比较u   对齐关系u   边界关系u   几何特征u   🔢 计算AOI关系完成:u      主框: (r  z) u      副框: (u      关系: u
   , 距离: r   u
   , 重叠: u      边界距离: 左=u   , 右=u   , 上=u   , 下=u   ❌ 计算AOI关系出错: u   计算出错: )rb  r  r   rm  r  degreesatan2absr  r"  rM  r   r1   rQ   rM   )Hr*   r   r!  r"  	main_areasub_areamain_center
sub_centermain_aspect_ratiosub_aspect_ratiomain_x1main_y1main_x2main_y2sub_x1sub_y1sub_x2sub_y2	center_dx	center_dycenter_distancer  anglerelative_positiondxdynearest_distancefar_dxfar_dyfarthest_distancer  r  r  r  is_overlappingr  overlap_type
union_arearj  
area_ratiowidth_ratioheight_ratioaspect_ratio_diffsize_relationshipleft_alignedright_alignedtop_alignedbottom_alignedh_center_alignedv_center_alignedleft_distanceright_distancetop_distancebottom_distancemin_bounding_x1min_bounding_y1min_bounding_x2min_bounding_y2min_bounding_recth_gapv_gapis_adjacentsame_rowsame_columnquadrantcontainmentrelative_sizeshape_similarity
ratio_diff	max_ratior   rV   sH    ``                                                                     r+   calculate_aoi_relationshipsz,yolo_model_loder.calculate_aoi_relationships  sh
   F	9P2OPPL.KLL "<== !)HX,>>Iw''(*;;H#C=8G+<+AA8C=S[\dSeijSjCjkK!#,)9Q)>>wW_O`deOe@efJJRS[J\_`J` 1HX4F FfklqfrGNxGX[\G\ww/'(2CCbghmbn  (}hsmWG&')::GhxFX<XWG$S\73<FF#gg&66AR8RFF #1A6I"1A6I ggilY\&ABO LLIy!ABEqy 9~	)c)ny.H$,!Y#i.009AH8!09AH8! QGf,fw.>?@BQGf,fw.>?@B#yyQQ7 Wv-.Gf4D0EFFWv-.Gf4D0EFF $		&!)fai*? @ Wf-JWf-JWf-JWf-J'*4Pj9PN`n3q*z"9:SJQ[D[=\\tuL q #q(#+L#+L9,1I#1L!X-#7L!Y.#7L#1L #X-<J/9A~,+1C 2:AX-5<JBI'BRUVBV(7+gg.>>\abg\hKELXEVYZEZ8H-0AA`efk`lL #$58H$H I :#$s*$2!c!$2!$2! w/0I=L& 01Y>Mg./9<K 6!12i?N";q>JqM#ABiO";q>JqM#ABiO #W,M#g-N!G+L$w.O "'62O!'62O!'62O!'62O$$(?:)O;	! DRC&(&7*:;WZ[ehklsu{h|[|  B  CJ  LR  S  V`  `  XaECQC&(&7*:;WZ[ehklsu{h|[|  B  CJ  LR  S  V`  `  XaE +i7K#v-B71BCH&&0EFg4EFK 9$iZ)?)iZ'I
,B)iZ'I	,A)Y&9y+@)Y9,Y91L#Y9,!! 332!552) C 4c! 4 . !E%L04De4T#&  !25E!EF
 13CD	#&S*y2H)I#I  &c]%c]!)'!2"*8"4"+%0%*+<a%@ %S\$S\!(!1")("3"*%/%*+;Q%?!, %6$)/1$=$-$-',-=q'A',->'B$)%O! %3$0$0-2y[\}<)3Kbcef-g-2hYZl<(3J`acd-e$.!&sA! %**a$8$)+q$9$),$:',->'B$5! (4'4'2'5-=-=$-$1$2$0$3!  +<*/*/$/$,$/! %-$/$1',-=q'A	!UPFd ||		79		L#q#r(SZJ[I\\]^fgo^p]qrs		La~RPWHXGYYZ[bck[lZmno		K(9':*_UXDYYcdpcqrs		1-~FVV\]i\jjp  rA  qB  C  DM 	9||		7Ax@As1vh788	9s#   +] \] 	^8^	^^)NTr  )rt   )r   )r   )r   )rk  )r  )r   )F)NFN)r1  333333?)rg  )r  )r  )`r  r  r  __doc__rM   r  r,   r1   r   r  rG   rW   rO   rP   listr]   r`   ro   rb   r   r   r   r   r   r   r   r  r  r  r
  r  r  r  rN   r   r   r  r   ra  r/  r   r   r   rH  rO  rP  rT  rU  rb  rc  r  r  rI  r  r  r  r  r  r  r  r  r;  r*  r,  r  r5  r/  r0  r1  rU  r  r  r  r  r  r  r  r  r4  r'  r)  r  r  r  r  r  r  r  r  r  r  r  r  r  r  rf  r  r-   r+   r   r   :   s   D(s (D (>C S C *s uT3Y7G ,. .4 .`)3 )T )V.c . .`62 62 62p#*#0=4F F FP'=# '=C '=R* * *XpS p pae pd? ?4C4&c &d &P$9S $9L=2	Y3 	YT 	Y
d3 
d 
dd 
d\c \d \0-d+$Z
S#X 
"#bjj #s #bjj #J>*RZZ >*c >*@N*rzz N* N*`@ @T @_b @gj @.$2:: $t $L;bjj ;$ ;"** 3 QSQ[Q[ :	U6Bpa+F$B,:l\*D *t *44"** 4C 4 4lD T *E d 2/U /t /b4 2	>D9# D9L  **c *"s "s "65"t 5"nt $R"4 R"hb"4 b"H["4 ["z0D 0T 0dA"T A"e A"^b A"F1 1 1SW 1f,4 ,T ,e ,\94 9D 9v"$4 "$\a "$lqrvx{r{l| "$Hirzz i iRTR\R\ iV9HBJJ 9Hd 9HvnD nt n`d nbe$ eD eT ePBBJJ B$ B\` Bvz B  UW  U_  U_ B  ko BJNrzz N NRU Not N  @D N`
 
 
2.U .3 .X[ .`e .`2D 2T 2,4 44 4QU 4l\C

 \C$ \CPT \C]b \C|M

 M$ MPT M>*Gbjj *G *Gd *GXA"** AD ARV A<)KBJJ )Kd )KD )KY^ )KVBRZZ Bt BT BZ_ B*<D <T <Rrzz R RE RRW Rdg R2 4 QU @_2:: _d _e _]a _8R9D R94 R9TW R9`d R9r-   r   sam_model_listr  
batch_size
seg_paramsr2   c                   ()*+ | r|s| S |i }|j                  dd      (|j                  dd      *|j                  dd      )|j                  dd	      +|j                  d
d	      }| D cg c]   }t        |t              r|j                  r|" }}|st	        d       y	t        |      D cg c]  \  }}t        |t              rd|v r||f }	}}|	st	        d       y	t        |	      }
t        |      }|rt	        d       t	        d| d|
        ()*+fd}ddlm	}m
} t        j                         }g }t        |	      D ]'  \  }\  }}||z  }||   }|j                  ||||f       ) g } ||d      5 }|D ci c]  }|j                  ||      | }} ||      D ]t  }	 |j                         }|j                  |       |rNt        |      t!        d|
dz        z  dk(  r0t        |      |
z  dz  }t	        d|ddt        |       d|
 d       v 	 ddd       t        j                         } | |z
  }!t'        d" |D              }"t        |      |"z
  }#t'        d# |D              }$|rt	        d$       t	        d%|
 d&|" d'|#        t	        d(|!d)d*       t        |      dkD  r_|$t        |      z  }%|!dkD  r|$|!z  nd}&|!dkD  rt        |      |!z  nd}'t	        d+|%d)d*       t	        d,|&d-d.       t	        d/|'d-d0       |#dk(  S c c}w c c}}w c c}w # t"        $ rN}||   }|\  }}}}|j                  d	||dddd       |rt	        d| d | d!t%        |              Y d}~d}~ww xY w# 1 sw Y   bxY w)1u  
    多模型FastSAM分割推理（优化版）
    
    使用ThreadPoolExecutor进行高效的并行处理，减少线程管理和同步开销。
    
    主要优化：
    1. 使用ThreadPoolExecutor替代手动线程管理
    2. 预分配任务，避免队列竞争  
    3. 减少不必要的内存拷贝
    4. 简化日志输出
    
    Args:
        sam_model_list: FastSAM模型实例列表 [yolo_model_loder, ...]
        deleted_list: 检测项列表，每个检测项必须包含'image'字段
        batch_size: 保留参数（兼容性），实际不使用
        seg_params: 分割参数字典
    
    Returns:
        bool: 是否所有任务都成功完成
    Nu   置信度阈值rg  	   IOU阈值r     输入尺寸r   u   高精掩码Fr   u"   ❌ 没有可用的已加载模型r  u   ❌ 没有有效的任务u*   🚀 开始FastSAM并行推理 (优化版)u      可用模型数量: u   , 任务数: c                 n   | \  }}}}t        j                         }	 t        j                         }t        t        |d   j                  dd             }|d   j                  dd \  }}	|j                  |d   |j                   |dd      }
t        j                         |z
  }d}d}d}|
r|
d   j                  |
d   j                  j                  }t        |      }|dkD  rM|g t        |d      |d	|||	fdd
}t        j                  |j                  |d      d      }d}t        |      D ]  }||   j                         j!                         }||   j#                         }||z  }|dk(  r|j                  dd |d<   ||t%        |      |j                  t'        |j(                        dd}|d   j+                  |        |dkD  rRt        j,                  |      j#                         }d	|d   |   d<   ||d<   t%        ||   j#                               |d<   t%        |      |d<   t        ||z  d      |d<   |D cg c]  }t%        |j#                                c}|d<   ||d<   |   j#                         }||   j                         j!                         |d<   t%        |      |d<   d	|d<   t        |d      |d<   ||d<   ||d<   d|v rO|d   j/                  dd      |d   j/                  d d      z  }t        |t        |d      z  d      |d!<   |d!   |d"<   d	}t%        |      }n7dg t        |d      |dd#|||	fdd$	|d<   ndg t        |d      |dd%|||	fdd$	|d<   |s"|j1                  dddt        |d      ||d&       t        j                         |z
  }||||||d+S c c}w # t2        $ rr}dg d|dt'        |      d't5               v rndd(t5               v rd)t5               v r	fnddd$	|d<   |j1                  dddt'        |      |d*       d}d}d}Y d}~d}~ww xY w),u   处理单个分割任务r  Nrt   r  F)r   retina_masksr   r   rj  rn  r   r   rs   T)r  r  r   processing_workerr   r  r  r7  r   rz   r  r7  )r  r  r  
mask_shape
mask_dtyper  r  r  r%  largest_mask_areatotal_mask_areaaverage_mask_area
mask_areasr	     分割掩码   掩码面积   有精细分割   分割推理时间   分割掩码数量   处理workerrC  r>  r?  u   掩码覆盖率largest_mask_coverageu   找到掩码但都无效)	r  r  r   rr  r   r  r  r  r7  u   未检测到分割掩码)ry  rz  r{  r|  r}  r~  seg_imgsz_curr=  r<  )ry  rz  r{  u   分割错误r~  r   task_id	worker_idr  r   total_task_time)r^   r   r"  r  r   r   r   r  r  ra   rM  r:   r   viewr   r4   r{  itemr   rM   r   r   r\  rE  r  rQ   locals)!r   r  detect_itemr   r  task_start_timeinference_startr  r=  r<  seg_resultsr   r   r  r  r  r	  rx  rv  r3  r  mask_area_singler.  largest_idxrN  largest_areabox_arearV   task_total_timeseg_confidence_threshold	seg_imgszseg_iou_thresholdseg_retina_maskss!                                r+   process_single_taskz5mulity_sam_run_optimized.<locals>.process_single_taskC  s6   15.eY++-g	"//1O  K$8$>$>r$B CYOM /:'.B.H.H!.L+O^++G$||-#-% & 	K "..0?BN GIJ{1~33?#A,,11 Z
> '1!#*/*B-6#'*7*9>)J15
"J "'5::j"+E1!MJ&'O  %Z0$)#JNN$4$:$:$<	+5c?+?+?+A('+;; !8BK//RTSTBUJ'>? +.*3),-=)>*3//*-ioo*>*/%	 #7+229=#  1( "A~&+ll:&>&C&C&EIM
7+K8F;F
#78:=j>U>Z>Z>\:]
#67 584HJ016;Oj<XZ[6\J23MW/XZTDIIK0@Z/XJ|, 1;K- $.k#:#?#?#AL272D2H2H2J2P2P2RK/25l2CK/59K 128=na8PK 458BK 452;K/ #k1#.{#;#?#?#KkZeNfNjNjksuvNw#w9>|cRZ\]N^?^`a9b$56>IJ[>\
#:;"G #L 1I '(!#*/*B-6#(!;*7*9>)J151K- #$&+NA&>)2$7&3&5~%F-1-L) ""$($%',*/*B*4$-$ F ++-? "",.
 	
w 0Y~  	  "#%. Q3Bfh3N-TXFW[a[cFchx  }C  }E  iE/>!B  KO)-)K%  $ !#( #A )   NIG1	s,   H,N9 
 N4*D*N9 4N9 9	P4A(P//P4r   r	   zFastSAM-Worker)max_workersthread_name_prefixrz   r  r  u   📊 进度: z.0fz% (r9  r   r  u   ❌ Worker-u    处理任务 r  c              3   ,   K   | ]  }|d    s	d  yw)r   rz   Nr  r  rs     r+   r  z+mulity_sam_run_optimized.<locals>.<genexpr>,  s     ;7aa	l7s   
c              3   &   K   | ]	  }|d      yw)r   Nr  r  s     r+   r  z+mulity_sam_run_optimized.<locals>.<genexpr>.  s     DGqq!12Gs   u&   
📊 FastSAM推理完成 (优化版):u      总任务: u
   , 成功: u
   , 失败: u      总耗时: r   r[   u      平均推理时间: u      理论加速比: rZ   r$  u      实际吞吐量: u    任务/秒)rE  r   r   r   r0   ry  r   ra   concurrent.futuresr
   r   r^   r   r   submitr   r  rQ   rM   r   ),rj  r  rk  rl  r   mavailable_modelsr   r  valid_taskstotal_tasksnum_workersr  r
   r   rd   	task_argsr  r  	model_idxr   rB  executorr   future_to_taskfuturer   progressrV   task_args_for_futurer   r  end_time
total_timesuccess_countfailed_counttotal_inference_timeavg_inference_timetheoretical_speedup
throughputr  r  r  r  s,                                           @@@@r+   mulity_sam_run_optimizedr    s   ,  
)~~.?E"{C8~s3I!~~ne<nnY.G $2 Q>a$Q(89a>O>O > Q 23 -6l,C B,CD t,D t9,CK B )*k"K&'K:<'}M+OPx
v D""$J I%.{%;!!G[O	 +';yAB &< G	HX	Y]eW`aW`t(//*=tDdJW`a">2F]v& s7|c![B5F.GG1L"7|k9C?HM(3s3w<.+VWXY 3 
Z<   "HJ&J;7;;Mw<-/LDGDD79{m:m_J|n]^z#.c23w<!!5G!DGQTU~"6"C[\6@1nW
2!J+,>s+C3GH()<S(ACD(C(8DE1eQBp b  ]'5f'=$+?(Ay$&!*!"&''(   K	{.	SVWXSYRZ[\] 
Z	YsV   .%L1"L?N L!N ,A1L&N !N &	M=/AM82N 8M==N  N
detect_model_listdetect_paramsc           	         ddl }| r|y|i }|j                  dd      }|j                  dd      }|j                  dd      }|j                  d	d
      }d}	d}
t        |       D ]Q  \  }}|	t        |d      r'|j	                         r&|}	|}
|rt        d|         n|}	|}
|rt        d| d        n |	yt        d      }t        |       D ]I  \  }}|		 t        |d      r.|j                         }|j                  dd      }||k  r|}|}	|}
n|}	|}
 nK |	r|rt        d|
 d|dd       |	[|rt        d       | D ]I  }||}	| j                  |      }
t        |d      r$	 |j                  |       |rt        d|
 d        n |	|rt        d       y	 |rt        d|
 d         |j                         }|	j                  ||	j                  ||d!      } |j                         }||z
  }|rt        d"|
 d#|d$d%       |S #  Y ExY w#  |rt        d|
 d       Y xY w# t        $ r&}|rt        d&|
 d't        |              Y d}~yd}~ww xY w)(u  
    多模型YOLO检测推理（优化版）- 负载均衡模式
    
    从多个检测模型中挑选一个不忙的模型来处理单个图像
    
    Args:
        detect_model_list: YOLO检测模型实例列表 [yolo_model_loder, ...]（已初始化完成）
        src_image: 输入图像 (np.ndarray)
        batch_size: 保留参数（兼容性），实际不使用
        detect_params: 检测参数字典
    
    Returns:
        model_results: 检测结果，如果所有模型都忙则返回None
    r   Nrn  rk  ro  r   r   Fu   最大等待时间g      @r   is_model_busyu   🎯 选择空闲模型 u   🎯 选择模型 u    (无状态管理)r'  
get_statustask_durationu   🎯 选择负载最轻模型 u
    (负载: r   zs)uC   ⚠️ 所有模型都忙，等待或使用第一个可用模型...wait_until_idle)timeoutu   ✅ 模型 u    已变为空闲u   ⚠️ 等待模型 u    空闲超时，强制使用u   ❌ 没有可用的检测模型u   🚀 使用模型 u    进行检测推理)r   rj  r   r   u   ⚡ 模型 u    推理完成，耗时: r8  r[   u   ❌ 模型 u    推理失败: )r^   rE  ry  rn   r  r0   r  r  r   r  r   r   r   rQ   rM   model_results_list)r  	src_imagerk  r  r^   model_iou_thresholdr   r   max_wait_timeavailable_modelselected_model_idxr   r   min_loadr   current_loadmodel_startr2  	model_endr   rV   s                        r+   mulity_detect_run_optimizedr  A  s*    	 1 '++K>nc2E	51G!%%&:C@M O /05= 5/*&&("'%&"4QC89 $O!"*1#-?@A% 1* <!"34HAu}5,/"--/F#)::oq#AL#h.#/*/-.* ',O)*&! 5( w23E2FjQYZ]P^^`ab WX 'E "'%6%<%<U%C" 5"34k--m-D"!K0B/CCS"TU  '" 34&'9&::MNO'd'') (11"))# 2 
 &D%%'	"[0K 233KN[^K__bcdq,k"!$89K8LLh"ijB  K 23?3q6(KLs1   >H+#H"A.H1 HH.1	I :II r6  )%rh  rer  r{  r   typingr   r   r   r^   sysr   pathlibr   r   shutil	threadingqueuer:   torchvision.transforms
transformsPILr   r  r
   r   rm   r   rl   r   r   ri  r   r   r  r  r  r  r-   r+   <module>r     s    
 
  & &  
 	       +   ?  "  6LG9 LG9\NvT v vSV vko v{ vr	H4 HPS Hko HCY  "!"s   "B BB