File size: 9,186 Bytes
b27cd24
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
import cv2
import tkinter as tk
from tkinter import ttk
import os
import json

# === CONFIGURATION ===
image_folder = "ImagesOnline"   # <- Change this to your image folder path
image_extensions = (".jpg", ".jpeg", ".png", ".bmp")

# === IMAGE LIST ===
image_files = [os.path.join(image_folder, f) for f in os.listdir(image_folder) if f.lower().endswith(image_extensions)]
image_files.sort()  # Optional: sort the images

output_folder = "GT_json"
os.makedirs(output_folder, exist_ok=True)

# === MAIN LOOP ===
for image_path in image_files:
    image_base = os.path.splitext(os.path.basename(image_path))[0]
    json_output_path = os.path.join(output_folder, f"{image_base}.json")

    # Skip if already annotated
    if os.path.exists(json_output_path):
        print(f"Skipping {image_path} (annotation exists)")
        continue

    print(f"\n=== Processing: {image_path} ===")

    # Reset global variables for each image
    start_point = None
    end_point = None
    drawing = False

    # Load the image
    image = cv2.imread(image_path)
    clone = image.copy()
    original_height, original_width = image.shape[:2]

    # Prepare annotation dictionary
    annotation = {
        "line_shape": {
            "turns": None,
            "description": None
        },
        "people": {
            "number_of_people": None,
            "direction_they_are_facing": None,
            "start_person_description": None,
            "end_person_description": None,
            "counter_person_description": None
        },
        "boundary": {
            "boundary_present": None,
            "boundary_types": None
        },
        "start_of_line": {
            "visible": None,
            "location_if_visible": None,
            "direction_to_turn_if_not_visible": None
        },
        "end_of_line": {
            "visible": None,
            "location_if_visible": None,
            "direction_to_turn_if_not_visible": None
        },
        "line_purpose": None,
        "line_completeness": None,
        "line_coordinates": None  # Set in draw_line()
    }

    # === Define Functions ===

    def submit_annotations(entries):
        annotation["line_shape"]["turns"] = int(entries["Number of turns"].get())
        annotation["line_shape"]["description"] = entries["Line shape"].get()

        annotation["people"]["number_of_people"] = int(entries["Number of people in line"].get())
        annotation["people"]["direction_they_are_facing"] = entries["What direction is the line facing"].get()
        annotation["people"]["start_person_description"] = entries["Description of the person at the start of the line"].get()
        annotation["people"]["end_person_description"] = entries["Description of the person at the end of the line"].get()
        annotation["people"]["counter_person_description"] = entries["Description of the person at the counter"].get()

        annotation["line_purpose"] = entries["Line purpose"].get()

        annotation["boundary"]["boundary_present"] = entries["Is there a boundary?"].get().lower() == "yes"
        annotation["boundary"]["boundary_types"] = entries["Boundary types"].get()

        annotation["end_of_line"]["visible"] = entries["Do we see the end of line?"].get()
        annotation["end_of_line"]["location_if_visible"] = entries["If yes, where is the end of the line in the image?"].get()
        annotation["end_of_line"]["direction_to_turn_if_not_visible"] = entries["If not, in what direction should you move camera to see the end of the line?"].get()

        annotation["start_of_line"]["visible"] = entries["Do we see the start of line?"].get()
        annotation["start_of_line"]["location_if_visible"] = entries["If yes, where is the start of the line in the image?"].get()
        annotation["start_of_line"]["direction_to_turn_if_not_visible"] = entries["If not, in what direction should you move camera to see the start of the line?"].get()

        annotation["line_completeness"] = entries["Does the image show a full line or partial line?"].get()

        print("Annotation Properties:", annotation)

        image_base = os.path.splitext(os.path.basename(image_path))[0]
        json_output_path = os.path.join(output_folder, f"{image_base}.json")
        with open(json_output_path, "w") as f:
            json.dump(annotation, f, indent=4)
        print(f"Saved annotation to {image_base}.json")

        # Close GUI when submit is clicked
        root.destroy()

    def setup_annotation_gui():
        global root
        root = tk.Tk()
        root.title(f"Annotation Input: {os.path.basename(image_path)}")
        root.resizable(True, True)
        fields = {
            "Number of turns": tk.Entry,
            "Line shape": ttk.Combobox,
            "What direction is the line facing": ttk.Combobox,
            "Number of people in line": tk.Entry,
            "Line purpose": tk.Entry,
            "Description of the person at the start of the line": tk.Entry,
            "Description of the person at the end of the line": tk.Entry,
            "Description of the person at the counter": tk.Entry,
            "Is there a boundary?": ttk.Combobox,
            "Boundary types": ttk.Combobox,
            "Do we see the end of line?": ttk.Combobox,
            "If yes, where is the end of the line in the image?": ttk.Combobox,
            "If not, in what direction should you move camera to see the end of the line?": ttk.Combobox,
            "Do we see the start of line?": ttk.Combobox,
            "If yes, where is the start of the line in the image?": ttk.Combobox,
            "If not, in what direction should you move camera to see the start of the line?": ttk.Combobox,
            "Does the image show a full line or partial line?": ttk.Combobox
        }
        options = {
            "Line shape": ["Straight", "Curved", "S-shaped", "Angled","other"],
            "What direction is the line facing": ["Facing towards","Facing away","Facing sideways","other"],
            "Is there a boundary?": ["yes", "no"],
            "Boundary types": ["none", "cones", "rope dividers", "stanchions","other"],
            "Do we see the end of line?": ["yes", "no"],
            "If yes, where is the end of the line in the image?": ["far left", "center left", "center", "center right", "far right","N/A"],
            "If not, in what direction should you move camera to see the end of the line?": ["left", "right","back","N/A"],
            "Do we see the start of line?": ["yes", "no"],
            "If yes, where is the start of the line in the image?": ["far left", "center left", "center", "center right", "far right","N/A"],
            "If not, in what direction should you move camera to see the start of the line?": ["left", "right","back","N/A"],
            "Does the image show a full line or partial line?": ["full", "partial"]
        }
        entries = {}
        for field, widget_type in fields.items():
            row = tk.Frame(root)
            label = tk.Label(row, width=70, text=field, anchor='w')
            if field in options:
                entry = widget_type(row, values=options[field], state="readonly")
                entry.set(options[field][0])
            else:
                entry = widget_type(row)
            row.pack(side=tk.TOP, fill=tk.X, padx=5, pady=5)
            label.pack(side=tk.LEFT)
            entry.pack(side=tk.RIGHT, expand=tk.YES, fill=tk.X)
            entries[field] = entry
        submit_button = tk.Button(root, text="Submit", command=lambda: submit_annotations(entries))
        submit_button.pack(side=tk.BOTTOM, pady=10)
        root.update()
        return root

    def draw_line(event, x, y, flags, param):
        global start_point, end_point, drawing, image
        if event == cv2.EVENT_LBUTTONDOWN:
            if start_point is None:
                start_point = (x, y)
                cv2.circle(image, start_point, 5, (255, 0, 0), -1)  # Blue dot
                cv2.imshow("Annotation Tool", image)
            else:
                end_point = (x, y)
                cv2.arrowedLine(image, start_point, end_point, color=(0, 0, 255), thickness=2, line_type=cv2.LINE_AA, tipLength=0.05)
                cv2.imshow("Annotation Tool", image)

                # Save line coordinates
                annotation["line_coordinates"] = {
                    "start": {"x": start_point[0], "y": start_point[1]},
                    "end": {"x": end_point[0], "y": end_point[1]}
                }
                print(f"Line coordinates saved: Start - {start_point}, End - {end_point}")

    # === Setup drawing window (image size)
    cv2.namedWindow("Annotation Tool", cv2.WINDOW_NORMAL)
    cv2.imshow("Annotation Tool", image)
    cv2.setMouseCallback("Annotation Tool", draw_line)

    # === Setup annotation GUI
    gui = setup_annotation_gui()

    # === Start GUI loop
    gui.mainloop()

    # === Cleanup OpenCV window
    cv2.destroyAllWindows()

print("\nAll images processed!")