
    miF6                     x    d dl Z d dlZd dlZd dlZddZddZddZddZd Z	ddZ
d Zd	 Zed
k(  r e        yy)    Nc           
         t        j                  d }t        j                  | |||      }t        j                  ddt        j
                  z  dd      }dt        |      z  dz  }|d   dz  |d   dz  f}g }	|D ]c  }
t        |d   |t        j                  |
      z  z         }t        |d   |t        j                  |
      z  z         }|	j                  ||f       e ||z  }t        |      D ]  }t        j                  |d   |d   d	ft        j                  
      }t        |	      D ]g  \  }\  }}t        ddt        j                  dt        j
                  z  dz  |z  |z  |z         z  z         }t        j                  |||fd|||fd       i |j!                  |        |j#                          t%        d|  d| d       | |	fS )z}
    Creates an MP4 video where bright dots appear at the 10th roots of unity.
    Dots blink randomly to aid detection.
    mp4vr      
   Fendpoint皙?      dtype      g      ?zGenerated video: z with z frames)cv2VideoWriter_fourccVideoWriternplinspacepiminintcossinappendrangezerosuint8	enumeratecirclewritereleaseprint)output_pathdurationfpsimg_sizefourccoutanglesradiuscenterroot_pointsangxytotal_frames	frame_idximgi	intensitys                     =/home/per/Documents/Universal Solver/roots_from_video_dots.pygenerate_target_videor7   	   s   
 ##V,F
//+vsH
=C [[AbeeGR%8F3x= 1$Fqk1nhqk1n-FK #q	FRVVC[001q	FRVVC[001Aq6"#
 c>L<( 	hhXa[!4BHHE";/ 	OIAv1C#q255y3/JS/PST/T(U"UUVIJJsQFBIy(I2N	O 			# KKM	k]&g
FG##    c           
      x   t        j                  | t         j                        }t        j                  |dd      }t	        t        j                  t        j                  |d      dd            }t        j                  ||dt         j                        \  }}t        j                  |dt         j                  t         j                  dd      }t        j                  ||      }	t        j                  d	t
        j                        }
t        j                  |	t         j                   |
      }	t        j                  |	t         j"                  |
      }	t        j$                  |	t         j&                  t         j(                        \  }}g }|D ]  }t        j*                  |      }|d
k  rt        j,                  |      \  \  }}}||cxk  r|k  sEn Ht        j.                  |d      }|dkD  rdt
        j0                  z  |z  ||z  z  nd}|dk  rt	        |      t	        |      }}t	        |t3        d|dz
        |dz   t3        d|dz
        |dz   f   j5                               }|j7                  ||||f        |j9                  d d       |dd
 D cg c]  \  }}}}||f c}}}S c c}}}w )zm
    Returns list of (x, y) detected dot centers.
    Uses adaptive thresholding plus contour filtering.
    )   r:   r   gX@(            i)r   r      Tgư>   g        gffffff?r
   r   c                     | d   | d   fS )Nr   r    )items    r6   <lambda>zdetect_dots.<locals>.<lambda>Q   s    Qa1 r8   )keyreverseN)r   cvtColorCOLOR_BGR2GRAYGaussianBlurr   r   clip
percentile	thresholdTHRESH_BINARYadaptiveThresholdADAPTIVE_THRESH_GAUSSIAN_C
bitwise_oronesr   morphologyEx
MORPH_OPENMORPH_CLOSEfindContoursRETR_EXTERNALCHAIN_APPROX_SIMPLEcontourAreaminEnclosingCircle	arcLengthr   maxmeanr   sort)frame
min_radius
max_radiusgrayblurpercentile_level_thresh_fixedthresh_adaptivethreshkernelcontoursdotscntarear/   r0   r+   	perimetercircularityx_iy_i
brightnesss                          r6   detect_dotsrr   +   sQ   
 <<s112DD&!,D2772==t#<b#FGmmD*:CARARSOA|++&&

