Skip to content

Commit 2c440a1

Browse files
author
arch
committed
add option to load previous tracking result #22
1 parent 4184a05 commit 2c440a1

File tree

4 files changed

+71
-21
lines changed

4 files changed

+71
-21
lines changed

funscript_editor/__main__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ def main():
1010
parser = argparse.ArgumentParser()
1111
parser.add_argument("--generator", action = 'store_true', help = "Run only the generator")
1212
parser.add_argument("--multiaxis", action = 'store_true', help = "Show options for multiaxis output")
13+
parser.add_argument("--no-tracking", action = 'store_true', help = "Use previous tracking result")
1314
parser.add_argument("--logs", action = 'store_true', help = "Enable logging")
1415
parser.add_argument("--stdout", action = 'store_true', help = "Enable stdout logging")
1516
parser.add_argument("-i", "--input", type = str, help = "Video File")
@@ -22,4 +23,4 @@ def main():
2223
os.environ['PATH'] = os.getcwd() + os.sep + os.environ['PATH']
2324

2425
if not args.generator: show_editor()
25-
else: generate_funscript(args.input, args.start, args.end, args.output, args.multiaxis, args.logs, args.stdout)
26+
else: generate_funscript(args.input, args.start, args.end, args.output, args.multiaxis, args.no_tracking, args.logs, args.stdout)

