From d7d2e7549eb9f4475deb36309a001f58116995da Mon Sep 17 00:00:00 2001 From: Q Date: Wed, 25 Jun 2025 22:26:31 +0300 Subject: [PATCH] tracking --- tsmark/video_annotator.py | 282 +++++++++++++++++++++++++++----------- 1 file changed, 205 insertions(+), 77 deletions(-) diff --git a/tsmark/video_annotator.py b/tsmark/video_annotator.py index bd2baba..8db451b 100755 --- a/tsmark/video_annotator.py +++ b/tsmark/video_annotator.py @@ -282,7 +282,7 @@ class Marker: (current[1], current[2]), (current[3], current[4]), color, - 1, + 2, ) cv2.circle(frame, (current[6], current[7]), 10, color, 1) @@ -483,80 +483,13 @@ class Marker: if self.opts.output_points is None: return - old_nr = self.nr - - curr_point = self.get_point() - if curr_point[0] is None: - self.add_message("Not in point frame (green)") - return - - max_frames = int(min(self.point_tracking_length * self.fps, self.frames - self.nr - 1)) - cv2.namedWindow("tsmark - tracker", flags=cv2.WINDOW_AUTOSIZE | cv2.WINDOW_KEEPRATIO | cv2.WINDOW_GUI_NORMAL) - tracker = cv2.TrackerKCF_create() - - self.video_reader.set(cv2.CAP_PROP_POS_FRAMES, self.nr) - ok, frame = self.video_reader.read() - frame = cv2.resize(frame.copy(), self.video_res) - bbox = tuple([*curr_point[0:2], *curr_point[6:8]]) - ok = tracker.init(frame, bbox) - tracked = {} - for i in range(max_frames): - # Read a new frame - ok, frame = self.video_reader.read() - frame = cv2.resize(frame.copy(), self.video_res) - if not ok: - break - - ok, bbox = tracker.update(frame) - # Draw bounding box - if ok: - # Tracking success - p1 = (int(bbox[0]), int(bbox[1])) - p2 = (int(bbox[0] + bbox[2]), int(bbox[1] + bbox[3])) - cv2.rectangle(frame, p1, p2, (255, 0, 0), 2, 1) - tracked[i] = bbox - cv2.putText(frame, "Tracking...", (100, 80), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 0, 255), 2) - else: - # Tracking failure - cv2.putText( - frame, "Tracking failure detected", (100, 80), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 0, 255), 2 - ) - - # Display result - cv2.imshow("tsmark - tracker", frame) - - # Exit if ESC pressed - if cv2.waitKey(1) & 0xFF == ord("q"): # if press SPACE bar - break - - done = False - while True: - if done: - break - self.video_reader.set(cv2.CAP_PROP_POS_FRAMES, self.nr + 1) - for i in range(max_frames): - show_time = time.time() - ok, frame = self.video_reader.read() - frame = cv2.resize(frame.copy(), self.video_res) - cv2.putText(frame, "Replay...", (100, 80), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 0, 255), 2) - if i in tracked: - bbox = tracked[i] - p1 = (int(bbox[0]), int(bbox[1])) - p2 = (int(bbox[0] + bbox[2]), int(bbox[1] + bbox[3])) - cv2.rectangle(frame, p1, p2, (255, 0, 0), 2, 1) - cv2.imshow("tsmark - tracker", frame) - if cv2.waitKey(1) & 0xFF == ord("q"): # if press SPACE bar - done = True - break - - time_to_wait = self.viewer_spf - time.time() + show_time - if time_to_wait > 0: - time.sleep(time_to_wait) - - cv2.destroyWindow("tsmark - tracker") - - self.nr = old_nr - 1 - self.read_next = True + tracker_gui = TrackerGUI(self) + if len(tracker_gui.points) > 0: + for nr in tracker_gui.points: + self.points[self.point_index][nr] = tracker_gui.points[nr] + self.interpolate_points() + self.nr = max(tracker_gui.points)-1 + self.read_next = True def interpolate_points(self): @@ -936,7 +869,7 @@ class Marker: ret, frame = self.video_reader.read() if ret == True: - draw_wait = 200 if self.paused or self.point_click == 0 else 1 + draw_wait = 200 if self.paused or ( self.paused and self.point_click == 0 ) else 1 if (not self.paused) or self.read_next: self.read_next = False @@ -1037,7 +970,7 @@ class Marker: elif k & 0xFF == ord("f"): # modify FPS FPS_modifier = (FPS_modifier + 1) % len(FPS_modifiers) - self.add_message(f"Player speed {FPS_modifiers[FPS_modifier]}") + self.add_message(f"Player speed {round(1/FPS_modifiers[FPS_modifier],2)}") elif k & 0xFF == ord("a"): # toggle crop offset self.crop_click = 0 if self.crop_click == 1 else 1 self.crop[2] = True @@ -1064,6 +997,54 @@ class Marker: self.point_click = 0 else: self.point_index = chr(k2) + elif k & 0xFF == ord("g"): # Go to + self.shadow_text( + frame_visu, + "Enter frame or time", + (20, 70), + 0.9, + 2, + (255,255,255), + ) + cv2.imshow("tsmark", frame_visu) + entered_chars="" + while True: + frame_query = frame_visu.copy() + self.shadow_text( + frame_query, + entered_chars, + (20, 100), + 0.9, + 2, + (255,255,255), + ) + cv2.imshow("tsmark", frame_query) + del frame_query + k2 = cv2.waitKey(0) + if k2 & 0xFF == ord("q") or k2 & 0xFF == 27: + break + elif k2 & 0xFF == ord("g") or k2 & 0xFF == 13: + try: + self.nr = int(entered_chars) -1 + except ValueError: + try: + self.nr = self.parse_time(entered_chars) + except Exception: + self.add_message("Cannot parse time") + break + self.read_next = True + break + elif k2 & 0xFF == 8: # backspace + entered_chars = entered_chars[0:-1] + elif k2 & 0xFF in digits_ords: + entered_chars += str(digits_ords.index(k2 & 0xFF)) + elif k2 & 0xFF == ord(":"): + entered_chars += ":" + elif k2 & 0xFF == ord("."): + entered_chars += "." + else: + pass + elif k & 0xFF == ord("t"): # tracking self.track_point() @@ -1106,3 +1087,150 @@ class Marker: cv2.destroyAllWindows() self.print_timestamps() self.save_timestamps() + + +class TrackerGUI: + def __init__(self, marker): + + self.marker = marker + self.start() + + def start(self): + + + old_nr = self.marker.nr + + curr_point = self.marker.get_point() + if curr_point[0] is None: + self.marker.add_message("Not in point frame (green)") + return + + max_frames = int(min(self.marker.point_tracking_length * self.marker.fps, self.marker.frames - self.marker.nr - 1)) + cv2.namedWindow("tsmark - tracker", flags=cv2.WINDOW_AUTOSIZE | cv2.WINDOW_KEEPRATIO | cv2.WINDOW_GUI_NORMAL) + tracker = cv2.TrackerKCF_create() + + self.marker.video_reader.set(cv2.CAP_PROP_POS_FRAMES, self.marker.nr) + ok, frame = self.marker.video_reader.read() + frame = cv2.resize(frame.copy(), self.marker.video_res) + bbox = tuple([*curr_point[0:2], *curr_point[6:8]]) + ok = tracker.init(frame, bbox) + tracked = {} + for i in range(max_frames): + # Read a new frame + ok, frame = self.marker.video_reader.read() + frame = cv2.resize(frame.copy(), self.marker.video_res) + if not ok: + break + + ok, bbox = tracker.update(frame) + # Draw bounding box + if ok: + # Tracking success + p1 = (int(bbox[0]), int(bbox[1])) + p2 = (int(bbox[0] + bbox[2]), int(bbox[1] + bbox[3])) + cv2.rectangle(frame, p1, p2, (255, 0, 0), 2, 1) + tracked[i] = [*bbox,1] + cv2.putText(frame, "Tracking...", (100, 80), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 0, 255), 2) + else: + # Tracking failure + cv2.putText( + frame, "Tracking failure detected", (100, 80), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 0, 255), 2 + ) + + # Display result + cv2.imshow("tsmark - tracker", frame) + + # Exit if ESC pressed + if cv2.waitKey(1) & 0xFF == ord("q"): # if press SPACE bar + break + + done = False + paused = False + seek = False + cut_after = max_frames + while True: + if done: + break + self.marker.video_reader.set(cv2.CAP_PROP_POS_FRAMES, self.marker.nr + 1) + i = 0 + while True: + show_time = time.time() + if done: + break + if paused: + frame = frame_copy.copy() + if (not paused) or seek: + ok, frame = self.marker.video_reader.read() + frame = cv2.resize(frame.copy(), self.marker.video_res) + frame_copy = frame.copy() + i += 1 + seek = False + + cv2.putText(frame, f"Replay... {i}", (100, 80), cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 0, 255), 2) + if i in tracked: + bbox = tracked[i] + p1 = (int(bbox[0]), int(bbox[1])) + p2 = (int(bbox[0] + bbox[2]), int(bbox[1] + bbox[3])) + color = (0,255,0) if cut_after > i else (0, 192, 192) + thicc = 2 if cut_after > i else 1 + cv2.rectangle(frame, p1, p2, color, thicc, 1) + cv2.imshow("tsmark - tracker", frame) + k = cv2.waitKey(1) + if k & 0xFF == ord("q"): # if press SPACE bar + done = True + break + elif k & 0xFF == 32: # space + paused = not paused + # Movement ================= + elif k & 0xFF == 83 or k & 0xFF == ord("l"): # right arrow + i += int(self.marker.fps) - 1 + seek = True + elif k & 0xFF == 81 or k & 0xFF == ord("j"): # left arrow + i -= int(self.marker.fps) + 1 + seek = True + # Move by frame + elif k & 0xFF == ord("."): + paused = True + seek = True + elif k & 0xFF == ord(","): + paused = True + i -= 2 + seek = True + elif k & 0xFF == ord("x"): + cut_after = i + #if i in tracked: + # tracked[i][4] = 1 - tracked[i][4] + + time_to_wait = self.marker.viewer_spf - time.time() + show_time + if time_to_wait > 0: + time.sleep(time_to_wait) + + if i >= max_frames: + i = max_frames-1 + paused = True + seek = True + if i<0: + i=0 + paused = True + seek = True + + if seek: + self.marker.video_reader.set(cv2.CAP_PROP_POS_FRAMES, self.marker.nr + 1 + i) + + + cv2.destroyWindow("tsmark - tracker") + + self.marker.nr = old_nr - 1 + self.marker.read_next = True + self.points = {} + for i in sorted(list(tracked.keys())): + if i >= cut_after: + continue + self.points[self.marker.nr+1+i] = [ + tracked[i][0], + tracked[i][1], + tracked[i][0]+tracked[i][2], + tracked[i][1]+tracked[i][3], + ] + +