O ^^L/:FWWVRXX&Ffcnnf=Ffcoov>F""63+<+<c>U>UVKHaD =s#"9//4A-:-c40IHQTXHX!bee)d*i).CD^aKT!1vs1vCT#aq/#'"93q#'?3QR7;R"RSXXZ[JKKc:{;<= 	II14I@%)#2Y//zq!QQF///s    J5c                    g }t        |       D ]  \  }}d}t        |      D ]K  \  }\  }}}	t        j                  ||z
  ||z
        |k  s*|	dz   }
||	z  |z   |
z  ||	z  |z   |
z  |
f||<   d} n |rd|j	                  t        |      t        |      df        |D 	cg c]/  \  }}}	t        t        |            t        t        |            |	f1 c}	}}S c c}	}}w )NFr
   T)sortedr   r   hypotr   floatr   round)pointsmin_distancemergedr/   r0   placedidxmxmycount	new_counts              r6   deduplicate_pointsr   U   s    Fv 	31$-f$5 	 C"b%xxBB',6!AI	 "U
Q);b5j1nPY=Y[des	 MM58U1Xq12	3 FLLLkaESq]CaM51LLLs    4Cc           	         | sg S t        j                  t        j                  | t         j                        d      }t	        |      D cg c]  }g  }}| D ]  }t        j
                  |d   |d   z
  |d   |d   z
        }t        t        j                  |t         j                  z   dt         j                  z  z  |z              |z  }||   j                  |        g }	|D ]l  }
|
st        j                  |
t         j                        }|	j                  t        t        j                  |d      j                  t                           n t        |	|      S c c}w )Nr   r   axisr
   r   )r   r\   arrayfloat32r   arctan2r   floorr   r   tupleastypesort_roots_by_angle)rx   frame_shapeexpected_countr,   rd   binspointanglebin_idxrootsbucket
bucket_arrs               r6   estimate_roots_from_pointsr   d   s,   	WWRXXfBJJ7a@Fn-.1B.D. $

58fQi/qF1I1EFbhh1ruu9 =OPQTbbWU#$
 E EXXfBJJ7
U277:A6==cBCD	E
 uk22 /s   	E"c                 ~    | j                   dk(  r$t        j                  | t        j                        } t	        |       S )Nr   )ndimr   rG   COLOR_GRAY2BGRrr   )
projections    r6   detect_from_projectionr   x   s/    !\\*c.@.@A
z""r8   c           	         t        j                  | t         j                        }g }|D ]  \  }}t        d||z
        }t	        |j
                  d   ||z   dz         }t        d||z
        }	t	        |j
                  d   ||z   dz         }
||	|
||f   }|j                  dk(  r|j                  d        t        |j                               }|dk  r|j                  d        t        dt        |dz              }||k\  }t        j                  |      s|j                  d        t        j                  |      \  }}|||f   j                  t        j                        }|t        j                  ||      z   }|	t        j                  ||      z   }|j                  t        t        |            t        t        |            f        |S )Nr   r
         g?)weights)r   rG   rH   r[   r   shapesizer   r   r   anynonzeror   r   averagerw   )r^   expected_rootssearch_radiusra   refinedr/   r0   x0x1y0y1patch	local_maxrL   maskyyxxr   cxcys                       r6   refine_roots_from_expectedr   ~   s   <<s112DG 91A%&AM 1A 56A%&AM 1A 56RUBrE\"::?NN4 		$	q=NN4 3y4/01		!vvd|NN4 D!BB-&&rzz2"**R11"**R11E"IE"I78394 Nr8   c                 D    |d   dz  |d   dz  ft        | fd      S )Nr
   r   r   c                 T    t        j                  | d   d   z
  | d   d   z
        S )Nr
   r   )r   r   )pr,   s    r6   rD   z%sort_roots_by_angle.<locals>.<lambda>   s-    

