
    3j5              	          % S r SSKJr  SSKrSSKrSSKrSSKrSSKrSSKr	SSK
rSSKJrJrJr  SSKrSSKrSSKrSSSSSSSSS.rS\S	'    " S
 S5      rS\0rSS0rg)a  
ComfyUI custom node: Image Mask Comparer
=========================================

Compares the masked regions of two images and returns a boolean
indicating whether they match above a configurable similarity
threshold.  Useful for verifying that a specific region (e.g. a logo
or label) has been preserved after an AI generation or inpainting
step.

Retry behaviour
---------------
When ``max_retries`` > 0 and the comparison fails the node will:

1. **Randomise** the seed of every KSampler / noise node it finds
   in the prompt so that ComfyUI's cache is invalidated and a
   genuinely new image is generated.
2. **Queue** the modified prompt via direct access to the internal
   ``PromptServer.prompt_queue`` (with HTTP POST as fallback).
3. **Interrupt** the current execution so downstream nodes never
   see the bad result.

The loop repeats until the comparison passes or ``max_retries``
total attempts have been made, then gives up and outputs ``False``.
    )annotationsN)TupleDictAnyseed
noise_seed)KSamplerKSamplerAdvancedSamplerCustomSamplerCustomAdvancedRandomNoiseNoise_RandomNoiseKSamplerProviderBasicSchedulerzDict[str, str]_KNOWN_SEED_FIELDSc                     \ rS rSr% Sr0 rS\S'   \SS j5       rSr	S\S'   S	r
S\S
'   SrS\S'   SrS\S'   Sr\SS j5       r\SS j5       r\SS j5       r\S 5       r\S 5       r    S               SS jjrSrg)ImageMaskComparer;   zCCompare masked regions of two images; optionally retry on mismatch.zDict[str, int]_retry_countsc           
     :    SSSSSSSSS.4S	S
SSSS.4S.SSS.S.$ )N)IMAGE)MASKFLOAT?              ?{Gz?)defaultminmaxstepINT   r   2      )image_aimage_bmask	thresholdmax_retriesPROMPT	UNIQUE_ID)prompt	unique_id)requiredhidden )clss    D/home/wildlama/comfy/ComfyUI/custom_nodes/va1/image_mask_comparer.pyINPUT_TYPESImageMaskComparer.INPUT_TYPESB   sS     &%! $SdK
  !!BB  #(
 	
    )BOOLEANr   r   zTuple[str, ...]RETURN_TYPES)is_match
