diff --git a/norfair/common_reference_ui.py b/norfair/common_reference_ui.py new file mode 100644 index 00000000..a9936c38 --- /dev/null +++ b/norfair/common_reference_ui.py @@ -0,0 +1,711 @@ +# from tkinter import +import tkinter as tk +from copy import deepcopy + +import cv2 +import numpy as np +from PIL import Image, ImageTk, UnidentifiedImageError + +from norfair import Video +from norfair.camera_motion import HomographyTransformationGetter, TransformationGetter + +transformation = None + +window = None + +button_finish = None + +reference_point_canvas = None +footage_point_canvas = None + +canvas_reference = None +canvas_footage = None + +reference_original_size = None +reference_canvas_size = None +footage_original_size = None +footage_canvas_size = None + +footage_point = None +reference_point = None + +skipper = None + +points = None +points_sampled = None + +mode_annotate = None + +frame_options_annotations = None +handling_mark_functions = None +handle_mark_annotation = None + + +def set_reference( + reference: str, + footage: str, + transformation_getter: TransformationGetter = None, + detector=None, + desired_size=700, + motion_estimator=None, +): + + global window + + global transformation + + global button_finish + + global reference_point_canvas + global footage_point_canvas + + global canvas_reference + global canvas_footage + + global reference_original_size + global reference_canvas_size + global footage_original_size + global footage_canvas_size + + global footage_point + global reference_point + + global skipper + + global points + global points_sampled + + global mode_annotate + + global frame_options_annotations + global handling_mark_functions + global handle_mark_annotation + + if transformation_getter is None: + transformation_getter = HomographyTransformationGetter( + method=cv2.RANSAC, + ransac_reproj_threshold=1000, + max_iters=2000, + confidence=0.995, + proportion_points_used_threshold=0.9, + ) + + skipper = {} + + desired_size = 700 + radius = max(int(desired_size / 100), 1) + + points = {} + points_sampled = len(points) + + transformation = None + + window = tk.Tk() + + frame_options = tk.Frame() + frame_images = tk.Frame() + frame_options_annotations = tk.Frame(master=frame_options) + + # utilities + + def estimate_transformation(points): + global button_finish + if len(points) >= 4: + curr_pts = np.array( + [point["reference"] for point in points.values()] + ) # use current points as reference points + prev_pts = np.array( + [point["footage"] for point in points.values()] + ) # use previous points as footage points (to deduce reference -> footage) + + try: + + button_finish.configure(fg="black", highlightbackground="green") + return transformation_getter(curr_pts, prev_pts)[1] + except np.linalg.LinAlgError: + button_finish.configure( + fg="grey", highlightbackground="SystemButtonFace" + ) + return None + else: + button_finish.configure(fg="grey", highlightbackground="SystemButtonFace") + return None + + def test_transformation( + change_of_coordinates, canvas, point, original_size, canvas_size + ): + point_in_new_coordinates = change_of_coordinates(np.array([point]))[0] + point_in_canvas_coordinates = np.multiply( + point_in_new_coordinates, + np.array( + [canvas_size[0] / original_size[0], canvas_size[1] / original_size[1]] + ), + ).astype(int) + + draw_point_in_canvas(canvas, point_in_canvas_coordinates, "blue") + + def remove_drawings_in_canvas(canvas): + if len(canvas.find_withtag("myPoint")) > 0: + canvas.delete("myPoint") + + def draw_point_in_canvas(canvas, point, color="green"): + remove_drawings_in_canvas(canvas) + canvas.create_oval( + point[0] - radius, + point[1] - radius, + point[0] + radius, + point[1] + radius, + fill=color, + tags="myPoint", + ) + + ######### MAKSE SUBBLOCK TO FINISH + + frame_options_finish = tk.Frame(master=frame_options) + + space = tk.Label( + master=frame_options_finish, + text="", + foreground="white", + width=40, + height=1, + ) + button_finish = tk.Button( + master=frame_options_finish, + text="Finished!", + width=30, + height=1, + bg="blue", + fg="gray", + command=lambda: handle_finish(), + ) + + def handle_finish(): + global window + global transformation + + if transformation is not None: + window.destroy() + for info in skipper.values(): + if info["video"] is not None: + info["video"].video_capture.release() + cv2.destroyAllWindows() + return transformation + else: + print("Can't leave without estimating the transformation.") + + space.pack(side=tk.TOP) + button_finish.pack(side=tk.TOP) + frame_options_finish.pack(side=tk.BOTTOM) + + ###### MAKE SUBBLOCK TO SEE POINTS AND CHOOSE THEM + def handle_mark_annotation(key): + def handle_annotation(event): + points[key]["marked"] = not points[key]["marked"] + + if points[key]["marked"]: + points[key]["button"].configure(fg="black", highlightbackground="red") + draw_point_in_canvas( + canvas_footage, points[key]["footage_canvas"], color="red" + ) + draw_point_in_canvas( + canvas_reference, points[key]["reference_canvas"], color="red" + ) + else: + points[key]["button"].configure( + fg="black", highlightbackground="SystemButtonFace" + ) + canvas_footage.delete("myPoint") + canvas_reference.delete("myPoint") + + return handle_annotation + + handling_mark_functions = {} + for key, couple in points.items(): + + handling_mark_functions[key] = handle_mark_annotation(key) + + new_button = tk.Button( + master=frame_options_annotations, + text=f"{key}: reference {couple['reference']} <-> footage {couple['footage']}", + width=35, + height=1, + bg="blue", + fg="black", + highlightbackground="SystemButtonFace", + ) + + new_button.bind("