1Q4&)3CQqTFSTIEU(V r8   )rE   )rt   )rx   r   r,   s     @r6   r   r      s-    !n!;q>Q#67F&VWWr8   c                     t        j                  d      } | j                  dt        dd       | j                  ddd	
       | j                  dt        dd       | j                  dt        dd       | j                  ddd
       | j                         }|j                  r?t        j                  j                  |j                        r|j                  }t        j                  |      }|j                         \  }}|st        d       y |j                  d d \  }}|dz  |dz  f}dt        ||      z  dz  }	t!        j"                  ddt         j$                  z  dd      }
g }|
D ]c  }t	        |d   |	t!        j&                  |      z  z         }t	        |d   |	t!        j(                  |      z  z         }|j+                  ||f       e |j-                          n=t/        d|j0                  |j2                        \  }}|j4                  rt        d       y t        j                  |      }|j7                         st        d       y d}g }g }d }d }d }t9        t;        |            D cg c]  }g  }}|j<                  xrR t?        t        j@                  jC                  d            xs( t?        t        j@                  jC                  d            }d}	 |j                         \  }}|snQ|j                  }t        jD                  |t        jF                        }|0|jI                  t         jJ                        }|jM                         }n8||jI                  t         jJ                        z  }t!        jN                  ||      }tQ        ||      }|D cg c]  }||	 }}t;        |      dk  r2tS        |      }|r%|j+                  tU        ||j                               tW        |      D ](  \  }}|	||   j+                  |       ||   | d  ||<   * g } tW        |      D ]q  \  }}!|!rV| j+                  tY        t!        jZ                  t!        j\                  |!      d       jI                  t                           ^| j+                  ||          s t_        d! |D              t;        |      k(  r|j+                  |        || d  }|r%|j+                  tU        ||j                               |r+t!        jZ                  |d       jI                  t              }"nt!        j\                  | t        "      }"|jM                         }#|D ]   \  }}t        j`                  |#||fd#d$d       " |D ]"  }|\  }}t        j`                  |#||fd%d&d'       $ |"D ]   \  }}t        j`                  |#||fd(d)d'       " t        jb                  |#d*| d+t;        |       d,d-t        jd                  d.d/d       |r;t        jf                  d0|#       t        jh                  d      d1z  tk        d2      k(  rn|dz  }h|j-                          |rt        jl                          t;        |      |k  rk|h|eg }$t!        jn                  |tq        |d      z  dd1      jI                  t         jr                        }%tQ        t        jD                  |%t        jt                        |      }&tQ        t        jD                  |t        jt                        |      }'|$jw                  |&D cg c]  }||	 c}       |$jw                  |'D cg c]  }||	 c}       |$jw                  ty        |%             |$jw                  ty        |             t{        |$      }$t}        |$D cg c]
  \  }}}||f c}}}|      }(t;        |(      dk(  r|j+                  |(       t;        |      |k  rj|rh|f|D )cg c]  })|)D ]  }|  }*})}t{        |*      }*t}        |*D cg c]
  \  }}}||f c}}}|      }+t;        |+      dk(  r|j+                  |+       |sp|nt        |      rc|j+                  |D !cg c]H  }!tY        t!        jZ                  t!        j\                  |!      d       jI                  t                    J c}!       |r|r|t!        jZ                  |d       },tW        |,      D -.cg c]P  \  }-}.t         j                  j                  t!        j\                  |.      t!        j\                  ||-         z
        R }/}-}.t        d3t!        jZ                  |/      d4d5       t;        |      |k  rt        d6t;        |       d7       t        d8t;        |,       d9       y t        d:       y c c}w c c}w c c}w c c}w c c}}}w c c}})w c c}}}w c c}!w c c}.}-w );Nu8   Real‑time root extraction from video of blinking dots.)descriptionz--video zGPath to existing video (if not provided, a synthetic one is generated).)typedefaulthelpz--generate-only
store_truez!Only generate the video and exit.)actionr   z--fpsr   z!Frames per second for generation.z
--durationz(Duration in seconds for generated video.z	--displayzShow cv2.imshow preview window.zCannot read videor   r	   r   Fr   r
   target_roots.mp4)r$   r%   r&   zVideo generated. Exiting.zCannot open videor:   DISPLAYWAYLAND_DISPLAYr   c              3   2   K   | ]  }t        |        y w)N)bool).0historys     r6   	<genexpr>zmain.<locals>.<genexpr>   s     8tG}8s   r   r   )r   r   r=   r   )r   r=   r   r   r@   )r=   r   r   zFrame z | Detected: z/10)r      gffffff?)r=   r=   r=   zRoot Trackerr=   qz'
Final average distance to true roots: z.2fz pixelszUsed z6 complete detections plus frame accumulation fallback.z
Recovered z/10 root positions.z*Not enough detections to compute accuracy.)BargparseArgumentParseradd_argumentstrr   
parse_argsvideoospathexistsr   VideoCapturereadr#   r   r   r   r   r   r   r   r   r"   r7   r%   r&   generate_onlyisOpenedr   lendisplayr   environgetrG   rH   r   r   copymaximumr   rr   r   r   r   r\   r   sumr    putTextFONT_HERSHEY_SIMPLEXimshowwaitKeyorddestroyAllWindowsrJ   r[   r   r   extendr   r   r   alllinalgnorm)0parserargs
video_pathcapretsamplehwr,   r+   r*   
true_rootsr.   r/   r0   max_historyestimated_rootsall_detectionsaccumulatedmax_projectionr   rd   root_tracksdisplay_enabledr2   r^   ra   detectedr   detected_pointsblob_detectedr|   tracked_estimater   	avg_rootsr   projection_candidates
mean_framemean_guided
max_guided	recovered	detectionpooled	consensuslast_avgr4   est	distancess0                                                   r6   mainr     s   $$1klF
	R  ?H  I
),Ehi
c2<_`
3Akl
L?`aDzzbggnnTZZ0ZZ
 z*hhjV%&||BQ1Q$1s1ay1$Q"%%e<
 	&CF1I 445AF1I 445Aq!f%	& 	 "7CU@D;?88"E
J -. 

:
&C<<>!" KONKNK$S_56!26K6ll RZZ^^I&'R4

?P0Q+R  I
XXZ
Ukk||E3#5#56++bjj1K!YY[N4;;rzz22KZZ=N .eZ@.6LU%:K5LL"$'.M%%&9-&UV#H- 	CJC C ''.#.s#3[LM#BC 	C
 %k2 	9LC ''bggbhhw6Ga.P.W.WX[.\(]^ ''
38		9 8K88C
OK""#34-{lm<O!!"5ou{{"STa8??DI!1=I **,  	;FQJJwA;:	; % 	<EDAqJJwA;;	<   	<FQJJwA;;	< 	Gvi[c/>R=SSVWYa,,c=!	EJJ~w/{{1~$C0Q	E H KKM
?k)k.E+Ja "WW[3y!+<<aELLRXXV
0j#J\J\1]_ij/^SM_M_0`blm
$$%ZHYe%Z[$$%YuGXe%YZ$$%;J%GH$$%;N%KL 23H I.F[/\/\71aA/\^ij	y>R""9-
?k)nAX)7OIYOE%O%OO#F+.f/M/M71aA/M{[	y>R""9- {63{;K& 
 "''"((7+!4;;C@A 
 	
 :+*A77?3#,X#68C YY^^BHHSMBHHZ]4K$KL 8	 889KC8PPWXY+-E#o.//efg
3x=/)<=>:;g 7, Mz &[%Y 0]
 P/M 
8sJ   6	g%g-g5g=ggg4gg",g(Ag/Ag4__main__)r   r   r   )  r  )r@      )   )r   )   )r   numpyr   r   r   r7   rr   r   r   r   r   r   r  __name__rB   r8   r6   <module>r     sT    
  	 
$D'0TM3(#@Xf<P zF r8   