Web platform for sharing free data for ML and research

By using this site, you agree to have cookies stored on your device, strictly for functional purposes, such as storing your session and preferences.

Dismiss

 picture-annotation.py

View raw Download
text/x-script.python • 5.03 kiB
Python script, ASCII text executable
        
            
1
from pyscript import document
2
from pyodide.ffi import create_proxy
3
4
document.getElementById("shape-options").style.display = "flex"
5
6
image = document.getElementById("annotation-image")
7
zone = document.getElementById("annotation-zone")
8
confirm_button = document.getElementById("annotation-confirm")
9
cancel_button = document.getElementById("annotation-cancel")
10
11
confirm_button.style.display = "none"
12
cancel_button.style.display = "none"
13
14
shape_type = ""
15
bbox_pos = None
16
new_shape = None
17
18
19
def follow_cursor(event):
20
rect = zone.getBoundingClientRect()
21
x = event.clientX - rect.left
22
y = event.clientY - rect.top
23
vertical_ruler.style.left = str(x) + "px"
24
horizontal_ruler.style.top = str(y) + "px"
25
26
27
# These are functions usable in JS
28
cancel_bbox_proxy = create_proxy(lambda event: cancel_bbox(event))
29
make_bbox_proxy = create_proxy(lambda event: make_bbox(event))
30
follow_cursor_proxy = create_proxy(follow_cursor)
31
32
33
def switch_shape(event):
34
global shape_type
35
shape = event.currentTarget.id
36
shape_type = shape
37
print("Shape is now of type:", shape)
38
39
vertical_ruler = document.getElementById("annotation-ruler-vertical")
40
horizontal_ruler = document.getElementById("annotation-ruler-horizontal")
41
vertical_ruler_2 = document.getElementById("annotation-ruler-vertical-secondary")
42
horizontal_ruler_2 = document.getElementById("annotation-ruler-horizontal-secondary")
43
helper_message = document.getElementById("annotation-helper-message")
44
45
helper_message.innerText = "Select a shape type then click on the image to begin defining it"
46
47
48
def cancel_bbox(event):
49
global bbox_pos, new_shape
50
51
if new_shape is not None and event is not None:
52
# Require event so the shape is kept when it ends normally
53
new_shape.remove()
54
new_shape = None
55
zone.removeEventListener("click", make_bbox_proxy)
56
document.removeEventListener("keydown", cancel_bbox_proxy)
57
cancel_button.removeEventListener("click", cancel_bbox_proxy)
58
59
bbox_pos = None
60
vertical_ruler.style.display = "none"
61
horizontal_ruler.style.display = "none"
62
vertical_ruler_2.style.display = "none"
63
horizontal_ruler_2.style.display = "none"
64
document.body.style.cursor = "auto"
65
cancel_button.style.display = "none"
66
helper_message.innerText = "Select a shape type then click on the image to begin defining it"
67
68
def make_bbox(event):
69
global new_shape, bbox_pos
70
zone_rect = zone.getBoundingClientRect()
71
72
if bbox_pos is None:
73
helper_message.innerText = "Now define the second point"
74
75
bbox_pos = [(event.clientX - zone_rect.left) / zone_rect.width,
76
(event.clientY - zone_rect.top) / zone_rect.height]
77
vertical_ruler_2.style.left = str(bbox_pos[0] * 100) + "%"
78
horizontal_ruler_2.style.top = str(bbox_pos[1] * 100) + "%"
79
vertical_ruler_2.style.display = "block"
80
horizontal_ruler_2.style.display = "block"
81
82
else:
83
x0, y0 = bbox_pos.copy()
84
x1 = (event.clientX - zone_rect.left) / zone_rect.width
85
y1 = (event.clientY - zone_rect.top) / zone_rect.height
86
87
rectangle = document.createElementNS("http://www.w3.org/2000/svg", "rect")
88
89
new_shape.appendChild(rectangle)
90
zone.appendChild(new_shape)
91
92
minx = min(x0, x1)
93
miny = min(y0, y1)
94
maxx = max(x0, x1)
95
maxy = max(y0, y1)
96
97
rectangle.setAttribute("x", str(minx * image.naturalWidth))
98
rectangle.setAttribute("y", str(miny * image.naturalHeight))
99
rectangle.setAttribute("width", str((maxx - minx) * image.naturalWidth))
100
rectangle.setAttribute("height", str((maxy - miny) * image.naturalHeight))
101
rectangle.setAttribute("fill", "none")
102
rectangle.classList.add("shape-bbox")
103
104
cancel_bbox(None)
105
106
def open_shape(event):
107
global new_shape, bbox_pos
108
if bbox_pos:
109
return
110
print("Creating a new shape of type:", shape_type)
111
new_shape = document.createElementNS("http://www.w3.org/2000/svg", "svg")
112
new_shape.setAttribute("width", "100%")
113
new_shape.setAttribute("height", "100%")
114
zone_rect = zone.getBoundingClientRect()
115
new_shape.setAttribute("viewBox", f"0 0 {image.naturalWidth} {image.naturalHeight}")
116
117
if shape_type == "shape-bbox":
118
helper_message.innerText = ("Define the first point at the intersection of the lines "
119
"by clicking on the image, or click the cross to cancel")
120
121
cancel_button.addEventListener("click", cancel_bbox_proxy)
122
document.addEventListener("keydown", cancel_bbox_proxy)
123
cancel_button.style.display = "block"
124
bbox_pos = None
125
zone.addEventListener("click", make_bbox_proxy)
126
vertical_ruler.style.display = "block"
127
horizontal_ruler.style.display = "block"
128
document.body.style.cursor = "crosshair"
129
130
131
for button in list(document.getElementById("shape-selector").children):
132
button.addEventListener("click", create_proxy(switch_shape))
133
print("Shape", button.id, "is available")
134
135
136
zone.addEventListener("mousemove", follow_cursor_proxy)
137
zone.addEventListener("click", create_proxy(open_shape))
138