
    iyU                       d Z ddlZddlZddlmZ ddlZddlZddl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mZmZmZ ddlZd ZdzdZd	 Zd
edee	ee
f      fdZde	ee
f   d
edefdZd{de
dededefdZd
edeej<                     fdZdej<                  d
edefdZ d
edefdZ!dej<                  de	ee
f   fdZ"dede	ee
f   fdZ#dedee	ee
f      fdZ$d|dede
de
fdZ%d|dZ&d|dZ'd|dZ(d|dZ)d  Z*d! Z+d" Z,d# Z-d$ Z.d% Z/d}d'Z0d~d(Z1	 	 	 dd)Z2d* Z3d+ Z4d, Z5d-dd&d.d.d.d-d.d/i f
d0Z6d-d1d1d2dd&d.d.d.d-d.i fd3Z7d-d1dd2dd&d.d.d.d-d.i fd4Z8d-d1ddd&d.d.d.d-d.i fd5Z9d-dd&d.d/d.d.d-d6i f
d7Z:d-dd&d.d8d.d.d-d6i f
d9Z;d: Z<d; Z=	 	 	 	 	 dd<Z>	 	 	 	 	 dd=Z?dd>Z@dd?ZAdd@ZBddAZCddBZDddCZEddDZFddEZGddFZHddGZIdH ZJ	 ddIZK	 ddJZLddKZMddLZNddMZO	 	 ddNZPdO ZQdP ZRg dQfdRZSd|dSZTddTZUddUZV	 	 ddVZWddWZXddXZYddYZZddZZ[d|d[Z\d|d\Z]d|d]Z^d^ Z_d_ Z`dd`ZaddaZbddbZcdceddedfdeZedfeffdgZgddceddedfdhZhd|diZidj Zj	 	 ddkZk	 	 ddlZlddej<                  dmemdnendoeddpedej<                  fdqZoddej<                  dmemdpedej<                  fdrZp	 	 	 ddsZq	 	 ddtZrdduZsddej<                  dvemdej<                  fdwZtddxZuddyZvy)u   
公用工具函数模块
    N)property_interning_dict)DictAnyOptionalList)Image	ImageDraw	ImageFontc                     |j                  d      sd|z   }t        j                  j                  | d|       }t	        j                  |      }|S )u8   
    使用glob模块读取指定后缀名的文件
    .*)
startswithospathjoinglob)	directory	extensionpattern	file_lists       D:\pyccd\funcs\utils\utils.pyget_files_by_extension_globr      sM    
 $)O	 ggll9)o6G 		'"I       c                 b   t        j                  t        j                  | t        j                              }t        j                  |      }t        j                  ||      }|j                  ||||       t        j                  t        j                  |      t        j                        }	|	S )u.   
    在OpenCV图像上添加中文文字
    )fontfill)r   	fromarraycv2cvtColorCOLOR_BGR2RGBr	   Drawr
   truetypetextnparrayCOLOR_RGB2BGR)
imgr$   position	font_path	font_sizecolorimg_pildrawr   img_cvs
             r   put_Text_cnr0   &   s    
 oocll30A0ABCG >>'"D i3D 	IIh4eI4 \\"((7+S->->?FMr   c                 h   t         j                  j                  |       s!dt         j                  j                  |       v r t         j                  j	                  |       }n| }|r8t         j                  j                  |      s	 t        j                  |d       yy# t        $ r
}Y d}~yd}~ww xY w)u3   检测路径是否存在，不存在则逐级创建r   T)exist_okNF)r   r   isfilebasenamedirnameexistsmakedirs	Exception)	file_pathdir_pathes      r   ensure_path_existsr<   ;   s     
ww~~i C277+;+;I+F$F77??9- x0	KK40   		s   B 	B1,B1r9   returnc                     	 t        | dd      5 }t        j                  |      cddd       S # 1 sw Y   yxY w# t        $ r}t	        d|        Y d}~yd}~ww xY w)u   
    加载JSON文件为字典
    
    Args:
        file_path: JSON文件路径
        
    Returns:
        Dict: JSON数据字典，失败返回None
    rutf-8encodingNu   加载JSON文件失败: )openjsonloadr8   print)r9   fr;   s      r   load_json_filerH   O   sN    )S73q99Q< 433 (,-s)   ; /	; 8; ; 	AAAdatac                     	 t        |dd      5 }t        j                  | |dd       ddd       y# 1 sw Y   yxY w# t        $ r}t	        d	|        Y d}~yd}~ww xY w)
u   
    保存字典到JSON文件
    
    Args:
        data: 要保存的数据字典
        file_path: 保存路径
        
    Returns:
        bool: 是否保存成功
    wr@   rA   F   ensure_asciiindentNT   保存JSON文件失败: rC   rD   dumpr8   rF   )rI   r9   rG   r;   s       r   save_json_filerS   a   sZ    )S73qIIdAE!< 4 4 (,-s)   ? 3? <? ? 	A AA filepathrB   c                     fd	  |       }t        |d|      5 }t        j                  ||dd       ddd       y# 1 sw Y   yxY w# t        $ r}t	        d	|        Y d}~yd}~ww xY w)
us  
    保存JSON文件的增强版本，支持不可序列化的数据
    对于不可序列化的对象，会使用pickle进行序列化并转换为base64字符串
    
    Args:
        data: 要保存的数据
        filepath: 文件路径
        encoding: 文件编码，默认为utf-8
    
    Returns:
        bool: 保存成功返回True，失败返回False
    c           	         	 t        j                  |        | S # t        t        f$ r. t	        | t
              r3| j                         D ci c]  \  }}| |       nc c}}w c}}cY S t	        | t        t        f      r| D cg c]
  } |       nc c}w c}cY S t	        | t              r d| D cg c]
  } |       nc c}w c}icY S 	 t        j                  |       }t        j                  |      j                  d      }|t        |       j                  dcY S # t         $ r& t#        |       t        |       j                  dcY cY S w xY ww xY w)u+   递归处理对象，使其可JSON序列化__set__ascii)__pickled____type__)__str__rZ   )rD   dumps	TypeError
ValueError
isinstancedictitemslisttuplesetpicklebase64	b64encodedecodetype__name__r8   str)objkvitempickledencodedmake_serializables         r   rr   z,save_json_file_ex.<locals>.make_serializable   s$   	QJJsOJ:& 	Q#t$<?IIKHKDAq,Q//KHHC$/<?@CD)$/C@@C%!#L$5d$;#LMMQ$ll3/G$..w7>>wGG+2S	@R@RSS  Q'*3xT#Y=O=OPPQ	Qs^    3EA! E-EB	E!E6C
EAD%"E%*EEEErK   rA   FrL   rM   NTrP   rQ   )rI   rT   rB   serializable_datarG   r;   rr   s         @r   save_json_file_exrt   t   ss    Q0-d3 (C(3qII'qI 4  4  (,-s3   A AA A
A 
A 	A.A))A.c                    	 t        j                  | t         j                        }| j                         j	                  d      d   }|dv r7t        j                  |t
        j                  t
        j                  z        }|S t        j                  |t
        j                        }|S # t        $ r}t        d|        Y d}~yd}~ww xY w)u   
    加载浮点数图像文件（支持中文路径）
    
    Args:
        file_path: 图像文件路径
        
    Returns:
        numpy.ndarray: 浮点数图像数组，失败返回None
    dtyper   )exrhdrtifftifu   加载浮点数图像失败: N)r%   fromfileuint8lowersplitr   imdecodeIMREAD_ANYDEPTHIMREAD_ANYCOLORIMREAD_COLORr8   rF   )r9   img_dataextr(   r;   s        r   load_image_unicoder      s    ;;y9 oo%%c*2.//,,x)<)<s?R?R)RSC
 
 ,,x)9)9:C
 -aS12s   BB* %B* *	C3CCimagec                     	 t         j                  j                  |      d   }t        j                  ||       \  }}|r|j                  |       yy# t        $ r}t        d|        Y d}~yd}~ww xY w)u   
    保存图像文件（支持中文路径）
    
    Args:
        image: 图像数组
        file_path: 保存路径
        
    Returns:
        bool: 是否保存成功
       TF   保存图像失败: N)r   r   splitextr   imencodetofiler8   rF   )r   r9   r   successencoded_imgr;   s         r   save_image_unicoder      so    	ggy)!,"||C7y) $QC()s   AA 	A3A..A3c                     t         j                  j                  |       xr t         j                  j                  |       S )u   
    验证文件是否存在
    
    Args:
        file_path: 文件路径
        
    Returns:
        bool: 文件是否存在
    )r   r   r6   r3   )r9   s    r   validate_file_existsr      s)     77>>)$B	)BBr   c                     | dddS | j                   }d|d   |d   t        |      dkD  r|d   ndt        | j                        | j                  dS )	u~   
    获取图像信息
    
    Args:
        image: 图像数组
        
    Returns:
        Dict: 图像信息字典
    Fu   图像为空)validerrorTr   r   rL   )r   heightwidthchannelsrw   size)shapelenrk   rw   r   )r   r   s     r   get_image_infor      s^     }88KKE(q #E
QE!HAU[[!

 r   r$   c                   	 ddl 	ddl}d}|j                  || |j                  |j                  z        }|D ]$  }	  	j
                  |j                               c S  d}|j                  || |j                        }|D ]$  }	  	j
                  |j                               c S  d}|j                  || |j                        }|D ]$  }	  	j
                  |j                               c S  	fd} ||       }|r|d   S i S # 	j                  $ r Y w xY w# 	j                  $ r Y w xY w# 	j                  $ r Y xw xY w)u  
    从字符串中提取JSON格式的内容并转换为字典
    
    Args:
        text (str): 包含JSON内容的字符串
        
    Returns:
        Dict[str, Any]: 解析后的字典，如果没有找到有效JSON则返回空字典
        
    Examples:
        >>> text = "这是一段文字```json
{"破损-1": {"位置": [100, 200]}}
```更多文字"
        >>> result = extract_json_from_string(text)
        >>> print(result)
        {'破损-1': {'位置': [100, 200]}}
    r   N```json\s*\n?(.*?)\n?``````\s*\n?(.*?)\n?```z\{[^{}]*(?:\{[^{}]*\}[^{}]*)*\}c                 :   g }g }d}t        |       D ]p  \  }}|dk(  r|s|}|j                  |       !|dk(  s'|s*|j                          |r=|dk7  sC| ||dz    }	  j                  |      }|j                  |       d}r |S # j                  $ r Y w xY w)u   递归查找JSON对象rx   {}r   	enumerateappendpoploadsJSONDecodeError)	sresultsstackstarticharjson_strrl   rD   s	           r   find_json_objectsz3extract_json_from_string.<locals>.find_json_objects4  s     |GAts{ET"IIK Ub[#$U1Q3<!",$**X"6C#NN3/ !# $    $33 ! !   #BBB)rD   refindallDOTALL
IGNORECASEr   stripr   )
r$   r   json_block_patternmatchesmatchcode_block_patternbrace_patternr   json_objectsrD   s
            @r   extract_json_from_stringr     sQ      5jj+T299r}}3LMG	4::ekkm,,  1jj+T299=G	4::ekkm,,  7Mjjbii8G	4::ekkm,, 0 %T*LAIi ## 		 ## 		 ## 		s5   DDD/DDD,+D,/E Ec                    ddl ddl}g }d}|j                  || |j                  |j                  z        }|D ]2  }	 |j                   j                  |j                                      4 |sVd}|j                  || |j                        }|D ]2  }	 |j                   j                  |j                                      4 |sfd} ||       }|S # j                  $ r Y w xY w# j                  $ r Y lw xY w)u   
    从字符串中提取所有JSON格式的内容
    
    Args:
        text (str): 包含JSON内容的字符串
        
    Returns:
        List[Dict[str, Any]]: 所有解析成功的JSON字典列表
    r   Nr   r   c                 :   g }g }d}t        |       D ]p  \  }}|dk(  r|s|}|j                  |       !|dk(  s'|s*|j                          |r=|dk7  sC| ||dz    }	  j                  |      }|j                  |       d}r |S # j                  $ r Y w xY w)Nrx   r   r   r   r   )	r   objectsr   r   r   r   r   rl   rD   s	           r   find_all_json_objectsz;extract_all_json_from_string.<locals>.find_all_json_objectsy  s    GEE$Q<43;  !LL&S[		$"'(qs|H%&0djj&: 's 3 %'E (  N $(#7#7 % $%r   )	rD   r   r   r   r   r   r   r   r   )	r$   r   r   r   r   r   r   r   rD   s	           @r   extract_all_json_from_stringr   S  s    G 5jj+T299r}}3LMG	NN:4::ekkm45  4**/ryyAEztzz%++-89  	. (-NS ## 		 '' s#   /C/C-C*)C*-C?>C?default_valuec                 H    	 t        |       }|r|S |S # t        $ r |cY S w xY w)u  
    安全地从字符串中提取JSON，失败时返回默认值
    
    Args:
        text (str): 包含JSON的字符串
        default_value (Any): 提取失败时的默认返回值
        
    Returns:
        Any: 提取的JSON数据或默认值
    )r   r8   )r$   r   results      r   safe_extract_jsonr     s3    )$/v2]2 s     !!c                    ddddt         j                  d}|i }i ||}t        | j                        dk(  r$t        j                  | t         j
                        n| }|d   dk(  r,t        j                  |t         j                  dd	|d
         }n|d   dk(  r,t        j                  |t         j                  d	d|d
         }ntt        j                  |t         j                  dd	|d
         }t        j                  |t         j                  d	d|d
         }t        j                  |dz  |dz  z         }t        j                  t        j                  |            }t        j                  ||d   |d   |d         \  }}	|	S )  
    使用Sobel算子检测特定方向的边缘
    
    Args:
        image: 输入图像
        params: 参数字典，包含以下键值:
            - direction: str, 检测方向 ('horizontal', 'vertical', 'both')
            - ksize: int, Sobel核大小 (1, 3, 5, 7)
            - threshold: int, 二值化阈值 (0-255)
            - max_value: int, 二值化最大值 (0-255)
            - threshold_type: int, 阈值类型 (cv2.THRESH_BINARY, cv2.THRESH_BINARY_INV等)
    
    Returns:
        edges: 检测到的边缘图像
    both   2      )	directionksize	threshold	max_valuethreshold_typer   
horizontalr   r   r   r   verticalrL   r   r   r   r   THRESH_BINARYr   r   r    COLOR_BGR2GRAYSobelCV_64Fr%   sqrtr~   absoluter   
r   paramsdefault_paramsfinal_paramsgraysobelsobelxsobely_edgess
             r   detect_edges_by_directionr     se   $ ++N ~/n//L 7:%++6F!6K3<<s112QVDK L0		$

AqW8MN	k	"j	0		$

AqW8MN 4Qg9NO4Qg9NO	FAI-. HHR[['(E}}UL$='4lCS6TVHAu Lr   c                    ddddddt         j                  d}|i }i ||}t        | j                        dk(  r$t        j                  | t         j
                        n| }|d   dk(  r,t        j                  |t         j                  d	d
|d         }n|d   dk(  r,t        j                  |t         j                  d
d	|d         }ntt        j                  |t         j                  d	d
|d         }t        j                  |t         j                  d
d	|d         }t        j                  |dz  |dz  z         }t        j                  t        j                  |            }t        j                  ||d   |d   |d         \  }}	|	S )r   r   r   Tr   Fr   r   r   	normalizer   apply_thresholdr   r   r   r   r   r   r   r   rL   r   r   r   r   r   s
             r   detect_edges_gradientr     sk   2 " ++N ~/n//L 7:%++6F!6K3<<s112QVDK L0		$

AqW8MN	k	"j	0		$

AqW8MN 4Qg9NO4Qg9NO	FAI-. HHR[['(E}}UL$='4lCS6TVHAu Lr   c                    ddddddt         j                  d}|i }i ||}t        | j                        dk(  r$t        j                  | t         j
                        n| }|d   dk(  r,t        j                  |t         j                  d	d
|d         }n+t        j                  |t         j                  d
d	|d         }t        j                  |d
kD  |d
      }|d   rS|j                         d
kD  r*t        j                  ||j                         z  dz        }n@t        j                  |      }n*t        j                  t        j                  |d
d            }|d   r$t        j                  ||d   |d   |d         \  }}|S )u  
    检测从暗到亮的变化（正梯度）
    
    Args:
        image: 输入图像
        params: 参数字典，包含以下键值:
            - direction: str, 检测方向 ('horizontal', 'vertical')
            - ksize: int, Sobel核大小 (1, 3, 5, 7)
            - normalize: bool, 是否归一化到0-255
            - threshold: int, 可选的二值化阈值
            - apply_threshold: bool, 是否应用二值化
    
    Returns:
        positive_edges: 正梯度边缘图像
    r   r   Tr   Fr   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r    r   r   r   r%   wheremaxr~   clipr   )r   r   r   r   r   r   positive_edgesr   s           r   detect_positive_gradientr     sr   $ " ++N ~/n//L 7:%++6F!6K3<<s112QVDK L0		$

AqW8MN		$

AqW8MN XXeai2NK !#XXn~7I7I7K&Kc&QRNXXn5N"''.!S"AB %&MM.,{:S(4[(A<P`Cac> r   c                    ddddddt         j                  d}|i }i ||}t        | j                        dk(  r$t        j                  | t         j
                        n| }|d   dk(  r,t        j                  |t         j                  d	d
|d         }n+t        j                  |t         j                  d
d	|d         }t        j                  |d
k  | d
      }|d   rS|j                         d
kD  r*t        j                  ||j                         z  dz        }n@t        j                  |      }n*t        j                  t        j                  |d
d            }|d   r$t        j                  ||d   |d   |d         \  }}|S )u  
    检测从亮到暗的变化（负梯度）
    
    Args:
        image: 输入图像
        params: 参数字典，包含以下键值:
            - direction: str, 检测方向 ('horizontal', 'vertical')
            - ksize: int, Sobel核大小 (1, 3, 5, 7)
            - normalize: bool, 是否归一化到0-255
            - threshold: int, 可选的二值化阈值
            - apply_threshold: bool, 是否应用二值化
    
    Returns:
        negative_edges: 负梯度边缘图像
    r   r   Tr   Fr   r   r   r   r   r   r   r   r   r   r   r   r   )r   r   r   r   r   r   negative_edgesr   s           r   detect_negative_gradientr   Q  st   $ " ++N ~/n//L 7:%++6F!6K3<<s112QVDK L0		$

AqW8MN		$

AqW8MN XXeai%3NK !#XXn~7I7I7K&Kc&QRNXXn5N"''.!S"AB %&MM.,{:S(4[(A<P`Cac> r   c                 P   	 |j                         j                  d      d   }|dv r-t        j                  dg}t        j                  d| |      \  }}n|dk(  r-t        j
                  dg}t        j                  d| |      \  }}nh|d	v rt        j                  d
|       \  }}nJ|dv rt        j                  d|       \  }}n,t        j                  dg}t        j                  d| |      \  }}|r|j                  |       yy# t        $ r}t        d|        Y d}~yd}~ww xY w)u   
    保存图像到中文路径
    
    Args:
        image: OpenCV图像数组
        file_path: 包含中文的文件路径
    
    Returns:
        bool: 是否保存成功
    r   rx   )jpgjpeg_   z.jpgpngr   z.png)bmpz.bmp)r|   r{   z.tiffTFr   N)	r   r   r   IMWRITE_JPEG_QUALITYr   IMWRITE_PNG_COMPRESSIONr   r8   rF   )r   r9   r   encode_paramr   r   r;   s          r   save_image_chinese_pathr     s   oo%%c*2. /!44b9L#&<<|#L G[E\77;L#&<<|#L G[G^#&<<#> G[O##&<<#? G[  44b9L#&<<|#L G[y) $QC()s   D D 	D%D  D%c                      t        j                         } t        d       | j                         j	                  d      D ]  }t        d|         y )Nu   详细错误堆栈:
  )	traceback
