Skip to content

Commit c7e5e26

Browse files
author
arch
committed
improve process speed for 1+ tracker
1 parent e8afc9c commit c7e5e26

File tree

4 files changed

+57
-28
lines changed

4 files changed

+57
-28
lines changed

funscript_editor/algorithms/funscriptgenerator.py

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
import funscript_editor.algorithms.signalprocessing as sp
3434
import numpy as np
35+
import multiprocessing as mp
3536

3637
@dataclass
3738
class FunscriptGeneratorParameter:
@@ -75,6 +76,32 @@ class FunscriptGeneratorParameter:
7576
max_threshold: float = float(HYPERPARAMETER['max_threshold'])
7677

7778

79+
def merge_score(item: list, number_of_trackers: int) -> list:
80+
""" Merge score for given number of trackers
81+
82+
Note:
83+
Python multiprocessing methods use a mp.SimpleQueue to pass tasks to the worker processes.
84+
Everything that goes through the mp.SimpleQueue must be pickable.
85+
In python functions are only picklable if they are defined at the top-level of a module.
86+
87+
Args:
88+
item (list): score for each tracker
89+
number_of_trackers (int): number of used tracker (pairs)
90+
91+
Returns:
92+
list: merged score
93+
"""
94+
if number_of_trackers == 1:
95+
return item[0] if len(item) > 0 else []
96+
else:
97+
max_frame_number = max([len(item[i]) for i in range(number_of_trackers)])
98+
arr = np.ma.empty((max_frame_number,number_of_trackers))
99+
arr.mask = True
100+
for tracker_number in range(number_of_trackers):
101+
arr[:item[tracker_number].shape[0],tracker_number] = item[tracker_number]
102+
return list(filter(None.__ne__, arr.mean(axis=1).tolist()))
103+
104+
78105
class FunscriptGeneratorThread(QtCore.QThread):
79106
""" Funscript Generator Thread
80107
@@ -301,6 +328,7 @@ def min_max_selector(self,
301328
self.clear_keypress_queue()
302329
trackbarValueMin = lower_limit
303330
trackbarValueMax = upper_limit
331+
self.logger.info("Waiting for user input for max and min action position")
304332
while True:
305333
try:
306334
preview = image.copy()
@@ -314,6 +342,7 @@ def min_max_selector(self,
314342
trackbarValueMax = cv2.getTrackbarPos("Max", self.window_name)
315343
except: pass
316344

345+
self.logger.info("Receive values for max and min action position")
317346
self.__show_loading_screen(preview.shape)
318347
return (trackbarValueMin, trackbarValueMax) if trackbarValueMin < trackbarValueMax else (trackbarValueMax, trackbarValueMin)
319348

@@ -348,6 +377,7 @@ def calculate_score(self, bboxes) -> None:
348377
'distance': [np.array([]) for _ in range(self.params.number_of_trackers)],
349378
'roll': [np.array([]) for _ in range(self.params.number_of_trackers)]
350379
}
380+
self.logger.info("Calculate score for %d Tracker(s)", self.params.number_of_trackers)
351381
for tracker_number in range(self.params.number_of_trackers):
352382
woman_center = [self.get_center(item) for item in bboxes['Woman'][tracker_number]]
353383

@@ -383,21 +413,19 @@ def calculate_score(self, bboxes) -> None:
383413
score['x'][tracker_number] = np.array([w[0] - min([x[0] for x in bboxes['Woman'][tracker_number]]) for w in bboxes['Woman'][tracker_number]])
384414
score['y'][tracker_number] = np.array([max([x[1] for x in bboxes['Woman'][tracker_number]]) - w[1] for w in bboxes['Woman'][tracker_number]])
385415

386-
def get_mean(item, number_of_trackers) -> list:
387-
if number_of_trackers == 1:
388-
return item[0] if len(item) > 0 else []
389-
else:
390-
max_frame_number = max([len(item[i]) for i in range(number_of_trackers)])
391-
arr = np.ma.empty((max_frame_number,number_of_trackers))
392-
arr.mask = True
393-
for tracker_number in range(number_of_trackers):
394-
arr[:item[tracker_number].shape[0],tracker_number] = item[tracker_number]
395-
return list(filter(None.__ne__, arr.mean(axis=1).tolist()))
416+
self.logger.info("Merge Scores")
417+
pool, handle = {}, {}
418+
for metric in score.keys():
419+
pool[metric] = mp.Pool(1)
420+
handle[metric] = pool[metric].starmap_async(merge_score, [(score[metric], self.params.number_of_trackers)])
421+
422+
for metric in score.keys():
423+
score[metric] = handle[metric].get()[0]
424+
pool[metric].close()
396425

397-
self.score['x'] = sp.scale_signal(get_mean(score['x'], self.params.number_of_trackers), 0, 100)
398-
self.score['y'] = sp.scale_signal(get_mean(score['y'], self.params.number_of_trackers), 0, 100)
399-
self.score['distance'] = sp.scale_signal(get_mean(score['distance'], self.params.number_of_trackers), 0, 100)
400-
self.score['roll'] = sp.scale_signal(get_mean(score['roll'], self.params.number_of_trackers), 0, 100)
426+
self.logger.info("Scale Score to 0 - 100")
427+
for metric in score.keys():
428+
self.score[metric] = sp.scale_signal(score[metric], 0, 100)
401429

402430

403431
def scale_score(self, status: str, metric : str = 'y') -> None:
@@ -456,6 +484,7 @@ def scale_score(self, status: str, metric : str = 'y') -> None:
456484
desired_min = 0
457485
desired_max = 99
458486

487+
self.logger.info("Scale score %s to user input", metric)
459488
self.score[metric] = sp.scale_signal(self.score[metric], desired_min, desired_max)
460489

461490

@@ -959,12 +988,11 @@ def tracking(self) -> str:
959988

960989
self.__show_loading_screen(first_frame.shape)
961990
self.logger.info("Raw tracking data: %d Tracking points for %d seconds of the video", len(bboxes["Woman"]), int(len(bboxes["Woman"])*(self.params.skip_frames + 1)/self.video_info.fps))
962-
bboxes = self.correct_bboxes(bboxes, delete_last_predictions)
963991
video.stop()
992+
bboxes = self.correct_bboxes(bboxes, delete_last_predictions)
964993
self.logger.info(status)
965994
self.logger.info('Interpolate tracking boxes')
966995
interpolated_bboxes = self.interpolate_bboxes(bboxes)
967-
self.logger.info('Calculate score')
968996
self.calculate_score(interpolated_bboxes)
969997
return status
970998

@@ -1161,7 +1189,6 @@ def run(self) -> None:
11611189
json.dump(self.score, f)
11621190

11631191
if len(self.score[self.params.metric]) >= HYPERPARAMETER['min_frames']:
1164-
self.logger.info("Scale score")
11651192
self.scale_score(status, metric=self.params.metric)
11661193

11671194
if len(self.score[self.params.metric]) < HYPERPARAMETER['min_frames']:

funscript_editor/algorithms/signalprocessing.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ def scale_signal(signal :list, lower: float = 0, upper: float = 99) -> list:
1717
"""
1818
if len(signal) == 0: return signal
1919
if len(signal) == 1: return [lower]
20-
return [(float(upper) - float(lower)) * (x - min(signal)) / (max(signal) - min(signal)) + float(lower) for x in signal]
20+
signal_min = min(signal)
21+
signal_max = max(signal)
22+
return [(float(upper) - float(lower)) * (x - signal_min) / (signal_max - signal_min) + float(lower) for x in signal]
2123

