o
    i*                 
   @   sH  d Z ddlZddlZddlZddlmZmZmZm	Z	m
Z
 ddlZddlZddlZddlZddlZddlmZ ejeZejeZeejvrMeje ddlmZ zddlmZ ddlmZ dd	lmZ W n. ey Z z"e d
e  G dd dZ!e! ZG dd dZ"e"Ze"ZW Y dZ[ndZ[ww dd Z#G dd deZ$dS )u[   
极耳翻折检测器实现
从原始ear_fold_detection_plugin.py中提取的检测逻辑
    N)DictAnyListTupleOptional)datetime   )BaseDetector)yolo_model_loder)yolo_cls_model_loader)utilsu    ⚠️ 无法导入utils模块: c                   @   s   e Zd Zedd ZdS )	TempUtilsc                 C   s  z| du rt d tjdtjdW S | jdd \}}t|d t|d t|d t|d	 f\}}}}td
t||d }td
t||d }t|| |}t|| |}	||ks_||	krt d| d| d| d| d| d|  tjtd|td|dftjdW S | ||	||f }
|
jd
 |ks|
jd |krtj||dftjd}|
jdd \}}|
|d|d|f< |W S |
W S  ty } z t d|  tj|	d	d|	dddftjdW  Y d}~S d}~ww )u9   从图像中根据AOI提取子图像，包含边界检查Nu   错误：输入图像为None)d   r      dtype   xywidthheightr   r   u   警告：无效AOI区域 x=, y=, w=, h=u   , 图像尺寸=r   u   图像提取失败: r   )
printnpzerosuint8shapeintmaxmin	Exceptionget)imageaoiZimg_hZimg_wr   r   whx2y2resultpaddedZresult_hZresult_we r-   ;   D:\pyccd\极耳翻折-拆分\detectors\ear_fold_detector.pyget_cv_img_fronm_aoi"   s2   4,$2zTempUtils.get_cv_img_fronm_aoiN)__name__
__module____qualname__staticmethodr/   r-   r-   r-   r.   r   !   s    r   c                   @   s   e Zd Zdd Zdd ZdS )TempModelLoaderc                 C   s
   d| _ d S )Nu   模型加载器未正确导入)model_load_errorselfr-   r-   r.   __init__J   s   
zTempModelLoader.__init__c                 C   s   t d|  dS )Nu   ⚠️ 临时模型加载器: F)r   )r7   pathdevicer-   r-   r.   load_from_path_with_deviceM   s   z*TempModelLoader.load_from_path_with_deviceN)r0   r1   r2   r8   r;   r-   r-   r-   r.   r4   I   s    r4   c              
   C   s  zl| \}}|\}}|\}}||krd| | }	|}
|	|
fW S ||kr/|}	d| | }
|	|
fW S || }|| }|| ||  }|| ||  }|dkrN| W S d|| ||  |  | }|||  }	|||  }
|	|
fW S  t y } ztd|  | W  Y d}~S d}~ww )u  
    计算一个点关于一条直线的镜像点
    
    Args:
        point: 要镜像的点 (x, y)
        line_point1: 直线上的第一个点 (x1, y1)
        line_point2: 直线上的第二个点 (x2, y2)
        
    Returns:
        tuple: 镜像后的点坐标 (x', y')
    r   r   u   镜像点计算异常: N)r"   r   )pointZline_point1Zline_point2pxpyx1y1r(   r)   Zmirror_xZmirror_yabcdenominatorZfactorr,   r-   r-   r.   mirror_point_across_lineU   s6   


rE   c                       s  e Zd ZdZ fddZdefddZd+deeef de	fd	d
Z
dd Zd+dejdeeef deeef fddZdd Zdejdeeef deeef fddZdeeef fddZd+dedejdeeef deeef fddZd+dejdeeef deeef fddZd,dd Zdejdeeef deeef fd!d"Zd#d$ Zdeeef fd%d&Zd-d'd(Z fd)d*Z  ZS ).EarFoldDetector   极耳翻折检测器c                    s^   t  jdddd d | _d | _d | _t | _t | _t | _	d| _
d| _d| _d | _d S )NrG   z1.0.0u+   基于YOLO的极耳翻折单图检测算法)nameversiondescriptionzcuda:0r   )superr8   	cut_modeldetect_modelgm_cls_model	threadingLockcut_model_lockdetect_model_lockgm_cls_model_lock	cuda_name	run_countZerror_countcached_paramsr6   	__class__r-   r.   r8      s   



zEarFoldDetector.__init__returnc                 C   s   dS )u'   返回当前检测器的配置文件名zear_fold_detection_params.jsonr-   r6   r-   r-   r.   get_config_filename   s   z#EarFoldDetector.get_config_filenameNconfig_paramsc              
   C   s   z+t d |dur|| _n|  | _t | _t | _t | _|   t d d| _	W dS  t
yJ } zt dt|  d| _	W Y d}~dS d}~ww )u   
        初始化检测器，加载模型和配置
        
        Args:
            config_params: 配置参数字典，如果为None则使用默认配置
        u&   🚀 初始化极耳翻折检测器...Nu   ✅ 检测器初始化成功Tu   ❌ 检测器初始化失败: F)r   
parametersget_default_parametersr
   rL   rM   r   rN   _warm_up_modelsinitializedr"   str)r7   r[   r,   r-   r-   r.   
initialize   s$   
zEarFoldDetector.initializec              
   C   sT  zt d | jdi }| jdi }| jdi }| jr|drz]|dd}|dd}|rt d	| d
| d | j|| jrvtjjdd||dftj	d}| j
 | jj|| j|dd W d   n1 slw   Y  t d n	t d| jj  W n ty } zt d|  W Y d}~nd}~ww | jr|drz|dd}|dd}	|dd}