similarity	image_outRETURN_NAMEScomparestrFUNCTIONzimage/compareCATEGORYTc                   U R                   S:X  a  U S   OU nUR                  5       R                  5       R                  5       R	                  [
        R                  5      n[
        R                  " USS5      nUR                   S:X  a  [
        R                  " U/S-  SS9nUR                   S:X  a!  UR                  S   S:X  a  US S 2S S 2S S24   nU$ )	Nr#   r   r   r         axis)
ndimdetachcpunumpyastypenpfloat32clipstackshape)imgtarrs      r3   _image_to_numpy!ImageMaskComparer._image_to_numpy_   s    hh!mCFhhjnn$$&--bjj9ggc3$88q=((C5192.C88q=SYYq\Q.aBQBh-C
r6   c                .   U nUR                   S:X  a  USS S 2S S 2S4   nOUR                   S:X  a  US   nUR                  5       R                  5       R                  5       R	                  [
        R                  5      n[
        R                  " USS5      $ )Nr#   r   rC   r   r   )rG   rH   rI   rJ   rK   rL   rM   rN   )r(   rR   rS   s      r3   _mask_to_numpy ImageMaskComparer._mask_to_numpyj   st    66Q;!Q1*AVVq[!Ahhjnn$$&--bjj9wwsC%%r6   c                   [         R                  " U 5      nSnUR                  5        H  u  p4UR                  SS5      nUR                  S0 5      n[        R                  U5      nU(       aD  Xv;   a?  Xg   n[        U[        [        45      (       a   [        R                  " SS5      Xg'   US-  nM  S HG  n	X;   d  M
  [        Xi   [        [        45      (       d  M)  [        R                  " SS5      Xi'   US-  nMI     M     X4$ )zvReturn a deep copy of *prompt* with every sampler seed randomised.

Returns ``(modified_prompt, num_seeds_changed)``.
r   
class_type inputsr%   l          )r   r   )
copydeepcopyitemsgetr   
isinstanceintfloatrandomrandint)
r-   modifiedchangednode_id	node_datarZ   r\   
seed_fieldvalfields
             r3   _randomize_seeds"ImageMaskComparer._randomize_seedsu   s     ==("*.."2G"|R8J]]8R0F ,//
;Jj2(cC<00)/5)AF&qLG 0?z&-#u'N'N$*NN1e$<FMqLG 0 #3&   r6   c                      SSK Jn   U R                  nUR                  R                  R                  5        H  u  p#[        R                  " U5      s  $    g! [         a     gf = f)zDeep-copy the currently-running queue item.

Must be called *before* ``interrupt_processing`` while the item
is still present in ``currently_running``.
r   PromptServerN)	serverrq   instanceprompt_queuecurrently_runningr_   r]   r^   	Exception)rq   ps_piditems       r3   _capture_queue_item%ImageMaskComparer._capture_queue_item   sV    	+&&B oo??EEG
}}T** H 		s   AA A 
A%$A%c                \   ^ ^ UU 4S jn[         R                  " USS9R                  5         g)z;Put a seed-randomised copy of the prompt back in the queue.c                   > [         R                  " S5        Sn Tb   SSKJn  UR                  n[        T5      n[        [        R                  " 5       5      US'   [        R                  US   5      u  pEXCS'   UR                  R                  [        U5      5        [        SU S35        S	n U (       d  Tb   Su  px SSKJn  UR                  n[!        USS5      n[!        USS5      n	U	S;   a  Sn	U	n[        R                  T5      u  pSU SU S3n["        R$                  " SU
05      R'                  S5      n[(        R*                  R-                  UUSS0S9n[(        R*                  R/                  USS9  [        SU S35        S	n U (       d  [        S5        g g ! [         a  n[        S
U 35         S nAGNS nAff = f! [         a     Nf = f! [         a  n[        SU 35         S nANgS nAff = f)N      ?Fr   rp   r%   rB   u6   [ImageMaskComparer] Re-queued (direct) — randomised z	 seed(s).Tz,[ImageMaskComparer] Direct re-queue failed: )	127.0.0.1  portr   addressr   )z0.0.0.0r[   zhttp://:z/promptr-   zutf-8zContent-Typezapplication/json)dataheaders   )timeoutu4   [ImageMaskComparer] Re-queued (HTTP) — randomised z*[ImageMaskComparer] HTTP re-queue failed: zw[ImageMaskComparer] All re-queue strategies failed.  Enable 'Auto Queue' in ComfyUI (Extra Options) for manual retries.)timesleeprr   rq   rs   listr>   _uuiduuid4r   rm   rt   puttupleprintrv   getattrjsondumpsencodeurllibrequestRequesturlopen)successrq   rw   new_item
new_promptnexchostr   addrrf   urlr   reqfallback_prompt
queue_items                 r3   _worker+ImageMaskComparer._requeue.<locals>._worker   s   JJsOG %P3%..B#J/H"%ekkm"4HQK$5$F$FxPQ{$SMJ",QKOO''h8&&'S	3 #G
 :N!2JD
7)22&r648&r9kB?2#.D# #4"D"D_"UKH#D64&8C::x&:;BB7KD ..00!!/1C D 1 C
 NN**3*:&&'S	3 #G * I ! PHNOOP  % " ! NFseLMMNsU   BF  :G ?6G 5BG  
G*F>>G
GG GG 
G8 G33G8T)targetdaemonN)	threadingThreadstart)r   r   r   s   `` r3   _requeueImageMaskComparer._requeue   s$    =	~ 	5;;=r6   Nc                z   U(       a  [        U5      OSnU R                  U5      n	U R                  U5      n
U R                  U5      nU	R                  u  pnU
R                  S S X4:w  a%  [        R
                  " XU4[        R                  S9n
UR                  S S X4:w  a%  [        R
                  " XU4[        R                  S9nUS:  n[        [        R                  " U5      5      nUS:X  a!  U R                  R                  US 5        SSU4$ [        R                  " U/U-  SS	9nU	U   R                  [        R                  5      nU
U   R                  [        R                  5      n[        R                   " [        R"                  " UU-
  5      5      nSU-
  n[        R                   " U5      [        R                   " U5      nnUU-
  UU-
  nn[        R$                  " [        R&                  " US-  5      [        R&                  " US-  5      -  5      nUS
:  a  US:  a  SOSnO;[)        [        R*                  " [        R&                  " UU-  5      U-  SS5      5      n[-        [)        [        R*                  " SU-  SU-  -   SS5      5      S5      nUU:  nU(       aS  U R                  R/                  US5      nU R                  R                  US 5        [1        SUS SU SU S35        SUU4$ U R                  R/                  US5      S-   nUU R                  U'   US:  aS  UU:  aM  [1        SUS SU SU SU S3	5        U R3                  5       n U R5                  U U5        SSKJn!  U!" 5         SUU4$ U R                  R                  US 5        [1        SUS SU SU S35        SUU4$ )N_defaultrB   )interpolationr~   r   Tr   rD   rE   g:0yE>r   r   g333333?g?r#   z'[ImageMaskComparer] MATCH  (similarity z.4fz >= z	)  after z" retry(ies).  Continuing workflow.r%   z*[ImageMaskComparer] MISMATCH  (similarity z < z)  attempt /u'    — randomising seeds & re-queuing …)interrupt_processingFu    attempt(s) — giving up.)r>   rT   rW   rP   cv2resizeINTER_LINEARINTER_NEARESTrb   rL   count_nonzeror   poprO   rK   float64meanabssqrtsumrc   rN   roundr`   r   rz   r   nodesr   )"selfr&   r'   r(   r)   r*   r-   r.   rh   abmhwc	mask_bool
num_maskedmask_3dpixels_apixels_bmaesimilarity_maemean_amean_ba_cb_cdenomnccr:   r9   attempts_usedattemptr   r   s"                                     r3   r=   ImageMaskComparer.compare   s    %.#i.:   )  )%''a772A;1& 

1!fC4D4DEA772A;1& 

1!fC4E4EFAG	)))45
?""7D1#w'' ((I;?4W:$$RZZ0W:$$RZZ0ggbffX012s*BGGH,=f$h&7Ssax(266#(+;;<4<t#CsSy 1E 93DEC"''#.s:CEF

 *  ..227A>M""7D1)#.d9+ >&'IK
 *g.. $$((!4q8&-7#?w4)#.c) =")1[M 256 113JMM*f-2 " :w// 	w-%c*#i[ 9I79	

 z7++r6   r1   )returnzDict[str, Dict[str, Any]])rQ   torch.Tensorr   
np.ndarray)r(   r   r   r   )r-   dictr   zTuple[dict, int])r   r#   NN)r&   r   r'   r   r(   r   r)   rc   r*   rb   r-   zdict | Noner.   z
str | Noner   z Tuple[bool, float, torch.Tensor])__name__
__module____qualname____firstlineno____doc__r   __annotations__classmethodr4   r8   r<   r?   r@   OUTPUT_NODEstaticmethodrT   rW   rm   rz   r   r=   __static_attributes__r1   r6   r3   r   r   ;   s,   M %'M>& 
 
* %BL/A$KL/KHc#Hc#K   & & ! !<    B> B>T  " $_,_, _, 	_,
 _, _, _, _, 
*_, _,r6   r   zImage Mask Comparer)r   
__future__r   r]   r   rd   r   r   urllib.requestr   uuidr   typingr   r   r   r   rJ   rL   torchr   r   r   NODE_CLASS_MAPPINGSNODE_DISPLAY_NAME_MAPPINGSr1   r6   r3   <module>r      s   4 #        # # 
   !' , , , , , & &
& N 
O, O,h * 
 . r6   