format_excrF   r   r   )error_tracebacklines     r   error_message_showr    sI    **,O 

   %%'--d34&k 4r   c                 R    | d   }| d   }| d   }| d   }|}|}||z   }||z   }||||fS Nr   r   rL   r    )	rectxyr   r   x1y1x2y2s	            r   xyxy_from_xywhr    sQ    QAQAGE!WF	
B	
B	
UB	
VBBr   c                 v    | d   }| d   }| d   }| d   }|}|}t        ||z
        }t        ||z
        }||||fS r
  )abs)	r  x0y0r  r  r  r  rK   hs	            r   xywh_from_xyxyr    sX    	aB	aB	aB	aB
A
ABrE
ABrE
Aq!Q<r   c                 6    | d   }| d   }| d   }| d   }||||fS )u   
    从AOI字典中获取xywh格式的坐标
    
    Args:
        aoi: AOI字典，包含'x', 'y', 'width', 'height'
        
    Returns:
        tuple: (x, y, width, height)
    r  r  r   r   r  )aoir  r  r   r   s        r   xywh_from_aoir    s7     	CACALE]Fq%  r   c                 *    t        t        |             S N)r  r  )r  s    r   xyxy_from_aoir    s    -,--r   r   c                    | sy| D ]  } n i }| d   d   }| d   d   }| d   d   }	| d   d   }
t        t        ||z
        |z  dz         }t        |      D ]  }dg ||z  |z   i d|| <    d}i }|D ]U  }d}| D ]  }|d   }|d   }t        ||z
        }||   d   }t        t	        |      t	        |      z  dz         }t        |      }t        |||z  z
        }||z
  dk\  r n||k  sr|}|||   d	   vrEi ||   d	   |<   |||   d	   |   d
<   g ||   d	   |   d<   ||   d	   |   d   j                  |       ||   d	   |   d
xx   |z  cc<   ||   d	   |   d   j                  |        t        ||   d	         |kD  st        ||   d	         }t        ||   d	   j                         d       }|||   d<   ||   }X |S )u  
    对一组数值进行投票，返回最常见的数值及其出现次数
    
    Args:
        dataList: 数值列表
        diff: 允许的数值差异范围，默认10
        
    Returns:
        (most_common_value, count): 最常见的数值及其出现次数
    Nr   r   rx   )valuedatascur_votediff_collectr#        ?rL   r$  nolinesc                     | d   d   S )Nr   r&  r  r  s    r   <lambda>zvote_for_diff.<locals>.<lambda>,  s    ]^_`]abf]gr   keylineList)
rF   intr  rangefloatrk   r   r   sortedra   )dataListdiffmin_votemax_vote	vote_diffrI   	vote_dictstart_value
start_dict	end_valueend_dictnum_of_voter   cur_maxcur_dict
vote_paramold_invr!  	interDictcur_deccur_diffcur_invcur_strcur_modsorted_lists                            r   vote_for_diffrH    s}      I1+a.K1+a.JQIQH c(X-.59:K;X0!#	!I   GH
DGEQI%+-.G ,Z8H%.5?:S@AG'lG7w'9:;G  A%"!)J"7"GGEGIj).9'BKRIj).9'B4HNPIj).9'B7Kj).9'B7KRRS\]j).9'B4HGSHj).9'B7KRRS\]1 6 y$^45?)J/?@G :!6~!F!L!L!NSghK0;Ij!*- ,HE  R Or   c           	      |   g }g }| D ]q  }|d   }t        |d   ||      st        j                  |      }	|	j                  d       |	j                  g        |	j                  d       |j                  |	       s t        t	        |            D ]  }
||
   }d}t        |
dz   t	        |            D ]  }||   }t        |d   |d   z
        }t        ||z
        }||k  s0||d   k  s9|}||d<   ||k  sFg }|j                  t        |             |j                  |d          |d   j                  |         g }t        t	        |            D ]t  }
||
   }t	        |d         dkD  s|d   j                  d        |d   }|d   d   d   }|d   d   d   }|j                  ||g|t        |      t        |      d	       v |j                  d
        t               }g }|D ]L  }|d   }|d   }||vs||vs|j                  |d          |j                  |       |j                  |       N |S )u  
    对一组线段进行投票，返回与参考线平行，且满足距离要求的线段组
    过滤重复使用的线段，保留最接近目标宽度的线段对

    Args:
        dataList: 线段列表，每个元素为 (x0, y0, x1, y1)
        line_info0: 参考线段信息
        arg_area: 允许的面积差异范围，默认2
        target_width: 目标宽度，默认180
        target_area: 目标宽度容差，默认10
        
    Returns:
        list: 最优的线段对列表，无重复使用的线段
    r   逖 rx   r   rL   r   c                     | d   S Nr   r  r)  s    r   r*  z#vote_for_parallel.<locals>.<lambda>l      AaDr   r+  )	line_pairr3  	line0_key	line1_keyc                     | d   S )Nr3  r  r)  s    r   r*  z#vote_for_parallel.<locals>.<lambda>y  s    qyr   rO  rP  rN  )calculate_lines_parallelismcopyr   r/  r   r  r.  sortrc   rd   add)r2  
line_info0arg_areatarget_widthtarget_arearesult_lines	dataList0	line_infor  line_info_tempmark_itr	mark_infomin_diffcur_itrcur_info	cur_widthrC  cur_info_tempcandidate_pairsline0line1
diff_value
used_linesfiltered_pairs	pair_inforO  rP  s                              r   vote_for_parallelrl  8  so     LI	|&z!}dHE!YYy1N!!(+!!"%!!"%^,  #i.)h'	X\3y>:G )HIaL8A;67I9|34H("x{*'H"*HQK+-(*%,,S];%,,Yq\: **=9 ; *& O#i.)h'	y|q aL.1aLEaLOA&E"1a+J""#U^""5\"5\	$  *" 01 JN$	k*	k*	 J&9J+F!!)K"89NN9%NN9% % r   c                 r   g }g }| D ]`  }	|	d   }
t        |d   |
|      st        j                  |	      }|j                  d       |j                  g        |j                  |       b t        t	        |            D ]  }||   }d}t        |dz   t	        |            D ]  }||   }t        |d   |d   z
        }t        ||z
        }||k  s0||d   k  s9|}||d<   ||k  sFg }|j                  t        |             |j                  |d          |d   j                  |         |j                  d        t        t	        |            D ]_  }||   }t	        |d         dkD  s|d   j                  d        |d   }|d   d   d   }||g}t        |       |j                  |       a |S )	u  
    对一组线段进行投票，返回与参考线平行，且满足距离要求的线段组

    Args:
        dataList: 线段列表，每个元素为 (x0, y0, x1, y1)
        line0: 第一条线段
        line1: 第二条线段
        arg_area: 允许的面积差异范围，默认2
        target_width: 目标宽度，默认200
        target_area: 目标宽度容差，默认2
        
    Returns:
        (most_common_line, count): 最常见的线段及其出现次数
    r   rJ  r   rL   r   c                     | d   S NrL   r  r)  s    r   r*  z/vote_for_parallel_func_filter.<locals>.<lambda>  s    1r   r+  c                     | d   S rL  r  r)  s    r   r*  z/vote_for_parallel_func_filter.<locals>.<lambda>  rM  r   )	rR  rS  r   r/  r   r  r.  rT  rF   )r2  rV  rW  rX  rY  funcfunc_paramsrZ  r[  r\  r  r]  r^  r_  r`  ra  rb  rc  rC  rd  rf  rg  	line_copes                          r   vote_for_parallel_func_filterrt    s   ( LI	| 'z!}dHE!YYy1N!!(+!!"%^,  #i.)h'	X\3y>:G )HIaL8A;67I9|34H("x{*'H"*HQK+-(*%,,S];%,,Yq\: **=9 ;	 *& NN~N&#i.)h'	y|q aL.1aLEaLOA&EI9	* * r   c                 P    |d   }|d   }||d   z   }||d   z   }| ||||f   }|S Nr  r  r   r   r  )r   r  r  r  r  r  	aoi_images          r   get_cv_img_fronm_aoirx    sL    	SB	SB	c'l	B	c(m	BbeRUl#Ir   c                     | |y| j                   dd \  }}|d   }|d   }||d   z   }||d   z   }t        d|      }t        d|      }	t        ||      }
t        ||      }|
|k  s||	k  ry| |	|||
f   }|S )u<  
    从图像中根据AOI提取子图像，如果AOI超过图像边界则取最大重叠部分
    
    Args:
        image: 输入图像 (numpy.ndarray)
        aoi: AOI字典，包含'x', 'y', 'width', 'height'
        
    Returns:
        numpy.ndarray: 提取的子图像，如果没有重叠则返回None
    NrL   r  r  r   r   r   )r   r   min)r   r  
img_height	img_widthr  r  r  r  
overlap_x0
overlap_y0
overlap_x1
overlap_y1rw  s                r   get_cv_img_fronm_aoi_exr    s     } "KKOJ	 
SB	SB	c'l	B	c(m	B QJQJY#JZ$J Z:#; j+Z
-BBCIr   c                 2    i }| |d<   ||d<   ||d<   ||d<   |S rv  r  )r  r  r   r   r  s        r   get_aoi_xywhr    s0    
CCHCHCLCMJr   r      leftc           	      p   |}|}|}d}t        | j                        dk(  r+t        j                  | ||||t        j                  d      }n*t        j                  | ||||t        j                  d      }g |
d<   t        |      D ]  }|dk  s|dk  r|
d   j                  d        y |
d   j                  d| d	| d
|        d }t        |      }t        |      }t        |      }|	dk(  rt        |||||d      }nV|	dk(  rt        |||||d      }n?|	dk(  rt        |||||d      }n(|	dk(  rt        |||||d      }nt        |||||d      }|$||z  }||z  }||z  }|
d   j                  d       t        |t              rt        |      dkD  rnt        |d   t        t        t        j                  f      rFt        |d         dk(  r5g }|D ]*  }|\  }}}}|j                  ||z
  ||z
  ||z
  ||z
  g       , |c S t        |      dk(  r|\  }}}}||z
  ||z
  ||z
  ||z
  gc S |c S  y )Nr  r   r   r   r   r!  r      尝试信息u'   线段尝试参数过低，停止尝试u(   开始尝试：当前参数 : threshold=, minLineLength=, maxLineGap=r  )dirtyperightupdownu*   未找到线段，降低线段检测参数   )r   r   r   copyMakeBorderBORDER_CONSTANTr/  r   r.  C_HoughLinesP_find_verticalC_HoughLinesP_find_horizontalr_   rb   rc   r%   ndarray)r   rhor   minLineLength
maxLineGapthreshold_diffminLineLength_diffmaxLineGap_diff	try_timesdir_typereturn_dictcur_thresholdcur_minLineLengthcur_maxLineGappaddingpadded_image	try_indexcur_linecorrected_linesr  r  r  r  r  s                           r   C_Find_Line_Who_Strongr    s    M%N G
5;;1))%'7G(+(;(;9N ))%'7G(+(;(;1F #%K9%	1 1A 5'../XYd c 	N#**-UVcUddt  vG  uH  HU  Vd  Ue  ,f  	gM* 12^,v2c=2C^]cH  2c=2C^]dH 4c=2C^]aH 4c=2C^]cH 3c=2C^]cH ^+M!33o-N'../[\ (D)x=1$HQK$rzzAZ)[`cdlmndo`ptu`u&(O ()-BB'..7
BwJ7
TVW^T^/_` !) +*]a'%-NBBwJ7
BwJ7
KKOi &j r   d      c                 f   |}|}|}|}|}|}d}d}g }g }g |d<   t        |      D ]  }|dk  s
|dk  s|dk  r|d   j                  d        n|dk  s
|dk  s|dk  r|d   j                  d        nl|d   j                  d| d| d|        |d   j                  d	| d| d|        t        | dt        |      t        |      t        |      d
      }t        | dt        |      t        |      t        |      d      }|#||z  }||	z  }||
z  }|d   j                  d       |#||z  }||	z  }||
z  }|d   j                  d       ||2t	        |d   d   |d   d   z
        }||k  rI|d   j                  d| d| d| d       ||dz  z  }||	dz  z  }||
z  }||dz  z  }||	dz  z  }||
z  }nM||kD  rH|d   j                  d| d| d| d       ||dz  z  }||	dz  z  }||
dz  z  }||z  }||	dz  z  }||
z  }t	        ||z
        |k  s|d   j                  d| d| d| d| d| 
       |d   j                  d| d| d|        |d   j                  d| d| d|        |dz   |d<   t	        ||z
        }||k  st|}g }g }||g}|j                  d| d| d|        |j                  d| d| d|        ||k  s n ||d<   t        |      dk(  r"d|d<   |D ]  }|d   j                  |        |S d |d<   |d   j                  d!       g }|S )"NrJ  r  r   u0   上边沿检测检测参数过低，停止尝试u0   下边沿线段检测参数过低，停止尝试u1   开始尝试：上边沿当前参数 : threshold=r  r  u1   开始尝试：下边沿当前参数 : threshold=r  r  r   r  r  r  r  <   未找到上边沿线段，降低上边沿线段检测参数<   未找到下边沿线段，降低下边沿线段检测参数r   u   当前高度 u    小于目标高度    ±,   ,可能是重要线段被忽略,继续尝试rL   u    大于目标高度 ,   ,可能是干扰线段被记录,继续尝试u   成功找到上边沿线段 u    和下边沿线段 u   ,高度 u    符合目标高度 u"   上边沿最终参数 : threshold=u"   下边沿最终参数 : threshold=   尝试次数   成功   结果   失败3   所有尝试均未成功找到符合要求的线段)r/  r   r  r.  r  r   )r   r  r   areamin_arear   r  r  r  r  r  r  r  up_thresholddown_thresholdup_minLineLengthdown_minLineLengthup_maxLineGapdown_maxLineGaprC  min_Diff	cur_lines
info_linesr  up_line	down_line
cur_heightinfo	line_lists                                r   C_Find_Height_Auto_Liker  X  s    LN$&M OHHIJ"$K9%	!/!38H18L'../abA!3a!7Oa<O'../abN#**-^_k^ll|  ~N  }O  O\  ]j  \k  ,l  	mN#**-^_m^nn~  @R  S  S`  ap  `q  ,r  	s/qC$5./=)4

 2qC$701?+V
	
 ?N*L 22_,M'../mnn,N"44.O'../mn?i/1a71:a=89
'..zlJ^_e^ffhimhn  o[  0\  ]NQ..L 2Q 66_,Mnq00N"4q"88.O& '..zlJ^_e^ffhimhn  o[  0\  ]NQ..L 2Q 66_q00Mn,N"4q"88.OzF"#t+'..1MgYVjktjuu}  I  ~J  J^  _e  ^f  fh  im  hn  0o  p'..1ST`Saaq  sC  rD  DQ  R_  Q`  0a  b'..1STbSccs  uG  tH  HU  Ve  Uf  0g  h*3a-K':./H8##	
$i0	!!$F|nTdeudv  wD  ER  DS  #T  U!!$F~FVVfgyfz  {H  IX  HY  #Z  [h& &@ #,K
9~ (HD'..t4  (HN#**+`a	r   c                 6   t        j                  | t         j                        }i }t        ||||||||||	|
||      }d|v rWg |d<   |d   D ]J  }|j	                  dd      j	                  dd      }|j	                  dd      }|d   j                  |       L d	|v r|d	   |d	<   d
|v r|d
   |d
<   |sg S g }| j                  dd \  }}|j                  dd \  }}|D ]8  }|d   }|\  }}}}|}|dz
  |z
  }|}|dz
  |z
  } |j                  |||| gg       : |S )u|  
    自动查找符合指定宽度的左右边沿线段
    通过旋转图像90度调用C_Find_Height_Auto_Like来实现
    
    Args:
        image: 输入图像
        rho: 距离分辨率，默认1
        width: 目标宽度，默认100
        area: 宽度容差，默认30
        min_area: 最小容差，默认20
        threshold: 初始累加器阈值，默认30
        minLineLength: 初始最小线段长度，默认50
        maxLineGap: 初始最大线段间隙，默认5
        threshold_diff: 阈值递减步长，默认5
        minLineLength_diff: 最小线段长度递减步长，默认5
        maxLineGap_diff: 最大间隙递增步长，默认1
        try_times: 最大尝试次数，默认5
        return_dict: 返回详细信息的字典
        
    Returns:
        list: 包含左右边沿线段的列表 [left_line, right_line]，失败返回空列表
    )r  r   r  r  r   r  r  r  r  r  r  r  r  u	   上边沿u	   左边沿u	   下边沿u	   右边沿u   高度u   宽度r  r  NrL   r   r   )r   rotateROTATE_90_CLOCKWISEr  replacer   r   )!r   r  r   r  r  r   r  r  r  r  r  r  r  rotated_imageinternal_return_dictheight_linesr  converted_infooriginal_linesoriginal_heightoriginal_widthrotated_heightrotated_width
line_groupr  r  r  r  r  original_x1original_y1original_x2original_y2s!                                    r   C_Find_Width_Auto_Liker    s   : JJuc&=&=>M  +#%-'(L" --&(N#(8D!\\+{CKKKYdeN+33HhGN'..~>	 9 --&:>&JN#'' 4X >H 	 N&+kk"1o#O^$1$7$7$;!NM #
!}BB #a'",#a'", 	[+{STU #" r   c                    |}|}|}|}|}|}g |d<   t        |
      D ]  }|dk  s
|dk  s|dk  r|d   j                  d        n_|dk  s
|dk  s|dk  r|d   j                  d        n9|d   j                  d| d| d|        |d   j                  d| d| d|        t        | dt        |      t        |      t        |      d	
      }t        | dt        |      t        |      t        |      d
      }|#||z  }||z  }||	z  }|d   j                  d       |#||z  }||z  }||	z  }|d   j                  d       ||2t	        |d   d   |d   d   z
        }|||z
  k  rM|d   j                  d| d| d| d       ||dz  z  }||dz  z  }||	z  }||dz  z  }||dz  z  }||	dz  z  }|||z   kD  rM|d   j                  d| d| d| d       ||dz  z  }||dz  z  }||	dz  z  }||z  }||dz  z  }||	dz  z  }|d   j                  d| d| d| d| d| 
       |d   j                  d| d| d|        |d   j                  d| d| d|        |dz   |d<   d|d<   g }|j                  |       |j                  |       |c S  |d   j                  d| d| d|        |d   j                  d| d| d|        |