|dd}|	rht d| d
| d | j|	| jr_dddddd d!}| j| |d"i }|d#d}|| j_|
| j_|r,|d$d%|d&d%|d'd%|d(d%|d)d%|d*d%d+}| D ]\}}| j|| qtjjdd||dftj	d}| j | jj|| j||dd, W d   n	1 sUw   Y  t d- n	t d.| jj  W n ty } zt d/|  W Y d}~nd}~ww | jr|drz_|dd0}|dd}|rt d1| d
| d | j|| jrtjjdd||dftj	d}| j | jj|| j|d2 W d   n	1 sw   Y  t d3 n	t d4| jj  W n ty } zt d5|  W Y d}~nd}~ww t d6 W dS  ty) } zt d7|  W Y d}~dS d}~ww )8ui   
        预热模型：使用虚拟数据进行一次推理，确保模型完全加载并优化
        u   🔥 开始模型预热...   极耳裁切模型参数   极耳翻折检测模型参数   隔膜检测模型参数   模型路径   输入尺寸    u     🔥 预热裁切模型 (r   z)...r      r   r   F)r:   imgszverboseNu        ✅ 裁切模型预热完成u%       ⚠️ 裁切模型加载失败: u"       ❌ 裁切模型预热失败:    置信度阈值皙?	   IOU阈值?u     🔥 预热检测模型 (JEjezaGMqiaoqigemofencengZclass1Zclass3Zclass4class0Zclass2Zclass5   独立置信度参数   启用独立置信度   极耳置信度皙?   折痕置信度   月牙置信度   极耳内插置信度   极耳内嵌置信度   分层置信度rp   rq   rr   rs   rt   ru   r:   Ziourj   rk   u        ✅ 检测模型预热完成u%       ⚠️ 检测模型加载失败: u"       ❌ 检测模型预热失败:    u!     🔥 预热隔膜分类模型 ()r:   rj   u&       ✅ 隔膜分类模型预热完成u+       ⚠️ 隔膜分类模型加载失败: u(       ❌ 隔膜分类模型预热失败: u   🔥 模型预热完成！u   ❌ 模型预热异常: )r   r\   r#   rL   r;   rT   r   randomZrandintr   rQ   	predictExr5   r"   rM   set_class_namesuse_independent_confglobal_confitemsset_class_confidencerR   rN   load_from_pathrS   predict)r7   Zcut_model_paramsZdetect_model_paramsgm_cls_model_paramsZ	cut_imgszcut_model_pathZdummy_imager,   Zdetect_imgszZdetect_model_pathZdetect_confidenceZ
detect_iouusr_class_nameindependent_confindependent_conf_enabledindependent_conf_values
class_name
conf_valueZgm_imgszZgm_model_pathr-   r-   r.   r^      s   






	

zEarFoldDetector._warm_up_modelsr$   paramsc              
   C   sX  | j sddiS td |dur|n| j}zkt }| ||}i }d|v r,d|d< |W S |dg |d< |di |d< |d	d
|d	< |jdd \}}|di }	|	dd}
||
 }||
 }| |dg |||d< t }td|| dd |W S  t	y } z tdt
|  ddl}|  ddt
| iW  Y d}~S d}~ww )u   
        执行检测（仅翻折检测）
        按照run_all的输出格式设计，主要输出标注相关信息
           错误信息   检测器未初始化u    🔍 开始极耳翻折检测...N   异常结束   推理异常结束cbv1_text_itemsresult_info   结果NGr   rc   rf   rg   
draw_itemsdraw_items_original   检测耗时: .2f   秒u   ❌ 检测异常: r   u   检测异常: )r_   r   r\   timeperf_counter_run_detectionr#   r   _scale_draw_items_to_originalr"   r`   	traceback	print_exc)r7   r$   r   detection_params
start_timeZ
raw_resultr*   original_heightoriginal_widthmodel_paramsZmodel_input_sizescale_xscale_yend_timer,   r   r-   r-   r.   detectA  sD   zEarFoldDetector.detectc                 C   s  i }|s|S t |D ]\}}| }|ddkrPd|v rOd|v rOt|d d | t|d d | d|d< t|d d | t|d d | d|d< n|ddkrsd	|v rrt|d	 d | t|d	 d | d|d	< nc|dd
krd|v rg }|d D ]}	|t|	d | t|	d | d q||d< n6|ddkrd|v rt|d d | t|d d | d|d< d|v r|| d }
t|d |
 |d< ||d| < q
|S )u  
        将512x512图像的绘图项坐标还原到原始图像尺寸
        参考主程序detect_only的坐标还原逻辑
        
        Args:
            draw_items: 绘图项列表（512x512尺寸）
            scale_x: X方向缩放比例
            scale_y: Y方向缩放比例
            
        Returns:
            dict: 还原到原始图像尺寸的绘图项字典
        type	rectangletopLeftbottomRightr   r   r   r   textpositionpolygonpointscirclecenterradiusr   item_)	enumeratecopyr#   floatappend)r7   r   r   r   r   iitemZscaled_itemZscaled_pointsr<   Z	avg_scaler-   r-   r.   r     sP   




z-EarFoldDetector._scale_draw_items_to_originalc                 C   s  i }i |d< i |d< g |d d< g |d d< d|d< | di }| dd	}| d
d}| dd}| dd}| di }	|	 dd}
| dd}| di }| di }| dd}| dd}| dd}| dd}| dd}| d d!}| d"d#}| d$d%}| d&d}| d'd(}| d)d*}| d+d}| d,d-}| d.d-}| d/d}| d0d(}| d1d}| d2d}| d3d4} | d5d6}!| d7d8}"| d9d}#| d:d	}$| d;d<}%| d=i }&|& dd	}'|& dd>}(| d?i })|) d@d}*|) dAd}+|},|,jdBdC \}-}.t|,||f},tdD|. dE|- dF| dE|  t }/|/}0| j|| j	}1|1sWtdG| jj
  |d d dH| jj
  |S dIdJdKdLdMdNdO}2| j|2 |
