@@ -60,6 +60,7 @@ def __init__(self,
6060 QtCore .QThread .__init__ (self )
6161 self .params = params
6262 self .funscript = funscript
63+ self .video_info = FFmpegStream .get_video_info (self .params .video_path )
6364 self .timer = cv2 .getTickCount ()
6465
6566 # XXX destroyWindow(...) sems not to delete the trackbar. Workaround: we give the window each time a unique name
@@ -69,14 +70,14 @@ def __init__(self,
6970 self .x_text_start = 50
7071 self .font_size = 0.6
7172 self .tracking_fps = []
72- self .scone_x = []
73- self .scone_y = []
73+ self .score = {
74+ 'x' : [],
75+ 'y' : []
76+ }
7477 self .bboxes = {
7578 'Men' : [],
7679 'Woman' : []
77- }
78-
79- self .video_info = FFmpegStream .get_video_info (self .params .video_path )
80+ }
8081
8182
8283 #: completed event with reference to the funscript with the predicted actions, status message and success flag
@@ -88,7 +89,7 @@ def __init__(self,
8889 logger = logging .getLogger (__name__ )
8990
9091
91- def determine_monitor_scaling (self , frame_width , frame_height ) -> float :
92+ def determine_preview_scaling (self , frame_width , frame_height ) -> float :
9293 """ Determine the scaling for current monitor setup
9394
9495 Args:
@@ -106,7 +107,7 @@ def determine_monitor_scaling(self, frame_width, frame_height) -> float:
106107 self .logger .error ("Monitor resolution info not found" )
107108 else :
108109 # asume we use the largest monitor for scipting
109- self .params .preview_scaling *= max (scale )
110+ self .params .preview_scaling = float ( SETTINGS [ 'preview_scaling' ]) * max (scale )
110111
111112
112113 def drawBox (self , img : np .ndarray , bbox : tuple ) -> np .ndarray :
@@ -251,18 +252,14 @@ def calculate_score(self) -> None:
251252 We use x0,y0 from the predicted tracking boxes to create a diff score
252253 """
253254 if self .params .track_men :
254- self .score_x = [m [0 ] - w [0 ] for w , m in zip (self .bboxes ['Woman' ], self .bboxes ['Men' ])]
255- self .score_y = [m [1 ] - w [1 ] for w , m in zip (self .bboxes ['Woman' ], self .bboxes ['Men' ])]
255+ self .score [ 'x' ] = [m [0 ] - w [0 ] for w , m in zip (self .bboxes ['Woman' ], self .bboxes ['Men' ])]
256+ self .score [ 'y' ] = [m [1 ] - w [1 ] for w , m in zip (self .bboxes ['Woman' ], self .bboxes ['Men' ])]
256257 else :
257- self .score_x = [max ([x [0 ] for x in self .bboxes ['Woman' ]]) - w [0 ] for w in self .bboxes ['Woman' ]]
258- self .score_y = [max ([x [1 ] for x in self .bboxes ['Woman' ]]) - w [1 ] for w in self .bboxes ['Woman' ]]
258+ self .score [ 'x' ] = [max ([x [0 ] for x in self .bboxes ['Woman' ]]) - w [0 ] for w in self .bboxes ['Woman' ]]
259+ self .score [ 'y' ] = [max ([x [1 ] for x in self .bboxes ['Woman' ]]) - w [1 ] for w in self .bboxes ['Woman' ]]
259260
260- # NOTE: Scaling with the anomaly function sometimes makes the result even worse
261- # self.score_x = sp.scale_signal_with_anomalies(self.score_x, 0, 100, lower_quantile=0.05, upper_quantile=0.99999)
262- # self.score_y = sp.scale_signal_with_anomalies(self.score_y, 0, 100, lower_quantile=0.05, upper_quantile=0.99999)
263-
264- self .score_x = sp .scale_signal (self .score_x , 0 , 100 )
265- self .score_y = sp .scale_signal (self .score_y , 0 , 100 )
261+ self .score ['x' ] = sp .scale_signal (self .score ['x' ], 0 , 100 )
262+ self .score ['y' ] = sp .scale_signal (self .score ['y' ], 0 , 100 )
266263
267264
268265 @staticmethod
@@ -290,18 +287,18 @@ def scale_score(self, status: str, direction : str = 'y') -> None:
290287 status (str): a status/info message to display in the window
291288 direction (str): scale the 'y' or 'x' score
292289 """
293- if len (self .score_y ) < 2 : return
290+ if len (self .score [ 'y' ] ) < 2 : return
294291
295292 cap = cv2 .VideoCapture (self .params .video_path )
296293 width = int (cap .get (cv2 .CAP_PROP_FRAME_WIDTH ))
297294 height = int (cap .get (cv2 .CAP_PROP_FRAME_HEIGHT ))
298295
299296 if direction == 'x' :
300- min_frame = np .argmin (np .array (self .score_x )) + self .params .start_frame
301- max_frame = np .argmax (np .array (self .score_x )) + self .params .start_frame
297+ min_frame = np .argmin (np .array (self .score [ 'x' ] )) + self .params .start_frame
298+ max_frame = np .argmax (np .array (self .score [ 'x' ] )) + self .params .start_frame
302299 else :
303- min_frame = np .argmin (np .array (self .score_y )) + self .params .start_frame
304- max_frame = np .argmax (np .array (self .score_y )) + self .params .start_frame
300+ min_frame = np .argmin (np .array (self .score [ 'y' ] )) + self .params .start_frame
301+ max_frame = np .argmax (np .array (self .score [ 'y' ] )) + self .params .start_frame
305302
306303 cap .set (cv2 .CAP_PROP_POS_FRAMES , min_frame )
307304 successMin , imgMin = cap .read ()
@@ -339,9 +336,9 @@ def scale_score(self, status: str, direction : str = 'y') -> None:
339336 desired_max = 99
340337
341338 if direction == 'x' :
342- self .score_x = sp .scale_signal (self .score_x , desired_min , desired_max )
339+ self .score [ 'x' ] = sp .scale_signal (self .score [ 'x' ] , desired_min , desired_max )
343340 else :
344- self .score_y = sp .scale_signal (self .score_y , desired_min , desired_max )
341+ self .score [ 'y' ] = sp .scale_signal (self .score [ 'y' ] , desired_min , desired_max )
345342
346343
347344 def plot_y_score (self , name : str , idx_list : list , dpi : int = 300 ) -> None :
@@ -352,20 +349,20 @@ def plot_y_score(self, name: str, idx_list: list, dpi : int = 300) -> None:
352349 idx_list (list): list with all frame numbers with funscript action points
353350 dpi (int): picture output dpi
354351 """
355- if len (self .score_y ) < 2 : return
352+ if len (self .score [ 'y' ] ) < 2 : return
356353 if len (idx_list ) < 2 : return
357354 rows = 2
358- figure = Figure (figsize = (max ([6 ,int (len (self .score_y )/ 50 )]), rows * 3 + 1 ), dpi = dpi )
355+ figure = Figure (figsize = (max ([6 ,int (len (self .score [ 'y' ] )/ 50 )]), rows * 3 + 1 ), dpi = dpi )
359356 ax = figure .add_subplot (2 ,1 ,1 ) # Rows, Columns, Position
360357 ax .title .set_text ('Motion in y direction' )
361358 # TODO why is there an offset of 1 in the data?
362- ax .plot (self .score_y [max ((0 ,idx_list [0 ]- 1 )):idx_list [- 1 ]])
363- ax .plot (idx_list , [self .score_y [idx ] for idx in idx_list ], 'o' )
359+ ax .plot (self .score [ 'y' ] [max ((0 ,idx_list [0 ]- 1 )):idx_list [- 1 ]])
360+ ax .plot (idx_list , [self .score [ 'y' ] [idx ] for idx in idx_list ], 'o' )
364361 ax .legend (['Tracker Prediction' ,'Local Max and Min' ], loc = 'upper right' )
365362 ax = figure .add_subplot (2 ,1 ,2 )
366363 ax .title .set_text ('Funscript' )
367- ax .plot (idx_list , [self .score_y [idx ] for idx in idx_list ])
368- ax .plot (idx_list , [self .score_y [idx ] for idx in idx_list ], 'o' )
364+ ax .plot (idx_list , [self .score [ 'y' ] [idx ] for idx in idx_list ])
365+ ax .plot (idx_list , [self .score [ 'y' ] [idx ] for idx in idx_list ], 'o' )
369366 figure .savefig (fname = name , dpi = dpi , bbox_inches = 'tight' )
370367
371368
@@ -376,15 +373,15 @@ def plot_scores(self, name: str, dpi : int = 300) -> None:
376373 name (str): file name for the figure
377374 dpi (int): picture output dpi
378375 """
379- if len (self .score_y ) < 2 : return
376+ if len (self .score [ 'y' ] ) < 2 : return
380377 rows = 2
381- figure = Figure (figsize = (max ([6 ,int (len (self .score_y )/ 50 )]), rows * 3 + 1 ), dpi = dpi )
378+ figure = Figure (figsize = (max ([6 ,int (len (self .score [ 'y' ] )/ 50 )]), rows * 3 + 1 ), dpi = dpi )
382379 ax = figure .add_subplot (2 ,1 ,1 ) # Rows, Columns, Position
383380 ax .title .set_text ('Motion in x direction' )
384- ax .plot (self .score_x )
381+ ax .plot (self .score [ 'x' ] )
385382 ax = figure .add_subplot (2 ,1 ,2 )
386383 ax .title .set_text ('Motion in y direction' )
387- ax .plot (self .score_y )
384+ ax .plot (self .score [ 'y' ] )
388385 figure .savefig (fname = name , dpi = dpi , bbox_inches = 'tight' )
389386
390387
@@ -428,7 +425,7 @@ def get_vr_projection_config(self, image :np.ndarray) -> None:
428425 """
429426 config = PROJECTION [self .params .projection ]
430427
431- self .mointor_scale = self . determine_monitor_scaling (config ['parameter' ]['width' ], config ['parameter' ]['height' ])
428+ self .determine_preview_scaling (config ['parameter' ]['width' ], config ['parameter' ]['height' ])
432429
433430 # NOTE: improve processing speed to make this menu more responsive
434431 if image .shape [0 ] > 6000 or image .shape [1 ] > 6000 :
@@ -514,6 +511,7 @@ def get_bbox(self, image: np.ndarray, txt: str) -> tuple:
514511 round (bbox [3 ]/ self .params .preview_scaling )
515512 )
516513
514+ # revert the zoom
517515 if self .params .use_zoom :
518516 bbox = (round (bbox [0 ]/ self .params .zoom_factor )+ zoom_bbox [0 ],
519517 round (bbox [1 ]/ self .params .zoom_factor )+ zoom_bbox [1 ],
@@ -524,18 +522,6 @@ def get_bbox(self, image: np.ndarray, txt: str) -> tuple:
524522 return bbox
525523
526524
527- def get_first_frame (self ) -> np .ndarray :
528- """ Get the first frame image
529-
530- Returns:
531- np.ndarray: opencv image
532- """
533- cap = cv2 .VideoCapture (str (self .params .video_path ))
534- if self .params .start_frame > 0 : cap .set (cv2 .CAP_PROP_POS_FRAMES , self .params .start_frame )
535- success , first_frame = cap .read ()
536- cap .release ()
537- return first_frame
538-
539525
540526 def get_flat_projection_config (self ,
541527 first_frame :np .ndarray ) -> dict :
@@ -548,16 +534,16 @@ def get_flat_projection_config(self,
548534 dict: config
549535 """
550536 h , w = first_frame .shape [:2 ]
551- config = PROJECTION [self .params .projection ]
537+ config = copy . deepcopy ( PROJECTION [self .params .projection ])
552538
553- if config ['parameter' ]['height' ] == - 1 :
539+ if PROJECTION [ self . params . projection ] ['parameter' ]['height' ] == - 1 :
554540 scaling = config ['parameter' ]['width' ] / float (w )
555541 config ['parameter' ]['height' ] = round (h * scaling )
556- elif config ['parameter' ]['width' ] == - 1 :
542+ elif PROJECTION [ self . params . projection ] ['parameter' ]['width' ] == - 1 :
557543 scaling = config ['parameter' ]['height' ] / float (h )
558544 config ['parameter' ]['width' ] = round (w * scaling )
559545
560- self .mointor_scale = self . determine_monitor_scaling (config ['parameter' ]['width' ], config ['parameter' ]['height' ])
546+ self .determine_preview_scaling (config ['parameter' ]['width' ], config ['parameter' ]['height' ])
561547
562548 return config
563549
@@ -583,12 +569,12 @@ def tracking(self) -> str:
583569
584570 first_frame = video .read ()
585571 bboxWoman = self .get_bbox (first_frame , "Select Woman Feature" )
586- trackerWoman = StaticVideoTracker (first_frame , bboxWoman , limit_searchspace = False ) # TODO limit_searchspace for flat videos
572+ trackerWoman = StaticVideoTracker (first_frame , bboxWoman )
587573 self .bboxes ['Woman' ].append (bboxWoman )
588574
589575 if self .params .track_men :
590576 bboxMen = self .get_bbox (self .drawBox (first_frame , bboxWoman ), "Select Men Feature" )
591- trackerMen = StaticVideoTracker (first_frame , bboxMen , limit_searchspace = False ) # TODO limit_searchspace for flat videos
577+ trackerMen = StaticVideoTracker (first_frame , bboxMen )
592578 self .bboxes ['Men' ].append (bboxMen )
593579
594580 if self .params .max_playback_fps > (self .params .skip_frames + 1 ):
@@ -598,7 +584,7 @@ def tracking(self) -> str:
598584
599585 status = "End of video reached"
600586 self .clear_keypress_queue ()
601- last_frame , frame_num = None , 1 # first frame is was init frame
587+ last_frame , frame_num = None , 1 # first frame is init frame
602588 while video .isOpen ():
603589 cycle_start = time .time ()
604590 frame = video .read ()
@@ -726,12 +712,12 @@ def apply_shift(self, frame_number, position: str) -> int:
726712 """
727713 if position in ['max' , 'top' ] and self .params .direction != 'x' :
728714 if frame_number >= - 1 * self .params .shift_top_points \
729- and frame_number + self .params .shift_top_points < len (self .score_y ): \
715+ and frame_number + self .params .shift_top_points < len (self .score [ 'y' ] ): \
730716 return self .params .start_frame + frame_number + self .params .shift_top_points
731717
732718 if position in ['min' , 'bottom' ] and self .params .direction != 'x' :
733719 if frame_number >= - 1 * self .params .shift_bottom_points \
734- and frame_number + self .params .shift_bottom_points < len (self .score_y ): \
720+ and frame_number + self .params .shift_bottom_points < len (self .score [ 'y' ] ): \
735721 return self .params .start_frame + frame_number + self .params .shift_bottom_points
736722
737723 return self .params .start_frame + frame_number
@@ -747,9 +733,9 @@ def get_score_with_offset(self, idx_dict) -> list:
747733 list: score with offset
748734 """
749735 if self .params .direction == 'x' :
750- return self .score_x
736+ return self .score [ 'x' ]
751737
752- score = copy .deepcopy (self .score_y )
738+ score = copy .deepcopy (self .score [ 'y' ] )
753739 score_min , score_max = min (score ), max (score )
754740 for idx in idx_dict ['min' ]:
755741 score [idx ] = max (( score_min , min ((score_max , score [idx ] + self .params .bottom_points_offset )) ))
@@ -762,23 +748,23 @@ def get_score_with_offset(self, idx_dict) -> list:
762748
763749 def run (self ) -> None :
764750 """ The Funscript Generator Thread Function """
765- # NOTE: score_y and score_x should have the same number size so it should be enouth to check one score length
751+ # NOTE: score['y'] and score['x'] should have the same number size so it should be enouth to check one score length
766752 with Listener (on_press = self .on_key_press ) as listener :
767753 status = self .tracking ()
768- if len (self .score_y ) >= HYPERPARAMETER ['min_frames' ]:
754+ if len (self .score [ 'y' ] ) >= HYPERPARAMETER ['min_frames' ]:
769755 if self .params .direction != 'x' :
770756 self .scale_score (status , direction = 'y' )
771757 else :
772758 self .scale_score (status , direction = 'x' )
773759
774- if len (self .score_y ) < HYPERPARAMETER ['min_frames' ]:
760+ if len (self .score [ 'y' ] ) < HYPERPARAMETER ['min_frames' ]:
775761 self .finished (status + ' -> Tracking time insufficient' , False )
776762 return
777763
778764 if self .params .direction != 'x' :
779- idx_dict = sp .get_local_max_and_min_idx (self .score_y , self .video_info .fps )
765+ idx_dict = sp .get_local_max_and_min_idx (self .score [ 'y' ] , self .video_info .fps )
780766 else :
781- idx_dict = sp .get_local_max_and_min_idx (self .score_x , self .video_info .fps )
767+ idx_dict = sp .get_local_max_and_min_idx (self .score [ 'x' ] , self .video_info .fps )
782768
783769 idx_list = [x for k in ['min' , 'max' ] for x in idx_dict [k ]]
784770 idx_list .sort ()
0 commit comments