|d<   d|d<   |d   j                  d        g }|S )!Nr  r   u0   右边沿检测检测参数过低，停止尝试u0   左边沿线段检测参数过低，停止尝试u1   开始尝试：右边沿当前参数 : threshold=r  r  u1   开始尝试：左边沿当前参数 : threshold=r  r  r  r  r  r   u   当前宽度 u    小于目标宽度 r  r  rL   u    大于目标宽度 r  u   成功找到右边沿线段 u    和左边沿线段 u   ,宽度 u    符合目标宽度 u"   右边沿最终参数 : threshold=u"   左边沿最终参数 : threshold=r  r  r  r  r  )r/  r   r  r.  r  )r   r  r   r  r   r  r  r  r  r  r  r  right_thresholdleft_thresholdright_minLineLengthleft_minLineLengthright_maxLineGapleft_maxLineGapr  
right_line	left_linerc  r  s                          r   C_Find_Width_Auto_Like0r    s_     ON'&! O"$K9%	Q"5"9>QTU>U'../abA!3a!7Oa<O'../abN#**-^_n^oo  AT  @U  Ub  cs  bt  ,u  	vN#**-^_m^nn~  @R  S  S`  ap  `q  ,r  	s0qC$812+,g


 0qC$701?+V
	
 ~-O#55/'../mnn,N"44.O'../mn!2
1a(9Q<?:;	ut|#'..ykI]^c]ddfgkfl  mY  0Z  [~11O#5#99/nq00N"4q"8822O%'..ykI]^c]ddfgkfl  mY  0Z  [~11O#5#99! 33n,N"4q"8822O'..1Mj\Ymnwmx  yA  BK  AL  L`  af  `g  gi  jn  io  0p  q'..1STcSddt  vI  uJ  JW  Xh  Wi  0j  k'..1STbSccs  uG  tH  HU  Ve  Uf  0g  h*3a-K'$,K!IZ(Y's &t &&)KOK\\l  nA  mB  BO  P`  Oa  (b  c&&)KNK[[kl~k  @M  N]  M^  (_  `"+K$K&&'\]Ir   r   c           
          t        |	      D ]Y  }t        | ||||z  z
  |||z  z
  |||z  z
  |      }|)|dz   |
d<   |||z  z
  |
d<   |||z  z
  |
d<   |||z  z   |
d<   d|
d<   |c S  |	|
d<   d	|
d<   y 
Nr  r   r  r   r  r  r  r  r  )r/  r  r   r  r   r  r  r  r  r  r  r  r  r  r'  s                r   %C_HoughLinesP_find_vertical_auto_feedr  d  s     9%	+)n"<<')6H*HH!I$??
 *3a-K''09~3M'MK$+89GY;Y+YK((2Y5P(PK%$,K!L! &" #,K$Kr   r  c           
          t        |	      D ]Y  }t        | ||||z  z
  |||z  z
  |||z  z
  |      }|)|dz   |
d<   |||z  z
  |
d<   |||z  z
  |
d<   |||z  z   |
d<   d|
d<   |c S  |	|
d<   d	|
d<   y r  )r/  r  r  s                r   'C_HoughLinesP_find_horizontal_auto_feedr    s     9%	-)n"<<')6H*HH!I$??
 *3a-K''09~3M'MK$+89GY;Y+YK((2Y5P(PK%$,K!L! &$ #,K$Kr   c                 n   | j                   dd \  }}|\  }}||z  }||z  }t        | j                         dk(  rt        j                  ||| j                   d   f| j                        }t        |      D ]  }	t        |      D ]  }
t        |	|z        }t        |	dz   |z        }t        |
|z        }t        |
dz   |z        }t        | j                   d         D ])  }| |||||f   }t        j                  |      ||	|
|f<   +   |S t        j                  ||f| j                        }t        |      D ]u  }	t        |      D ]e  }
t        |	|z        }t        |	dz   |z        }t        |
|z        }t        |
dz   |z        }| ||||f   }t        j                  |      ||	|
f<   g w |S )u"   使用中值的方式进行 resizeNrL   r   rv   r   )r   r   r%   zerosrw   r/  r.  median)r   target_sizer  rK   target_wtarget_hscale_xscale_yr   r   jstart_yend_ystart_xend_xcregions                    r   median_resizer    s   ;;r?DAq$Hh (lG(lG
5;;18Xu{{1~>ekkRxA8_a'k*QUg-.a'k*QUg-. u{{1~.A"75='%-#BCF&(ii&7F1a7O / % !2 M 8X.ekkBxA8_a'k*QUg-.a'k*QUg-.wu}gem;<!yy0q!t % ! Mr   c                    | j                   dd \  }}|\  }}||z  }||z  }	t        | j                         dk(  rnt        j                  ||| j                   d   f| j                        }
t        |      D ],  }t        |      D ]  }t        ||	z        }t        |dz   |	z        }t        ||z        }t        |dz   |z        }t        | j                   d         D ]  }| |||||f   }t        j                  |j                               }t        |      }|dk(  r	d|
|||f<   K|dk  rt        d||z         }nt        ||dz
        }|dk  rt        d||z         }nt        ||dz
        }||kD  r||}}|||dz    }t        j                  |      |
|||f<     / |
S t        j                  ||f| j                        }
t        |      D ]
  }t        |      D ]  }t        ||	z        }t        |dz   |	z        }t        ||z        }t        |dz   |z        }| ||||f   }t        j                  |j                               }t        |      }|dk(  rd|
||f<   |dk  rt        d||z         }nt        ||dz
        }|dk  rt        d||z         }nt        ||dz
        }||kD  r||}}|||dz    }t        j                  |      |
||f<     |
S )u:   使用排序后指定范围平均值的方式进行 resizeNrL   r   rv   r   r   )r   r   r%   r  rw   r/  r.  rT  flattenr   rz  mean)r   r  	start_pntend_pntr  rK   r  r  r  r  r   r   r  r  r  r  r  r  r  sorted_region
region_len	start_idxend_idxselected_valuess                           r   check_resizer    s'   ;;r?DAq$Hh (lG(lG
5;;18Xu{{1~>ekkRxA8_a'k*QUg-.a'k*QUg-. u{{1~.A"75='%-#BCF$&GGFNN,<$=M!$]!3J "Q*+q!Qw  !1}$':	+A$B	$'	:>$B	{"%ag)=">"%gzA~"> !7*-4i7	 '4Igai&HO&(ggo&>F1a7O9 / % !Z MM 8X.ekkBxA8_a'k*QUg-.a'k*QUg-.wu}gem;< "(8 9 /
 ?#$F1a4L q= #AzI'= >I #IzA~ >IQ;!!Z'%9:G!':>:G w&)0)wI #0	'!)"D!ww7q!tC % !H Mr   c                     t        j                  | |t        j                  dz  |||      }t	        |d      }|yt        |      \  }}|y|yd}|dk(  r|d   }|S |dk(  r|d	   }|S |d
k(  r|}|S |d   }|S )F  
    使用Hough变换检测垂直线段
    
    Args:
        image: 输入图像
        rho: 距离分辨率
        theta: 角度分辨率
        threshold: 累加器阈值
        minLineLength: 最小线段长度
        maxLineGap: 最大线段间隙
        
    Returns:
        lines: 检测到的线段列表
    rL   thetar   r  r  
   angle_toleranceNr  r   r  rx   all)r   HoughLinesPr%   pifilter_vertical_linessort_lines_by_center_x	r   r  r   r  r  r  r'  center_x_listr  s	            r   r  r  )  s    * OOE3beeAgZgt~E "%<E}1%8E=} }D&Qx K 
G	Ry K 
E	
 K Qx Kr   c                     t        j                  | |t        j                  dz  |||      }t	        |d      }|yt        |      \  }}|y|yd}|dk(  r|d   }|S |dk(  r|d	   }|S |d
k(  r|}|S |d   }|S )r  rL   r  r	  r
  Nr  r   r  rx   r  )r   r  r%   r  filter_horizontal_linessort_lines_by_center_yr  s	            r   r  r  [  s    * OOE3beeai9\i  wA  BE $E2>E}1%8E=} }D$Qx K 
F	Ry K 
E	
 K Qx Kr   c                 8   | t        |       dk(  r|rdg fS yd }g }g }| D ]W  }|d   \  }}	}
} |||	|
|      }t        ||z
        }|dkD  rd|z
  }||k  s6|j                  |       |j                  |       Y |rt        j                  |      nd}|r||fS |S )u  
    根据角度筛选CV直线组
    
    Args:
        lines: cv2.HoughLinesP 返回的直线数组 [[[x1, y1, x2, y2]], ...]
        target_angle: 目标角度（度），默认90度（垂直线）
        angle_tolerance: 角度容差（度），默认±10度
        return_angles: 是否同时返回每条线的角度信息，默认False
        
    Returns:
        filtered_lines: 筛选后的直线数组
        line_angles: 如果return_angles=True，则返回(filtered_lines, angles)元组
    Nr   c                     || k(  ry||z
  || z
  z  }t        j                  |      }t        j                  |      }|dk  r|dz  }|S )u*   计算直线与水平线的夹角（度）     V@r      r%   arctandegreesr  r  r  r  slope	angle_rad	angle_degs          r   calculate_line_anglez3filter_lines_by_angle.<locals>.calculate_line_angle  sU    8 bR"W%IIe$	JJy)	 q=Ir   Z   r  )r   r  r   r%   r&   )r'  target_angler  return_anglesr!  filtered_linesline_anglesr  r  r  r  r  angle
angle_diffs                 r   filter_lines_by_angler)    s     }E
a8O  NKaBB$RR4 -.
 ?z)J(!!$'u%  2@RXXn-TN{**r   c                     t        | d|      S )u   
    筛选垂直线（90度左右）
    
    Args:
        lines: cv2.HoughLinesP 返回的直线数组
        angle_tolerance: 角度容差（度），默认±10度
        
    Returns:
        vertical_lines: 垂直线数组
    r"  r#  r  r)  r'  r  s     r   r  r    s     !RYYr   c                     t        | d|      S )u   
    筛选水平线（0度或180度左右）
    
    Args:
        lines: cv2.HoughLinesP 返回的直线数组
        angle_tolerance: 角度容差（度），默认±10度
        
    Returns:
        horizontal_lines: 水平线数组
    r   r+  r,  r-  s     r   r  r    s     !QXXr   c                     t        | ||      S )u(  
    筛选对角线（45度或135度左右）
    
    Args:
        lines: cv2.HoughLinesP 返回的直线数组
        target_angle: 目标角度（45或135度）
        angle_tolerance: 角度容差（度），默认±15度
        
    Returns:
        diagonal_lines: 对角线数组
    r+  r,  )r'  r#  r  s      r   filter_diagonal_linesr0    s     !\Sbccr   c                    | t        |       dk(  rdddg dS d }g }g }g }g }| D ]{  }|d   \  }	}
}} ||	|
||      }|j                  |       t        |dz
        |k  r|j                  |       L||k  s|d|z
  k\  r|j                  |       k|j                  |       } |rt        j                  |      nd|rt        j                  |      nd|rt        j                  |      |dS d|dS )u  
    将直线按角度分类为垂直线、水平线和其他线
    
    Args:
        lines: cv2.HoughLinesP 返回的直线数组
        vertical_tolerance: 垂直线角度容差
        horizontal_tolerance: 水平线角度容差
        
    Returns:
        dict: 包含分类结果的字典
        {
            'vertical': 垂直线数组,
            'horizontal': 水平线数组,
            'others': 其他角度线数组,
            'angles': 所有线的角度列表
        }
    Nr   )r   r   othersanglesc                     || k(  ry||z
  || z
  z  }t        j                  |      }t        j                  |      }|dk  r|dz  }|S Nr  r   r  r  r  s          r   r!  z5classify_lines_by_angle.<locals>.calculate_line_angle  Q    8bR"W%IIe$	JJy)	q=Ir   r"  r  )r   r   r  r%   r&   )r'  vertical_tolerancehorizontal_tolerancer!  vertical_lineshorizontal_linesother_lines
all_anglesr  r  r  r  r  r'  s                 r   classify_lines_by_angler=    s"   $ }E
a	
 	
 NKJaBB$RR4%  urz?00!!$'**e>R8R.S##D)t$  1?BHH^,D4Dbhh/0$+6"((;'	  =A	 r   c                    | t        |       dk(  ryg }| D ]O  }|d   \  }}}}t        j                  ||z
  dz  ||z
  dz  z         }	|	|k\  s7||	|k  s?|j                  |       Q |rt        j                  |      S dS )u  
    根据线段长度筛选直线
    
    Args:
        lines: cv2.HoughLinesP 返回的直线数组
        min_length: 最小长度
        max_length: 最大长度，None表示不限制
        
    Returns:
        filtered_lines: 筛选后的直线数组
    Nr   rL   )r   r%   r   r   r&   )
r'  
min_length
max_lengthr%  r  r  r  r  r  lengths
             r   filter_lines_by_lengthrB  5  s     }E
aNaBB"r'Ab145ZZ%76Z;O!!$'  (6288N#?4?r   c                    | t        |       dk(  r|r	dddg g dfS yd }d }g }g }g }	g }
g }| D ]  }|d   \  }}}} |||||      } |||||      }|j                  |       |	j                  |       d}|rFd}|D ]?  \  }}|dk  r|dz  }|dkD  r|dz  }||k  r||cxk  r|k  s+n .d} n||k\  s||k  s=d} n ||k\  xr |du xs ||k  }|s|s|j                  |       |
j                  |       |j                  |        |rt        j                  |      nd}|rt        |       t        |      ||	|
|d	}||fS |S )
u  
    高级直线筛选函数，支持多个角度范围和长度筛选
    
    Args:
        lines: cv2.HoughLinesP 返回的直线数组
        angle_ranges: 角度范围列表，例如 [(85, 95), (175, 185)] 或 [(85, 95), (-5, 5)]
        min_length: 最小长度
        max_length: 最大长度
        return_details: 是否返回详细信息
        
    Returns:
        filtered_lines: 筛选后的直线数组
        details: 如果return_details=True，返回详细信息字典
    Nr   )totalfilteredr3  lengthsc                     || k(  ry||z
  || z
  z  }t        j                  |      }t        j                  |      }|dk  r|dz  }|S r5  r  r  s          r   r!  z2advanced_line_filter.<locals>.calculate_line_angled  r6  r   c                 J    t        j                  || z
  dz  ||z
  dz  z         S ro  )r%   r   )r  r  r  r  s       r   calculate_line_lengthz3advanced_line_filter.<locals>.calculate_line_lengthn  s&    wwR!|rBwl233r   TFr  )rD  rE  r<  all_lengthsfiltered_anglesfiltered_lengths)r   r   r%   r&   )r'  angle_rangesr?  r@  return_detailsr!  rI  r%  r<  rJ  rK  rL  r  r  r  r  r  r'  rA  angle_match	min_angle	max_anglelength_matchrZ  detailss                            r   advanced_line_filterrT  P  s    }E
a1!rbQQQ4 NJKOaBB$RR4&r2r26% 6" K(4$	9q=$Is?$I	) E6Y6&*	)Ui-?&* )5" *, D"d*Bf
.B 	 <!!$'""5)##F+G J 0>288N+4LZN+$&. 0
 W$$r   c                 :   | t        |       dk(  rdg fS g }| D ]'  }|d   \  }}}}||z   dz  }|j                  ||f       ) |j                  d |        |D 	cg c]  }	|	d   	 }
}	|D 	cg c]  }	|	d   	 }}	t        j                  |
      |fS c c}	w c c}	w )uZ  
    按照直线中心点的X坐标排序
    
    Args:
        lines: cv2.HoughLinesP 返回的直线数组 [[[x1, y1, x2, y2]], ...]
        ascending: 是否升序排列，True为升序，False为降序
        
    Returns:
        sorted_lines: 按X坐标排序后的直线数组
        center_x_list: 对应的中心点X坐标列表
    Nr          @c                     | d   S Nr   r  ro   s    r   r*  z(sort_lines_by_center_x.<locals>.<lambda>      d1gr   r,  reverser   r   r   rT  r%   r&   )r'  	ascendinglines_with_center_xr  r  r  r  r  center_xro   sorted_linesr  s               r   r  r         }E
aRx aBBGs?""D(#34  !59}M )<<(;DG(;L<)<=)<T!W)<M=88L!=00 ==   B.Bc                 :   | t        |       dk(  rdg fS g }| D ]'  }|d   \  }}}}||z   dz  }|j                  ||f       ) |j                  d |        |D 	cg c]  }	|	d   	 }
}	|D 	cg c]  }	|	d   	 }}	t        j                  |
      |fS c c}	w c c}	w )uZ  
    按照直线中心点的Y坐标排序
    
    Args:
        lines: cv2.HoughLinesP 返回的直线数组 [[[x1, y1, x2, y2]], ...]
        ascending: 是否升序排列，True为升序，False为降序
        
    Returns:
        sorted_lines: 按Y坐标排序后的直线数组
        center_y_list: 对应的中心点Y坐标列表
    Nr   rV  c                     | d   S rX  r  rY  s    r   r*  z(sort_lines_by_center_y.<locals>.<lambda>  rZ  r   r[  r   r]  )r'  r^  lines_with_center_yr  r  r  r  r  center_yro   ra  center_y_lists               r   r  r    rb  rc  c           	         | t        |       dk(  r
|rdg g dfS yg }t        |       D ]m  \  }}|d   \  }}}	}
||	z   dz  }||
z   dz  }|j                         dk(  r|}n!|j                         dk(  r|}nt        d      |j	                  |||||d       o |j                  d	 | 
       |D cg c]  }|d   	 }}|rW|D cg c]  }|d   |d   f c}|D cg c]  }|d   	 c}|D cg c]  }|d   	 c}||d}t        j                  |      |fS t        j                  |      S c c}w c c}w c c}w c c}w )u  
    通用的直线中心点排序函数
    
    Args:
        lines: cv2.HoughLinesP 返回的直线数组
        sort_by: 排序依据，'x' 或 'y'
        ascending: 是否升序排列
        return_details: 是否返回详细信息
        
    Returns:
        sorted_lines: 排序后的直线数组
        details: 如果return_details=True，返回详细信息字典
    Nr   )center_coordsoriginal_indicesrV  r  r  u   sort_by 必须是 'x' 或 'y')r  r`  rg  
sort_valueoriginal_indexc                     | d   S )Nrl  r  rY  s    r   r*  z&sort_lines_by_center.<locals>.<lambda>  s	    D$6r   r[  r  r`  rg  rl  rm  )rj  sort_valuesrk  sort_byr^  )r   r   r   r^   r   rT  r%   r&   )r'  rp  r^  rN  r\  r   r  r  r  r  r  r`  rg  rl  ro   ra  rS  s                    r   sort_lines_by_centerrq    s    }E
a22FFF IU#4aBBGs?Gs?==?c!!J]]_#!J<==  $
 	 $* NN6INN .77YTDLYL7OXYyttJ/j1AByY;DE94D.9EDM NID&6!7I N"
 xx%w..88L!! 8 ZE Ns   1D-D2D7.D<c                    | t        |       dk(  ry|dd \  }}g }| D ]  }|d   \  }}t        j                  |      }t        j                  |      }	||z  }
||	z  }t	        t        j
                  |dz  |dz  z               }t	        |
||	 z  z         }t	        |||z  z         }t	        |
||	 z  z
        }t	        |||z  z
        }|j                  ||||gg        |rt        j                  |      S dS )u   
    简化版本的HoughLines转换函数
    使用参数方程直接计算端点
    
    Args:
        lines: HoughLines返回的结果
        image_shape: 图像形状
        
    Returns:
        numpy.ndarray: HoughLinesP格式的线段数组
    Nr   rL   )r   r%   cossinr.  r   r   r&   )r'  image_shaper   r   line_segmentsr  r  r  	cos_theta	sin_thetar  r  r   r  r  r  r  s                    r   convert_hough_lines_simplery  %  s    }E