| j_|| j_|
r|	 dPdQ|	 dRdQ|	 dSdQ|	 dTdQ|	 dUdQ|	 dVdQdW}3|3 D ]\}4}5| j|4|5 q| jN z| jj|,| j	||ddX}6W n7 ty }7 z*tdYt|7  |d d dZt|7  d|d[< |W  Y dB}7~7W  dB   S dB}7~7ww W dB   n	1 sw   Y  t }8|8|0 }9td\|8|0 d]d^ | j}:|:|6};t }<td_|<|8 d]d^ | j|;d`\}=}>|;D ]}?|?da |2v rC|2|?da  |?da< q2t }@tdb|@|< d]d^ d}At|;dckr_d}A|r%|d-ksl|d-kr|,jdBdC \}-}.t|.| }Bt|-| }Ctdd|. dE|- dF|B dE|C  tde| df|  tj|,|B|Cftjdg},|;D ]f}?|? dhi }D|Drt|Ddi | |Ddi< t|Ddj | |Ddj< t|Ddk | |Ddk< t|Ddl | |Ddl< t|Ddm | |Ddm< t|Ddn | |Ddn< |Ddk |Ddi  |Ddo< |Ddl |Ddj  |Ddp< |Ddo |Ddp  |?dq< qtdrt|; ds ntdt| du| dv t }Etdw|E|@ d]d^ g }Fg }Gd}Hd}Id}Jd}Kd}Ld8}Md}N|;D ];}?|?da dIkri }O|?dh di |OdE< |?dh dj |Odx< |?dh do |Odo< |?dh dp |Odp< t|,|O}P|P|?dy< |F|O qHd}Qt|Fdckr|rd}Q|;D ]}?i }O|?dh di |OdE< |?dh dj |Odx< |?dh do |Odo< |?dh dp |Odp< t|,|O}P|P|?dy< d}R|?da dKkrd}H|?da dJkrd}I|?da dNkrd}J|?da dLkrd}K|?da dMkrd}L|Qrt|Fd8krq|Fd8 }Sdzd{ }T|?da dKkr)|T|O|S}U|U|k r)d|?d|< d}Rtd}|Ud~d| d |?da dJkrL|T|O|S}U|U|k rLd|?d|< d}Rtd|Ud~d| d |?da dNkro|T|O|S}U|U|k rod|?d|< d}Rtd|Ud~d| d |?da dLkr|OdE |Odo dC  }V|SdE }W|V|Wkrd|?d|< d}Rtd|V d|W d |?da dMkr|OdE |Odo dC  }V|SdE }W|V|Wkrd|?d|< d}Rtd|V d|W d |?da dJkrd|?da< |?da dIkrِqi }X|P|Xdy< |O|Xd< |?da |Xda< |?d |Xd< |rZ|?da dv rZt|FdckrZt| |Odp |Odo |d  krP|OdE |Fd8 dE  |Fd8 do |d  krP|Odp |Fd8 dp  |d krPd|?d|< d}Ntd|Odp |Odo   d|?d  d q|RrX|G|X q|Rrq|G|X td|?d  d|?da  d qt }Ytd|Y|E d]d^ d	}ZdB}Sd}[t|Fd8krt|Gd8kr|d d d dc}Mn|d d d dc}Mt|Fdckr|d d d |Zd }Zdc}Md}\d}]t|Fdckr|Fd8 }S|Sdo || k r|d d d dc}M|Zd }Z|Sdp || kr|d d d dc}M|Zd }Zt|Gd8kr
	 |GD ]}^|^d }_|^dy }`| j|S|_}a|a|_d< d8|^d< |_dE |SdE dC k rS|ad d |Sdo d* k rQdc|^d< dc}M|d d d |Zd }Zq|^da dKkrtt|_dE |SdE  t|Sdp  |]}]|Md8krtdC}M|r|_do |Sdo  |kr|_dp |_do  |krdc}M|d d d |d d d q|^da dNkr