funscript_editor/api.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ def generate_funscript(
3030
end_time :float,
3131
output_file: str,
3232
include_multiaxis_options: bool = False,
33+
no_tracking: bool = False,
3334
enable_logging: bool = False,
3435
stdout_logging: bool = False) -> None:
3536
""" Generate a funscript with minimal UI
@@ -40,6 +41,7 @@ def generate_funscript(
4041
end_time (float): end time in milliseconds (set -1.0 to use video end)
4142
output_file (str): path for the output file
4243
include_multiaxis_options (bool): include options for multiaxis output
44+
no_tracking (bool): Use previous tracking result
4345
enable_logging (bool): enable logging
4446
stdout_logging (bool): enable stdout logging
4547
"""
@@ -57,7 +59,7 @@ def generate_funscript(
5759
logger.info("Args: video_file=%s, start_time=%s, end_time=%s, output_file=%s", \
5860
str(video_file), str(start_time), str(end_time), str(output_file))
5961
app = QtWidgets.QApplication(sys.argv)
60-
w = FunscriptGeneratorWindow(video_file, start_time, end_time, output_file, include_multiaxis_options)
62+
w = FunscriptGeneratorWindow(video_file, start_time, end_time, output_file, include_multiaxis_options, no_tracking)
6163
w.setFixedHeight(5)
6264
w.setFixedWidth(5)
6365
w.move(1,1)

funscript_editor/data/ffmpegstream.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,19 @@ def get_projection(
216216

217217
return projection
218218

219+
@staticmethod
220+
def millisec_to_frame(millis: float, fps: float) -> int:
221+
""" Get Frame number for given millisec timestamp in video
222+
223+
Args:
224+
millisec (float): millisec timestamp
225+
fps (float): video frames per seconds
226+
227+
Returns:
228+
int: frame number
229+
"""
230+
return int(round(float(millis)/(float(1000)/float(fps)))) if millis > 0.0 else 0
231+
219232

220233
@staticmethod
221234
def frame_to_timestamp(frame_number: int, fps: float) -> str:

funscript_editor/ui/funscript_generator_window.py

Lines changed: 53 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,16 @@ class FunscriptGeneratorWindow(QtWidgets.QMainWindow):
3333
end_time (float): end position in video (timestamp in milliseconds) use -1.0 for video end.
3434
output_file (str, Funscript): csv output file path (Optional you can pass a funscript object where to store the result)
3535
include_multiaxis (bool): include multiaxis output
36+
no_tracking (bool): Use previous tracking result
3637
"""
3738

3839
def __init__(self,
3940
video_file: str,
4041
start_time: float,
4142
end_time: float,
4243
output_file: str,
43-
include_multiaxis: bool = False):
44+
include_multiaxis: bool = False,
45+
no_tracking: bool = False):
4446
super(FunscriptGeneratorWindow, self).__init__()
4547
self.allow_close = False
4648
self.raw_output = False
@@ -72,29 +74,22 @@ def __init__(self,
7274
sys.exit()
7375

7476
self.video_info = FFmpegStream.get_video_info(video_file)
75-
cap = cv2.VideoCapture(video_file)
76-
self.fps = cap.get(cv2.CAP_PROP_FPS)
77-
height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
78-
width = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
79-
video_aspect_ratio = float(width) / max((1, float(height)))
80-
cap.release()
81-
8277
self.video_file = video_file
83-
self.is_sbs_vr_video = True if 1.9 < video_aspect_ratio < 2.1 else False
8478
self.output_file = output_file
85-
86-
self.start_frame = int(round(float(start_time)/(float(1000)/float(self.fps)))) if start_time > 0.0 else 0
87-
self.end_frame = int(round(float(end_time)/(float(1000)/float(self.fps)))) if end_time > 0.0 and start_time < end_time else -1
79+
self.start_frame = FFmpegStream.millisec_to_frame(start_time, self.video_info.fps)
80+
self.end_frame = FFmpegStream.millisec_to_frame(end_time, self.video_info.fps) if end_time > 0.0 and start_time < end_time else -1
8881

8982
self.__logger.info("Set End Time to Frame Number %d", self.end_frame)
90-
9183
self.__logger.info("Hyperparameter:" + str(HYPERPARAMETER))
9284
self.__logger.info("Config:" + str(SETTINGS))
9385

94-
self.settings = {}
95-
self.settings_dialog = SettingsDialog(self.settings, include_vr = True, include_multiaxis = include_multiaxis)
96-
self.settings_dialog.applySettings.connect(self.run)
97-
self.settings_dialog.show()
86+
if no_tracking:
87+
self.continue_with_tracking_result()
88+
else:
89+
self.settings = {}
90+
self.settings_dialog = SettingsDialog(self.settings, include_vr = True, include_multiaxis = include_multiaxis)
91+
self.settings_dialog.applySettings.connect(self.run)
92+
self.settings_dialog.show()
9893

9994

10095
__logger = logging.getLogger(__name__)
@@ -103,6 +98,43 @@ def __init__(self,
10398
openCutWidget = QtCore.pyqtBoundSignal
10499

105100

101+
def continue_with_tracking_result(self):
102+
self.__logger.info("Use previous tracking result")
103+
if not os.path.exists(definitions.RAW_TRACKING_DATA_CAHCE_FILE):
104+
self.__show_message("Tracking result not found")
105+
sys.exit()
106+
107+
with open(definitions.RAW_TRACKING_DATA_CAHCE_FILE, 'r') as fd:
108+
cache_content = json.load(fd)
109+
110+
if any(x not in cache_content for x in ["videoFile", "fps", "actions"]):
111+
self.__show_message("Invalid tracking result cache file")
112+
sys.exit()
113+
114+
current_video_filename = os.path.basename(self.video_file)
115+
if cache_content["videoFile"] != current_video_filename:
116+
self.__show_message(f"tracking result for {current_video_filename} not found")
117+
sys.exit()
118+
119+
if cache_content["fps"] != self.video_info.fps:
120+
self.__show_message(f"Video propberies has changed")
121+
sys.exit()
122+
123+
self.funscripts = {metric: Funscript(self.video_info.fps) \
124+
for metric in cache_content["actions"]}
125+
126+
self.score = {metric: [ \
127+
item["pos"] \
128+
for item in cache_content["actions"][metric] \
129+
] \
130+
for metric in cache_content["actions"] }
131+
132+
start_time = min([cache_content["actions"][metric][0]["at"] for metric in cache_content["actions"]])
133+
self.start_frame = FFmpegStream.millisec_to_frame(float(start_time), self.video_info.fps)
134+
self.__logger.info("Set start frame to %d", self.start_frame)
135+
self.__next_postprocessing(None, [], [])
136+
137+
106138
def closeEvent(self, event):
107139
if self.allow_close:
108140
event.accept()
@@ -134,7 +166,7 @@ def __show_message(self, message :str, error: bool = False) -> None:
134166

135167
# Step 1
136168
def __tracking_completed(self, score, projection_config, tracking_points, msg, success) -> None:
137-
self.funscripts = {k.replace('inverted', '').strip(): Funscript(self.fps) \
169+
self.funscripts = {k.replace('inverted', '').strip(): Funscript(self.video_info.fps) \
138170
for k in self.settings['trackingMetrics'].split('+')}
139171

140172
if not success:
@@ -192,6 +224,8 @@ def __scaling_completed(self, score):
192224
raw_tracking_data_json_output = {
193225
'version': 1,
194226
'comment': "MTFG RAW DATA",
227+
'fps': self.video_info.fps,
228+
'videoFile': os.path.basename(self.video_file),
195229
'actions': {}
196230
}
197231

@@ -208,7 +242,7 @@ def __scaling_completed(self, score):
208242

209243
if not self.raw_output:
210244
self.__logger.info("Post Processing Data")
211-
#NOTE: delete the raw data from funscript
245+
#NOTE: delete the raw data from funscripts
212246
for key in self.funscripts:
213247
self.funscripts[key].clear_actions()
214248
self.__next_postprocessing(None, [], [])

0 commit comments

Comments
 (0)