aOMFEM!W
U FF5M	FF5M	 9_9_ q619 456	 iI:../i)++,iI:../i)++,r2r2./0) , '4288M"==r   c           	         ddl }ddl}t        |j                        dk(  r |j                  ||j
                        }n|j                         } |j                  |||      }	 |j                  |	|j                  |j                        \  }
}g }|
D ]  } |j                  |      }||k  r |j                  |      \  }}}}t        ||z        }t        ||z        }t        ||z   |z        }t        ||z   |z        }| j                  dd \  }}t        dt        ||dz
              }t        dt        ||dz
              }t        dt        ||            }t        dt        ||            }|j!                  ||||g        |S )uK  
    在缩小的图像中查找指定灰度范围的区域，并返回在原图中对应的矩形坐标
    
    Args:
        cv_image: 原始图像 (numpy.ndarray)
        cw_midan_image: 缩小后的图像 (numpy.ndarray) 
        scale_factor: 缩放倍数，即cv_image缩小了多少倍得到cw_midan_image
        gray_min: 灰度最小值 (int, 0-255)
        gray_max: 灰度最大值 (int, 0-255)
        min_area: 最小区域面积，过滤掉过小的区域 (int)
        
    Returns:
        list: 矩形列表，每个矩形格式为 [x1, y1, x2, y2] (原图坐标)
    r   Nr   rL   r   )r   numpyr   r   r    r   rS  inRangefindContoursRETR_EXTERNALCHAIN_APPROX_SIMPLEcontourAreaboundingRectr.  r   rz  r   )cv_imagecw_midan_imagescale_factorgray_mingray_maxr  r   r%   gray_scaledmaskcontoursr   	rect_listcontourr  r  r  rK   r  x1_origy1_origx2_origy2_origorig_height
orig_widths                            r   !find_gray_regions_in_scaled_imager  O  s      > A%"cll>33E3EF$))+ 3;;{Hh7D ##""4):):C<S<STKHaIsw'(? &S%%g.
1a a,&'a,&'q1u,-q1u,- #+..!"4ZaWj1n56aWkAo67aWj12aWk23'7GW=>- 0 r   c                 |   ddl }ddl}t        | j                  d         t        |j                  d         z  }t	        |j                        dk(  r |j
                  ||j                        }n|j                         } |j                  |||      }	 |j                  |	dkD        }
g }t        |
d   |
d         D ]|  \  }}t        t        |      |z  dz         }t        t        |      |z  dz         }| j                  dd \  }}d|cxk  r|k  sXn [d|cxk  r|k  sgn j|j                  ||g       ~ |S )u  
    在缩小的图像中查找指定灰度范围的所有点，并返回在原图中对应的点坐标
    
    Args:
        cv_image: 原始图像 (numpy.ndarray)
        cw_midan_image: 缩小后的图像 (numpy.ndarray)
        scale_factor: 缩放倍数
        gray_min: 灰度最小值 (int, 0-255)
        gray_max: 灰度最大值 (int, 0-255)
        
    Returns:
        list: 点坐标列表，每个点格式为 [x, y] (原图坐标)
    r   Nr   r   r%  rL   )r   r{  r0  r   r   r    r   rS  r|  r   zipr.  r   )r  r  r  r  r  r   r%   
cur_factorr  r  points_scaledpoints_origr  r  x_origy_origr  r  s                     r    find_gray_points_in_scaled_imager    s:    x~~a()E.2F2Fq2I,JJJ > A%"cll>33E3EF$))+ 3;;{Hh7D BHHTAX&M KM!$mA&671U1X
*S01U1X
*S01 #+..!"4Z##V(Ak(A/0 8 r   c                 b   | rt        |       dk(  rg S ddldfd	}d }| D cg c]  }t        |       }}dgt        |      z  }g }t        t        |            D ]4  }	||	   r
||	   g}
d||	<   |	g}|ru|j	                  d      }||   }t        t        |            D ]E  }||   r	 ||||   d      }||k  s|
j                  ||          d||<   |j                  |       G |rut        |
      dk(  r|j                  |
d          |
D cg c]  }|d   	 }}|
D cg c]  }|d   	 }}|
D cg c]  }|d	   	 }}|
D cg c]  }|d
   	 }}t        |      t        |      t        |      t        |      g}|j                  |       7 |S c c}w c c}w c c}w c c}w c c}w )u  
    合并距离较近的矩形框
    
    Args:
        rect_list: 矩形列表，每个矩形格式为 [x1, y1, x2, y2]
        distance_threshold: 距离阈值，小于此距离的框会被合并
        merge_method: 合并方法
            - 'union': 取所有框的外接矩形（默认）
            - 'center': 基于中心点距离合并
            - 'overlap': 基于重叠区域合并
        
    Returns:
        list: 合并后的矩形列表，格式为 [x1, y1, x2, y2]
    r   Nrz  c                    | \  }}}}|\  }}}	}
|dk(  rA||z   dz  }||z   dz  }||	z   dz  }||
z   dz  } j                   ||z
  dz  ||z
  dz  z         S |dk(  rtt        ||      }t        ||	      }t        ||      }t        ||
      }||k  r||k  ryt        d||z
        }t        d||z
        } j                   ||z  ||z  z         S y)u!   计算两个矩形之间的距离centerrL   rz  r   N)r   r   rz  )rect1rect2methodx1_1y1_1x2_1y2_1x1_2y1_2x2_2y2_2	center1_x	center1_y	center2_x	center2_yr  r  topbottomdxdyr%   s                        r   calculate_distancez2merge_close_rectangles.<locals>.calculate_distance  s   !&dD$!&dD$X)I)I)I)I277I	1A5Y9NQR8RRSSu_ tT?DdOEdD/Ct_F u} Qu%BQf%B2772b52b5=)) r   c                     | \  }}}}|\  }}}}	t        ||      }
t        ||      }t        ||      }t        ||	      }|
|||gS )u'   合并两个矩形为一个外接矩形)rz  r   )r  r  r  r  r  r  r  r  r  r  	merged_x1	merged_y1	merged_x2	merged_y2s                 r   merge_two_rectanglesz4merge_close_rectangles.<locals>.merge_two_rectangles  sY    !&dD$!&dD$dO	dO	dO	dO	9i;;r   FTr   rL   r   )rz  )r   r{  rb   r/  r   r   rz  r   )r  distance_thresholdmerge_methodr  r  r  
rectanglesmergedr   r   current_groupqueuecurrent_idxcurrent_rectr  distanceall_x1all_y1all_x2all_y2merged_rectr%   s                        @r   merge_close_rectanglesr    s    I!+	*<
< *33$t*J3Ws:&FF3z?#!9 $Aq	 ))A,K%k2L3z?+!9-lJqM5Q11!((A7 $F1ILLO ,	   }"MM-*+ +88-$d1g-F8*78-$d1g-F8*78-$d1g-F8*78-$d1g-F8 FFFF	K MM+&U $X Mc 4H 9888s   FF&F"8F'
F,c                    | rt        |       dk(  rg S ddl}ddlm} g }| D ],  }|\  }}}}	||z   dz  }
||	z   dz  }|j	                  |
|g       .  |j
                  |      } ||d      j                  |      }|j                  }t        |      }g }|D ]  }|dk(  r4 |j                  ||k(        d   }|D ]  }|j	                  | |           = |j                  ||k(        d   }|D cg c]  }| |   	 }}t        |      dk(  r|j	                  |d          |D cg c]  }|d   	 }}|D cg c]  }|d   	 }}|D cg c]  }|d   	 }}|D cg c]  }|d   	 }}t        |      t        |      t        |      t        |      g}|j	                  |        |S c c}w c c}w c c}w c c}w c c}w )	u   
    基于中心点距离合并矩形框
    
    Args:
        rect_list: 矩形列表，每个矩形格式为 [x1, y1, x2, y2]
        distance_threshold: 中心点距离阈值
        
    Returns:
        list: 合并后的矩形列表
    r   N)DBSCANrL   r   )epsmin_samplesrx   r   )r   r{  sklearn.clusterr  r   r&   fitlabels_rd   r   rz  r   )r  r  r%   r  centersr  r  r  r  r  r`  rg  
clusteringlabelsunique_labelsr   labelindicesidxgroup_rectsr  r  r  r  r  s                            r   #merge_rectangles_by_center_distancer  )	  s    I!+	& GBBGq=Gq=(+,	  bhhwG .A>BB7KJF KMFB;bhhv/2Gin-  bhhv/2G5<=Wc9S>WK=;1$k!n- /::kd$q'k:.9:kd$q'k:.9:kd$q'k:.9:kd$q'k: KKKK	 k*3 6 M' > ;:::s   /F($F-6F2F7F<c           
         | rt        |       dk(  rg S d }| D cg c]  }t        |       }}t        |      D ]  }d}g }dgt        |      z  }	t        t        |            D ]  }
|	|
   r	||
   }d|	|
<   t        d      }d}t        |
dz   t        |            D ]$  }|	|   r	 ||||         }||k  s||k  s!|}|}& |dk7  rd||   }t	        |d   |d         t	        |d   |d         t        |d   |d         t        |d	   |d	         g}|j                  |       d|	|<   d}|j                  |        |}|r |S  |S c c}w )
u  
    迭代式合并矩形框，直到没有可合并的框为止
    
    Args:
        rect_list: 矩形列表
        distance_threshold: 距离阈值
        max_iterations: 最大迭代次数，防止无限循环
        
    Returns:
        list: 合并后的矩形列表
    r   c                     | \  }}}}|\  }}}}	t        ||      }
t        ||      }t        ||      }t        ||	      }|
|k  r||k  ryt        d|
|z
        }t        d||z
        }||z  ||z  z   dz  S )u'   计算两个矩形之间的最小距离r   r%  )r   rz  )r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  s                   r   calculate_min_distancez:merge_rectangles_iterative.<locals>.calculate_min_distancex	  s    !&dD$!&dD$4D$$oT45=SF]D5L!C&L!22#%%r   FTinfrx   r   rL   r   )r   rb   r/  r0  rz  r   r   )r  r  max_iterationsr  r  current_rects	iteration
merged_any	new_rectsusedr   r  min_distance	merge_idxr  r  r  r  s                     r   merge_rectangles_iterativer  i	  s    I!+	&" -66IDT$ZIM6>*	
	w]++s=)*AAw(+LDG !<LI1q5#m"4571,a@PQ11h6M#+L !I 6 B%i0Qq2Qq2Qq2Qq2	   -"&Y!
  .C +F " ] +\ a 7s   Ec                 J    t        | |||||      }|sg S t        |||      }	|	S )u  
    在缩小图像中查找灰度区域并自动合并相近的区域
    
    Args:
        cv_image: 原始图像
        cw_midan_image: 缩小后的图像
        scale_factor: 缩放倍数
        gray_min: 灰度最小值
        gray_max: 灰度最大值
        min_area: 最小区域面积
        merge_distance: 合并距离阈值
        merge_method: 合并方法
        
    Returns:
        list: 合并后的矩形列表
    )r  r  )r  r  )
r  r  r  r  r  r  merge_distancer  r  merged_rectss
             r   find_and_merge_gray_regionsr  	  sB    ( 2.,(HI
 	 *n!L
 r   c                    ddl }| j                         }t        | j                        dk(  r| j                  \  }}}n| j                  \  }}t	        ||dz  |dz        }|dk  r|S t        | j                        dk(  r@||d|ddddf<   ||||z
  |ddddf<   ||ddd|ddf<   ||dd||z
  |ddf<   |S ||d|ddf<   ||||z
  |ddf<   ||ddd|f<   ||dd||z
  |f<   |S )u%  
    将图像四周宽度为w的范围内的灰度数据改为指定值
    
    Args:
        image: 输入图像 (numpy.ndarray)
        border_width: 边框宽度 (int)
        gray_value: 指定的灰度值 (int, 0-255)
        
    Returns:
        numpy.ndarray: 处理后的图像
    r   Nr   rL   r{  rS  r   r   rz  )r   border_width
gray_valuer%   r   r   r   r   s           r   set_border_gray_valuer  	  sB     ZZ\F 5;;1"'++x |UaZ1=Lq
5;;1 (2q~q!#$3=vl"6)1a/0'1q!L.!#$1;q%$U*A-. M %/q~q !0:vl"6)1,-$.q!L. !.8q%$U**+Mr   c                 v   ddl }| j                         }t        | j                        dk(  r| j                  \  }}}n| j                  \  }}t	        ||dz  |dz        }|dk  r|S  |j
                  |||      }	t        | j                        dk(  rZt        |      D ]J  }
|	|
   ||
ddddf<   |	|
   ||dz
  |
z
  ddddf<   |	|
   |dd|
ddf<   |	|
   |dd|dz
  |
z
  ddf<   L |S t        |      D ]>  }
|	|
   ||
ddf<   |	|
   ||dz
  |
z
  ddf<   |	|
   |dd|
f<   |	|
   |dd|dz
  |
z
  f<   @ |S )uI  
    将图像四周宽度为w的范围内设置为渐变值
    
    Args:
        image: 输入图像 (numpy.ndarray)
        border_width: 边框宽度 (int)
        inner_value: 内侧灰度值 (int, 0-255)
        outer_value: 外侧灰度值 (int, 0-255)
        
    Returns:
        numpy.ndarray: 处理后的图像
    r   Nr   rL   r   )r{  rS  r   r   rz  linspacer/  )r   r  inner_valueouter_valuer%   r   r   r   r   gradientr   s              r   set_border_gradientr  
  sm    ZZ\F
5;;1"'++x|UaZ1=Lq r{{;\BH
5;;1|$A&qkF1a7O'/{F6!8A:q!#$&qkF1a7O&.qkF1eAgai?# %* M |$A#A;F1a4L$,QKF6!8A:q=!#A;F1a4L#+A;F1eAgai<  % Mr   )r  r  r  r  c                 &   ddl }| j                         }t        | j                        dk(  r| j                  \  }}}n| j                  \  }}t	        ||dz  |dz        }|dk  r|S t        | j                        dk(  rPd|v r||d|ddddf<   d|v r||||z
  |ddddf<   d|v r||ddd|ddf<   d|v r||dd||z
  |ddf<   |S d|v r||d|ddf<   d|v r||||z
  |ddf<   d|v r||ddd|f<   d|v r||dd||z
  |f<   |S )	u  
    选择性地将图像指定边的宽度为w的范围内的灰度数据改为指定值
    
    Args:
        image: 输入图像 (numpy.ndarray)
        border_width: 边框宽度 (int)
        gray_value: 指定的灰度值 (int, 0-255)
        sides: 要修改的边 (list)，可选: 'top', 'bottom', 'left', 'right'
        
    Returns:
        numpy.ndarray: 处理后的图像
    r   Nr   rL   r  r  r  r  r  )	r   r  r  sidesr%   r   r   r   r   s	            r   set_selective_border_gray_valuer  K
  sv    ZZ\F
5;;1"'++x|UaZ1=Lq
5;;1E>+5F1\>1a'(u7AF6,&v-q!34U?+5F1ana'(e5?F1eL(.12 M E>(2F1\>1$%u4>F6,&v-q01U?(2F1an$%e2<F1eL(../Mr   c                    ddl }| j                         }t        | j                        dk(  r| j                  \  }}}d}	n| j                  \  }}d}	t	        ||dz  |dz        }|dk  r|S |d }t        |      D ]p  }
t        |      D ]`  }|
|k  xs |
||z
  k\  xs ||k  xs |||z
  k\  }|s&|	r ||
|ddf   } |||
|      s=|||
|ddf<   H||
|f   } |||
|      sZ|||
|f<   b r |S )uZ  
    基于条件函数设置边框灰度值
    
    Args:
        image: 输入图像 (numpy.ndarray)
        border_width: 边框宽度 (int)
        gray_value: 指定的灰度值 (int, 0-255)
        condition_func: 条件函数，接收(x, y, original_value)，返回bool
        
    Returns:
        numpy.ndarray: 处理后的图像
    r   Nr   TFrL   c                      y)NTr  )r  r  vals      r   r*  z/set_border_based_on_condition.<locals>.<lambda>
  s    4r   )r{  rS  r   r   rz  r/  )r   r  r  condition_funcr%   r   r   r   r   is_colorr  r  	in_borderoriginal_values                 r   set_border_based_on_conditionr  }
  s7    ZZ\F
5;;1"'++x|UaZ1=Lq / 6]uA\) FQ&<2G-G FL(F,-1E,E  %+Aq!G_N%aN;*4q!Qw%+AqD\N%aN;'1q!t    Mr   c                    t        | j                        dk(  rt        j                  |       }t	        d      D ]  }| dddd|f   j                  t        j                        }||   j                  t        j                        }||z
  }|||z  z   }t        j                  |dd      }|j                  t        j                        |dddd|f<    |S | j                  t        j                        }|j                  t        j                        }||z
  }|||z  z   }t        j                  |dd      }|j                  t        j                        }|S )   
    中心拉伸
    r   Nr   r   )	r   r   r%   
zeros_liker/  astypefloat32r   r~   )	r   	center_cvalphar   r   channelcenter_datar3  new_channels	            r   enhance_center_stretchr  
  s#    5;;1u%qAAaEl))"**5G#A,--bjj9K[(D%4K ''+q#6K'..rxx8F1Qq5M   ,,rzz*&&rzz2$!EDL0ggk1c2##BHH-r   c                 ,   d }||z   | j                   d   kD  rd}d}t        | j                         dk(  r| j                   \  }}}g }t        |      D ]  }| d d d d |f   }	t        j                  |	d      }	||z   |	j                   d   k\  rt        j
                  |	      }
|
}
n!t        j
                  |	d d || f         }
|
}
|j                  |
        |}|S t        j                  |d      }t        j
                  |d d || f         }
|
}
|S )Nr   r   axis)r   r   r/  r%   rT  r  r   )center_imagestart_wend_wcenter_meanr   r   r   channel_meansr   channel_mean0channel_means              r   enhance_center_get_center_meanr  
  s%   K%<--a00
<!#"."4"4xxA(Aq1MGGM:M-"5"5a"88!yy7+!yyq'5&.7H)IJ+  . ! $ 	 ggk2yyQ->!?@#r   c                 	   d}d}	d}
|dk(  r)|j                   d   }
||z   |j                   d   kD  r-d}d}n(|j                   d   }
||z   |j                   d   kD  rd}d}t        |j                         dk(  r|j                   \  }}}g }t        |      D ]  }|dddd|f   }t        j                  |d      }||z   |
k\  rt        j
                  |      }||z   }n;t        |j                   ||       t        j
                  |dd|| f         }||z   }|j                  |        |}	n;t        j                  |	d      }	t        j
                  |	|| ddf         }||z   }|dk(  rt        |j                         dk(  ru|j                   \  }}}t        j                  d||f      }t        d      D ];  }|dddd|f   }|j                  dd      }|}|	|	|   }||z
  }||dddd|f<   = |}n|j                  dd      }|}|	|	}||z
  }|}n^|d	k(  rt        |j                         dk(  rt|j                   \  }}}t        j                  |d|f      }t        d      D ];  }|dddd|f   }|j                  dd      }|}|	|	|   }||z
  }||dddd|f<   = |}n|j                  dd      }|}|	|	}||z
  }|}nt        |j                         dk(  rt|j                   \  }}}t        j                  d||f      }t        d      D ];  }|dddd|f   }|j                  dd      }|}|	|	|   }||z
  }||dddd|f<   = |}n |j                  dd      }|}|	|	}||z
  }|}t        | j                         dk(  rt        j                  |       }t        d      D ]  }| dddd|f   j                  t        j                        }|dddd|f   j                  t        j                        }|||z  z
  }t        j                  |dd
      }|j                  t        j                        |dddd|f<    |j                  t        j                        }||	fS | j                  t        j                        }|||z  z
  }t        j                  |dd
      }|j                  t        j                        }|j                  t        j                        }||	fS )r  r   Nr   r   r   r
  T)r  keepdimsr   r   )r   r   r/  r%   rT  r  rF   r   r  r   r  r  r   r~   )r   r  center_valuer  dirr  r  	gray_diffuse_datar  max_wr   r   r   r  r   r  r  center_heightcenter_widthcenter_channelshorizontal_datacenter_channelr  center_value0vertical_datar   r  	use_data0r  s                                 r   enhance_center_stretch_imager#  
  sS    HKE