tt|_dE |SdE  |Sdo  t|Sdo  |\}\t|_dE |SdE  |Sdo  }b|b|Sdo | krt|Gdckr|Md8ks|MdCkrd}Mndc}M|Zd }Zn|Md8ks|MdCkrd}M|d d d q|_dE |_do dC  }c|_dx |_dp dC  }d|Sdx |Sdp dC  }e|_dE |_dx f|_dE |_do  |_dx f|_dE |_do  |_dx |_dp  f|_dE |_dx |_dp  fg}f|d|ek rj|fd8 }g|fdC }h|fdc }id}jn|fdc }g|fd }h|fdC }id}jt |i|g|h}k|c|df|j|i|k|g|hgd|^d< d}l|kd8 |SdE  |Sdo | k rdc}M|Zd }Z|d d d d}l|_dE |SdE  |Sdo | k r|lsdc}M|Zd }Z|d d d td| d|_dE |SdE   d|Sdo |  d d}l|ls|Mdckrd}M|d d d q|\d-k r|]dQk rdc}M|Zd }Zt }mtd|m|Y d]d^ d}n| j!"|'}o|*r4|Mdckr4|Md8kr4d}n|+r9d}n|Nr>d}ni }pdB}q|SdBur|S# }q|qdE t| |qdE< |qdx t|qdp d*  |qdx< |qdp dC |qdp< t||qdo< |qdE d8k r|qdo t|qdE  |qdo< d8|qdE< |q# }r|rdo dC |rdo< t$|,|q}st|sd}sdB}t|
r|qdBu
rŐztd|SdBu d|   |SdBu
ru| d8k
ru|SdE |Sdx |Sdo |Sdp f\}u}v}w}xt|w|  }yt|x|  }z|u|w|y dC  }{|v|x|z dC  }|g }}t%dD ]P}~t%dD ]H}|||z|~dc  d  }|{|y|dc  d  }||,jd8 k 	rC||,jdc k 	rCt|,jdk	r8|}t|,||d8f  q|}t|,||f  qqg }|sjdBdC \}}t%dD ]F}~t%dD ]>}||~dc  d }||dc  d }||k 	r||k 	rt|sjdk	r|t|s||d8f  	q\|t|s||f  	q\	qVt|}dk	r|}&  t|}dCk	r|}dcd n|}}t'|t| }|t|dC  }|}d }nd8 } }}t|dk
r|&  t|dCk	r|dcd n|}t'|t| }|t|dC  }|d }nd8 } }}t|| }t|| }||||||||t|| d	}ttd|dd|dd|d |"|  k
o=|!kn  }|"|  k
oJ|!kn  }|
rs|
rV|
ss|Mdck
rrdc}M|Zd }Z|d d d|dÛd|dÛ n$	 n"td|SdBu d|   |SdBu 
rtdƃ | d8k
rtd|  dȝ W n3 t
y }7 ztdt|7  |d d dt|7  dB}tW Y dB}7~7ndB}7~7ww td|  |SdBur>|nr>|or/ddddddќ}| j!| | j!j(|sdddҍ}| j!)|}td|  |r.|da |pd< |d |pd< |da dks|da dks|da dkr$d|pd< nd|pd< dc}M|Zd }Zn| j!j
|pd< |os>| j!j
|pd< t }||m |pd< td||m d]d^ d|d< |Md8krad|d< nO|Mdckrkd|d< nE|MdCkryd|d< d|d< n7|Mdkrd|d< d|d< n)|Mdkrd|d< d|d< n|Mdkrd|d< d|d< n|Mdkrd|d< d|d< g }g }|;D ]}?d||?v rq|? dhi }D|Dr\|Ddi |Ddj }}|Ddk |Ddl }}|? dad}4|? dd8}|4 d|d~}|| d8d6d8dd6d8d8dd6d6d8dd6d8d6dd8d6d6dd6dd8ddW}| |4dddd}dt|t|dt|t|dd8dC|dd}|| |4 d|d~dv}d|dd|t|t|d ddd}|| q|GD ]
}^d||^v rjq`d|^v rj|^d }|d }|d }|d }|\}g}hdddcdCd6d8d8dt|gd8 t|gdc dt|hd8 t|hdc dgdd}|| ddd8dCd8d6d8dt|d8 t|dc dt|d8 t|dc dgdd}|| |D ].}ddd8dcd6d6d8dt|d8 t|dc dt|d8 t|dc dgdd}|| qdt|d8 t|dc ddd8dCd8d8d6ddd}|| dt|d8 t|dc ddd8dCd8d6d8ddd}|| |D ]!}dt|d8 t|dc ddd8dcd6d8d8ddd}|| qHq`|SdBurt|SdE |Sdo |  }ddd8dd6d8d8dt|t|Sdx dt|t|Sdx |Sdp  dgdd}|| t|SdE |Sdo |  }dt|SdE t|Sdx dt|t|Sdx |Sdp  ddcdCd6d8d8ddd}|| d|pv rbd|pd  d|pd  d|pd d]d}|pd dkrd8d6d8dnd6d8d8d}d|dd|ddddd}|| dt* v rb|pd dkr/d8d6d8dnd6d8d8d}dt|qdE t|qdx dt|qdE |qdo  t|qdx |qdp  dd8dC|dd}|| d|9d]d d|d  d| j+dg}t,|D ]E\}~}|Md8kr|~dckrd8d6d8dnd8d6d8d}|d dkr|~dckrd6d8d8d}d|dd|dd|~d  ddd}|| q~|tdBurtd|td dd|td d d	|td dd
|td d}d|td dd|td d}d|ddd6d6d8dddddd}|| || d|td dd
|td d}d|td dd|td d}d|ddd6d6d8dddddd}|| || d|td dd|td d}d|td dd|td d}d|ddd8d6d6dddddd}|| || ntd td d|Zddd8d6d6dddddd}|| ||Z ||d< ||d< |S (  uR   
        核心检测逻辑 - 基于原始run_delect方法的完整实现
        result_imager      算法错误   算法消息r   r   rc   re   rh   rl   rm   rn   ro   rf   rg   rx   ry   F   横向纹理附加检测T   横向纹理附加检测参数   极耳翻折用户参数*   翻折保护距离（极耳高度比例）0   翻折起点保护距离（极耳高度比例）{Gz?0   翻折起点扩展距离（极耳高度比例）           极耳高度（像素）      极耳高度保护阈值333333?   极耳宽度（像素）     极耳宽度保护阈值      ?   分层保护阈值皙?   月牙宽高NG   月牙宽度皙?   月牙高度      ?   启用自动缩放功能   检测后图片高度缩放      ?   检测后图片宽度缩放   启用相对位置筛选器   重叠度阈值   启用灰度检测   灰度范围NG   灰度内缩ffffff?   灰度差值MAXri      灰度差值MINr      算法存图   算法存图路径"   算法存图最大占用硬盘(MB)   rd   r      隔膜用户参数   启用隔膜分析   隔膜全检Nr   u   🔧 缩放图像: r   z ->    模型加载失败: u   翻折模型加载失败: rp   rq   rr   rs   rt   ru   rv   rz   r{   r|   r}   r~   r   r   r   r   u   ❌ 模型推理失败: u   翻折模型推理失败: r   u   翻折模型推理时间: .4f    秒u   提取检测列表时间: g333333?   类型字符u   合并检测列表时间: r   u   🔧 自动缩放图像: u      宽度缩放比例: u   , 高度缩放比例: )interpolation	   AOI位置r?   r@   r(   r)   center_xcenter_yr   r      面积u5   ✅ 图像和检测结果缩放完成，共缩放了 u    个检测框u*   🔧 未启用图像缩放 (宽度比例: u   , 高度比例: )u   自动缩放时间: r   r$   c                 S   s   t | d |d }t | d |d }t| d | d  |d |d  }t| d | d  |d |d  }||ks<||kr>dS || ||  }| d | d  }|dkrTdS || S )u-   计算item_aoi被container_aoi包含的比例r   r   r   r   r   r   )r    r!   )Zitem_aoiZcontainer_aoir?   r@   r(   r)   Zintersection_areaZ	item_arear-   r-   r.   calculate_containment_ratio  s   ""zCEarFoldDetector._run_detection.<locals>.calculate_containment_ratiou	   不显示u    月牙检测项包含度不足: .3fz < u   ，设置为不显示u    折痕检测项包含度不足: u    分层检测项包含度不足: u&   内插未超出左边界: item_center=z > je_left=u&   内嵌未超出左边界: item_center=zhehengr%      索引)r      横纹最低长宽比   横纹最低风险高度   横纹最低风险宽度u5   🔍 检测到可能的横向纹理误检，长宽比u   ，AOI索引 u    被标记为不显示u
   AOI索引 u
   ，类型 u4    被添加到其他AOI列表，包含度检查通过u   检测框处理时间: u    ❌ 未检测到极耳,有翻折u%   ❌ 未检测到极耳及其他翻折u;   ❌ 检测到多个极耳,理论上拆图只拆单个极耳zduojier;
   u1   ❌ 极耳高度过低，判定为首极耳翻折zgaoduguodi;u(   ❌ 极耳宽度过大，判定为错位zcuowei;u   与极耳关系posu   位置关系u   水平距离u   ❌ 检测到极耳翻折zneicha;u   ❌ 检测到月牙宽高异常u    检测到月牙   z
dafenceng;u    检测到分层u7   上半部分，沿左上-右下对角线镜像右上角r   u7   下半部分，沿右上-左下对角线镜像右下角)u   中心位置u   位置描述   原始角点	   镜像点   对角线端点u   镜像分析z	dafanzhe;zfanzheguoshen;u!     保护距离判定:判定阈值u    水平距离 u    > 保护距离 u&   ，且未被之前的翻折判定为NG   u       检测到小翻折zdafencengC2;u   翻折识别时间: )r   r   u&   🔍 灰度检测条件检查: je_aoi=z, gray_inward_ratio=   )	je_mean	je_medianje_maxgm_mean	gm_mediangm_maxmax_diff	mean_diffmedian_diffu*   ✅ 灰度检测数据已创建: JE均值=z.1fu   , GM均值=u	   , 差值=zhuiduNG;u(   ❌ 灰度差值异常: 最高值差值=r   u   , 均值差值=u"   ⚠️ 跳过灰度检测: je_aoi=u2      - je_aoi为空，检查极耳检测是否成功z   - gray_inward_ratio=u   ，需要>0u   ❌ 灰度检测异常: u   灰度检测异常: u1   ℹ️ 灰度检测已禁用: gray_detect_enable=OKZfanguangZfanguang_pluseZdazhouZneicha)r   r   r   r   r
  )Ztop_kZuse_yolo_preprocessu   隔膜分类Top1结果: u   类别u   分类置信度	   置信度zgemoNG;u   模型错误u   推理耗时u   隔膜识别时间: u   月牙u   异常u	   无极耳u	   多极耳u	   小翻折u   分层或月牙unknown   综合置信度:)rgrB         r   r   )r   r   r   	lineStylepenWidthcolorshow(r   ZArial   )r   r   Z