2224

2325
def scale_signal_with_anomalies(

funscript_editor/data/ffmpegstream.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -70,15 +70,16 @@ def __del__(self):
7070

7171
def watchdog_timeout(self):
7272
""" Watchdog timeout for ffmpeg stream """
73-
self.logger.error("FFmpegStream Timeout")
74-
self.timeout = True
75-
self.stopped = True
76-
try: self.pipe.terminate()
77-
except: pass
78-
try: self.pipe.stdout.close()
79-
except: pass
80-
try: self.pipe.stderr.close()
81-
except: pass
73+
if not self.stopped:
74+
self.logger.error("FFmpegStream Timeout")
75+
self.timeout = True
76+
self.stopped = True
77+
try: self.pipe.terminate()
78+
except: pass
79+
try: self.pipe.stdout.close()
80+
except: pass
81+
try: self.pipe.stderr.close()
82+
except: pass
8283

8384

8485
@staticmethod

funscript_editor/ui/funscript_editor_window.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,6 @@ def __generate_funscript(self):
311311
start_time = self.video_player.get_current_timestamp_in_millis
312312
next_action = self.funscript.get_next_action(self.video_player.get_current_timestamp_in_millis+100)
313313
end_time = next_action['at'] if next_action['at'] > self.video_player.get_current_timestamp_in_millis+100 else -1.0
314-
self.__logger.info("Stop at {}".format(end_time))
315314

316315
self.funscript_generator_window = FunscriptGeneratorWindow(
317316
self.video_player.get_video_file,

0 commit comments

Comments
 (0)