l!!!$eO|11!44GE!!!$eO|11!44GE
<!#"."4"4xxA(Aq1MGGM:M%'!ww}5+i7m))7E:!ww}Qwv~5E'FG+i7   . ! $ ggk2ww{7E6>1+<=>#i/ l|!!"a';G;M;M8M< hh<'IJO 1X!-a!e!4',,!d,C ,*$/NM-/)/!A&  'H +//Q/FO(M& +-=O&H	
	|!!"a';G;M;M8M<HHmQ%HIM1X!-a!e!4',,!d,C ,*$/NM-/'-a!e$  %H )--1t-DM(M& +)M9M$H |!!"a';G;M;M8M< hh<'IJO 1X!-a!e!4',,!d,C ,*$/NM-/)/!A&  'H +//Q/FO(M& +-=O&H 5;;1u%qAAaEl))"**5G 1Q..rzz:I!UY%67K''+q#6K'..rxx8F1Qq5M  ??288,{"" ,,rzz*!12ggk1c2##BHH-??288,{""r   c                    ddl }t        | d   t              st        | d   |j                        r| d   \  }}}}n| \  }}}}t        |d   t              st        |d   |j                        r|d   \  }}	}
}n|\  }}	}
} |j                  ||z
  ||z
  g      } |j                  |
|z
  ||	z
  g      }|j
                  j                  |      }|j
                  j                  |      }|dk(  s|dk(  r	|dk(  rdS dS ||z  }||z  } |j                  ||      } |j                  |dd      } |j                  t        |            }|dk(  r |j                  |      S |S )u{  
    计算两条线段之间的夹角
    
    Args:
        line1: 第一条线段，格式为 [x1, y1, x2, y2] 或 [[x1, y1, x2, y2]]
        line2: 第二条线段，格式为 [x1, y1, x2, y2] 或 [[x1, y1, x2, y2]]
        unit: 角度单位，'degrees'(度) 或 'radians'(弧度)
        
    Returns:
        float: 两条线段之间的夹角(0-90度或0-π/2弧度)
    r   Nr          g            ?)r{  r_   rb   r  r&   linalgnormdotr   arccosr  r  )rg  line2unitr%   r  r  r  r  r  r  r  r  vector1vector2length1length2unit_vector1unit_vector2dot_productr  s                       r   calculate_angle_between_linesr4    s     %(D!Za"**%E!&qdD$!&dD$%(D!Za"**%E!&qdD$!&dD$ bhhtTD[12GbhhtTD[12G iinnW%GiinnW%G !|w!|i's0S0 W$LW$L "&&|4K "''+tS1K 		#k*+Iyrzz)$$r   c                    ddl }t        | d   t              st        | d   |j                        r| d   \  }}}}n| \  }}}}t        |d   t              st        |d   |j                        r|d   \  }}	}
}n|\  }}	}
} |j                  ||z
  ||z
  g      } |j                  |
|z
  ||	z
  g      } |j
                  |d   |d         } |j
                  |d   |d         }||z
  }||j                  kD  r"|d|j                  z  z  }||j                  kD  r"||j                   k  r#|d|j                  z  z  }||j                   k  r#|dk(  r |j                  |      S |S )u  
    计算两条线段之间的有向夹角（考虑方向）
    
    Args:
        line1: 第一条线段
        line2: 第二条线段
        unit: 角度单位
        
    Returns:
        float: 两条线段之间的有向夹角(-180到180度或-π到π弧度)
    r   Nr   rL   r  )r{  r_   rb   r  r&   arctan2r  r  )rg  r+  r,  r%   r  r  r  r  r  r  r  r  r-  r.  angle1angle2r(  s                    r   calculate_angle_with_directionr9    s     %(D!Za"**%E!&qdD$!&dD$%(D!Za"**%E!&qdD$!&dD$ bhhtTD[12GbhhtTD[12G RZZ
GAJ/FRZZ
GAJ/F &J ruu
a"%%i
 ruu

v
a"%%i
 v
 yrzz*%%r   c                 B    t        | |d      }||k  xs |d|z
  k\  }||fS )u  
    判断两条线是否平行
    
    Args:
        line1: 第一条线段
        line2: 第二条线段
        angle_threshold: 角度阈值(度)，小于此值认为平行
        
    Returns:
        tuple: (is_parallel, angle) 是否平行和夹角
    r  r"  )r4  )rg  r+  angle_thresholdr'  is_parallels        r   rR  rR    s6     *%	BE?*Me_8L.MKr   c                 F    t        | |d      }t        |dz
        |k  }||fS )u  
    判断两条线是否垂直
    
    Args:
        line1: 第一条线段
        line2: 第二条线段
        angle_threshold: 角度阈值(度)，与90度的差值小于此值认为垂直
        
    Returns:
        tuple: (is_perpendicular, angle) 是否垂直和夹角
    r  r"  )r4  r  )rg  r+  r;  r'  is_perpendiculars        r    calculate_lines_perpendicularityr?    s0     *%	BE52:/9U""r   c                 n   ddddddd}|i }i ||}t        | j                        dk(  r$t        j                  | t        j                        n| }|d   dk(  r,t        j
                  |t        j                  dd	|d
         }n|d   dk(  r,t        j
                  |t        j                  d	d|d
         }ntt        j
                  |t        j                  dd	|d
         }t        j
                  |t        j                  d	d|d
         }t        j                  |dz  |dz  z         }t        j                  |      }|d   r)|j                         d	kD  r||j                         z  dz  }t        j                  |      }|d   r(t        j                  ||d   k\  ||d   k  z  |d	      }|S |}|S )u[  
    使用Sobel算子检测特定方向的边缘 (v2版本 - 支持阈值范围)
    
    Args:
        image: 输入图像
        params: 参数字典，包含以下键值:
            - direction: str, 检测方向 ('horizontal', 'vertical', 'both')
            - ksize: int, Sobel核大小 (1, 3, 5, 7)
            - threshold_min: int, 最小阈值 (0-255)
            - threshold_max: int, 最大阈值 (0-255)
            - apply_threshold: bool, 是否应用阈值范围过滤
            - normalize: bool, 是否归一化到0-255
    
    Returns:
        edges: 检测到的边缘图像
    r   r   r   r   Tr   r   threshold_minthreshold_maxr   r   r   r   r   r   r   r   rL   r   r   rB  rC  )r   r   r   r    r   r   r   r%   r   r   r   r~   r   )	r   r   r   r   r   r   r   r   r   s	            r   detect_edges_gradient_v2rD    s   & "N ~/n//L 7:%++6F!6K3<<s112QVDK L0		$

AqW8MN	k	"j	0		$

AqW8MN 4Qg9NO4Qg9NO	FAI-. KKE K 99;?EIIK'#-E HHUOE %&l?33l?3351
 L Lr   c                 v   ddddddd}|i }i ||}t        | j                        dk(  r$t        j                  | t        j                        n| }|d   dk(  r,t        j
                  |t        j                  dd	|d
         }n+t        j
                  |t        j                  d	d|d
         }t        j                  |d	kD  |d	      }|d   r)|j                         d	kD  r||j                         z  dz  }t        j                  |      }|d   r&t        j                  ||d   k\  ||d   k  z  |d	      }|S )uV  
    检测从暗到亮的变化（正梯度）(v2版本 - 支持阈值范围)
    
    Args:
        image: 输入图像
        params: 参数字典，包含以下键值:
            - direction: str, 检测方向 ('horizontal', 'vertical')
            - ksize: int, Sobel核大小 (1, 3, 5, 7)
            - threshold_min: int, 最小阈值 (0-255)
            - threshold_max: int, 最大阈值 (0-255)
            - apply_threshold: bool, 是否应用阈值范围过滤
            - normalize: bool, 是否归一化到0-255
    
    Returns:
        positive_edges: 正梯度边缘图像
    r   r   r   r   TrA  r   r   r   r   r   r   r   rB  rC  r   r   r   r    r   r   r   r%   r   r   r~   )r   r   r   r   r   r   r   s          r   detect_positive_gradient_v2rG  Y  sN   & "N ~/n//L 7:%++6F!6K3<<s112QVDK L0		$

AqW8MN		$

AqW8MN XXeai2N K !#+n.@.@.BBSHN XXn-N %&|O<<|O<<>A
 r   c                 x   ddddddd}|i }i ||}t        | j                        dk(  r$t        j                  | t        j                        n| }|d   dk(  r,t        j
                  |t        j                  dd	|d
         }n+t        j
                  |t        j                  d	d|d
         }t        j                  |d	k  | d	      }|d   r)|j                         d	kD  r||j                         z  dz  }t        j                  |      }|d   r&t        j                  ||d   k\  ||d   k  z  |d	      }|S )uV  
    检测从亮到暗的变化（负梯度）(v2版本 - 支持阈值范围)
    
    Args:
        image: 输入图像
        params: 参数字典，包含以下键值:
            - direction: str, 检测方向 ('horizontal', 'vertical')
            - ksize: int, Sobel核大小 (1, 3, 5, 7)
            - threshold_min: int, 最小阈值 (0-255)
            - threshold_max: int, 最大阈值 (0-255)
            - apply_threshold: bool, 是否应用阈值范围过滤
            - normalize: bool, 是否归一化到0-255
    
    Returns:
        negative_edges: 负梯度边缘图像
    r   r   r   r   TrA  r   r   r   r   r   r   r   rB  rC  rF  )r   r   r   r   r   r   r   s          r   detect_negative_gradient_v2rI    sP   & "N ~/n//L 7:%++6F!6K3<<s112QVDK L0		$

AqW8MN		$

AqW8MN XXeai%3N K !#+n.@.@.BBSHN XXn-N %&|O<<|O<<>A
 r   c                    | j                         }t        |t        t        f      rt	        j
                  |g      }nt	        j
                  |      }t        | j                        dk(  r|d   |||d   k  <   |S t        | j                        dk(  rV| j                  d   dk(  rDt        d      D ]6  }t        |      |kD  r||   n|d   }||dddd|f   |dddd|f   |k  <   8 |S )ub  
    对图像的每个通道应用最小值阈值处理
    
    Args:
        image: cv2图像，可以是单通道(H,W)或三通道(H,W,3)
        min_values: 每个通道的最小值，可以是单个数值或包含每个通道最小值的列表/数组
    
    Returns:
        处理后的图像，低于最小值的像素被设置为最小值
    rL   r   r   N)	rS  r_   r.  r0  r%   r&   r   r   r/  )r   
min_valuesr   r  min_vals        r   apply_channel_min_thresholdrM    s     ZZ\F *sEl+XXzl+
XXj)
 5;;1)3Av
1%& M 
U[[	Q	5;;q>Q#6QxG-0_w-Fj)JWXMGELF1a=!&Aw"7'"AB   Mr   c                 0   | j                         j                  t        j                        }t	        |t
        t        f      rt        j                  |g      }nt        j                  |      }d }t        | j                        dk(  rO| j                  \  }}|d   }t        |      D ],  }t        |      D ]  }|||f   |k  s || ||      |||f<    . nt        | j                        dk(  r| j                  d   dk(  ry| j                  \  }}}	t        |      D ][  }t        |      D ]K  }t        d      D ];  }
t        |      |
kD  r||
   n|d   }||||
f   |k  s' || ||      }||
   ||||
f<   = M ] |j                  | j                        S )u  
    对图像的每个通道应用最小值阈值处理，用周围3x3邻域的中值替换低于最小值的像素
    
    Args:
        image: cv2图像，可以是单通道(H,W)或三通道(H,W,3)
        min_values: 每个通道的最小值，可以是单个数值或包含每个通道最小值的列表/数组
    
    Returns:
        处理后的图像，低于最小值的像素被3x3邻域中值替换
    c                    | j                   dd \  }}t        d|dz
        }t        ||dz         }t        d|dz
        }t        ||dz         }| ||||f   }	t        | j                         dk(  rt	        j
                  |	j                   t              }
||z
  }||z
  }d|cxk  r|
j                   d   k  r%n n"d|cxk  r|
j                   d   k  r
n nd|
||f<   |	|
   }t        |      dkD  rt	        j                  |      S | ||f   S t	        j
                  |	j                   dd t              }
||z
  }||z
  }d|cxk  r|
j                   d   k  r%n n"d|cxk  r|
j                   d   k  r
n nd|
||f<   g }t        |	j                   d         D ]K  }|	dddd|f   |
   }|j                  t        |      dkD  rt	        j                  |      n| |||f          M t	        j                  |      S )u-   获取3x3邻域（除了中心点）的中值NrL   r   r   rv   F)r   r   rz  r   r%   onesboolr  r/  r   r&   )r(   rowcolr  rK   	start_rowend_row	start_colend_colneighborhoodr  
center_row
center_colvalid_pixelsmediansr  s                   r   get_3x3_neighbor_medianzBapply_channel_min_threshold_mdian.<locals>.get_3x3_neighbor_median  s   yy!}1 37O	aq/37O	aq/ 9W,i.??@syy>Q77<--T:DyJyJJ.A.1
3RTZZPQ]3R/4Z+,'-L.1,.?!.C299\*VSRUXV 77<--bq1>DyJyJJ.A.1
3RTZZPQ]3R/4Z+,G<--a01+Aq!G4T:#l:Ka:Oryy6UXY\^acdYdUef 2 88G$$r   rL   r   r   )rS  r  r%   r  r_   r.  r0  r&   r   r   r/  rw   )r   rK  r   r]  r  rK   rL  rR  rS  r  r  neighbor_medianss               r   !apply_channel_min_threshold_mdianr_    s    ZZ\  ,F *sEl+XXzl+
XXj)
$%N 5;;1{{1Q-8CQx#s(#g-'>uc3'OF38$    
U[[	Q	5;;q>Q#6++1a8CQx$QxG58_w5Nj1T^_`TaGc3/07:+B5#s+S(4DW4MsC01  (    ==%%r   c                    | j                         j                  t        j                        }t	        |t
        t        f      rt        j                  |g      }nt        j                  |      }|!t        j                  dt              }d|d<   nt        j                  |t              }d	d}t        | j                        dk(  r]| j                  \  }}	|d   }
t        |      D ]:  }t        |	      D ]*  }|||f   }|r||
kD  n||
k  }|s || |||||      |||f<   , < nt        | j                        dk(  r| j                  d   dk(  r| j                  \  }}	}t        |      D ]l  }t        |	      D ]\  }t        d      D ]L  }t        |      |kD  r||   n|d   }
||||f   }|r||
kD  n||
k  }|s2 || |||||      }|B||   ||||f<   N ^ n |j                  | j                        S )
u  
    使用自定义掩膜对图像进行阈值处理，用邻域统计值替换目标像素
    
    Args:
        image: cv2图像，可以是单通道(H,W)或三通道(H,W,3)
        threshold_values: 每个通道的阈值，可以是单个数值或包含每个通道阈值的列表/数组
        mask: 掩膜数组，指定要计算统计值的邻域区域，True的位置参与计算
        above_threshold: 布尔值，True表示处理高于阈值的像素，False表示处理低于阈值的像素
        use_median: 布尔值，True使用中值，False使用均值
        boundary_mode: 边界处理模式，'skip', 'pad_zero', 'pad_edge', 'pad_reflect', 'ignore_pixel'
    
    Returns:
        处理后的图像
    )r   r   rv   F)r   r   c           	         | j                   d d \  }}|j                   \  }}	|dz  |	dz  }}