fontFamilyZfontSizer   r   r!  r  r  r  r   )r   ZisClosedr  r  r   r   r!  r   g      @)r   r   r   r  r  r   r!  g      @zGM: ,zs)   g      $@g      Y@gm_aoizModel: szResult: zcount: dg      9@u(   🔍 准备显示灰度检测数据: JE=r  z, GM=r  u   极耳: 平均值=u    中值=r  z	JE: Mean=z Median=g     @_@u   隔膜: 平均值=r  z	GM: Mean=g     b@u   极耳，隔膜: 平均值差=r  u    中值差=r  zDiff: Mean Diff=z Median Diff=g     e@u+   ⚠️ 灰度检测数据为空，未显示u   准备显示结果数据g      i@r   r   )-r#   r   cv2resizer   r   r   rM   r;   rT   r5   r   r   r   r   r   r   rR   r   r"   r`   extract_detection_list$merge_overlapping_detections_inplacelenr   ZINTER_LINEARr   r/   Zcalculate_aoi_relationshipsr!   absr   rE   rN   r   r   get_cv_img_fronm_aoi_exrangesortsumr   Zget_top1_resultlocalsrU   r   )r7   r$   r   r*   r   
model_pathZmodel_confidence_thresholdZmodel_iou_thresholdrj   r   r   Zhorizontal_texture_checkhorizontal_texture_paramZ
usr_paramsZfanzhe_protect_ratioZfanzhe_protect_startZfanzhe_protect_expandZ	JE_heightZJE_height_ratioZJE_widthZJE_width_ratioZJE_fenceng_thresholdZyueya_wh_ng_enableZyueya_width_ngZyueya_height_ngZenable_auto_scalingZdetect_img_height_scaleZdetect_img_width_scaleZenable_pos_filterZpos_filter_thresholdZgray_detect_enableZgray_ng_enableZgray_inward_ratioZgray_diff_maxZgray_diff_minZsave_image_by_modelZsave_image_pathZsave_image_max_sizer   Zgm_cls_model_pathZgm_cls_model_imgszZgm_cls_usr_paramsZenable_gm_clsZenable_gm_cls_all	src_imager   r   r   Zmodel_startload_resultr   r   r   r   model_resultsr,   Z	model_endZ
model_costZcur_delect_modelZdeleted_listextract_detection_list_endmerge_success	merge_msgZdetect_itemZ	merge_endZhas_other_itemZ	new_widthZ
new_heightZaoi_posZauto_bg_endZje_aoi_listZother_aoi_listZ	has_yueyaZ
has_fanzheZhas_fencengZ
has_neichaZhas_neiqianZfanzhe_resultZhas_horizontal_texturetemp_aoiZimage0Zuse_pos_filterZneed_appendZje_aoir   ZcontainmentZitem_centerZje_left	temp_itemZaoi_seg_endZng_infoZsee_gmZ
fenceng_upZ
yueya_downZ
other_itemZ	other_aoiZother_imageZother_aoi_resultZfenceng_posZother_center_xZother_center_yZje_center_yZother_cornersZdiagonal_p1Zdiagonal_p2Ztarget_pointZposition_descZcur_pntZisNGZcheck_je_endZ
use_gm_cnnZcls_load_successZ	gm_resultr&  Zjegm_aoiZgm_image_clsZgray_detect_dataZje_xZje_yZje_wZje_hZinward_wZinward_hZinward_start_xZinward_start_yZ	je_pointsr   jr   r   Z	gm_pointsZgm_hZgm_wZje_filteredr  r  r  Zgm_filteredr  r  r  r  r  Zmax_diff_in_rangeZmean_diff_in_rangeZcustom_class_namesresultsZtop1_resultZ	gm_je_endr   r   r?   r@   r(   r)   Z
confidenceZconf_strZ	color_mapr   Z	rect_itemZ
label_textZ	text_itemZmirror_analysisZmirror_pointZoriginal_pointZdiagonal_pointsZdiagonal_lineZmirror_lineZ
diag_pointZconnection_lineZoriginal_circleZmirror_circleZdiag_circleZ	protect_xZprotect_lineZstart_rect_rightZprotect_rectZgm_textZgm_text_colorZgm_text_itemZgm_rect_colorZgm_rect_itemZstatus_textsr   Z
text_colorZtemp_strZtemp_str_enZje_text_itemZdiff_text_itemZng_text_itemr-   r-   r.   r     s   







	
 