g }t        |      D ]  }t        |	      D ]  }|||f   s||
z
  |z   }||z
  |z   }|dk(  r5d|cxk  r|k  s-n 0d|cxk  r|k  s<n ?|j                  | ||f          V|dk(  rEd|cxk  r|k  r(n n%d|cxk  r|k  rn n|j                  | ||f          |j                  d       |dk(  rIt        dt	        |dz
  |            }t        dt	        |dz
  |            }|j                  | ||f          |dk(  r|dk  r| }n||k\  r|dz
  ||z
  dz   z
  }|dk  r| }n||k\  r|dz
  ||z
  dz   z
  }d|cxk  r|k  r)n n&d|cxk  r|k  rn n|j                  | ||f          _|j                  | ||f          w|dk(  s~d|cxk  r|k  rn nd|cxk  r|k  s/n t        | j                         dk(  r| ||f   n	| ||d d f   c c S |j                  | ||f            t        |      dk(  r)t        | j                         dk(  r| ||f   S | ||d d f   S t        j                  |      }t        | j                         dk(  r,|rt        j                  |      S t        j                  |      S |rt        j                  |d	      S t        j                  |d	      S )
NrL   skipr   pad_zeropad_edger   pad_reflectignore_pixelr
  )
r   r/  r   r   rz  r   r%   r&   r  r  )r(   rR  rS  r  
use_medianboundary_moder  rK   mask_hmask_wrY  rZ  valid_pixels_listmask_rmask_cimg_rimg_c	clamped_r	clamped_cr[  s                       r   get_neighbor_statisticzAapply_channel_threshold_with_mask.<locals>.get_neighbor_statistich  s   yy!}1!'1fkJ
FmF-'*,v5E*,v5E$.>>a5n1n-44S5FG&*4>>a5n1n-44S5FG-44Q7&*4$'3qsE?$;	$'3qsE?$;	)00Y	5I1JK&-7 19%*FE"aZ$%EUQY]$;E 19%*FE"aZ$%EUQY]$;E >>a5n1n-44S5FG-44Sc]C&.8 !UQ1>>47		Na4G3sCx=SQTVY[\Q\M]])00UE\1BC[ ( $b  !Q&$'		Na$73sCx=MSc1=MM xx 12syy>Qyy..ww|,, yyA66ww|!44r   rL   r   r   )Trb  )rS  r  r%   r  r_   r.  r0  r&   rP  rQ  r   r   r/  rw   )r   threshold_valuesr  above_thresholdrg  rh  r   rr  r  rK   threshold_valrR  rS  	pixel_valshould_processr  r  neighbor_statss                     r   !apply_channel_threshold_with_maskry  I  s     ZZ\  ,F "S%L188%5$6788$45 |wwvT*T
xxD)I5X 5;;1{{1(+8CQx"38,	@O)m";V_boVo!'=eS#tU_an'oF38$    
U[[	Q	5;;q>Q#6++1a8CQx$QxGADEUAVY`A`$4W$=fvwxfyM &sC'8 9IDSi-&?ZcfsZsN%)?sCQUWacp)q)58Fw8OF3W#45  (    ==%%r   c                    | t        d      | j                  dd \  }}||k(  r| j                         S t        | j                        dk(  r5| j                  d   }t	        j
                  |||f|| j                        }nAt        |t        t        f      r|d   n|}t	        j
                  ||f|| j                        }||kD  rO|dk(  r| dd||z
  df   }	|	S |dk(  r| ddd|f   }	|	S |d	k(  r||z
  dz  }
| dd|
|
|z   f   }	|	S t        d
      ||z
  }|dk(  r2t        | j                        dk(  r| |dd|df<   |S | |dd|df<   |S |dk(  r2t        | j                        dk(  r| |ddd|f<   |S | |ddd|f<   |S |d	k(  r=|dz  }
t        | j                        dk(  r| |dd|
|
|z   f<   |S | |dd|
|
|z   f<   |S t        d
      )un  
    根据目标宽度调整图像，如果超出则截断，如果不足则填补
    
    Args:
        image: 输入图像 (numpy.ndarray)
        target_width: 目标宽度 (int)
        direction: 截断或填补方向 (str)
            - 'left': 从左侧截断或在左侧填补
            - 'right': 从右侧截断或在右侧填补
            - 'center': 居中截断或居中填补
        fill_color: 填补颜色，默认黑色 (tuple)
            - 灰度图: (0,) 或 0
            - 彩色图: (B, G, R) 如 (0, 0, 0) 表示黑色
            
    Returns:
        numpy.ndarray: 处理后的图像
    N   输入图像不能为空rL   r   rv   r   r  r  r  u6   direction 参数必须是 'left', 'right' 或 'center'
r^   r   rS  r   r%   fullrw   r_   rc   rb   )r   rX  r   
fill_colorcurrent_heightcurrent_widthr   target_image
fill_valuecroppedr  padding_widths               r   %resize_image_with_padding_or_croppingr    sv   $ }344$)KKO!NM $zz| 5;;1;;q>wwhG[`[f[fg '1eT]&KZ]Q[
ww=zQVQ\Q\]|#A}|;<<=G  '!A}},-G  ("$|39GAww'===>G  UVV %}45;;1$27Q./* ' 38Q./& # '!5;;1$27Q./  38Q./  ("#q(G5;;1$CHQ-(? ??@ 	 DIQ-(? ??@  UVVr   c                    | t        d      | j                  dd \  }}||k(  r| j                         S t        | j                        dk(  r5| j                  d   }t	        j
                  |||f|| j                        }nAt        |t        t        f      r|d   n|}t	        j
                  ||f|| j                        }||kD  rO|dk(  r| ||z
  dddf   }	|	S |dk(  r| d|ddf   }	|	S |d	k(  r||z
  dz  }
| |
|
|z   ddf   }	|	S t        d
      ||z
  }|dk(  r| ||dddf<   |S |dk(  r| |d|ddf<   |S |d	k(  r|dz  }
| ||
|
|z   ddf<   |S t        d
      )u  
    根据目标高度调整图像，如果超出则截断，如果不足则填补
    
    Args:
        image: 输入图像 (numpy.ndarray)
        target_height: 目标高度 (int)
        direction: 截断或填补方向 (str)
            - 'top': 从顶部截断或在顶部填补
            - 'bottom': 从底部截断或在底部填补
            - 'center': 居中截断或居中填补
        fill_color: 填补颜色，默认黑色 (tuple)
            
    Returns:
        numpy.ndarray: 处理后的图像
    Nr{  rL   r   rv   r   r  r  r  u6   direction 参数必须是 'top', 'bottom' 或 'center'r|  )r   target_heightr   r~  r  r  r   r  r  r  r  padding_heights               r   ,resize_image_height_with_padding_or_croppingr  &  s     }344$)KKO!NM &zz| 5;;1;;q>ww}hG[`[f[fg '1eT]&KZ]Q[
ww}=zQVQ\Q\]%N]:;Q>?G  ("N]NA-.G  ("%5!;GGGm$;;Q>?G  UVV '7/4L!+,  ("/4L.!+,  ("$)G@EL>!991<=  UVVr   r   r   c                    ddl }ddl}| t        d      | j                         }|j                  dd \  }}|j                         }|dvrt        d      |dk  rt        d      |dk(  rt        ||      }d|d|ddf<   |S |d	k(  rt        ||      }d|||z
  |ddf<   |S |d
k(  rt        ||      }d|ddd|f<   |S |dk(  rt        ||      }d|dd||z
  |f<   |S )u&  
    将图片指定方向的边缘像素设置为纯黑色
    
    Args:
        image: 输入图像 (numpy.ndarray)
        direction: 方向 ('up', 'down', 'left', 'right')
        width: 要设置为黑色的像素宽度
        
    Returns:
        numpy.ndarray: 处理后的图像
    r   Nr{  rL   r  r  r  r  :   方向参数必须是 'up', 'down', 'left', 'right' 之一   宽度必须大于0r  r  r  r  )r   r{  r^   rS  r   r   rz  )r   r   r   r   r%   result_imager   r|  s           r   set_edge_pixels_blackr  o  sA    }344 ::<L %**2A.FI !I77UVVz.// DE6"#$QuWaZ "  
f	E6"/0VE\&(!+,  
f	E9%#$Q%Z   
g	E9%56Q	%	112r   edge_configsc                     | j                         }|D ]7  }|j                  d      }|j                  d      }|s(|s+t        |||      }9 |S )u  
    同时设置多个方向的边缘为黑色
    
    Args:
        image: 输入图像
        edge_configs: 边缘配置列表，每个元素为 {'direction': str, 'width': int}
        
    Returns:
        numpy.ndarray: 处理后的图像
        
    Example:
        edge_configs = [
            {'direction': 'up', 'width': 10},
            {'direction': 'left', 'width': 20}
        ]
    r   r   )rS  getr  )r   r  r  configr   r   s         r   set_multiple_edges_blackr    sP    " ::<LJJ{+	

7#0y%PL  r   c                 :   ddl }ddl}| t        d      | j                         }|j                  dd \  }}|j                         }|dvrt        d      |dk  rt        d      t        |j                        dk(  rt        |t        t        f      r|d   n|}	n|}	|dk(  rt        ||      }|	|d|ddf<   |S |d	k(  rt        ||      }|	|||z
  |ddf<   |S |d
k(  rt        ||      }|	|ddd|f<   |S |dk(  rt        ||      }|	|dd||z
  |f<   |S )uW  
    将图片指定方向的边缘像素设置为指定颜色（扩展版本）
    
    Args:
        image: 输入图像
        direction: 方向 ('up', 'down', 'left', 'right')
        width: 要设置的像素宽度
        color: 颜色值，默认为黑色 (0, 0, 0)
        
    Returns:
        numpy.ndarray: 处理后的图像
    r   Nr{  rL   r  r  r  r  r  r  r  )r   r{  r^   rS  r   r   r   r_   rb   rc   rz  )
r   r   r   r,   r   r%   r  r   r|  r  s
             r   set_edge_pixels_with_colorr    sm    }344::<L$**2A.FI!I77UVVz.// <!#!+ED%=!AU1Xu

 DE6"#-QuWaZ   
f	E6"/9VE\&(!+,  
f	E9%#-Q%Z  	 
g	E9%5?Q	%	112r   c           	      n   dddddddt         j                  d}d}	 t         j                  j                         }|d	kD  rd}t	        d
| d       nt	        d       |i }i ||}t        | j                        dk(  r|re	 t        j                         }|j                  |        t         j                  j                  |t         j                        }|j                         }	n't        j                  | t         j                        }	n| }	|r	 t        j                         }|j                  |	       |d   }
|d   dk(  rt         j                  j                  t         j                  t         j                   dd	|
      }|j#                  |      }|j                         j%                  t&        j(                        }n|d   dk(  rt         j                  j                  t         j                  t         j                   d	d|
      }|j#                  |      }|j                         j%                  t&        j(                        }nm|d   dk(  rYt         j                  j                  t         j                  t         j                   dd	|
      }t         j                  j                  t         j                  t         j                   d	d|
      }|j#                  |      }|j#                  |      }	 t         j                  j+                  ||      }t         j                  j+                  ||      }t         j                  j-                  ||      }t         j                  j/                  |      }|j                         j%                  t&        j(                        }t	        d       nt1        d      |s|d   dk(  r,t        j2                  |	t         j4                  dd	|d         }n|d   dk(  r,t        j2                  |	t         j4                  d	d|d         }n|d   dk(  rut        j2                  |	t         j4                  dd	|d         }t        j2                  |	t         j4                  d	d|d         }t'        j.                  |dz  |dz  z         }nt1        d      |d   j7                         }|dk(  rt'        j8                  d	kD  |d	      }nG|dk(  rt'        j8                  d	k  | d	      }n&|dk(  rt'        j:                        }nt1        d      |d   r)|j=                         d	kD  r||j=                         z  dz  }t'        j>                  t'        j@                  |d	d            }|d    r|rf	 t        j                         }|j                  |       t         j                  jC                  ||d!   |d"   |d#         \  }}|j                         }|S t        jB                  ||d!   |d"   |d#         \  }}|S # t
        $ r"}t	        dt        |              Y d}~d}~ww xY w# t
        $ rH}t	        dt        |              t        j                  | t         j                        }	d}Y d}~zd}~ww xY w# t
        $ r}t	        dt        |              |j                         j%                  t&        j(                        }|j                         j%                  t&        j(                        }t'        j.                  |dz  |dz  z         }Y d}~wd}~ww xY w# t
        $ r$}t	        dt        |              d}Y d}~d}~ww xY w# t
        $ rF}t	        d$t        |              t        jB                  ||d!   |d"   |d#         \  }}Y d}~|S d}~ww xY w)%u}  
    通用边缘检测函数，使用Sobel算子检测特定方向和类型的边缘
    
    Args:
        image: 输入图像
        params: 参数字典，包含以下键值:
            - direction: str, 检测方向 ('horizontal', 'vertical', 'both')
                * 'horizontal': 检测水平方向的灰度变化（垂直边缘）
                * 'vertical': 检测垂直方向的灰度变化（水平边缘）
                * 'both': 两个方向都检测
            - edge_type: str, 边缘类型 ('all', 'positive', 'negative')
                * 'all': 检测所有边缘（默认）
                * 'positive': 只检测正梯度（从暗到亮）
                * 'negative': 只检测负梯度（从亮到暗）
            - ksize: int, Sobel核大小 (1, 3, 5, 7)
            - normalize: bool, 是否归一化到0-255
            - threshold: int, 二值化阈值 (0-255)
            - apply_threshold: bool, 是否应用二值化
            - max_value: int, 二值化最大值 (0-255)
            - threshold_type: int, 阈值类型 (cv2.THRESH_BINARY等)
    
    Returns:
        edges: 检测到的边缘图像
    r   r  r   Tr   Fr   )r   	edge_typer   r   r   r   r   r   r   u!   ✅ 使用CUDA加速 (设备数: )u%   ⚠️  CUDA不可用，设备数为0u   ⚠️  CUDA初始化失败: Nu/   ⚠️  CUDA颜色转换失败，回退到CPU: r   r   r   r   r   u"   ✅ GPU手动magnitude计算成功u%   ⚠️  GPU计算失败，回退CPU: rL   u=   direction 参数必须是 'horizontal', 'vertical' 或 'both'u/   ⚠️  CUDA Sobel计算失败，回退到CPU: r   r  positivenegativeu:   edge_type 参数必须是 'all', 'positive' 或 'negative'r   r   r   r   r   u/   ⚠️  CUDA阈值处理失败，回退到CPU: )"r   r   cudagetCudaEnabledDeviceCountrF   r8   rk   r   r   cuda_GpuMatuploadr    r   downloadcreateSobelFilterCV_8UC1CV_32Fapplyr  r%   float64multiplyrU  r   r^   r   r   r   r   r   r   r~   r   r   )r   r   r   use_cuda
cuda_countr;   r   	gpu_imagegpu_grayr   r   sobel_filter	gpu_sobelr   sobel_filter_xsobel_filter_y
gpu_sobelx
gpu_sobelygpu_sobelx_squaredgpu_sobely_squaredgpu_sum_squaresgpu_magnitudee2r   r   r  r   	gpu_edgesr   
gpu_results                                 r   detect_edges_universalr  r  s   6  ++	N H8XX779
>H5j\CD9;
 ~/n//L 5;;1	!OO-	  '88,,Y8J8JK((* <<s'9'9:D :	(HOOD! !)E K(L8"xx99#++szzSTVWY^_(..x8	!**,33BJJ?k*j8"xx99#++szzSTVWY^_(..x8	!**,33BJJ?k*f4!$!;!;CKKUVXY[`!a!$!;!;CKKUVXY[`!a+11(;
+11(;
;),):)::z)R&),):)::z)R&&)hhll3EGY&ZO$'HHMM/$BM)224;;BJJGE>? !!`aa $4IIdCJJ1L<QRE+&*4IIdCJJ1L<QRE+&&0YYtSZZA\'=RSFYYtSZZA\'=RSFGGFAI	12E\]] [)//1IJE1-	j	 UFA.	e	E"UVV K 99;?EIIK'#-E HHRWWUAs+,E %&OO-	  ' # 2 2 - - !12	!: #++-" L }}[)[)-.	HAu L}  8-c!fX6778"  !GAxPQ||E3+=+=> !v ! ;A#b'KL'00299"**EF'00299"**EFGGFAI	$9:E;  	CCF8LMH	r  GAxPQ== - - !12	5 L!s   A X A#X; G!\5 3B7Z *\5 A#]% 	X8X33X8;	Z=ZZ	\2B\-'\5 -\22\5 5	]">]]"%	^4.;^//^4c                    | y| j                   }|t        j                  k(  r| j                         S t	        | j
                        dk(  rt        j                  | d      }t        j                  | d      }||kD  rat        j                  | j                  t        j                        ||      }||z
  ||z
  z  dz  j                  t        j                        }|S t        j                  | t        j                        }|S t	        | j
                        dk(  rg }| j
                  \  }}}	t        |	      D ]  }
| dddd|
f   }t        j                  |d      }t        j                  |d      }||kD  r`t        j                  |j                  t        j                        ||      }||z
  ||z
  z  dz  j                  t        j                        }n%t        j                  |t        j                        }|j                  |        t        j                  |d	      }|S t        j                  | d      }t        j                  | d      }||kD  rat        j                  | j                  t        j                        ||      }||z
  ||z
  z  dz  j                  t        j                        }|S t        j                  | t        j                        }|S )
u   
    将图像标准化为适合显示的格式
    
    Args:
        image: 输入图像，任意数据类型
        
    Returns:
        numpy.ndarray: uint8格式的图像，像素值范围0-255
    NrL   r   c   g     o@rv   r   a   r
  )rw   r%   r~   rS  r   r   
percentiler   r  r  r   r/  r   r   )r   rw   p1p99clipped_image
normalizedr   r   r   num_channelsr  r  clipped_channelnormalized_channels                 r   normalize_image_for_displayr  ?  so    } KKE zz| 5;;1]]5!$mmE2& 8GGELL$<b#FM(2-#(;eCKKBHHUJh c uBHH=Jb [ 
U[[	Q	&+kk#| |$AAq!GnG w*B--,C Rx"$'''..*Db#"N'6';b&IE&Q%Y%YZ\ZbZb%c" &(]]7"((%K" OO./% %* XXhQ/
"  ]]5!$mmE2&8GGELL$<b#FM(2-#(;eCKKBHHUJ
  uBHH=J r   c                 *   d}d}	d}
|dk(  r)|j                   d   }
||z   |j                   d   kD  r-d}d}n(|j                   d   }
||z   |j                   d   kD  rd}d}t        |j                         dk(  r|j                   \  }}}g }t        |      D ]  }|dddd|f   }t        j                  |j                               }t        |      }||z   |k\  rt        j                  |      }n%|dkD  r|||  n||d }t        j                  |      }||z   }|j                  |        |}	nxt        j                  |j                               }t        |      }||z   |k\  rt        j                  |      }n%|dkD  r|||  n||d }t        j                  |      }||z   }|}	d }|dk(  rNt        |j                         dk(  r|j                   \  }}}t        j                  d||f      }t        d      D ]  }|dddd|f   }g }t        |      D ]&  }|dd|f   } ||||      }|j                  |       ( t        j                  |      j                  dd      }|} |	|	|   } || z
  }||dddd|f<    |}n|j                   \  }}g }t        |      D ]&  }|dd|f   } ||||      }|j                  |       ( t        j                  |      j                  dd      }|} |	|	} || z
  }|}n|dk(  rNt        |j                         dk(  r|j                   \  }}}t        j                  |d|f      }!t        d      D ]  }|dddd|f   }g }t        |      D ]&  }"||"ddf   }# ||#||      }|j                  |       ( t        j                  |      j                  dd      }|} |	|	|   } || z
  }||!dddd|f<    |!}n|j                   \  }}g }t        |      D ]&  }"||"ddf   }# ||#||      }|j                  |       ( t        j                  |      j                  dd      }!|} |	|	} |!| z
  }!|!}nKt        |j                         dk(  r|j                   \  }}}t        j                  d||f      }t        d      D ]  }|dddd|f   }g }t        |      D ]&  }|dd|f   } ||||      }|j                  |       ( t        j                  |      j                  dd      }|} |	|	|   } || z
  }||dddd|f<    |}nw|j                   \  }}g }t        |      D ]&  }|dd|f   } ||||      }|j                  |       ( t        j                  |      j                  dd      }|} |	|	} || z
  }|}t        | j                         dk(  rt        j                  |       }$t        d      D ]  }| dddd|f   j                  t        j                        }%|dddd|f   j                  t        j                        }&|%||&z  z
  }'t        j                  |'dd	      }'|'j                  t        j                        |$dddd|f<    |j                  t        j                        }|$|	fS | j                  t        j                        }%|%||z  z
  }'t        j                  |'dd	      }'|'j                  t        j                        }$|j                  t        j                        }|$|	fS )
uU   
    中心拉伸 - 在垂直均值和水平均值计算时也应用掐头去尾
    r   Nr   r   r   c                     t        |       dk(  ryt        j                  | j                               }t        |      }||z   |k\  rt        j                  |      S |dkD  r|||  n||d }t        j                  |      S )   计算掐头去尾的均值r   N)r   r%   rT  r  r  rI   r  r  sorted_data	total_lentrimmed_datas         r   calculate_trimmed_meanz?enhance_center_stretch_image_ex.<locals>.calculate_trimmed_mean  sw    t9>ggdlln-$	U?i'77;'':?!);wv6U\U]I^L77<((r   rx   r   r   )r   r   r/  r%   rT  r  r  r   r  r&   reshaper   r  r  r   r~   )(r   r  r  r  r  r  r  r  r  r  r  r   r   r   r  r   channel_datasorted_pixelstotal_pixelsr  trimmed_pixelsr  r  r  r  r  r  trimmed_meansrS  column_datatrimmed_meanr  r   r!  rR  row_datar   r  r"  r  s(                                           r   enhance_center_stretch_image_exr    sq    HKE
l""1%eO|11!44GE""1%eO|11!44GE
<!#"."4"4xxA'1a0L GGL$8$8$:;M}-L,.!ww}5 CH!)wv!>Q^_f_gQh!ww~6')3L  .% !( $  4 4 67=)U?l*77=1L ?Dai]7E6:][b[cMdN77>2L#i/") l|!!"a';G;M;M8M< hh<'IJO1X!-a!e!4 " .C"0C"8K#9+wPU#VL!((6 /
 -088B? ,*$/NM-/)/!A&  'H +7*<*<'M<M\**1c625k7ER$$\2 +
 !hh}5==aDO(M& +-=O&H	
	|!!"a';G;M;M8M<HHmQ%HIM1X!-a!e!4 " /C-c1f5H#9(GU#SL!((6 0
 -088Q? ,*$/NM-/'-a!e$  %H +7*<*<'M<M]+'Q/5hO$$\2 ,
 HH]3;;BBM(M& +)M9M$H |!!"a';G;M;M8M< hh<'IJO1X!-a!e!4 " .C"0C"8K#9+wPU#VL!((6 /
 -088B? ,*$/NM-/)/!A&  'H*6*<*<'M<M\**1c625k7ER$$\2 +
 !hh}5==aDO(M& +-=O&H
5;;1u%qAAaEl))"**5G 1Q..rzz:I!UY%67K''+q#6K'..rxx8F1Qq5M  ??288,{"" ,,rzz*!12ggk1c2##BHH-??288,{""r   c                    | |y| j                   }| j                  }	| j                  t        j                        }
|j                  t        j                        }d}d}d}|dk(  r)|j                  d   }||z   |j                  d   kD  r-d}d}n(|j                  d   }||z   |j                  d   kD  rd}d}t        |j                        dk(  r|j                  \  }}}g }t        |      D ]  }|dddd|f   }t        j                  |j                               }t        |      }||z   |k\  rt        j                  |      }n%|dkD  r|||  n||d }t        j                  |      }||z   }|j                  |        |}nxt        j                  |j                               }t        |      }||z   |k\  rt        j                  |      }n%|dkD  r|||  n||d }t        j                  |      }||z   }|}d }|dk(  rt        |j                        dk(  r|j                  \  }}}t        j                  d||ft        j                        }t        d      D ]  }|dddd|f   }g }t        |      D ]&  } |dd| f   }! ||!||      }"|j                  |"       ( t        j                  |t        j                        j                  dd	      }#t        |      }$|t        ||         }$|#|$z
  }#|#|dddd|f<    |}n|j                  \  }}g }t        |      D ]&  } |dd| f   }! ||!||      }"|j                  |"       ( t        j                  |t        j                        j                  dd	      }t        |      }$|t        |      }$||$z
  }|}nG|d
k(  rt        |j                        dk(  r|j                  \  }}}t        j                  |d|ft        j                        }%t        d      D ]  }|dddd|f   }g }t        |      D ]&  }&||&ddf   }' ||'||      }"|j                  |"       ( t        j                  |t        j                        j                  d	d      }#t        |      }$|t        ||         }$|#|$z
  }#|#|%dddd|f<    |%}n:|j                  \  }}g }t        |      D ]&  }&||&ddf   }' ||'||      }"|j                  |"       ( t        j                  |t        j                        j                  d	d      }%t        |      }$|t        |      }$|%|$z
  }%|%}nt        |j                        dk(  r|j                  \  }}}t        j                  d||ft        j                        }t        d      D ]  }|dddd|f   }g }t        |      D ]&  } |dd| f   }! ||!||      }"|j                  |"       ( t        j                  |t        j                        j                  dd	      }#t        |      }$|t        ||         }$|#|$z
  }#|#|dddd|f<    |}n|j                  \  }}g }t        |      D ]&  } |dd| f   }! ||!||      }"|j                  |"       ( t        j                  |t        j                        j                  dd	      }t        |      }$|t        |      }$||$z
  }|}t        |
j                        dk(  rkt        j                  |
t        j                        }(t        d      D ]7  }|
dddd|f   })|dddd|f   }*|)t        |      |*z  z
  }+|+|(dddd|f<   9 n|
t        |      |z  z
  }(|t        j                   k(  r6t        j"                  |(dd      j                  t        j                         },n|t        j$                  k(  r6t        j"                  |(dd      j                  t        j$                        },nk|t        j&                  k(  r6t        j"                  |(dd      j                  t        j&                        },n"|t        j(                  t        j                  fv r6|t        j(                  k(  r |(j                  t        j(                        },n|(},n	 t        j*                  |t        j,                        rPt        j.                  |      }-t        j"                  |(|-j0                  |-j2                        j                  |      },nUt        j*                  |t        j4                        r|(j                  |      },n|(j                  t        j(                        },|,j                  |	k(  sJ d|,j                   d|	 d       |,|fS # t6        $ r" |(j                  t        j(                        },Y Uw xY w)u  
    中心拉伸 - 支持多种数据类型，在垂直均值和水平均值计算时也应用掐头去尾
    修正版本，确保输入输出接口不变
    
    Args:
        image: 输入图像，支持各种数据类型（uint8, uint16, int16, float32, float64等）
        center_image: 中心图像，用于计算基准值
        center_value: 中心值，默认50
        alpha: 拉伸强度，默认1.0
        dir: 方向，'horizontal'或'vertical'，默认'horizontal'
        start_w: 掐头去尾的起始像素数，默认5
        end_w: 掐头去尾的结束像素数，默认5
        gray_diff: 灰度差值调整，默认0
        
    Returns:
        tuple: (result_image, center_mean) - 处理后的图像和中心均值
    N)NNr   r   r   r   c                 $   t        |       dk(  ryt        j                  | j                               }t        |      }||z   |k\  rt	        t        j
                  |            S |dkD  r|||  n||d }t	        t        j
                  |            S )r  r   r%  N)r   r%   rT  r  r0  r  r  s         r   r  z@enhance_center_stretch_image_ex2.<locals>.calculate_trimmed_mean  s    t9>ggdlln-$	U?i'-..:?!);wv6U\U]I^L.//r   rv   rx   r   r   i  i i  u   输出形状 u    与输入形状 u
    不匹配)rw   r   r  r%   r  r   r/  rT  r  r  r   r  r&   r  r0  r   r~   r   uint16int16r  
issubdtypeintegeriinforz  r   floatingr8   ).r   r  r  r  r  r  r  r  original_dtypeoriginal_shapeimage_floatcenter_image_floatr  r  r  r   r   r   r  r   r  r  r  r  r  r  r  r  r  r  r  r  rS  r  r  r  r   r!  rR  r  result_floatr  r"  r  r   r  s.                                                 r    enhance_center_stretch_image_ex2r  l  sL	   ( }, [[N[[N ,,rzz*K%,,RZZ8HKE l"((+eO177::GE"((+eO177::GE ##$)"4":":xxA-aAg6L GGL$8$8$:;M}-L,.!ww}5 CH!)wv!>Q^_f_gQh!ww~6')3L  .# !& $  2 : : <==)U?l*77=1L ?Dai]7E6:][b[cMdN77>2L#i/"0 l!''(A-;M;S;S8M< hh<'IQSQ[Q[\O1X!3AaE!: " .C"0C"8K#9+wPU#VL!((6 /
 -rzzBJJ1bQ %l 3*$)+a.$9M-/)/!A&  'H +=*B*B'M<M\*0C85k7ER$$\2 +
 !hh}BJJGOOPQSUVO!,/M& %k 2-=O&H	
	!''(A-;M;S;S8M<HHmQ%HPRPZPZ[M1X!3AaE!: " /C-c1f5H#9(GU#SL!((6 0
 -rzzBJJ2qQ %l 3*$)+a.$9M-/'-a!e$  %H +=*B*B'M<M]+-c1f55hO$$\2 ,
 HH]"**EMMbRSTM!,/M& %k 2)M9M$H !''(A-;M;S;S8M< hh<'IQSQ[Q[\O1X!3AaE!: " .C"0C"8K#9+wPU#VL!((6 /
 -rzzBJJ1bQ %l 3*$)+a.$9M-/)/!A&  'H*<*B*B'M<M\*0C85k7ER$$\2 +
 !hh}BJJGOOPQSUVO!,/M& %k 2-=O&H ;"}}[

CqA!!Aa%(G 1QI!U5\I%=>K"-L1Q	  #eElX&=> !q#.55bhh?	299	$q%077		B	288	#vu5<<RXXF	BJJ

3	3RZZ'!((4F!F	5}}^RZZ8xx/txxBII.Y~r{{;%,,^< &,,RZZ8 <<>)t]6<<.HYZhYiis+tt);  	5!((4F	5s   :C	f. .(gg	info_dict
font_scaleline_spacingdebug_enabledc                    d }	 | 	 |dd      S |	 || d      S t        |t              s || dt        |             S t        |      dk(  r	 || d      S | j                  dd \  }}|t        d	t        d
|dz              }|t        d|z        }d1dt        dt        dt        dt        ffd |      }|s	 || d      S t        j                  }	t        dt        d|z              }
d}g }|D ]W  }	 t        |      dkD  r|dd dz   }t        j                  ||	||
      d   }t        ||d         }|j                  |d          Y t        |      |z  dz   }t        ||dz         }t!        j"                  ||dft         j$                        }|}t'        |      D ]Q  \  }}	 t        |      dkD  r|dd dz   }d}|}t        j(                  ||||f|	|d|
t        j*                         ||z  }S ||k7  re	 ||kD  r0||z
  }t        j,                  |ddd|t        j.                  d%&      }n/||z
  }t        j,                  | ddd|t        j.                  d%&      } t!        j0                  | |g      }|r}t        d(       t        d)| d*|        t        d+| d*|        t        d,|j                  d    d*|j                  d           t        d-t        |              t        d.|        |S # t        $ rk}|rt        d|dd  dt        |              t        |t        |      t        |dz        z        }|j                  t        |dz               Y d}~td}~ww xY w# t        $ r\}|rt        d | d!t        |              t        j(                  |d"| d#d|f|	|d$|
t        j*                         ||z  }Y d}~-d}~ww xY w# t        $ rF}|rt        d't        |              t        ||      }| ddd|f   } |ddd|f   }Y d}~d}~ww xY w# t        $ rF}d/t        |       }|r#t        d0|        ddl} |j4                           || |      cY d}~S d}~ww xY w)2uw  
    在图片下方拼接黑底白字的字典信息
    
    Args:
        image: 输入图像 (BGR格式)
        info_dict: 要显示的字典信息
        font_scale: 字体大小，None时自动计算
        line_spacing: 行间距，None时自动计算
        debug_enabled: 是否启用调试信息
        
    Returns:
        np.ndarray: 拼接后的图像
    c                    	 | | j                   dd \  }}n-d\  }}t        j                  ||dft        j                        } t        j
                  }t        dt        d|dz              }t        d	t        d|z              }t        d
|z        }g }|j                  d       t        d|dz        }	t        |      j                  d      }
d}|
D ];  }t        |dz   |z         |	k  r||rd|z   n|z  }$|r|j                  d|z          |}= |r|j                  d|z          t        |      |z  dz   }t        j                  ||dft        j                        }|}|D ]I  }|j                  d      rd}nd}t	        j                  ||d|f||||t        j                         ||z  }K t        j                   | |g      }|S # t"        $ r}t        j                  dt        j                        }t	        j                  |ddt        j
                  ddd       t	        j                  |ddt        j
                  ddd	       t	        j                  |t        |      dd dt        j
                  ddd	       |cY d}~S d}~ww xY w) u!   创建包含错误信息的图像NrL   )i  i  r   rv   333333?333333?i   r   #   u
   ❌ ERROR:r        z   r  u   ❌r   r   r   r   r   r   r	     i  r   CRITICAL ERRORr	  r   ffffff?zCannot display errorr	  r  r%  r   r	     皙?)r   r%   r  r~   r   FONT_HERSHEY_SIMPLEXr   rz  r.  r   rk   r   r   r   putTextLINE_AAvstackr8   )original_imageerror_messager{  r|  r   error_font_scalefont_thicknesserror_line_spacingerror_linesmax_chars_per_linewordscurrent_lineworderror_text_height
error_areay_offsetr  r,   combined_imager;   fallback_images                        r   create_error_imagez5append_dict_info_to_image.<locals>.create_error_image  s   K	")(6(<(<Ra(@%
I )1%
I!#:y!*DBHH!U ++D"3CS(AB C,<(<$=>N!$R*:%:!; K|, "%Rb!9&,,S1EL|c)D015GG LS4ZdJL##**5<+?@#'L  ""5<#78 !$K 03E E J #4i"C288TJ *H#??5)'E ,EN$"KK	 ..% $*  YY
'CDN!! 		"XXm288DNKK(8(//k1FKK(>	//oqJKKAsY//oqJ!!		"s   GG	 		J
B-J?J
J
NzInput image is NonezInput dictionary is Nonez Input is not a dictionary, got: r   zInput dictionary is emptyrL   r  r  i  r   r   dprefix	max_depthr=   c                 4   g }|dk  r| dgS 	 | j                         D ]  \  }}	 t        |t              r8|j                  | | d        ||dz   |dz
        }|j	                  |       nt        |t
        t        f      r\t        |      dk  r|j                  | | d|        nw|j                  | | d|d    d	|d    d
|d    dt        |       d       nBt        |t              r|j                  | | d|d       n|j                  | | d|         	 |S # t        $ r-}|j                  | | dt        |       d       Y d}~;d}~ww xY w# t        $ r+}|j                  | dt        |       d       Y d}~|S d}~ww xY w)u!   将字典转换为文本行列表r   ...:r  r   r  : z: [z, z, ..., rx   u   ] (共u   项).3f
: <Error: >Nz<Dict processing error: )ra   r_   r`   r   extendrb   rc   r   r0  r8   rk   )	r  r  r  r'  r,  r!  	sub_linesr;   dict_to_text_liness	           r   r  z5append_dict_info_to_image.<locals>.dict_to_text_lines  s   EA~!(#''K"#'')JCJ%eT2!LLF8C5):;(:5&4-QZ]^Q^(_I!LL3'e}="5zQ %xuBug-F G %xuCazERSH:U\]bce]f\ggmnqrwnxmyy}-~   *%7 %xuBuSk-J K %xuBug-F G% #,2 L % JxuJs1vha%HIIJ  Kx'?AxqIJJLKsA   E# C<D*$E# *	E 3"EE# E  E# #	F, FFz*Failed to convert dictionary to text linesr   r  r  r  z+Warning: Failed to get text size for line: r   z..., error: r	  r  (   rv   r  zWarning: Failed to draw line r  z<Line z error>)r   r   r   r  r  z*Warning: Failed to handle width mismatch: u   📝 字典信息拼接完成:u      原图尺寸: r  u      文本区域尺寸: u      最终图像尺寸: u      文本行数: u      字体大小: z/Unexpected error in append_dict_info_to_image:    ❌ )r  r   )r_   r`   ri   r   r   r   rz  r.  rk   rb   r   r  getTextSizer   r8   rF   r%   r  r~   r   r  r  r  r  r  r  	print_exc)r   r  r  r  r  r  r{  r|  
text_linesr   r  max_text_widthtext_heightsr  	text_sizer;   total_text_heighttext_area_width	text_arear  r   x_posy_posr  	min_widthr  	error_msgr  r  s                               @r   append_dict_info_to_imager,  |  s   M"^y4=%d,ABB%e-GHH)T*%e/OPTU^P_O`-abby>Q%e-HII %BQ
I S#c9t+;"<=JrJ/L 	$  	  	S  	QU  	F (	2
%e-YZZ ''QA
N 34 D:t9s?9u,DOOD$
NSTUV	!$^Yq\!B##IaL1 "  
Ol:R? i")<= HH/!DBHHU	   ,GAt%)t9s?9u,D   EN#"KK	 L(- -R '5.'/9G # 2 2!1aG++9!I .	9G..q!Q++9E E9#5624%i[*>?+O+<A>O=PQR+N,@,@,C+DAnFZFZ[\F]E^_`%c*o%678%j\23}  : GSb	{R^_bcd_e^fgh!$^SYZRT_AU5U!V##C
R$899:T  ) 9!Bs1vhGHQCw'N!"KK	 L()B  5 Fs1vhOP	?;	a)m,%a)m4	5*  4Ec!fXN	D$%I!!%334s   
P+ 
P+ $P+ P+ A.P+ 1P+ 9AK:AP+ +AM16P+ >A$O "BP+ :	M.A M)#P+ )M..P+ 1	O:AOP+ OP+ 	P(";P#P+ #P((P+ +	Q:4;Q5/Q:5Q:c                    d }	 | |	 || d      S t        |t              s || dt        |             S | j                  dd \  }}g }	 |j	                         D ]  \  }}	 t        |t              r!|j                  | dt        |       d       nt        |t        t        f      r!|j                  | dt        |       d	       n_t        |t              r|j                  | d
|d       n7t        |      }	t        |	      dkD  r|	dd dz   }	|j                  | d
|	         	 |sdg}t        dt        d|dz              }t        d|z        }t        |      |z  dz   }t        j                   ||dft        j"                        }t$        j&                  }t        dt        d|z              }|}|D ]J  }	 t        |      dkD  r|dd dz   }t%        j(                  ||d|f||d|t$        j*                         ||z  }L t        j.                  | |g      S # t        $ r.}
|j                  | dt        |
      dd  d       Y d}
~
d}
~
ww xY w# t        $ r}
 || dt        |
             cY d}
~
S d}
~
ww xY w# t        $ r#}
|rt-        dt        |
              Y d}
~
d}
~
ww xY w# t        $ r1}
d t        |
       }|rt-        d!|         || |      cY d}
~
S d}
~
ww xY w)"uz   
    简化版本：在图片下方拼接关键信息
    
    只显示字典的第一层信息，适合快速预览
    c           
      p   	 | | j                   dd \  }}n-d\  }}t        j                  ||dft        j                        } t        j                  d|dft        j                        }t	        j
                  |ddt        j                  d	d
d       t	        j
                  |t        |      dd dt        j                  ddd       t        j                  | |g      S #  t        j                  dt        j                        }t	        j
                  |ddt        j                  dd