"*&


&
,.


$0

$ 



 
"

*






















	
	









	

	
	




	
&&
	&(
	,	
($$


	
$$


	
$$


	




	


zEarFoldDetector._run_detectionc                 C   s   ddiS )u<   
        获取检测器可用的检测函数列表
        r   u   翻折检测（仅检测）r-   r6   r-   r-   r.   get_available_functions  s   z'EarFoldDetector.get_available_functionsfunction_namec                 C   s"   |dkr
|  ||S td| )u-   
        调用指定的检测函数
        r   u   未知的函数名称: )r   
ValueError)r7   rA  r$   r   r-   r-   r.   call_function  s   zEarFoldDetector.call_functionc              
   C   s(  | j sddiS |dur|n| j}z]t }i }i }i }| ||}d|v r,|d |d< d|v r6|d |d< d|v r@|d |d< d|v rJ|d |d< d|v rYtd	 d
|d< |W S g |d< d|d v r|d d }	z(| |	|}d|v r|d D ]}
|d d|
  qxd|v rd
|d< |W W S W n' ty } ztdt	|  dt	| |d< |W  Y d}~W S d}~ww d|d v r|d d }z(| ||}d|v r|d D ]}
|d d|
  qd|v rd
|d< |W W S W n( ty } ztdt	|  dt	| |d< |W  Y d}~W S d}~ww ||d< ||d< | 
||||d< |r=|dd |dd |dd |rR|dd |dd |dd d|v r]|dd t }td|| dd |W S  ty } ztdt	|  ddt	| iW  Y d}~S d}~ww )uo   
        完整检测流程：极耳裁切 + 翻折检测
        从主程序迁移的 run_all 函数
        r   r   N   上极耳裁切框   下极耳裁切框   上极耳AOI   下极耳AOIr   u+   ❌ 检测异常结束，跳过后续步骤r   r   up_jr_imager   u
   上极耳:u   ❌ 上极耳检测失败: u   上极耳检测失败: down_jr_imageu
   下极耳:u   ❌ 下极耳检测失败: u   下极耳检测失败: u   上极耳结果u   下极耳结果r   r   r   r   r   u   ❌ 完整检测异常: u   完整检测异常: )r_   r\   r   r   _run_cutr   r   r   r"   r`   _restore_draw_items_to_originalpop)r7   r$   r   r   r   r*   	result_upresult_down
result_allZup_imager   r,   Z
down_imager   r-   r-   r.   run_all  s   
zEarFoldDetector.run_allrh   r   r   c                 C   s  ddl }||krtd| d dS t|tr_| D ]A\}}|r(| d| n|}t||jr=td| d|j d qt|ttfrO| ||||d	  qtd
| dt	|j
  qdS t|trt|D ]F\}	}
|rv| d|	 dnd|	 d}t|
|jrtd| d|
j d qht|
ttfr| |
|||d	  qhtd
| dt	|
j
  qhdS t||jrtd| d|j d dS td
| dt	|j
  dS )uA   递归打印字典中每个值的数据类型，查找numpy数组r   Nz  u   : <递归深度超限>.u     ❌ z: numpy.ndarray (shape=u   ) <-- 发现numpy数组!r   u     ✅ z: [])numpyr   
isinstancedictr   ndarrayr   list_debug_print_dict_typesr   r0   r   )r7   datar9   	max_depthZcurrent_depthr   keyvalueZcurrent_pathr   r   r-   r-   r.   rY  ]  s2   

 	z'EarFoldDetector._debug_print_dict_typesc           F      C   s  i }i |d< i |d< g |d d< g |d d< d|d< | di }| dd	}| d
d}| dd}| dd}| dd}	| di }
|
 dd}|
 dd}|
 dd}|
 dd}|
 dd}|
 dd}|
 dd}|
 dd}t }|}|jdd  \}}t|||f}t }td!|| d"d# | j|| j	}|std$| jj
  |d d d%| jj
  |S t }td&|| d"d# d'| j_|| j_d(d)i}| j| | jJ z| jj|| j	||d'd*}W n3 ty# } z&td+|  |d d d+|  d|d,< |W  Y d}~W  d   S d}~ww W d   n	1 s/w   Y  t }td-|| d"d# | j|}t } td.| | d"d# | j|d/\}!}"t }#td0|#|  d"d# |D ]}$|| }%|| }&t|$d1 d2 |% }'t|$d1 d3 |& }(t|$d1 d4 |% })t|$d1 d5 |& }*|'|)d   }+|(|*d   },|,|d  k }-|-r|}.|}/n|}.|}/|+t|/d6|  d   }0|,t|.d6|  d   }1t|/d6|  }2t|.d6|  }3|0|/ }0|2|/ }2|0d7k s
|1d7k s
|0|2 |ks
|1|3 |kr=td8|$ d9d:  td;|$d< d= td>|0 d?|1 d@|2 dA|3  tdB| dA|  dC|$d<< qrt|dDdE ddFdd  }g }4|D ]}$|$ }5i }6|| }%|| }&t|$d1 d2 |% |6dG< t|$d1 d3 |& |6dH< t|$d1 d4 |% |6d4< t|$d1 d5 |& |6d5< |6|5dI< t|$d1 d2 |% |5d1 d2< t|$d1 d3 |& |5d1 d3< t|$d1 dJ |% |5d1 dJ< t|$d1 dK |& |5d1 dK< t|$d1 dL |% |5d1 dL< t|$d1 dM |& |5d1 dM< t|$d1 d4 |% |5d1 d4< t|$d1 d5 |& |5d1 d5< |5d1 d4 |5d1 d5  |5dN< |4|5 qPt }7tdO|7|# d"d# t|4d6kr|4d7 }8|8d1 dM }9|9|d  k }-|8 }:|8d1  |:d1< |-rttdP|  |:d1 dM  |7  < |:d1 d3  |7  < |:d1 dK  |7  < n%tdQ|  |:d1 dM  |8  < |:d1 d3  |8  < |:d1 dK  |8  < |:d1 d4 |:d1 d5  |:dN< d6|:dR< |4|: tdSt|4 dT n"t|4d krtdUt|4 dV |d d dWt|4 dV |S d};d}<t|4d kr|4d7 }=|4d6 }>|=d1 dM |>d1 dM k r|=};|>}<n|>};|=}<|;d1  |dX< |<d1  |dY< i |;dZ< i |<dZ< |;d1 d2 |;d1 d4 d   |;dL< |;d1 d3 |;d1 d5 d   |;dM< |<d1 d2 |<d1 d4 d   |<dL< |<d1 d3 |<d1 d5 d   |<dM< |;dL t|d6|  d   |;dZ dG< |;dM t|d6|  d   |;dZ dH< t|d6|  |;dZ d4< t|d6|  |;dZ d5< |<dL t|d6|  d   |<dZ dG< |<dM t|d6|  d   |<dZ dH< t|d6|  |<dZ d4< t|d6|  |<dZ d5< t|;dZ dG ||  |;dZ dG< t|;dZ d4 ||  |;dZ d4< t|<dZ dG ||  |<dZ dG< t|<dZ d4 ||  |<dZ d4< |;dZ  |d[< |<dZ  |d\< td]t|d[   td^t|d\   t||;dZ }?t||<dZ }@t|?d_}?t|@d_}@t }A|?|d d`< |@|d da< td7|;dZ dG }Btd7|;dZ dH }Ctd7|<dZ dG }Dtd7|<dZ dH }E|B|C|;dZ d4 |;dZ d5 db|;d1 d2 |;d1 d3 |;d1 dJ |;d1 dK |;d1 dL |;d1 dM |;d1 d4 |;d1 d5 dc|;dZ d5 |;dZ d4 fd_d|;dZ d4  d|;dZ d5  ddde|D|E|<dZ d4 |<dZ d5 db|<d1 d2 |<d1 d3 |<d1 dJ |<d1 dK |<d1 dL |<d1 dM |<d1 d4 |<d1 d5 dc|<dZ d5 |<dZ d4 fd_d|<dZ d4  d|<dZ d5  ddde||dfdg|dh< di|d< tdj|A|7 d"d# |S )kuW   
        执行极耳裁切
        从主程序的 run_cut 方法迁移实现
        r   r   r   r   r   r   rb   re   rh   r  rm      裁切IOU阈值ro   rf   rg      合并检测框T   极耳裁切用户参数   上极耳宽度r      上极耳高度r      下极耳宽度   下极耳高度   极耳宽度扩展冗余r      极耳高度扩展冗余   极耳间距      隔膜获取深度Nr   u   ⏱️ 缩放时间: r   r   r   u   裁切模型加载失败: u!   ⏱️ 裁切模型加载时间: Frw   jierr   u   裁切模型推理失败: r   u!   ⏱️ 裁切模型推理时间: u   提取极耳框时间: r   u   合并极耳框时间: r   r?   r@   r   r   r   r   uB   ⚠️ 检测框会超出图像边界，将置信度降低到0.1: r   r  u      原始置信度: r  r   u      裁切AOI: x=r   r   r   u      图像尺寸: w=r{   c                 S   s   | d S )Nr  r-   )r   r-   r-   r.   <lambda>  s    z*EarFoldDetector._run_cut.<locals>.<lambda>)r\  reverser   r   r%   r(   r)   r   r   r   u   还原检测框时间: u/   检测到上极耳，生成下极耳，间距: u/   检测到下极耳，生成上极耳，间距: r   u/   ✅ 成功生成第二个极耳，现在共有 u
    个极耳u'   ⚠️ 检测到的极耳数量异常: u   ，预期为2u    检测到的极耳数量异常: rF  rG  Zcut_aoirD  rE  u   上极耳裁切框:u   下极耳裁切框:)rg   rg   rH  rI  )r   r   r   r   )r?   r@   r(   r)   r   r   r   r   )u   原始尺寸u   缩放后尺寸   缩放比例_x   缩放比例_y)   裁切区域u	   检测框   缩放信息)r   r   )	   上极耳	   下极耳u   源图像尺寸   极耳裁切信息r  u   裁切出图执行时间: )r#   r   r   r   r)  r*  r   rL   r;   rT   r5   r   r   r   r   rQ   r   r"   r+  r,  r   sortedr   r-  r`   r   r/  r    )Fr7   r$   r   r*   Z