d       |cY S xY w)u!   创建简单的错误信息图像NrL   ),  i  r   rv   P   zERROR:)r	     r  r  <   )r	  7   r  r  r   )r  r/  r   r  r  r%  )	r   r%   r  r~   r   r  r  rk   r  )r   r  r{  r|  r  fallbacks         r   create_simple_error_imagez:append_simple_dict_info.<locals>.create_simple_error_image  s   	)(6(<(<Ra(@%
I(0%
I!#:y!*DBHH!U2y!"4BHHEJKK
Hh8P8PRUWbdefKK
C$6s$;XsG_G_adfuwxy99nj9::	xxRXX>HKK"2Hc>V>VX[]hjklOs   CC! !AD5NzInput is NonezNot a dict: rL   z: {Dict,zitems}z: [List,zitems]r  r  r  %   r  r  r  r  zDict processing error: z<Empty or invalid dictionary>r%  r&  i  r1  r   rv   r   r0  M   r	  r  z%Warning: Failed to draw simple line: zSimple dict error: r  )r_   r`   ri   r   ra   r   r   rb   rc   r0  rk   r8   r   rz  r.  r%   r  r~   r   r  r  r  rF   r  )r   r  r  r5  r{  r|  simple_linesr,  r!  	value_strr;   r  r  total_heightr'  r   r  r  r  r+  s                       r   append_simple_dict_infor;    s   (K;=I-,UODD)T*,Ul4	?BS4TUU %BQ
I 	X'oo/
UJ!%.$++se9SZL,PQ#ED%=9$++se8CJ<v,NO#E51$++se2eC[,AB %(J	y>B.(1#2(>I$++se2i[,AB 0& ;<L c#y4'789
2
?+<(<7"< HHlIq9J	 ''QA
N 34 DLt9r>9u,DN#"KK	 L(! !, yy%+,,W ! J ''3%z#a&"+a(HIIJ 	X,U6McRSfX4VWW	XH  L A#a&JKL  ;)#a&2	D$%(	::	;s   J6 $J6 J6 I #CH"*I ,BJ6 AJ	J6 "	I+#II II 	J%I?9J:J6 ?JJ6 	J3J.)J6 .J33J6 6	K0?&K+%K0+K0c                    	 | rt        |       dk(  rt        d      | D cg c]  }||	 }}|st        d      t        |      dk(  r|d   j                         S g }d}	d}
t        |      D ]o  \  }}|j                  dd \  }}t        |j                        dk(  r|j                  d   nd}|j                  |||||d       t        |	|      }	t        |
|      }
q |r[t        d	       t        d
|
        t        d|	        t        dt        |              t        d|        t        d| d       g }|D ]  }|d   }t        |j                        dk(  r%t        j                  |t        j                        }n6|j                  d   dk(  r$t        j                  |t        j                        }|j                  |        |j                         dk(  rg }d}t        |      D ]  \  }}|j                  dd \  }}||	k(  r|}n|	|z
  }|dk(  r+t        j                  |d|ddt        j                  |      }nd|dk(  r+t        j                  ||dddt        j                  |      }n4|dz  }||z
  }t        j                  |||ddt        j                  |      }|j                  |       ||j                  d   z  }|st        d| d| d| d|j                  d    d|j                  d    
        ||t        |      dz
  z  z   }|	}t        j                   ||df|t        j"                        }d}t        |      D ]*  \  }}|j                  d   }||dd|||z   f<   |||z   z  }, n|j                         dk(  rg }d}t        |      D ]  \  }}|j                  dd \  }}||
k(  r|}n|
|z
  }|dk(  r+t        j                  |ddd|t        j                  |      }nd|dk(  r+t        j                  |dd|dt        j                  |      }n4|dz  }||z
  } t        j                  |dd|| t        j                  |      }|j                  |       ||j                  d   z  }|st        d| d| d| d|j                  d    d|j                  d    
        |
}||t        |      dz
  z  z   }t        j                   ||df|t        j"                        }d}!t        |      D ]*  \  }}|j                  d   }"|||!|!|"z   ddf<   |!|"|z   z  }!, nt        d      |rMt        d       t        d |j                  d    d|j                  d           t        d!t        |              |S c c}w # t$        $ r}#t        d"t'        |#              t        j(                  d#t        j"                        }$t        j*                  |$d$d%t        j,                  d&d'd       t        j*                  |$t'        |#      dd( d)t        j,                  d*d+d       t        j*                  |$d,| rt        |       nd d-t        j,                  d*d+d       |$cY d}#~#S d}#~#ww xY w).uY  
    将多张图片拼接到一起，以最大图为基础，小图添加黑边补齐
    
    Args:
        image_list: 图像列表 [image1, image2, image3, ...]
        direction: 拼接方向 ('horizontal' 或 'vertical')
        gap_size: 图像间的黑条宽度（像素）
        align: 对齐方式
            - horizontal拼接时: 'top', 'center', 'bottom'
            - vertical拼接时: 'left', 'center', 'right'
        fill_color: 填充颜色，默认黑色 (B, G, R)
        debug_enabled: 是否启用调试信息
        
    Returns:
        np.ndarray: 拼接后的图像
    r      图像列表不能为空N   没有有效的图像r   rL   r   )indexr   r   r   r   u   📏 图像尺寸分析:u      最大宽度: u      最大高度:       图像数量: u      拼接方向: u      间隙大小: pxr   r  r   r  r  r  u	      图像r  r  z -> rv   r   r  r  u5   direction 参数必须是 'horizontal' 或 'vertical'u   🎯 拼接完成:u      最终尺寸: u      拼接图像数: u   ❌ 图像拼接失败: r  zIMAGE CONCAT ERRORr  r  r  r  r  r%  r  zImages: r  )r   r^   rS  r   r   r   r   rF   r   r    COLOR_GRAY2BGRCOLOR_RGBA2BGRr   r  r  r%   r}  r~   r8   rk   r  r  r  )%
image_listr   gap_sizealignr~  r  r(   valid_images
image_info
max_height	max_widthr   r   r   r   processed_imagesr  aligned_imagestotal_widthr  r  aligned_imgpadding_neededpad_top
pad_bottomfinal_widthfinal_heightr  x_offsetr|  r:  pad_left	pad_rightr  r{  r;   error_images%                                        r   concatenate_images_with_paddingrX    s   &yS_1788 (2EzS_zE455 |!?'')) 

	-FAsIIbqMMFE'*399~':syy|H $  Z0JIu-I . ,.%i[12%j\23%c,&7%89:%i[12%hZr23 Dw-C399~"ll3(:(:;1"ll3(:(:;##C(  ??,NK#$45303		"1-!Z/"%K &0.%@N~&)&8&8NAq//z' (*&)&8&8Aq//z' #1A"5%3g%=
&)&8&8*a//z'
 %%k2{0033 IaS=/>:J${O`O`abOcNddefqfwfwxyfze{|}G 6L &C4G!4K(LLK%L 77L+q#A:UWU]U]^L H#N33IIaL	ADQI)= ==>I00 4
 __*,NL#$45303		"1- I-"%K &/%>N&)&8&8Aq.//z' ')&)&8&8A~q//z' $2Q#6$2X$=	&)&8&8Ax//z'
 %%k2 1 1! 44 IaS=/>:J${O`O`abOcNddefqfwfwxyfze{|}G 6L $K'(c.6IA6M*NNL 77L+q#A:UWU]U]^L H#N33 YYq\
BEXh&;;Q>?J11 4 TUU&(%l&8&8&;%<Al>P>PQR>S=TUV(^)<(=>?O FR  
(Q12hh}BHH=K!5x++S+q	BKQi++S/1	FK8zC
Oq+Q!RT]++S/1	F
sH   V VV/V I4V F4V DV V 	Z"CY<6Z<Zc           
      D   	 | rt        |       dk(  rt        d      | D cg c]  }||	 }}|st        d      t        |      }|dk(  r|d   j                         S t        d |D              |z  }	t        d |D              |z  }
t	        d |D              }t	        d	 |D              }|r=t        d
       t        d|        t        d|	dd|
d       t        d| d|        |dk  rG|dz  |z   }||k  r|rt        d       t        |d|d||      S |rt        d       t        |d|d||      S |dk  rL||z  ||dz
  z  z   }||k  r|rt        d       t        |d|d||      S |rt        d       t        |d|||      S |rt        d       t        dt        t        j                  t        j                  |                        }t        |||||      S c c}w # t        $ r1}t        dt        |              t        | d|d||      cY d}~S d}~ww xY w)uv  
    智能布局版本：自动选择横向或垂直拼接，或创建网格布局
    
    Args:
        image_list: 图像列表
        max_width: 最大输出宽度
        max_height: 最大输出高度
        gap_size: 间隙大小
        fill_color: 填充颜色
        debug_enabled: 调试模式
        
    Returns:
        np.ndarray: 拼接后的图像
    r   r=  Nr>  r   c              3   :   K   | ]  }|j                   d      ywr   Nr   .0r(   s     r   	<genexpr>z2concatenate_images_smart_layout.<locals>.<genexpr>  s     =		!   c              3   :   K   | ]  }|j                   d      ywr   Nr\  r]  s     r   r_  z2concatenate_images_smart_layout.<locals>.<genexpr>  s     >#1r`  c              3   :   K   | ]  }|j                   d      ywr[  r\  r]  s     r   r_  z2concatenate_images_smart_layout.<locals>.<genexpr>  s     ALSCIIaLLr`  c              3   :   K   | ]  }|j                   d      ywrb  r\  r]  s     r   r_  z2concatenate_images_smart_layout.<locals>.<genexpr>  s     B\cSYYq\\r`  u   📊 智能布局分析:r@  u      平均尺寸: z.0fr  u      最大尺寸: rL   u      选择: 横向拼接r   r  u/      选择: 垂直拼接（横向超出限制）r   r  u      选择: 网格布局r   u   ❌ 智能布局失败: )r   r^   rS  sumr   rF   rX  create_grid_layoutrz  r.  r%   ceilr   r8   rk   )rD  rJ  rI  rE  r~  r  r(   rG  
num_images	avg_width
avg_heightmax_img_widthmax_img_heighthorizontal_widthcolsr;   s                   r   concatenate_images_smart_layoutro    s    FxS_1788'1EzS_zE455&
??'')) ===
J	>>>K
ALAAB\BB,.%j\23%i_Aj5EFG%m_An5EFG ?,q08;9, 346 ,(JP]  !KL6 *h*m  1_,z9H
UV<WW9, 346 ,(JP]  !34) !Xz=  /0q#bggbggj&9:;<D%dHj- y F@  x(Q12.z<S[]givwwxsR   G% G G 1G% B;G% G% 84G% -G% 	AG%  G% %	H.&HHHc                    	 | st        d      t        |       }||z   dz
  |z  }t        d | D              }t        d | D              }|r"t        d| d|        t        d| d|        g }	t	        |      D ],  }
g }t	        |      D ]  }|
|z  |z   }||k  r| |   }t        |j
                        dk(  r$t        j                  |t        j                        }|j
                  d	d \  }}||z
  }||z
  }t        j                  ||dz  ||dz  z
  |dz  ||dz  z
  t        j                  |
      }|j                  |       t        j                  ||df|t        j                        }|j                  |        |st        |d|d|d      }|	j                  |       / |	rt        |	d|d|d      }|S t        d      # t         $ r1}t        dt#        |              t        | d|d||      cY d	}~S d	}~ww xY w)u  
    创建网格布局
    
    Args:
        image_list: 图像列表
        cols: 列数
        gap_size: 间隙大小
        fill_color: 填充颜色
        debug_enabled: 调试模式
        
    Returns:
        np.ndarray: 网格布局的图像
    r=  r   c              3   :   K   | ]  }|j                   d      ywr[  r\  r]  s     r   r_  z%create_grid_layout.<locals>.<genexpr>;  s     ;
		!
r`  c              3   :   K   | ]  }|j                   d      ywrb  r\  r]  s     r   r_  z%create_grid_layout.<locals>.<genexpr><  s     <#1r`  u   🔳 创建网格布局: r  u      单元格尺寸: rL   Nr  r   rv   r   r  Fr   u   无法创建网格布局u   ❌ 网格布局创建失败: )r^   r   r   rF   r/  r   r   r    rB  r  r  r   r%   r}  r~   rX  r8   rk   )rD  rn  rE  r~  r  rh  rowsrJ  rI  	grid_rowsrR  
row_imagesrS  img_idxr(   r  rK   pad_hpad_w
padded_img	empty_img
row_concatr   r;   s                           r   rf  rf  %  s7   ?x788_
T!A%$. ;
;;	<<<
-dV1TF;<(1ZLAB 	;CJT{*s*Z'$W-C399~*!ll30B0BC 99Ra=DAq&NE%ME!$!3!3
EEQJ$6
EEQJ$6++:	"J %%j1 !#Y(BJVXV^V^ _I%%i0/ #4 <h*e
   ,A F 4:x:uF M788 x.s1vh78.z<S[]givwwxs*   FG	 7G	 >G	 		H&G>8H>Hr  c           	         	 | || S t        |d         }t        |d         }|t        |d         z   }|t        |d         z   }| j                         }	t        j                  |	||f||f||       |7t        j                  |	t        |      ||dz
  ft        j                  d|d       |	S # t        $ r#}
t        d	t        |
              | cY d}
~
S d}
~
ww xY w)
uc  
    在图像上绘制AOI框
    
    Args:
        image: 输入图像 (BGR格式)
        aoi: AOI字典 {'x': int, 'y': int, 'width': int, 'height': int}
        color: 绘制颜色 (B, G, R)，默认绿色
        thickness: 线条粗细
        label: 标签文字，None则不显示
        
    Returns:
        np.ndarray: 绘制后的图像
    Nr  r  r   r   r	  r  rL   u   ❌ 绘制AOI失败: )	r.  rS  r   	rectangler  rk   r  r8   rF   )r   r  r,   	thicknessr  r  r  r  r  r  r;   s              r   draw_aoi_on_imager  u  s    =CKL S]S]#c'l###c(m$$zz| 	lRHr2hyI KKc%j2rBw-//eQ@  %c!fX./s#   B. B%B. .	C7CCCc                 "   	 | j                         }|j                         }t        |j                        dk(  r$t        j                  |t        j
                        }t        |j                        dk(  r$t        j                  |t        j                        }|j                  dd |j                  dd k7  r2t        j                  ||j                  d   |j                  d   f      }|dkD  j                  t        j                        }t        j                  |      }||ddddf<   |rnt        j                  |t        j                        }	|j                         j                  t        j                        }
|dk(  }t        j                  |      r|	|   j                  t        j                        }t        j                  t        j                  |      df|t        j                        }|dddf   dz  |dddf   d	z  z   |dddf   d
z  z   }t        j                   |d      }||z  }|j#                  dd      }||z  }t        j$                  |dd      }|
|   j                  t        j                        }|d|z
  z  ||z  z   }||
|<   n|j                         j                  t        j                        }
|j                  t        j                        }t        j&                  |||gd      }|
d|z
  z  ||z  z   }t        j(                  |dk(  ||
      }
t        j$                  |
dd      j                  t        j                        }
|
S # t*        $ r#}t-        dt/        |              | cY d}~S d}~ww xY w)u  
    将二值化图像按照指定透明度和颜色叠加到原图上，可选择是否保持原图亮度
    
    Args:
        original_image (np.ndarray): 原始图像
        binary_image (np.ndarray): 二值化图像
        overlay_color (tuple): 叠加颜色，BGR格式，默认绿色(0, 255, 0)
        alpha (float): 叠加透明度，0-1之间，默认0.3
        preserve_brightness (bool): 是否保持原图亮度，默认True
        
    Returns:
        np.ndarray: 叠加后的图像
    rL   r   Nr   r      rv   gv/?gbX9?gA`"?gư>rx   r   r
  u   叠加处理出错: )rS  r   r   r   r    rB  r   resizer  r%   r~   r   r  anyr}  re  maximumr  r   r   r   r8   rF   rk   )r   binary_imageoverlay_colorr  preserve_brightnessoriginalbinaryr  overlayoriginal_grayr   mask_regionsoriginal_brightnesscolor_layercolor_brightnessbrightness_ratioadjusted_colororiginal_pixelsblended_pixelsoverlay_floatmask_3dblendedr;   s                          r   overlay_binary_maskr    s$   U!&&(""$ x~~!#||Hc.@.@AH v||!\\&#*<*<=F >>"1bq!11ZZ):HNN1<M(NOF $$RXX. --)%1  LL33E3EFM ]]_++BJJ7F  19Lvvl#&3L&A&H&H&T# !ggrvvl';Q&?VXV`V`a %01$5$="-ad"3e";%<"-ad"3e";%< 
 $&::.>#E  $79I#I #3#;#;B#B !,/?!?!#C!@ #)"6"="=bjj"I "1AI!>RWAW!W (6|$ ]]_++BJJ7F#NN2::6M hhdD1:G E	*]U-BBGXXglGV<F C(//9 $SVH-.s   MM" "	N+N	N	Nc                    	 | j                         }t        |j                        dk(  r$t        j                  |t        j
                        }t        |j                        dk(  r%t        j                  |t        j                        }n|j                         }|j                  dd |j                  dd k7  r2t        j                  ||j                  d   |j                  d   f      }|dkD  j                  t        j                        }t        j                  |      }||ddddf<   |j                         j                  t        j                        }|j                  t        j                        }	t        j                  |||gd      }
|d|z
  z  |	|z  z   }t        j                  |
dk(  ||      }|j                  t        j                        S # t        $ r#}t!        dt#        |              | cY d}~S d}~ww xY w)	up  
    简化版本：将二值化图像叠加到原图上（不保持亮度）
    
    Args:
        original_image (np.ndarray): 原始图像
        binary_image (np.ndarray): 二值化图像  
        overlay_color (tuple): 叠加颜色，BGR格式
        alpha (float): 叠加透明度，0-1之间
        
    Returns:
        np.ndarray: 叠加后的图像
    rL   r   Nr   r   r  r
  u   简单叠加处理出错: )rS  r   r   r   r    rB  r   r  r  r%   r~   r   r  r   r   r8   rF   rk   )r   r  r  r  r  r  r  r  r   r  r  r  r;   s                r   overlay_binary_mask_simpler    s   $!&&(x~~!#||Hc.@.@AH|!!"a'\\,0B0BCF!&&(F>>"1bq!11ZZ):HNN1<M(NOF $$RXX. --)%1 ''

3rzz2 ((D$-A6 AI&)>>'Q,8}}RXX&& *3q6(34s   GG 	H$H<HH)zC://Windows//Fonts//simsun.ttcr   r  )r@   r  )r	  r  i  r   )rL   r  r	  )rL   r  r	  N)r   r   r   r  r  )r   r   r   r  r  )r"  r	  F)r	  )-      )r	  r	  )r   N)Nr   NF)T)r  TF)r   r   r	  )r   r   )r  union)r   )r  r	  )r   r   r	  r  r  )r   )r  r  )r   r&  r   r  r  r   )r  )r  )NFTrb  )r  r  )r  r  )r  )NNF)F)r   r	  r  r  F)i  i8  r	  r  F)r	  r  F)r   r   r   rL   N)r  333333?T)r  r  )w__doc__rD   r   xml.sax.handlerr   r   r{  r%   typingr   r   r   r   r  re   rf   rS  PILr   r	   r
   r   r   r0   r<   rk   rH   rQ  rS   rt   r  r   r   r   r   r   r   r   r   r   r   r   r   r  r  r  r  r  rH  rl  rt  rx  r  r  r  r  r  r  r  r  r  r  r  r  r)  r  r  r0  r=  rB  rT  r  r  rq  ry  r  r  r  r  r  r  r  r  r  r  r  r  r#  r4  r9  rR  r?  rD  rG  rI  rM  r_  ry  r  r  r.  r  rb   r  r  r  r  r  r  r`   r0  r,  r;  rX  ro  rf  r  r  r  r  r   r   <module>r     s<  
  	 3 
  , ,     + +  *(c htCH~&> $c3h C D &2C 23 2# 2D 2h# (2::*> :bjj S T .
CC 
CD 
C"** c3h 2N3 N4S> Nb?s ?tDcN/C ?DC  s $2h:x8t8t(T			! .M^Sn &'$&EP#L qA&R	IX 3qAR	]@ "rqAR	]@ "qAR	M^ D  D%NYx 0f /h9xZYd<~@6Yv1>1@9"v(>V IK9x :=+Zpd>@Ph CE?F"H2h5n Ln 0d2h4@ NQQRX#x5p-`$#$DL;z;z@S&lG&RRhGR5C 5 5n$ 84 4S 4`LZSl QTQRT#n RUUVL`V4RZZ V4D V4e V4jm V4  FJ V4  WY  Wa  Wa V4re;2:: e;$ e;t e;`b`j`j e;P RT=F05L^ LPSXVxrMx`&RZZ &d &cecmcm &RcJ1r   