cut_paramsr   Zcut_confidenceZcut_iou_thresholdZcut_input_sizeZcut_merge_detectZusr_dictZtop_jr_widthZtop_jr_heightZbottom_jr_widthZbottom_jr_heightZjr_width_expand_ratioZjr_height_expand_ratioZjier_spacingZgm_get_deepr   r6  Z
src_heightZ	src_widthZresize_imageZresize_timer7  Zcut_load_timer   r8  r,   Zcut_predict_timeZcut_jr_listr9  r:  r;  Zcut_merge_detect_endrj  r   r   Zorig_x1Zorig_y1Z
orig_widthZorig_heightZorig_center_xZorig_center_yZ
is_up_jierZjr_width_paramZjr_height_paramZ	cut_aoi_xZ	cut_aoi_yZcut_aoi_widthZcut_aoi_heightZsrc_jr_listr=  r<  Zaoi_resize_timeZsingle_jierZsingle_center_yZsecond_jierZup_jierZ	down_jierZjier1Zjier2rH  rI  Zcut_timeZup_actual_xZup_actual_yZdown_actual_xZdown_actual_yr-   r-   r.   rJ  }  s  
	

 
    $$$$    




















1zEarFoldDetector._run_cutc                 C   s  dd }| di }|si S i }d}|rd|v r|d D ]}| }	d|	d< |d d	kr]||d
 d |d
 d d|\}
}||d d |d d d|\}}|
|d|	d
< ||d|	d< n|d dkr||d d |d d d|\}}||d|	d< |d d d |d d d  d }|d | |	d< nG|d dkrg }|d D ]}||d |d d|\}}|||d q||	d< n|d dkr||d d |d d d|\}}||d|	d< d|d}|	||< |d7 }q|rd|v r|d D ]}| }	d|	d< |d d	kr:||d
 d |d
 d d|\}
}||d d |d d d|\}}|
|d|	d
< ||d|	d< n|d dkrt||d d |d d d|\}}||d|	d< |d d d |d d d  d }|d | |	d< nJ|d dkrg }|d D ]}||d |d d|\}}|||d q||	d< n|d dkr||d d |d d d|\}}||d|	d< d|d}|	||< |d7 }q|S )u  
        将512x512裁切图像的检测结果复原到原图坐标系
        从主程序的 restore_draw_items_to_original 方法迁移实现
        
        Args:
            result_up: 上极耳检测结果
            result_down: 下极耳检测结果  
            result_all: 裁切结果，包含极耳裁切信息
            
        Returns:
            dict: 复原到原图的绘图项字典，每个项目以唯一ID为键
        c           	      S   sX   || }| |d d  }||d d  }||d d  }||d d  }t |t |fS )u1   将512x512裁切图像坐标复原到原图坐标rp  rm  rn  ro  r   r   )r   )	Zx_cropZy_cropZear_typecut_infoZear_infoZx_cutZy_cutZ
x_originalZ
y_originalr-   r-   r.   restore_coordinates_to_original  s   zXEarFoldDetector._restore_draw_items_to_original.<locals>.restore_coordinates_to_originalrs  r   r   rq  u   来源r   r   r   r   r   r   r   r   r   rp  rm  rn  r   r   r   r   r   r   r   Z03dr   rr  )r#   r   r   )r7   rM  rN  rO  rv  ru  Zresult_dictZitem_counterr   Zrestored_itemr?   r@   r(   r)   ZcxZcyZ	scale_avgZrestored_pointsr<   r=   r>   ZtxZtyZitem_keyr-   r-   r.   rK    s   



z/EarFoldDetector._restore_draw_items_to_originalc              	   C   s   dddddd}ddddd	d
ddd}dd	d	d	d	d	d	d}dd	d	d	d	d	d	d}dd
dd}dddd|d|d}i dddd
dd
dddddddddd
dddd d!dd"dd#d$d%d$d&dd'd d(dddd)d*dd+d,d-}dd.d/}ddd0}ddd1}	||||||d2}
|
S )3uN   
        获取默认参数配置（从原始配置文件中提取）
        rh   rm   ro   rg   T)re   r  r^  rf   r_  r   r   r{   r   rh  r   )ra  rb  rc  rd  re  rf  rg  ri  F)ry   rz   r|   r}   r~   r   r   g      @r   )r   r  r  )re   rl   rn   rf   rx   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   ri   r   r9   r   )r   r   r   r   r   r   r   r   )re   rf   )r   r   )u   更新脚本地址u   更新UI地址)rb   r`  rc   r   rd   r   r-   )r7   Z
jrcut_dictZjrcut_usr_dictr   r5  Zdeleted_dictZfold_usr_dictZgm_dictZgm_usr_dictZupdate_dictZall_parametersr-   r-   r.   r]   X  s   
	
	z&EarFoldDetector.get_default_parametersc                 C   s&   | j rtd |   dS td dS )u   
        重写基类的预热方法
        
        如果检测器已初始化，再次执行模型预热
        如果未初始化，只记录警告信息
        u   🔥 执行检测器预热...u1   ⚠️ 检测器未初始化，无法执行预热N)r_   r   r^   r6   r-   r-   r.   warm_up  s   zEarFoldDetector.warm_upc                    s(   t    d| _d| _d| _td dS )u   清理资源Nu   🧹 检测器资源已清理)rK   cleanuprL   rM   rN   r   r6   rW   r-   r.   rx    s
   
zEarFoldDetector.cleanup)N)rh   r   r   )rY   N)r0   r1   r2   __doc__r8   r`   rZ   r   r   boolra   r^   r   rW  r   r   r   r@  rC  rP  rY  rJ  rK  r]   rw  rx  __classcell__r-   r-   rW   r.   rF      s:    !*u>(F        (.*	
g(   J 
}rF   )%ry  r)  rT  r   r   typingr   r   r   r   r   rO   jsonossysr   r   r9   dirname__file__Zcurrent_dirZ
parent_dirr   base_detectorr	   Zutils.model_utilsr
   Zutils.model_cls_utilsr   r   ImportErrorr,   r   r   r4   rE   rF   r-   r-   r-   r.   <module>   s>    
%74