├── README.md
├── data
└── anchors.csv
├── demo.gif
├── demo_3D.gif
├── demo_process_video.py
├── demo_process_video_3D.py
├── models
├── hand_landmark.tflite
├── hand_landmark_3d.tflite
└── palm_detection_without_custom_op.tflite
└── src
├── multi_hand_tracker.py
└── plot_hand.py
/README.md:
--------------------------------------------------------------------------------
1 | # IMPORTANT
2 | This project is no longer being maintained as Mediapipe has since added [Python bindings](https://google.github.io/mediapipe/getting_started/python_framework.html) and [handedness detection](https://github.com/google/mediapipe/releases/tag/v0.7.5) which works faster and better than the hacks used here. Furthermore, Mediapipe has since [improved their handtracking models](https://github.com/google/mediapipe/releases/tag/0.8.0). This project will remain in it's current state as a study of models from Mediapipe.
3 |
4 | # Multi Hand Tracker on Python
5 |
6 | Python wrapper for Google's [Mediapipe Multi-Hand Tracking](https://github.com/google/mediapipe/blob/master/mediapipe/docs/multi_hand_tracking_mobile_gpu.md) pipeline. There are 2 predictor classes available. ```MultiHandTracker``` which predicts 2D keypoints and ```MultiHandTracker3D``` which predicts 3D keypoints. Keypoints generated from ```MultiHandTracker3D``` can be fed into ```is_right_hand``` to determine handedness (distinguish between right and left hand). ```is_right_hand``` is not part of Mediapipe's pipeline but I thought it'll be useful.
7 |
8 | This code is built upon [Metal Whale's](https://github.com/metalwhale/hand_tracking) python wrapper for [Mediapipe Hand Tracking](https://github.com/google/mediapipe/blob/master/mediapipe/docs/hand_tracking_mobile_gpu.md).
9 |
10 | ## Getting Started
11 |
12 | Basic usage, processing a single image for 2D keypoint predictions:
13 | ``` python
14 | from PIL import Image
15 | import numpy as np
16 | import multi_hand_tracker as mht
17 | import plot_hand
18 |
19 | img_path = "./test_pic.jpg"
20 | img = Image.open(img_path)
21 | img = np.array(img)
22 |
23 | palm_model_path = "./models/palm_detection_without_custom_op.tflite"
24 | landmark_model_path = "./models/hand_landmark.tflite"
25 | anchors_path = "./data/anchors.csv"
26 |
27 | # Initialise detector
28 | # the independent flag makes the detector process each image independently
29 | detector = mht.MultiHandTracker(palm_model_path, landmark_model_path, anchors_path, independent = True)
30 |
31 | # Get predictions
32 | kp_list, box_list = detector(img)
33 |
34 | # Plot predictions
35 | plot_hand.plot_img(img, kp_list, box_list)
36 | ```
37 |
38 | Basic usage, processing a single image for 3D keypoint predictions and determining handedness:
39 | ```python
40 | from PIL import Image
41 | import numpy as np
42 | import multi_hand_tracker as mht
43 | import plot_hand
44 |
45 | img_path = "./test_pic.jpg"
46 | img = Image.open(img_path)
47 | img = np.array(img)
48 |
49 | palm_model_path = "./models/palm_detection_without_custom_op.tflite"
50 | landmark_model_path = "./models/hand_landmark_3D.tflite"
51 | anchors_path = "./data/anchors.csv"
52 |
53 | # Initialise detector
54 | # independent flag not implemented for MultiHandTracker3D
55 | detector = mht.MultiHandTracker3D(palm_model_path, landmark_model_path, anchors_path)
56 |
57 | # Get predictions
58 | kp_list, box_list = detector(img)
59 |
60 | # Determine handedness of each prediction
61 | is_right = [mht.is_right_hand(kp) for kp in kp_list]
62 |
63 | # Plot predictions
64 | plot_hand.plot_img(img, kp_list, box_list, is_right=is_right)
65 | ```
66 |
67 | ### Requirements
68 |
69 | These are required to use the HandTracker module
70 |
71 | ```
72 | numpy
73 | opencv
74 | tensorflow
75 | shapely
76 | scipy
77 | ```
78 | To use the plotting functions you would need `matplotlib`
79 |
80 | ## Results
81 |
82 | Predictions from ```MultiHandTracker```:
83 |
84 |
85 |
86 | Video from [Signing Savvy](https://www.signingsavvy.com/sign/HAVE%20A%20GOOD%20DAY/8194/1).
87 |
88 | Predictions from ```MultiHandTracker3D```:
89 |
90 |
91 |
92 | Video from [Signing Savvy](https://www.signingsavvy.com/search/happy%2Bbirthday%2Bto%2Byou).
93 |
94 | Not very good when the hands occlude each other.
95 |
96 |
97 | ## Acknowledgments
98 |
99 | This work is a study of models developed by Google and distributed as a part of the [Mediapipe](https://github.com/google/mediapipe) framework.
100 | @metalwhale for the Python Wrapper for single hand tracking and for removing custom operations for the Palm Detections model.
101 |
--------------------------------------------------------------------------------
/data/anchors.csv:
--------------------------------------------------------------------------------
1 | 0.015625,0.015625,1,1
2 | 0.015625,0.015625,1,1
3 | 0.046875,0.015625,1,1
4 | 0.046875,0.015625,1,1
5 | 0.078125,0.015625,1,1
6 | 0.078125,0.015625,1,1
7 | 0.109375,0.015625,1,1
8 | 0.109375,0.015625,1,1
9 | 0.140625,0.015625,1,1
10 | 0.140625,0.015625,1,1
11 | 0.171875,0.015625,1,1
12 | 0.171875,0.015625,1,1
13 | 0.203125,0.015625,1,1
14 | 0.203125,0.015625,1,1
15 | 0.234375,0.015625,1,1
16 | 0.234375,0.015625,1,1
17 | 0.265625,0.015625,1,1
18 | 0.265625,0.015625,1,1
19 | 0.296875,0.015625,1,1
20 | 0.296875,0.015625,1,1
21 | 0.328125,0.015625,1,1
22 | 0.328125,0.015625,1,1
23 | 0.359375,0.015625,1,1
24 | 0.359375,0.015625,1,1
25 | 0.390625,0.015625,1,1
26 | 0.390625,0.015625,1,1
27 | 0.421875,0.015625,1,1
28 | 0.421875,0.015625,1,1
29 | 0.453125,0.015625,1,1
30 | 0.453125,0.015625,1,1
31 | 0.484375,0.015625,1,1
32 | 0.484375,0.015625,1,1
33 | 0.515625,0.015625,1,1
34 | 0.515625,0.015625,1,1
35 | 0.546875,0.015625,1,1
36 | 0.546875,0.015625,1,1
37 | 0.578125,0.015625,1,1
38 | 0.578125,0.015625,1,1
39 | 0.609375,0.015625,1,1
40 | 0.609375,0.015625,1,1
41 | 0.640625,0.015625,1,1
42 | 0.640625,0.015625,1,1
43 | 0.671875,0.015625,1,1
44 | 0.671875,0.015625,1,1
45 | 0.703125,0.015625,1,1
46 | 0.703125,0.015625,1,1
47 | 0.734375,0.015625,1,1
48 | 0.734375,0.015625,1,1
49 | 0.765625,0.015625,1,1
50 | 0.765625,0.015625,1,1
51 | 0.796875,0.015625,1,1
52 | 0.796875,0.015625,1,1
53 | 0.828125,0.015625,1,1
54 | 0.828125,0.015625,1,1
55 | 0.859375,0.015625,1,1
56 | 0.859375,0.015625,1,1
57 | 0.890625,0.015625,1,1
58 | 0.890625,0.015625,1,1
59 | 0.921875,0.015625,1,1
60 | 0.921875,0.015625,1,1
61 | 0.953125,0.015625,1,1
62 | 0.953125,0.015625,1,1
63 | 0.984375,0.015625,1,1
64 | 0.984375,0.015625,1,1
65 | 0.015625,0.046875,1,1
66 | 0.015625,0.046875,1,1
67 | 0.046875,0.046875,1,1
68 | 0.046875,0.046875,1,1
69 | 0.078125,0.046875,1,1
70 | 0.078125,0.046875,1,1
71 | 0.109375,0.046875,1,1
72 | 0.109375,0.046875,1,1
73 | 0.140625,0.046875,1,1
74 | 0.140625,0.046875,1,1
75 | 0.171875,0.046875,1,1
76 | 0.171875,0.046875,1,1
77 | 0.203125,0.046875,1,1
78 | 0.203125,0.046875,1,1
79 | 0.234375,0.046875,1,1
80 | 0.234375,0.046875,1,1
81 | 0.265625,0.046875,1,1
82 | 0.265625,0.046875,1,1
83 | 0.296875,0.046875,1,1
84 | 0.296875,0.046875,1,1
85 | 0.328125,0.046875,1,1
86 | 0.328125,0.046875,1,1
87 | 0.359375,0.046875,1,1
88 | 0.359375,0.046875,1,1
89 | 0.390625,0.046875,1,1
90 | 0.390625,0.046875,1,1
91 | 0.421875,0.046875,1,1
92 | 0.421875,0.046875,1,1
93 | 0.453125,0.046875,1,1
94 | 0.453125,0.046875,1,1
95 | 0.484375,0.046875,1,1
96 | 0.484375,0.046875,1,1
97 | 0.515625,0.046875,1,1
98 | 0.515625,0.046875,1,1
99 | 0.546875,0.046875,1,1
100 | 0.546875,0.046875,1,1
101 | 0.578125,0.046875,1,1
102 | 0.578125,0.046875,1,1
103 | 0.609375,0.046875,1,1
104 | 0.609375,0.046875,1,1
105 | 0.640625,0.046875,1,1
106 | 0.640625,0.046875,1,1
107 | 0.671875,0.046875,1,1
108 | 0.671875,0.046875,1,1
109 | 0.703125,0.046875,1,1
110 | 0.703125,0.046875,1,1
111 | 0.734375,0.046875,1,1
112 | 0.734375,0.046875,1,1
113 | 0.765625,0.046875,1,1
114 | 0.765625,0.046875,1,1
115 | 0.796875,0.046875,1,1
116 | 0.796875,0.046875,1,1
117 | 0.828125,0.046875,1,1
118 | 0.828125,0.046875,1,1
119 | 0.859375,0.046875,1,1
120 | 0.859375,0.046875,1,1
121 | 0.890625,0.046875,1,1
122 | 0.890625,0.046875,1,1
123 | 0.921875,0.046875,1,1
124 | 0.921875,0.046875,1,1
125 | 0.953125,0.046875,1,1
126 | 0.953125,0.046875,1,1
127 | 0.984375,0.046875,1,1
128 | 0.984375,0.046875,1,1
129 | 0.015625,0.078125,1,1
130 | 0.015625,0.078125,1,1
131 | 0.046875,0.078125,1,1
132 | 0.046875,0.078125,1,1
133 | 0.078125,0.078125,1,1
134 | 0.078125,0.078125,1,1
135 | 0.109375,0.078125,1,1
136 | 0.109375,0.078125,1,1
137 | 0.140625,0.078125,1,1
138 | 0.140625,0.078125,1,1
139 | 0.171875,0.078125,1,1
140 | 0.171875,0.078125,1,1
141 | 0.203125,0.078125,1,1
142 | 0.203125,0.078125,1,1
143 | 0.234375,0.078125,1,1
144 | 0.234375,0.078125,1,1
145 | 0.265625,0.078125,1,1
146 | 0.265625,0.078125,1,1
147 | 0.296875,0.078125,1,1
148 | 0.296875,0.078125,1,1
149 | 0.328125,0.078125,1,1
150 | 0.328125,0.078125,1,1
151 | 0.359375,0.078125,1,1
152 | 0.359375,0.078125,1,1
153 | 0.390625,0.078125,1,1
154 | 0.390625,0.078125,1,1
155 | 0.421875,0.078125,1,1
156 | 0.421875,0.078125,1,1
157 | 0.453125,0.078125,1,1
158 | 0.453125,0.078125,1,1
159 | 0.484375,0.078125,1,1
160 | 0.484375,0.078125,1,1
161 | 0.515625,0.078125,1,1
162 | 0.515625,0.078125,1,1
163 | 0.546875,0.078125,1,1
164 | 0.546875,0.078125,1,1
165 | 0.578125,0.078125,1,1
166 | 0.578125,0.078125,1,1
167 | 0.609375,0.078125,1,1
168 | 0.609375,0.078125,1,1
169 | 0.640625,0.078125,1,1
170 | 0.640625,0.078125,1,1
171 | 0.671875,0.078125,1,1
172 | 0.671875,0.078125,1,1
173 | 0.703125,0.078125,1,1
174 | 0.703125,0.078125,1,1
175 | 0.734375,0.078125,1,1
176 | 0.734375,0.078125,1,1
177 | 0.765625,0.078125,1,1
178 | 0.765625,0.078125,1,1
179 | 0.796875,0.078125,1,1
180 | 0.796875,0.078125,1,1
181 | 0.828125,0.078125,1,1
182 | 0.828125,0.078125,1,1
183 | 0.859375,0.078125,1,1
184 | 0.859375,0.078125,1,1
185 | 0.890625,0.078125,1,1
186 | 0.890625,0.078125,1,1
187 | 0.921875,0.078125,1,1
188 | 0.921875,0.078125,1,1
189 | 0.953125,0.078125,1,1
190 | 0.953125,0.078125,1,1
191 | 0.984375,0.078125,1,1
192 | 0.984375,0.078125,1,1
193 | 0.015625,0.109375,1,1
194 | 0.015625,0.109375,1,1
195 | 0.046875,0.109375,1,1
196 | 0.046875,0.109375,1,1
197 | 0.078125,0.109375,1,1
198 | 0.078125,0.109375,1,1
199 | 0.109375,0.109375,1,1
200 | 0.109375,0.109375,1,1
201 | 0.140625,0.109375,1,1
202 | 0.140625,0.109375,1,1
203 | 0.171875,0.109375,1,1
204 | 0.171875,0.109375,1,1
205 | 0.203125,0.109375,1,1
206 | 0.203125,0.109375,1,1
207 | 0.234375,0.109375,1,1
208 | 0.234375,0.109375,1,1
209 | 0.265625,0.109375,1,1
210 | 0.265625,0.109375,1,1
211 | 0.296875,0.109375,1,1
212 | 0.296875,0.109375,1,1
213 | 0.328125,0.109375,1,1
214 | 0.328125,0.109375,1,1
215 | 0.359375,0.109375,1,1
216 | 0.359375,0.109375,1,1
217 | 0.390625,0.109375,1,1
218 | 0.390625,0.109375,1,1
219 | 0.421875,0.109375,1,1
220 | 0.421875,0.109375,1,1
221 | 0.453125,0.109375,1,1
222 | 0.453125,0.109375,1,1
223 | 0.484375,0.109375,1,1
224 | 0.484375,0.109375,1,1
225 | 0.515625,0.109375,1,1
226 | 0.515625,0.109375,1,1
227 | 0.546875,0.109375,1,1
228 | 0.546875,0.109375,1,1
229 | 0.578125,0.109375,1,1
230 | 0.578125,0.109375,1,1
231 | 0.609375,0.109375,1,1
232 | 0.609375,0.109375,1,1
233 | 0.640625,0.109375,1,1
234 | 0.640625,0.109375,1,1
235 | 0.671875,0.109375,1,1
236 | 0.671875,0.109375,1,1
237 | 0.703125,0.109375,1,1
238 | 0.703125,0.109375,1,1
239 | 0.734375,0.109375,1,1
240 | 0.734375,0.109375,1,1
241 | 0.765625,0.109375,1,1
242 | 0.765625,0.109375,1,1
243 | 0.796875,0.109375,1,1
244 | 0.796875,0.109375,1,1
245 | 0.828125,0.109375,1,1
246 | 0.828125,0.109375,1,1
247 | 0.859375,0.109375,1,1
248 | 0.859375,0.109375,1,1
249 | 0.890625,0.109375,1,1
250 | 0.890625,0.109375,1,1
251 | 0.921875,0.109375,1,1
252 | 0.921875,0.109375,1,1
253 | 0.953125,0.109375,1,1
254 | 0.953125,0.109375,1,1
255 | 0.984375,0.109375,1,1
256 | 0.984375,0.109375,1,1
257 | 0.015625,0.140625,1,1
258 | 0.015625,0.140625,1,1
259 | 0.046875,0.140625,1,1
260 | 0.046875,0.140625,1,1
261 | 0.078125,0.140625,1,1
262 | 0.078125,0.140625,1,1
263 | 0.109375,0.140625,1,1
264 | 0.109375,0.140625,1,1
265 | 0.140625,0.140625,1,1
266 | 0.140625,0.140625,1,1
267 | 0.171875,0.140625,1,1
268 | 0.171875,0.140625,1,1
269 | 0.203125,0.140625,1,1
270 | 0.203125,0.140625,1,1
271 | 0.234375,0.140625,1,1
272 | 0.234375,0.140625,1,1
273 | 0.265625,0.140625,1,1
274 | 0.265625,0.140625,1,1
275 | 0.296875,0.140625,1,1
276 | 0.296875,0.140625,1,1
277 | 0.328125,0.140625,1,1
278 | 0.328125,0.140625,1,1
279 | 0.359375,0.140625,1,1
280 | 0.359375,0.140625,1,1
281 | 0.390625,0.140625,1,1
282 | 0.390625,0.140625,1,1
283 | 0.421875,0.140625,1,1
284 | 0.421875,0.140625,1,1
285 | 0.453125,0.140625,1,1
286 | 0.453125,0.140625,1,1
287 | 0.484375,0.140625,1,1
288 | 0.484375,0.140625,1,1
289 | 0.515625,0.140625,1,1
290 | 0.515625,0.140625,1,1
291 | 0.546875,0.140625,1,1
292 | 0.546875,0.140625,1,1
293 | 0.578125,0.140625,1,1
294 | 0.578125,0.140625,1,1
295 | 0.609375,0.140625,1,1
296 | 0.609375,0.140625,1,1
297 | 0.640625,0.140625,1,1
298 | 0.640625,0.140625,1,1
299 | 0.671875,0.140625,1,1
300 | 0.671875,0.140625,1,1
301 | 0.703125,0.140625,1,1
302 | 0.703125,0.140625,1,1
303 | 0.734375,0.140625,1,1
304 | 0.734375,0.140625,1,1
305 | 0.765625,0.140625,1,1
306 | 0.765625,0.140625,1,1
307 | 0.796875,0.140625,1,1
308 | 0.796875,0.140625,1,1
309 | 0.828125,0.140625,1,1
310 | 0.828125,0.140625,1,1
311 | 0.859375,0.140625,1,1
312 | 0.859375,0.140625,1,1
313 | 0.890625,0.140625,1,1
314 | 0.890625,0.140625,1,1
315 | 0.921875,0.140625,1,1
316 | 0.921875,0.140625,1,1
317 | 0.953125,0.140625,1,1
318 | 0.953125,0.140625,1,1
319 | 0.984375,0.140625,1,1
320 | 0.984375,0.140625,1,1
321 | 0.015625,0.171875,1,1
322 | 0.015625,0.171875,1,1
323 | 0.046875,0.171875,1,1
324 | 0.046875,0.171875,1,1
325 | 0.078125,0.171875,1,1
326 | 0.078125,0.171875,1,1
327 | 0.109375,0.171875,1,1
328 | 0.109375,0.171875,1,1
329 | 0.140625,0.171875,1,1
330 | 0.140625,0.171875,1,1
331 | 0.171875,0.171875,1,1
332 | 0.171875,0.171875,1,1
333 | 0.203125,0.171875,1,1
334 | 0.203125,0.171875,1,1
335 | 0.234375,0.171875,1,1
336 | 0.234375,0.171875,1,1
337 | 0.265625,0.171875,1,1
338 | 0.265625,0.171875,1,1
339 | 0.296875,0.171875,1,1
340 | 0.296875,0.171875,1,1
341 | 0.328125,0.171875,1,1
342 | 0.328125,0.171875,1,1
343 | 0.359375,0.171875,1,1
344 | 0.359375,0.171875,1,1
345 | 0.390625,0.171875,1,1
346 | 0.390625,0.171875,1,1
347 | 0.421875,0.171875,1,1
348 | 0.421875,0.171875,1,1
349 | 0.453125,0.171875,1,1
350 | 0.453125,0.171875,1,1
351 | 0.484375,0.171875,1,1
352 | 0.484375,0.171875,1,1
353 | 0.515625,0.171875,1,1
354 | 0.515625,0.171875,1,1
355 | 0.546875,0.171875,1,1
356 | 0.546875,0.171875,1,1
357 | 0.578125,0.171875,1,1
358 | 0.578125,0.171875,1,1
359 | 0.609375,0.171875,1,1
360 | 0.609375,0.171875,1,1
361 | 0.640625,0.171875,1,1
362 | 0.640625,0.171875,1,1
363 | 0.671875,0.171875,1,1
364 | 0.671875,0.171875,1,1
365 | 0.703125,0.171875,1,1
366 | 0.703125,0.171875,1,1
367 | 0.734375,0.171875,1,1
368 | 0.734375,0.171875,1,1
369 | 0.765625,0.171875,1,1
370 | 0.765625,0.171875,1,1
371 | 0.796875,0.171875,1,1
372 | 0.796875,0.171875,1,1
373 | 0.828125,0.171875,1,1
374 | 0.828125,0.171875,1,1
375 | 0.859375,0.171875,1,1
376 | 0.859375,0.171875,1,1
377 | 0.890625,0.171875,1,1
378 | 0.890625,0.171875,1,1
379 | 0.921875,0.171875,1,1
380 | 0.921875,0.171875,1,1
381 | 0.953125,0.171875,1,1
382 | 0.953125,0.171875,1,1
383 | 0.984375,0.171875,1,1
384 | 0.984375,0.171875,1,1
385 | 0.015625,0.203125,1,1
386 | 0.015625,0.203125,1,1
387 | 0.046875,0.203125,1,1
388 | 0.046875,0.203125,1,1
389 | 0.078125,0.203125,1,1
390 | 0.078125,0.203125,1,1
391 | 0.109375,0.203125,1,1
392 | 0.109375,0.203125,1,1
393 | 0.140625,0.203125,1,1
394 | 0.140625,0.203125,1,1
395 | 0.171875,0.203125,1,1
396 | 0.171875,0.203125,1,1
397 | 0.203125,0.203125,1,1
398 | 0.203125,0.203125,1,1
399 | 0.234375,0.203125,1,1
400 | 0.234375,0.203125,1,1
401 | 0.265625,0.203125,1,1
402 | 0.265625,0.203125,1,1
403 | 0.296875,0.203125,1,1
404 | 0.296875,0.203125,1,1
405 | 0.328125,0.203125,1,1
406 | 0.328125,0.203125,1,1
407 | 0.359375,0.203125,1,1
408 | 0.359375,0.203125,1,1
409 | 0.390625,0.203125,1,1
410 | 0.390625,0.203125,1,1
411 | 0.421875,0.203125,1,1
412 | 0.421875,0.203125,1,1
413 | 0.453125,0.203125,1,1
414 | 0.453125,0.203125,1,1
415 | 0.484375,0.203125,1,1
416 | 0.484375,0.203125,1,1
417 | 0.515625,0.203125,1,1
418 | 0.515625,0.203125,1,1
419 | 0.546875,0.203125,1,1
420 | 0.546875,0.203125,1,1
421 | 0.578125,0.203125,1,1
422 | 0.578125,0.203125,1,1
423 | 0.609375,0.203125,1,1
424 | 0.609375,0.203125,1,1
425 | 0.640625,0.203125,1,1
426 | 0.640625,0.203125,1,1
427 | 0.671875,0.203125,1,1
428 | 0.671875,0.203125,1,1
429 | 0.703125,0.203125,1,1
430 | 0.703125,0.203125,1,1
431 | 0.734375,0.203125,1,1
432 | 0.734375,0.203125,1,1
433 | 0.765625,0.203125,1,1
434 | 0.765625,0.203125,1,1
435 | 0.796875,0.203125,1,1
436 | 0.796875,0.203125,1,1
437 | 0.828125,0.203125,1,1
438 | 0.828125,0.203125,1,1
439 | 0.859375,0.203125,1,1
440 | 0.859375,0.203125,1,1
441 | 0.890625,0.203125,1,1
442 | 0.890625,0.203125,1,1
443 | 0.921875,0.203125,1,1
444 | 0.921875,0.203125,1,1
445 | 0.953125,0.203125,1,1
446 | 0.953125,0.203125,1,1
447 | 0.984375,0.203125,1,1
448 | 0.984375,0.203125,1,1
449 | 0.015625,0.234375,1,1
450 | 0.015625,0.234375,1,1
451 | 0.046875,0.234375,1,1
452 | 0.046875,0.234375,1,1
453 | 0.078125,0.234375,1,1
454 | 0.078125,0.234375,1,1
455 | 0.109375,0.234375,1,1
456 | 0.109375,0.234375,1,1
457 | 0.140625,0.234375,1,1
458 | 0.140625,0.234375,1,1
459 | 0.171875,0.234375,1,1
460 | 0.171875,0.234375,1,1
461 | 0.203125,0.234375,1,1
462 | 0.203125,0.234375,1,1
463 | 0.234375,0.234375,1,1
464 | 0.234375,0.234375,1,1
465 | 0.265625,0.234375,1,1
466 | 0.265625,0.234375,1,1
467 | 0.296875,0.234375,1,1
468 | 0.296875,0.234375,1,1
469 | 0.328125,0.234375,1,1
470 | 0.328125,0.234375,1,1
471 | 0.359375,0.234375,1,1
472 | 0.359375,0.234375,1,1
473 | 0.390625,0.234375,1,1
474 | 0.390625,0.234375,1,1
475 | 0.421875,0.234375,1,1
476 | 0.421875,0.234375,1,1
477 | 0.453125,0.234375,1,1
478 | 0.453125,0.234375,1,1
479 | 0.484375,0.234375,1,1
480 | 0.484375,0.234375,1,1
481 | 0.515625,0.234375,1,1
482 | 0.515625,0.234375,1,1
483 | 0.546875,0.234375,1,1
484 | 0.546875,0.234375,1,1
485 | 0.578125,0.234375,1,1
486 | 0.578125,0.234375,1,1
487 | 0.609375,0.234375,1,1
488 | 0.609375,0.234375,1,1
489 | 0.640625,0.234375,1,1
490 | 0.640625,0.234375,1,1
491 | 0.671875,0.234375,1,1
492 | 0.671875,0.234375,1,1
493 | 0.703125,0.234375,1,1
494 | 0.703125,0.234375,1,1
495 | 0.734375,0.234375,1,1
496 | 0.734375,0.234375,1,1
497 | 0.765625,0.234375,1,1
498 | 0.765625,0.234375,1,1
499 | 0.796875,0.234375,1,1
500 | 0.796875,0.234375,1,1
501 | 0.828125,0.234375,1,1
502 | 0.828125,0.234375,1,1
503 | 0.859375,0.234375,1,1
504 | 0.859375,0.234375,1,1
505 | 0.890625,0.234375,1,1
506 | 0.890625,0.234375,1,1
507 | 0.921875,0.234375,1,1
508 | 0.921875,0.234375,1,1
509 | 0.953125,0.234375,1,1
510 | 0.953125,0.234375,1,1
511 | 0.984375,0.234375,1,1
512 | 0.984375,0.234375,1,1
513 | 0.015625,0.265625,1,1
514 | 0.015625,0.265625,1,1
515 | 0.046875,0.265625,1,1
516 | 0.046875,0.265625,1,1
517 | 0.078125,0.265625,1,1
518 | 0.078125,0.265625,1,1
519 | 0.109375,0.265625,1,1
520 | 0.109375,0.265625,1,1
521 | 0.140625,0.265625,1,1
522 | 0.140625,0.265625,1,1
523 | 0.171875,0.265625,1,1
524 | 0.171875,0.265625,1,1
525 | 0.203125,0.265625,1,1
526 | 0.203125,0.265625,1,1
527 | 0.234375,0.265625,1,1
528 | 0.234375,0.265625,1,1
529 | 0.265625,0.265625,1,1
530 | 0.265625,0.265625,1,1
531 | 0.296875,0.265625,1,1
532 | 0.296875,0.265625,1,1
533 | 0.328125,0.265625,1,1
534 | 0.328125,0.265625,1,1
535 | 0.359375,0.265625,1,1
536 | 0.359375,0.265625,1,1
537 | 0.390625,0.265625,1,1
538 | 0.390625,0.265625,1,1
539 | 0.421875,0.265625,1,1
540 | 0.421875,0.265625,1,1
541 | 0.453125,0.265625,1,1
542 | 0.453125,0.265625,1,1
543 | 0.484375,0.265625,1,1
544 | 0.484375,0.265625,1,1
545 | 0.515625,0.265625,1,1
546 | 0.515625,0.265625,1,1
547 | 0.546875,0.265625,1,1
548 | 0.546875,0.265625,1,1
549 | 0.578125,0.265625,1,1
550 | 0.578125,0.265625,1,1
551 | 0.609375,0.265625,1,1
552 | 0.609375,0.265625,1,1
553 | 0.640625,0.265625,1,1
554 | 0.640625,0.265625,1,1
555 | 0.671875,0.265625,1,1
556 | 0.671875,0.265625,1,1
557 | 0.703125,0.265625,1,1
558 | 0.703125,0.265625,1,1
559 | 0.734375,0.265625,1,1
560 | 0.734375,0.265625,1,1
561 | 0.765625,0.265625,1,1
562 | 0.765625,0.265625,1,1
563 | 0.796875,0.265625,1,1
564 | 0.796875,0.265625,1,1
565 | 0.828125,0.265625,1,1
566 | 0.828125,0.265625,1,1
567 | 0.859375,0.265625,1,1
568 | 0.859375,0.265625,1,1
569 | 0.890625,0.265625,1,1
570 | 0.890625,0.265625,1,1
571 | 0.921875,0.265625,1,1
572 | 0.921875,0.265625,1,1
573 | 0.953125,0.265625,1,1
574 | 0.953125,0.265625,1,1
575 | 0.984375,0.265625,1,1
576 | 0.984375,0.265625,1,1
577 | 0.015625,0.296875,1,1
578 | 0.015625,0.296875,1,1
579 | 0.046875,0.296875,1,1
580 | 0.046875,0.296875,1,1
581 | 0.078125,0.296875,1,1
582 | 0.078125,0.296875,1,1
583 | 0.109375,0.296875,1,1
584 | 0.109375,0.296875,1,1
585 | 0.140625,0.296875,1,1
586 | 0.140625,0.296875,1,1
587 | 0.171875,0.296875,1,1
588 | 0.171875,0.296875,1,1
589 | 0.203125,0.296875,1,1
590 | 0.203125,0.296875,1,1
591 | 0.234375,0.296875,1,1
592 | 0.234375,0.296875,1,1
593 | 0.265625,0.296875,1,1
594 | 0.265625,0.296875,1,1
595 | 0.296875,0.296875,1,1
596 | 0.296875,0.296875,1,1
597 | 0.328125,0.296875,1,1
598 | 0.328125,0.296875,1,1
599 | 0.359375,0.296875,1,1
600 | 0.359375,0.296875,1,1
601 | 0.390625,0.296875,1,1
602 | 0.390625,0.296875,1,1
603 | 0.421875,0.296875,1,1
604 | 0.421875,0.296875,1,1
605 | 0.453125,0.296875,1,1
606 | 0.453125,0.296875,1,1
607 | 0.484375,0.296875,1,1
608 | 0.484375,0.296875,1,1
609 | 0.515625,0.296875,1,1
610 | 0.515625,0.296875,1,1
611 | 0.546875,0.296875,1,1
612 | 0.546875,0.296875,1,1
613 | 0.578125,0.296875,1,1
614 | 0.578125,0.296875,1,1
615 | 0.609375,0.296875,1,1
616 | 0.609375,0.296875,1,1
617 | 0.640625,0.296875,1,1
618 | 0.640625,0.296875,1,1
619 | 0.671875,0.296875,1,1
620 | 0.671875,0.296875,1,1
621 | 0.703125,0.296875,1,1
622 | 0.703125,0.296875,1,1
623 | 0.734375,0.296875,1,1
624 | 0.734375,0.296875,1,1
625 | 0.765625,0.296875,1,1
626 | 0.765625,0.296875,1,1
627 | 0.796875,0.296875,1,1
628 | 0.796875,0.296875,1,1
629 | 0.828125,0.296875,1,1
630 | 0.828125,0.296875,1,1
631 | 0.859375,0.296875,1,1
632 | 0.859375,0.296875,1,1
633 | 0.890625,0.296875,1,1
634 | 0.890625,0.296875,1,1
635 | 0.921875,0.296875,1,1
636 | 0.921875,0.296875,1,1
637 | 0.953125,0.296875,1,1
638 | 0.953125,0.296875,1,1
639 | 0.984375,0.296875,1,1
640 | 0.984375,0.296875,1,1
641 | 0.015625,0.328125,1,1
642 | 0.015625,0.328125,1,1
643 | 0.046875,0.328125,1,1
644 | 0.046875,0.328125,1,1
645 | 0.078125,0.328125,1,1
646 | 0.078125,0.328125,1,1
647 | 0.109375,0.328125,1,1
648 | 0.109375,0.328125,1,1
649 | 0.140625,0.328125,1,1
650 | 0.140625,0.328125,1,1
651 | 0.171875,0.328125,1,1
652 | 0.171875,0.328125,1,1
653 | 0.203125,0.328125,1,1
654 | 0.203125,0.328125,1,1
655 | 0.234375,0.328125,1,1
656 | 0.234375,0.328125,1,1
657 | 0.265625,0.328125,1,1
658 | 0.265625,0.328125,1,1
659 | 0.296875,0.328125,1,1
660 | 0.296875,0.328125,1,1
661 | 0.328125,0.328125,1,1
662 | 0.328125,0.328125,1,1
663 | 0.359375,0.328125,1,1
664 | 0.359375,0.328125,1,1
665 | 0.390625,0.328125,1,1
666 | 0.390625,0.328125,1,1
667 | 0.421875,0.328125,1,1
668 | 0.421875,0.328125,1,1
669 | 0.453125,0.328125,1,1
670 | 0.453125,0.328125,1,1
671 | 0.484375,0.328125,1,1
672 | 0.484375,0.328125,1,1
673 | 0.515625,0.328125,1,1
674 | 0.515625,0.328125,1,1
675 | 0.546875,0.328125,1,1
676 | 0.546875,0.328125,1,1
677 | 0.578125,0.328125,1,1
678 | 0.578125,0.328125,1,1
679 | 0.609375,0.328125,1,1
680 | 0.609375,0.328125,1,1
681 | 0.640625,0.328125,1,1
682 | 0.640625,0.328125,1,1
683 | 0.671875,0.328125,1,1
684 | 0.671875,0.328125,1,1
685 | 0.703125,0.328125,1,1
686 | 0.703125,0.328125,1,1
687 | 0.734375,0.328125,1,1
688 | 0.734375,0.328125,1,1
689 | 0.765625,0.328125,1,1
690 | 0.765625,0.328125,1,1
691 | 0.796875,0.328125,1,1
692 | 0.796875,0.328125,1,1
693 | 0.828125,0.328125,1,1
694 | 0.828125,0.328125,1,1
695 | 0.859375,0.328125,1,1
696 | 0.859375,0.328125,1,1
697 | 0.890625,0.328125,1,1
698 | 0.890625,0.328125,1,1
699 | 0.921875,0.328125,1,1
700 | 0.921875,0.328125,1,1
701 | 0.953125,0.328125,1,1
702 | 0.953125,0.328125,1,1
703 | 0.984375,0.328125,1,1
704 | 0.984375,0.328125,1,1
705 | 0.015625,0.359375,1,1
706 | 0.015625,0.359375,1,1
707 | 0.046875,0.359375,1,1
708 | 0.046875,0.359375,1,1
709 | 0.078125,0.359375,1,1
710 | 0.078125,0.359375,1,1
711 | 0.109375,0.359375,1,1
712 | 0.109375,0.359375,1,1
713 | 0.140625,0.359375,1,1
714 | 0.140625,0.359375,1,1
715 | 0.171875,0.359375,1,1
716 | 0.171875,0.359375,1,1
717 | 0.203125,0.359375,1,1
718 | 0.203125,0.359375,1,1
719 | 0.234375,0.359375,1,1
720 | 0.234375,0.359375,1,1
721 | 0.265625,0.359375,1,1
722 | 0.265625,0.359375,1,1
723 | 0.296875,0.359375,1,1
724 | 0.296875,0.359375,1,1
725 | 0.328125,0.359375,1,1
726 | 0.328125,0.359375,1,1
727 | 0.359375,0.359375,1,1
728 | 0.359375,0.359375,1,1
729 | 0.390625,0.359375,1,1
730 | 0.390625,0.359375,1,1
731 | 0.421875,0.359375,1,1
732 | 0.421875,0.359375,1,1
733 | 0.453125,0.359375,1,1
734 | 0.453125,0.359375,1,1
735 | 0.484375,0.359375,1,1
736 | 0.484375,0.359375,1,1
737 | 0.515625,0.359375,1,1
738 | 0.515625,0.359375,1,1
739 | 0.546875,0.359375,1,1
740 | 0.546875,0.359375,1,1
741 | 0.578125,0.359375,1,1
742 | 0.578125,0.359375,1,1
743 | 0.609375,0.359375,1,1
744 | 0.609375,0.359375,1,1
745 | 0.640625,0.359375,1,1
746 | 0.640625,0.359375,1,1
747 | 0.671875,0.359375,1,1
748 | 0.671875,0.359375,1,1
749 | 0.703125,0.359375,1,1
750 | 0.703125,0.359375,1,1
751 | 0.734375,0.359375,1,1
752 | 0.734375,0.359375,1,1
753 | 0.765625,0.359375,1,1
754 | 0.765625,0.359375,1,1
755 | 0.796875,0.359375,1,1
756 | 0.796875,0.359375,1,1
757 | 0.828125,0.359375,1,1
758 | 0.828125,0.359375,1,1
759 | 0.859375,0.359375,1,1
760 | 0.859375,0.359375,1,1
761 | 0.890625,0.359375,1,1
762 | 0.890625,0.359375,1,1
763 | 0.921875,0.359375,1,1
764 | 0.921875,0.359375,1,1
765 | 0.953125,0.359375,1,1
766 | 0.953125,0.359375,1,1
767 | 0.984375,0.359375,1,1
768 | 0.984375,0.359375,1,1
769 | 0.015625,0.390625,1,1
770 | 0.015625,0.390625,1,1
771 | 0.046875,0.390625,1,1
772 | 0.046875,0.390625,1,1
773 | 0.078125,0.390625,1,1
774 | 0.078125,0.390625,1,1
775 | 0.109375,0.390625,1,1
776 | 0.109375,0.390625,1,1
777 | 0.140625,0.390625,1,1
778 | 0.140625,0.390625,1,1
779 | 0.171875,0.390625,1,1
780 | 0.171875,0.390625,1,1
781 | 0.203125,0.390625,1,1
782 | 0.203125,0.390625,1,1
783 | 0.234375,0.390625,1,1
784 | 0.234375,0.390625,1,1
785 | 0.265625,0.390625,1,1
786 | 0.265625,0.390625,1,1
787 | 0.296875,0.390625,1,1
788 | 0.296875,0.390625,1,1
789 | 0.328125,0.390625,1,1
790 | 0.328125,0.390625,1,1
791 | 0.359375,0.390625,1,1
792 | 0.359375,0.390625,1,1
793 | 0.390625,0.390625,1,1
794 | 0.390625,0.390625,1,1
795 | 0.421875,0.390625,1,1
796 | 0.421875,0.390625,1,1
797 | 0.453125,0.390625,1,1
798 | 0.453125,0.390625,1,1
799 | 0.484375,0.390625,1,1
800 | 0.484375,0.390625,1,1
801 | 0.515625,0.390625,1,1
802 | 0.515625,0.390625,1,1
803 | 0.546875,0.390625,1,1
804 | 0.546875,0.390625,1,1
805 | 0.578125,0.390625,1,1
806 | 0.578125,0.390625,1,1
807 | 0.609375,0.390625,1,1
808 | 0.609375,0.390625,1,1
809 | 0.640625,0.390625,1,1
810 | 0.640625,0.390625,1,1
811 | 0.671875,0.390625,1,1
812 | 0.671875,0.390625,1,1
813 | 0.703125,0.390625,1,1
814 | 0.703125,0.390625,1,1
815 | 0.734375,0.390625,1,1
816 | 0.734375,0.390625,1,1
817 | 0.765625,0.390625,1,1
818 | 0.765625,0.390625,1,1
819 | 0.796875,0.390625,1,1
820 | 0.796875,0.390625,1,1
821 | 0.828125,0.390625,1,1
822 | 0.828125,0.390625,1,1
823 | 0.859375,0.390625,1,1
824 | 0.859375,0.390625,1,1
825 | 0.890625,0.390625,1,1
826 | 0.890625,0.390625,1,1
827 | 0.921875,0.390625,1,1
828 | 0.921875,0.390625,1,1
829 | 0.953125,0.390625,1,1
830 | 0.953125,0.390625,1,1
831 | 0.984375,0.390625,1,1
832 | 0.984375,0.390625,1,1
833 | 0.015625,0.421875,1,1
834 | 0.015625,0.421875,1,1
835 | 0.046875,0.421875,1,1
836 | 0.046875,0.421875,1,1
837 | 0.078125,0.421875,1,1
838 | 0.078125,0.421875,1,1
839 | 0.109375,0.421875,1,1
840 | 0.109375,0.421875,1,1
841 | 0.140625,0.421875,1,1
842 | 0.140625,0.421875,1,1
843 | 0.171875,0.421875,1,1
844 | 0.171875,0.421875,1,1
845 | 0.203125,0.421875,1,1
846 | 0.203125,0.421875,1,1
847 | 0.234375,0.421875,1,1
848 | 0.234375,0.421875,1,1
849 | 0.265625,0.421875,1,1
850 | 0.265625,0.421875,1,1
851 | 0.296875,0.421875,1,1
852 | 0.296875,0.421875,1,1
853 | 0.328125,0.421875,1,1
854 | 0.328125,0.421875,1,1
855 | 0.359375,0.421875,1,1
856 | 0.359375,0.421875,1,1
857 | 0.390625,0.421875,1,1
858 | 0.390625,0.421875,1,1
859 | 0.421875,0.421875,1,1
860 | 0.421875,0.421875,1,1
861 | 0.453125,0.421875,1,1
862 | 0.453125,0.421875,1,1
863 | 0.484375,0.421875,1,1
864 | 0.484375,0.421875,1,1
865 | 0.515625,0.421875,1,1
866 | 0.515625,0.421875,1,1
867 | 0.546875,0.421875,1,1
868 | 0.546875,0.421875,1,1
869 | 0.578125,0.421875,1,1
870 | 0.578125,0.421875,1,1
871 | 0.609375,0.421875,1,1
872 | 0.609375,0.421875,1,1
873 | 0.640625,0.421875,1,1
874 | 0.640625,0.421875,1,1
875 | 0.671875,0.421875,1,1
876 | 0.671875,0.421875,1,1
877 | 0.703125,0.421875,1,1
878 | 0.703125,0.421875,1,1
879 | 0.734375,0.421875,1,1
880 | 0.734375,0.421875,1,1
881 | 0.765625,0.421875,1,1
882 | 0.765625,0.421875,1,1
883 | 0.796875,0.421875,1,1
884 | 0.796875,0.421875,1,1
885 | 0.828125,0.421875,1,1
886 | 0.828125,0.421875,1,1
887 | 0.859375,0.421875,1,1
888 | 0.859375,0.421875,1,1
889 | 0.890625,0.421875,1,1
890 | 0.890625,0.421875,1,1
891 | 0.921875,0.421875,1,1
892 | 0.921875,0.421875,1,1
893 | 0.953125,0.421875,1,1
894 | 0.953125,0.421875,1,1
895 | 0.984375,0.421875,1,1
896 | 0.984375,0.421875,1,1
897 | 0.015625,0.453125,1,1
898 | 0.015625,0.453125,1,1
899 | 0.046875,0.453125,1,1
900 | 0.046875,0.453125,1,1
901 | 0.078125,0.453125,1,1
902 | 0.078125,0.453125,1,1
903 | 0.109375,0.453125,1,1
904 | 0.109375,0.453125,1,1
905 | 0.140625,0.453125,1,1
906 | 0.140625,0.453125,1,1
907 | 0.171875,0.453125,1,1
908 | 0.171875,0.453125,1,1
909 | 0.203125,0.453125,1,1
910 | 0.203125,0.453125,1,1
911 | 0.234375,0.453125,1,1
912 | 0.234375,0.453125,1,1
913 | 0.265625,0.453125,1,1
914 | 0.265625,0.453125,1,1
915 | 0.296875,0.453125,1,1
916 | 0.296875,0.453125,1,1
917 | 0.328125,0.453125,1,1
918 | 0.328125,0.453125,1,1
919 | 0.359375,0.453125,1,1
920 | 0.359375,0.453125,1,1
921 | 0.390625,0.453125,1,1
922 | 0.390625,0.453125,1,1
923 | 0.421875,0.453125,1,1
924 | 0.421875,0.453125,1,1
925 | 0.453125,0.453125,1,1
926 | 0.453125,0.453125,1,1
927 | 0.484375,0.453125,1,1
928 | 0.484375,0.453125,1,1
929 | 0.515625,0.453125,1,1
930 | 0.515625,0.453125,1,1
931 | 0.546875,0.453125,1,1
932 | 0.546875,0.453125,1,1
933 | 0.578125,0.453125,1,1
934 | 0.578125,0.453125,1,1
935 | 0.609375,0.453125,1,1
936 | 0.609375,0.453125,1,1
937 | 0.640625,0.453125,1,1
938 | 0.640625,0.453125,1,1
939 | 0.671875,0.453125,1,1
940 | 0.671875,0.453125,1,1
941 | 0.703125,0.453125,1,1
942 | 0.703125,0.453125,1,1
943 | 0.734375,0.453125,1,1
944 | 0.734375,0.453125,1,1
945 | 0.765625,0.453125,1,1
946 | 0.765625,0.453125,1,1
947 | 0.796875,0.453125,1,1
948 | 0.796875,0.453125,1,1
949 | 0.828125,0.453125,1,1
950 | 0.828125,0.453125,1,1
951 | 0.859375,0.453125,1,1
952 | 0.859375,0.453125,1,1
953 | 0.890625,0.453125,1,1
954 | 0.890625,0.453125,1,1
955 | 0.921875,0.453125,1,1
956 | 0.921875,0.453125,1,1
957 | 0.953125,0.453125,1,1
958 | 0.953125,0.453125,1,1
959 | 0.984375,0.453125,1,1
960 | 0.984375,0.453125,1,1
961 | 0.015625,0.484375,1,1
962 | 0.015625,0.484375,1,1
963 | 0.046875,0.484375,1,1
964 | 0.046875,0.484375,1,1
965 | 0.078125,0.484375,1,1
966 | 0.078125,0.484375,1,1
967 | 0.109375,0.484375,1,1
968 | 0.109375,0.484375,1,1
969 | 0.140625,0.484375,1,1
970 | 0.140625,0.484375,1,1
971 | 0.171875,0.484375,1,1
972 | 0.171875,0.484375,1,1
973 | 0.203125,0.484375,1,1
974 | 0.203125,0.484375,1,1
975 | 0.234375,0.484375,1,1
976 | 0.234375,0.484375,1,1
977 | 0.265625,0.484375,1,1
978 | 0.265625,0.484375,1,1
979 | 0.296875,0.484375,1,1
980 | 0.296875,0.484375,1,1
981 | 0.328125,0.484375,1,1
982 | 0.328125,0.484375,1,1
983 | 0.359375,0.484375,1,1
984 | 0.359375,0.484375,1,1
985 | 0.390625,0.484375,1,1
986 | 0.390625,0.484375,1,1
987 | 0.421875,0.484375,1,1
988 | 0.421875,0.484375,1,1
989 | 0.453125,0.484375,1,1
990 | 0.453125,0.484375,1,1
991 | 0.484375,0.484375,1,1
992 | 0.484375,0.484375,1,1
993 | 0.515625,0.484375,1,1
994 | 0.515625,0.484375,1,1
995 | 0.546875,0.484375,1,1
996 | 0.546875,0.484375,1,1
997 | 0.578125,0.484375,1,1
998 | 0.578125,0.484375,1,1
999 | 0.609375,0.484375,1,1
1000 | 0.609375,0.484375,1,1
1001 | 0.640625,0.484375,1,1
1002 | 0.640625,0.484375,1,1
1003 | 0.671875,0.484375,1,1
1004 | 0.671875,0.484375,1,1
1005 | 0.703125,0.484375,1,1
1006 | 0.703125,0.484375,1,1
1007 | 0.734375,0.484375,1,1
1008 | 0.734375,0.484375,1,1
1009 | 0.765625,0.484375,1,1
1010 | 0.765625,0.484375,1,1
1011 | 0.796875,0.484375,1,1
1012 | 0.796875,0.484375,1,1
1013 | 0.828125,0.484375,1,1
1014 | 0.828125,0.484375,1,1
1015 | 0.859375,0.484375,1,1
1016 | 0.859375,0.484375,1,1
1017 | 0.890625,0.484375,1,1
1018 | 0.890625,0.484375,1,1
1019 | 0.921875,0.484375,1,1
1020 | 0.921875,0.484375,1,1
1021 | 0.953125,0.484375,1,1
1022 | 0.953125,0.484375,1,1
1023 | 0.984375,0.484375,1,1
1024 | 0.984375,0.484375,1,1
1025 | 0.015625,0.515625,1,1
1026 | 0.015625,0.515625,1,1
1027 | 0.046875,0.515625,1,1
1028 | 0.046875,0.515625,1,1
1029 | 0.078125,0.515625,1,1
1030 | 0.078125,0.515625,1,1
1031 | 0.109375,0.515625,1,1
1032 | 0.109375,0.515625,1,1
1033 | 0.140625,0.515625,1,1
1034 | 0.140625,0.515625,1,1
1035 | 0.171875,0.515625,1,1
1036 | 0.171875,0.515625,1,1
1037 | 0.203125,0.515625,1,1
1038 | 0.203125,0.515625,1,1
1039 | 0.234375,0.515625,1,1
1040 | 0.234375,0.515625,1,1
1041 | 0.265625,0.515625,1,1
1042 | 0.265625,0.515625,1,1
1043 | 0.296875,0.515625,1,1
1044 | 0.296875,0.515625,1,1
1045 | 0.328125,0.515625,1,1
1046 | 0.328125,0.515625,1,1
1047 | 0.359375,0.515625,1,1
1048 | 0.359375,0.515625,1,1
1049 | 0.390625,0.515625,1,1
1050 | 0.390625,0.515625,1,1
1051 | 0.421875,0.515625,1,1
1052 | 0.421875,0.515625,1,1
1053 | 0.453125,0.515625,1,1
1054 | 0.453125,0.515625,1,1
1055 | 0.484375,0.515625,1,1
1056 | 0.484375,0.515625,1,1
1057 | 0.515625,0.515625,1,1
1058 | 0.515625,0.515625,1,1
1059 | 0.546875,0.515625,1,1
1060 | 0.546875,0.515625,1,1
1061 | 0.578125,0.515625,1,1
1062 | 0.578125,0.515625,1,1
1063 | 0.609375,0.515625,1,1
1064 | 0.609375,0.515625,1,1
1065 | 0.640625,0.515625,1,1
1066 | 0.640625,0.515625,1,1
1067 | 0.671875,0.515625,1,1
1068 | 0.671875,0.515625,1,1
1069 | 0.703125,0.515625,1,1
1070 | 0.703125,0.515625,1,1
1071 | 0.734375,0.515625,1,1
1072 | 0.734375,0.515625,1,1
1073 | 0.765625,0.515625,1,1
1074 | 0.765625,0.515625,1,1
1075 | 0.796875,0.515625,1,1
1076 | 0.796875,0.515625,1,1
1077 | 0.828125,0.515625,1,1
1078 | 0.828125,0.515625,1,1
1079 | 0.859375,0.515625,1,1
1080 | 0.859375,0.515625,1,1
1081 | 0.890625,0.515625,1,1
1082 | 0.890625,0.515625,1,1
1083 | 0.921875,0.515625,1,1
1084 | 0.921875,0.515625,1,1
1085 | 0.953125,0.515625,1,1
1086 | 0.953125,0.515625,1,1
1087 | 0.984375,0.515625,1,1
1088 | 0.984375,0.515625,1,1
1089 | 0.015625,0.546875,1,1
1090 | 0.015625,0.546875,1,1
1091 | 0.046875,0.546875,1,1
1092 | 0.046875,0.546875,1,1
1093 | 0.078125,0.546875,1,1
1094 | 0.078125,0.546875,1,1
1095 | 0.109375,0.546875,1,1
1096 | 0.109375,0.546875,1,1
1097 | 0.140625,0.546875,1,1
1098 | 0.140625,0.546875,1,1
1099 | 0.171875,0.546875,1,1
1100 | 0.171875,0.546875,1,1
1101 | 0.203125,0.546875,1,1
1102 | 0.203125,0.546875,1,1
1103 | 0.234375,0.546875,1,1
1104 | 0.234375,0.546875,1,1
1105 | 0.265625,0.546875,1,1
1106 | 0.265625,0.546875,1,1
1107 | 0.296875,0.546875,1,1
1108 | 0.296875,0.546875,1,1
1109 | 0.328125,0.546875,1,1
1110 | 0.328125,0.546875,1,1
1111 | 0.359375,0.546875,1,1
1112 | 0.359375,0.546875,1,1
1113 | 0.390625,0.546875,1,1
1114 | 0.390625,0.546875,1,1
1115 | 0.421875,0.546875,1,1
1116 | 0.421875,0.546875,1,1
1117 | 0.453125,0.546875,1,1
1118 | 0.453125,0.546875,1,1
1119 | 0.484375,0.546875,1,1
1120 | 0.484375,0.546875,1,1
1121 | 0.515625,0.546875,1,1
1122 | 0.515625,0.546875,1,1
1123 | 0.546875,0.546875,1,1
1124 | 0.546875,0.546875,1,1
1125 | 0.578125,0.546875,1,1
1126 | 0.578125,0.546875,1,1
1127 | 0.609375,0.546875,1,1
1128 | 0.609375,0.546875,1,1
1129 | 0.640625,0.546875,1,1
1130 | 0.640625,0.546875,1,1
1131 | 0.671875,0.546875,1,1
1132 | 0.671875,0.546875,1,1
1133 | 0.703125,0.546875,1,1
1134 | 0.703125,0.546875,1,1
1135 | 0.734375,0.546875,1,1
1136 | 0.734375,0.546875,1,1
1137 | 0.765625,0.546875,1,1
1138 | 0.765625,0.546875,1,1
1139 | 0.796875,0.546875,1,1
1140 | 0.796875,0.546875,1,1
1141 | 0.828125,0.546875,1,1
1142 | 0.828125,0.546875,1,1
1143 | 0.859375,0.546875,1,1
1144 | 0.859375,0.546875,1,1
1145 | 0.890625,0.546875,1,1
1146 | 0.890625,0.546875,1,1
1147 | 0.921875,0.546875,1,1
1148 | 0.921875,0.546875,1,1
1149 | 0.953125,0.546875,1,1
1150 | 0.953125,0.546875,1,1
1151 | 0.984375,0.546875,1,1
1152 | 0.984375,0.546875,1,1
1153 | 0.015625,0.578125,1,1
1154 | 0.015625,0.578125,1,1
1155 | 0.046875,0.578125,1,1
1156 | 0.046875,0.578125,1,1
1157 | 0.078125,0.578125,1,1
1158 | 0.078125,0.578125,1,1
1159 | 0.109375,0.578125,1,1
1160 | 0.109375,0.578125,1,1
1161 | 0.140625,0.578125,1,1
1162 | 0.140625,0.578125,1,1
1163 | 0.171875,0.578125,1,1
1164 | 0.171875,0.578125,1,1
1165 | 0.203125,0.578125,1,1
1166 | 0.203125,0.578125,1,1
1167 | 0.234375,0.578125,1,1
1168 | 0.234375,0.578125,1,1
1169 | 0.265625,0.578125,1,1
1170 | 0.265625,0.578125,1,1
1171 | 0.296875,0.578125,1,1
1172 | 0.296875,0.578125,1,1
1173 | 0.328125,0.578125,1,1
1174 | 0.328125,0.578125,1,1
1175 | 0.359375,0.578125,1,1
1176 | 0.359375,0.578125,1,1
1177 | 0.390625,0.578125,1,1
1178 | 0.390625,0.578125,1,1
1179 | 0.421875,0.578125,1,1
1180 | 0.421875,0.578125,1,1
1181 | 0.453125,0.578125,1,1
1182 | 0.453125,0.578125,1,1
1183 | 0.484375,0.578125,1,1
1184 | 0.484375,0.578125,1,1
1185 | 0.515625,0.578125,1,1
1186 | 0.515625,0.578125,1,1
1187 | 0.546875,0.578125,1,1
1188 | 0.546875,0.578125,1,1
1189 | 0.578125,0.578125,1,1
1190 | 0.578125,0.578125,1,1
1191 | 0.609375,0.578125,1,1
1192 | 0.609375,0.578125,1,1
1193 | 0.640625,0.578125,1,1
1194 | 0.640625,0.578125,1,1
1195 | 0.671875,0.578125,1,1
1196 | 0.671875,0.578125,1,1
1197 | 0.703125,0.578125,1,1
1198 | 0.703125,0.578125,1,1
1199 | 0.734375,0.578125,1,1
1200 | 0.734375,0.578125,1,1
1201 | 0.765625,0.578125,1,1
1202 | 0.765625,0.578125,1,1
1203 | 0.796875,0.578125,1,1
1204 | 0.796875,0.578125,1,1
1205 | 0.828125,0.578125,1,1
1206 | 0.828125,0.578125,1,1
1207 | 0.859375,0.578125,1,1
1208 | 0.859375,0.578125,1,1
1209 | 0.890625,0.578125,1,1
1210 | 0.890625,0.578125,1,1
1211 | 0.921875,0.578125,1,1
1212 | 0.921875,0.578125,1,1
1213 | 0.953125,0.578125,1,1
1214 | 0.953125,0.578125,1,1
1215 | 0.984375,0.578125,1,1
1216 | 0.984375,0.578125,1,1
1217 | 0.015625,0.609375,1,1
1218 | 0.015625,0.609375,1,1
1219 | 0.046875,0.609375,1,1
1220 | 0.046875,0.609375,1,1
1221 | 0.078125,0.609375,1,1
1222 | 0.078125,0.609375,1,1
1223 | 0.109375,0.609375,1,1
1224 | 0.109375,0.609375,1,1
1225 | 0.140625,0.609375,1,1
1226 | 0.140625,0.609375,1,1
1227 | 0.171875,0.609375,1,1
1228 | 0.171875,0.609375,1,1
1229 | 0.203125,0.609375,1,1
1230 | 0.203125,0.609375,1,1
1231 | 0.234375,0.609375,1,1
1232 | 0.234375,0.609375,1,1
1233 | 0.265625,0.609375,1,1
1234 | 0.265625,0.609375,1,1
1235 | 0.296875,0.609375,1,1
1236 | 0.296875,0.609375,1,1
1237 | 0.328125,0.609375,1,1
1238 | 0.328125,0.609375,1,1
1239 | 0.359375,0.609375,1,1
1240 | 0.359375,0.609375,1,1
1241 | 0.390625,0.609375,1,1
1242 | 0.390625,0.609375,1,1
1243 | 0.421875,0.609375,1,1
1244 | 0.421875,0.609375,1,1
1245 | 0.453125,0.609375,1,1
1246 | 0.453125,0.609375,1,1
1247 | 0.484375,0.609375,1,1
1248 | 0.484375,0.609375,1,1
1249 | 0.515625,0.609375,1,1
1250 | 0.515625,0.609375,1,1
1251 | 0.546875,0.609375,1,1
1252 | 0.546875,0.609375,1,1
1253 | 0.578125,0.609375,1,1
1254 | 0.578125,0.609375,1,1
1255 | 0.609375,0.609375,1,1
1256 | 0.609375,0.609375,1,1
1257 | 0.640625,0.609375,1,1
1258 | 0.640625,0.609375,1,1
1259 | 0.671875,0.609375,1,1
1260 | 0.671875,0.609375,1,1
1261 | 0.703125,0.609375,1,1
1262 | 0.703125,0.609375,1,1
1263 | 0.734375,0.609375,1,1
1264 | 0.734375,0.609375,1,1
1265 | 0.765625,0.609375,1,1
1266 | 0.765625,0.609375,1,1
1267 | 0.796875,0.609375,1,1
1268 | 0.796875,0.609375,1,1
1269 | 0.828125,0.609375,1,1
1270 | 0.828125,0.609375,1,1
1271 | 0.859375,0.609375,1,1
1272 | 0.859375,0.609375,1,1
1273 | 0.890625,0.609375,1,1
1274 | 0.890625,0.609375,1,1
1275 | 0.921875,0.609375,1,1
1276 | 0.921875,0.609375,1,1
1277 | 0.953125,0.609375,1,1
1278 | 0.953125,0.609375,1,1
1279 | 0.984375,0.609375,1,1
1280 | 0.984375,0.609375,1,1
1281 | 0.015625,0.640625,1,1
1282 | 0.015625,0.640625,1,1
1283 | 0.046875,0.640625,1,1
1284 | 0.046875,0.640625,1,1
1285 | 0.078125,0.640625,1,1
1286 | 0.078125,0.640625,1,1
1287 | 0.109375,0.640625,1,1
1288 | 0.109375,0.640625,1,1
1289 | 0.140625,0.640625,1,1
1290 | 0.140625,0.640625,1,1
1291 | 0.171875,0.640625,1,1
1292 | 0.171875,0.640625,1,1
1293 | 0.203125,0.640625,1,1
1294 | 0.203125,0.640625,1,1
1295 | 0.234375,0.640625,1,1
1296 | 0.234375,0.640625,1,1
1297 | 0.265625,0.640625,1,1
1298 | 0.265625,0.640625,1,1
1299 | 0.296875,0.640625,1,1
1300 | 0.296875,0.640625,1,1
1301 | 0.328125,0.640625,1,1
1302 | 0.328125,0.640625,1,1
1303 | 0.359375,0.640625,1,1
1304 | 0.359375,0.640625,1,1
1305 | 0.390625,0.640625,1,1
1306 | 0.390625,0.640625,1,1
1307 | 0.421875,0.640625,1,1
1308 | 0.421875,0.640625,1,1
1309 | 0.453125,0.640625,1,1
1310 | 0.453125,0.640625,1,1
1311 | 0.484375,0.640625,1,1
1312 | 0.484375,0.640625,1,1
1313 | 0.515625,0.640625,1,1
1314 | 0.515625,0.640625,1,1
1315 | 0.546875,0.640625,1,1
1316 | 0.546875,0.640625,1,1
1317 | 0.578125,0.640625,1,1
1318 | 0.578125,0.640625,1,1
1319 | 0.609375,0.640625,1,1
1320 | 0.609375,0.640625,1,1
1321 | 0.640625,0.640625,1,1
1322 | 0.640625,0.640625,1,1
1323 | 0.671875,0.640625,1,1
1324 | 0.671875,0.640625,1,1
1325 | 0.703125,0.640625,1,1
1326 | 0.703125,0.640625,1,1
1327 | 0.734375,0.640625,1,1
1328 | 0.734375,0.640625,1,1
1329 | 0.765625,0.640625,1,1
1330 | 0.765625,0.640625,1,1
1331 | 0.796875,0.640625,1,1
1332 | 0.796875,0.640625,1,1
1333 | 0.828125,0.640625,1,1
1334 | 0.828125,0.640625,1,1
1335 | 0.859375,0.640625,1,1
1336 | 0.859375,0.640625,1,1
1337 | 0.890625,0.640625,1,1
1338 | 0.890625,0.640625,1,1
1339 | 0.921875,0.640625,1,1
1340 | 0.921875,0.640625,1,1
1341 | 0.953125,0.640625,1,1
1342 | 0.953125,0.640625,1,1
1343 | 0.984375,0.640625,1,1
1344 | 0.984375,0.640625,1,1
1345 | 0.015625,0.671875,1,1
1346 | 0.015625,0.671875,1,1
1347 | 0.046875,0.671875,1,1
1348 | 0.046875,0.671875,1,1
1349 | 0.078125,0.671875,1,1
1350 | 0.078125,0.671875,1,1
1351 | 0.109375,0.671875,1,1
1352 | 0.109375,0.671875,1,1
1353 | 0.140625,0.671875,1,1
1354 | 0.140625,0.671875,1,1
1355 | 0.171875,0.671875,1,1
1356 | 0.171875,0.671875,1,1
1357 | 0.203125,0.671875,1,1
1358 | 0.203125,0.671875,1,1
1359 | 0.234375,0.671875,1,1
1360 | 0.234375,0.671875,1,1
1361 | 0.265625,0.671875,1,1
1362 | 0.265625,0.671875,1,1
1363 | 0.296875,0.671875,1,1
1364 | 0.296875,0.671875,1,1
1365 | 0.328125,0.671875,1,1
1366 | 0.328125,0.671875,1,1
1367 | 0.359375,0.671875,1,1
1368 | 0.359375,0.671875,1,1
1369 | 0.390625,0.671875,1,1
1370 | 0.390625,0.671875,1,1
1371 | 0.421875,0.671875,1,1
1372 | 0.421875,0.671875,1,1
1373 | 0.453125,0.671875,1,1
1374 | 0.453125,0.671875,1,1
1375 | 0.484375,0.671875,1,1
1376 | 0.484375,0.671875,1,1
1377 | 0.515625,0.671875,1,1
1378 | 0.515625,0.671875,1,1
1379 | 0.546875,0.671875,1,1
1380 | 0.546875,0.671875,1,1
1381 | 0.578125,0.671875,1,1
1382 | 0.578125,0.671875,1,1
1383 | 0.609375,0.671875,1,1
1384 | 0.609375,0.671875,1,1
1385 | 0.640625,0.671875,1,1
1386 | 0.640625,0.671875,1,1
1387 | 0.671875,0.671875,1,1
1388 | 0.671875,0.671875,1,1
1389 | 0.703125,0.671875,1,1
1390 | 0.703125,0.671875,1,1
1391 | 0.734375,0.671875,1,1
1392 | 0.734375,0.671875,1,1
1393 | 0.765625,0.671875,1,1
1394 | 0.765625,0.671875,1,1
1395 | 0.796875,0.671875,1,1
1396 | 0.796875,0.671875,1,1
1397 | 0.828125,0.671875,1,1
1398 | 0.828125,0.671875,1,1
1399 | 0.859375,0.671875,1,1
1400 | 0.859375,0.671875,1,1
1401 | 0.890625,0.671875,1,1
1402 | 0.890625,0.671875,1,1
1403 | 0.921875,0.671875,1,1
1404 | 0.921875,0.671875,1,1
1405 | 0.953125,0.671875,1,1
1406 | 0.953125,0.671875,1,1
1407 | 0.984375,0.671875,1,1
1408 | 0.984375,0.671875,1,1
1409 | 0.015625,0.703125,1,1
1410 | 0.015625,0.703125,1,1
1411 | 0.046875,0.703125,1,1
1412 | 0.046875,0.703125,1,1
1413 | 0.078125,0.703125,1,1
1414 | 0.078125,0.703125,1,1
1415 | 0.109375,0.703125,1,1
1416 | 0.109375,0.703125,1,1
1417 | 0.140625,0.703125,1,1
1418 | 0.140625,0.703125,1,1
1419 | 0.171875,0.703125,1,1
1420 | 0.171875,0.703125,1,1
1421 | 0.203125,0.703125,1,1
1422 | 0.203125,0.703125,1,1
1423 | 0.234375,0.703125,1,1
1424 | 0.234375,0.703125,1,1
1425 | 0.265625,0.703125,1,1
1426 | 0.265625,0.703125,1,1
1427 | 0.296875,0.703125,1,1
1428 | 0.296875,0.703125,1,1
1429 | 0.328125,0.703125,1,1
1430 | 0.328125,0.703125,1,1
1431 | 0.359375,0.703125,1,1
1432 | 0.359375,0.703125,1,1
1433 | 0.390625,0.703125,1,1
1434 | 0.390625,0.703125,1,1
1435 | 0.421875,0.703125,1,1
1436 | 0.421875,0.703125,1,1
1437 | 0.453125,0.703125,1,1
1438 | 0.453125,0.703125,1,1
1439 | 0.484375,0.703125,1,1
1440 | 0.484375,0.703125,1,1
1441 | 0.515625,0.703125,1,1
1442 | 0.515625,0.703125,1,1
1443 | 0.546875,0.703125,1,1
1444 | 0.546875,0.703125,1,1
1445 | 0.578125,0.703125,1,1
1446 | 0.578125,0.703125,1,1
1447 | 0.609375,0.703125,1,1
1448 | 0.609375,0.703125,1,1
1449 | 0.640625,0.703125,1,1
1450 | 0.640625,0.703125,1,1
1451 | 0.671875,0.703125,1,1
1452 | 0.671875,0.703125,1,1
1453 | 0.703125,0.703125,1,1
1454 | 0.703125,0.703125,1,1
1455 | 0.734375,0.703125,1,1
1456 | 0.734375,0.703125,1,1
1457 | 0.765625,0.703125,1,1
1458 | 0.765625,0.703125,1,1
1459 | 0.796875,0.703125,1,1
1460 | 0.796875,0.703125,1,1
1461 | 0.828125,0.703125,1,1
1462 | 0.828125,0.703125,1,1
1463 | 0.859375,0.703125,1,1
1464 | 0.859375,0.703125,1,1
1465 | 0.890625,0.703125,1,1
1466 | 0.890625,0.703125,1,1
1467 | 0.921875,0.703125,1,1
1468 | 0.921875,0.703125,1,1
1469 | 0.953125,0.703125,1,1
1470 | 0.953125,0.703125,1,1
1471 | 0.984375,0.703125,1,1
1472 | 0.984375,0.703125,1,1
1473 | 0.015625,0.734375,1,1
1474 | 0.015625,0.734375,1,1
1475 | 0.046875,0.734375,1,1
1476 | 0.046875,0.734375,1,1
1477 | 0.078125,0.734375,1,1
1478 | 0.078125,0.734375,1,1
1479 | 0.109375,0.734375,1,1
1480 | 0.109375,0.734375,1,1
1481 | 0.140625,0.734375,1,1
1482 | 0.140625,0.734375,1,1
1483 | 0.171875,0.734375,1,1
1484 | 0.171875,0.734375,1,1
1485 | 0.203125,0.734375,1,1
1486 | 0.203125,0.734375,1,1
1487 | 0.234375,0.734375,1,1
1488 | 0.234375,0.734375,1,1
1489 | 0.265625,0.734375,1,1
1490 | 0.265625,0.734375,1,1
1491 | 0.296875,0.734375,1,1
1492 | 0.296875,0.734375,1,1
1493 | 0.328125,0.734375,1,1
1494 | 0.328125,0.734375,1,1
1495 | 0.359375,0.734375,1,1
1496 | 0.359375,0.734375,1,1
1497 | 0.390625,0.734375,1,1
1498 | 0.390625,0.734375,1,1
1499 | 0.421875,0.734375,1,1
1500 | 0.421875,0.734375,1,1
1501 | 0.453125,0.734375,1,1
1502 | 0.453125,0.734375,1,1
1503 | 0.484375,0.734375,1,1
1504 | 0.484375,0.734375,1,1
1505 | 0.515625,0.734375,1,1
1506 | 0.515625,0.734375,1,1
1507 | 0.546875,0.734375,1,1
1508 | 0.546875,0.734375,1,1
1509 | 0.578125,0.734375,1,1
1510 | 0.578125,0.734375,1,1
1511 | 0.609375,0.734375,1,1
1512 | 0.609375,0.734375,1,1
1513 | 0.640625,0.734375,1,1
1514 | 0.640625,0.734375,1,1
1515 | 0.671875,0.734375,1,1
1516 | 0.671875,0.734375,1,1
1517 | 0.703125,0.734375,1,1
1518 | 0.703125,0.734375,1,1
1519 | 0.734375,0.734375,1,1
1520 | 0.734375,0.734375,1,1
1521 | 0.765625,0.734375,1,1
1522 | 0.765625,0.734375,1,1
1523 | 0.796875,0.734375,1,1
1524 | 0.796875,0.734375,1,1
1525 | 0.828125,0.734375,1,1
1526 | 0.828125,0.734375,1,1
1527 | 0.859375,0.734375,1,1
1528 | 0.859375,0.734375,1,1
1529 | 0.890625,0.734375,1,1
1530 | 0.890625,0.734375,1,1
1531 | 0.921875,0.734375,1,1
1532 | 0.921875,0.734375,1,1
1533 | 0.953125,0.734375,1,1
1534 | 0.953125,0.734375,1,1
1535 | 0.984375,0.734375,1,1
1536 | 0.984375,0.734375,1,1
1537 | 0.015625,0.765625,1,1
1538 | 0.015625,0.765625,1,1
1539 | 0.046875,0.765625,1,1
1540 | 0.046875,0.765625,1,1
1541 | 0.078125,0.765625,1,1
1542 | 0.078125,0.765625,1,1
1543 | 0.109375,0.765625,1,1
1544 | 0.109375,0.765625,1,1
1545 | 0.140625,0.765625,1,1
1546 | 0.140625,0.765625,1,1
1547 | 0.171875,0.765625,1,1
1548 | 0.171875,0.765625,1,1
1549 | 0.203125,0.765625,1,1
1550 | 0.203125,0.765625,1,1
1551 | 0.234375,0.765625,1,1
1552 | 0.234375,0.765625,1,1
1553 | 0.265625,0.765625,1,1
1554 | 0.265625,0.765625,1,1
1555 | 0.296875,0.765625,1,1
1556 | 0.296875,0.765625,1,1
1557 | 0.328125,0.765625,1,1
1558 | 0.328125,0.765625,1,1
1559 | 0.359375,0.765625,1,1
1560 | 0.359375,0.765625,1,1
1561 | 0.390625,0.765625,1,1
1562 | 0.390625,0.765625,1,1
1563 | 0.421875,0.765625,1,1
1564 | 0.421875,0.765625,1,1
1565 | 0.453125,0.765625,1,1
1566 | 0.453125,0.765625,1,1
1567 | 0.484375,0.765625,1,1
1568 | 0.484375,0.765625,1,1
1569 | 0.515625,0.765625,1,1
1570 | 0.515625,0.765625,1,1
1571 | 0.546875,0.765625,1,1
1572 | 0.546875,0.765625,1,1
1573 | 0.578125,0.765625,1,1
1574 | 0.578125,0.765625,1,1
1575 | 0.609375,0.765625,1,1
1576 | 0.609375,0.765625,1,1
1577 | 0.640625,0.765625,1,1
1578 | 0.640625,0.765625,1,1
1579 | 0.671875,0.765625,1,1
1580 | 0.671875,0.765625,1,1
1581 | 0.703125,0.765625,1,1
1582 | 0.703125,0.765625,1,1
1583 | 0.734375,0.765625,1,1
1584 | 0.734375,0.765625,1,1
1585 | 0.765625,0.765625,1,1
1586 | 0.765625,0.765625,1,1
1587 | 0.796875,0.765625,1,1
1588 | 0.796875,0.765625,1,1
1589 | 0.828125,0.765625,1,1
1590 | 0.828125,0.765625,1,1
1591 | 0.859375,0.765625,1,1
1592 | 0.859375,0.765625,1,1
1593 | 0.890625,0.765625,1,1
1594 | 0.890625,0.765625,1,1
1595 | 0.921875,0.765625,1,1
1596 | 0.921875,0.765625,1,1
1597 | 0.953125,0.765625,1,1
1598 | 0.953125,0.765625,1,1
1599 | 0.984375,0.765625,1,1
1600 | 0.984375,0.765625,1,1
1601 | 0.015625,0.796875,1,1
1602 | 0.015625,0.796875,1,1
1603 | 0.046875,0.796875,1,1
1604 | 0.046875,0.796875,1,1
1605 | 0.078125,0.796875,1,1
1606 | 0.078125,0.796875,1,1
1607 | 0.109375,0.796875,1,1
1608 | 0.109375,0.796875,1,1
1609 | 0.140625,0.796875,1,1
1610 | 0.140625,0.796875,1,1
1611 | 0.171875,0.796875,1,1
1612 | 0.171875,0.796875,1,1
1613 | 0.203125,0.796875,1,1
1614 | 0.203125,0.796875,1,1
1615 | 0.234375,0.796875,1,1
1616 | 0.234375,0.796875,1,1
1617 | 0.265625,0.796875,1,1
1618 | 0.265625,0.796875,1,1
1619 | 0.296875,0.796875,1,1
1620 | 0.296875,0.796875,1,1
1621 | 0.328125,0.796875,1,1
1622 | 0.328125,0.796875,1,1
1623 | 0.359375,0.796875,1,1
1624 | 0.359375,0.796875,1,1
1625 | 0.390625,0.796875,1,1
1626 | 0.390625,0.796875,1,1
1627 | 0.421875,0.796875,1,1
1628 | 0.421875,0.796875,1,1
1629 | 0.453125,0.796875,1,1
1630 | 0.453125,0.796875,1,1
1631 | 0.484375,0.796875,1,1
1632 | 0.484375,0.796875,1,1
1633 | 0.515625,0.796875,1,1
1634 | 0.515625,0.796875,1,1
1635 | 0.546875,0.796875,1,1
1636 | 0.546875,0.796875,1,1
1637 | 0.578125,0.796875,1,1
1638 | 0.578125,0.796875,1,1
1639 | 0.609375,0.796875,1,1
1640 | 0.609375,0.796875,1,1
1641 | 0.640625,0.796875,1,1
1642 | 0.640625,0.796875,1,1
1643 | 0.671875,0.796875,1,1
1644 | 0.671875,0.796875,1,1
1645 | 0.703125,0.796875,1,1
1646 | 0.703125,0.796875,1,1
1647 | 0.734375,0.796875,1,1
1648 | 0.734375,0.796875,1,1
1649 | 0.765625,0.796875,1,1
1650 | 0.765625,0.796875,1,1
1651 | 0.796875,0.796875,1,1
1652 | 0.796875,0.796875,1,1
1653 | 0.828125,0.796875,1,1
1654 | 0.828125,0.796875,1,1
1655 | 0.859375,0.796875,1,1
1656 | 0.859375,0.796875,1,1
1657 | 0.890625,0.796875,1,1
1658 | 0.890625,0.796875,1,1
1659 | 0.921875,0.796875,1,1
1660 | 0.921875,0.796875,1,1
1661 | 0.953125,0.796875,1,1
1662 | 0.953125,0.796875,1,1
1663 | 0.984375,0.796875,1,1
1664 | 0.984375,0.796875,1,1
1665 | 0.015625,0.828125,1,1
1666 | 0.015625,0.828125,1,1
1667 | 0.046875,0.828125,1,1
1668 | 0.046875,0.828125,1,1
1669 | 0.078125,0.828125,1,1
1670 | 0.078125,0.828125,1,1
1671 | 0.109375,0.828125,1,1
1672 | 0.109375,0.828125,1,1
1673 | 0.140625,0.828125,1,1
1674 | 0.140625,0.828125,1,1
1675 | 0.171875,0.828125,1,1
1676 | 0.171875,0.828125,1,1
1677 | 0.203125,0.828125,1,1
1678 | 0.203125,0.828125,1,1
1679 | 0.234375,0.828125,1,1
1680 | 0.234375,0.828125,1,1
1681 | 0.265625,0.828125,1,1
1682 | 0.265625,0.828125,1,1
1683 | 0.296875,0.828125,1,1
1684 | 0.296875,0.828125,1,1
1685 | 0.328125,0.828125,1,1
1686 | 0.328125,0.828125,1,1
1687 | 0.359375,0.828125,1,1
1688 | 0.359375,0.828125,1,1
1689 | 0.390625,0.828125,1,1
1690 | 0.390625,0.828125,1,1
1691 | 0.421875,0.828125,1,1
1692 | 0.421875,0.828125,1,1
1693 | 0.453125,0.828125,1,1
1694 | 0.453125,0.828125,1,1
1695 | 0.484375,0.828125,1,1
1696 | 0.484375,0.828125,1,1
1697 | 0.515625,0.828125,1,1
1698 | 0.515625,0.828125,1,1
1699 | 0.546875,0.828125,1,1
1700 | 0.546875,0.828125,1,1
1701 | 0.578125,0.828125,1,1
1702 | 0.578125,0.828125,1,1
1703 | 0.609375,0.828125,1,1
1704 | 0.609375,0.828125,1,1
1705 | 0.640625,0.828125,1,1
1706 | 0.640625,0.828125,1,1
1707 | 0.671875,0.828125,1,1
1708 | 0.671875,0.828125,1,1
1709 | 0.703125,0.828125,1,1
1710 | 0.703125,0.828125,1,1
1711 | 0.734375,0.828125,1,1
1712 | 0.734375,0.828125,1,1
1713 | 0.765625,0.828125,1,1
1714 | 0.765625,0.828125,1,1
1715 | 0.796875,0.828125,1,1
1716 | 0.796875,0.828125,1,1
1717 | 0.828125,0.828125,1,1
1718 | 0.828125,0.828125,1,1
1719 | 0.859375,0.828125,1,1
1720 | 0.859375,0.828125,1,1
1721 | 0.890625,0.828125,1,1
1722 | 0.890625,0.828125,1,1
1723 | 0.921875,0.828125,1,1
1724 | 0.921875,0.828125,1,1
1725 | 0.953125,0.828125,1,1
1726 | 0.953125,0.828125,1,1
1727 | 0.984375,0.828125,1,1
1728 | 0.984375,0.828125,1,1
1729 | 0.015625,0.859375,1,1
1730 | 0.015625,0.859375,1,1
1731 | 0.046875,0.859375,1,1
1732 | 0.046875,0.859375,1,1
1733 | 0.078125,0.859375,1,1
1734 | 0.078125,0.859375,1,1
1735 | 0.109375,0.859375,1,1
1736 | 0.109375,0.859375,1,1
1737 | 0.140625,0.859375,1,1
1738 | 0.140625,0.859375,1,1
1739 | 0.171875,0.859375,1,1
1740 | 0.171875,0.859375,1,1
1741 | 0.203125,0.859375,1,1
1742 | 0.203125,0.859375,1,1
1743 | 0.234375,0.859375,1,1
1744 | 0.234375,0.859375,1,1
1745 | 0.265625,0.859375,1,1
1746 | 0.265625,0.859375,1,1
1747 | 0.296875,0.859375,1,1
1748 | 0.296875,0.859375,1,1
1749 | 0.328125,0.859375,1,1
1750 | 0.328125,0.859375,1,1
1751 | 0.359375,0.859375,1,1
1752 | 0.359375,0.859375,1,1
1753 | 0.390625,0.859375,1,1
1754 | 0.390625,0.859375,1,1
1755 | 0.421875,0.859375,1,1
1756 | 0.421875,0.859375,1,1
1757 | 0.453125,0.859375,1,1
1758 | 0.453125,0.859375,1,1
1759 | 0.484375,0.859375,1,1
1760 | 0.484375,0.859375,1,1
1761 | 0.515625,0.859375,1,1
1762 | 0.515625,0.859375,1,1
1763 | 0.546875,0.859375,1,1
1764 | 0.546875,0.859375,1,1
1765 | 0.578125,0.859375,1,1
1766 | 0.578125,0.859375,1,1
1767 | 0.609375,0.859375,1,1
1768 | 0.609375,0.859375,1,1
1769 | 0.640625,0.859375,1,1
1770 | 0.640625,0.859375,1,1
1771 | 0.671875,0.859375,1,1
1772 | 0.671875,0.859375,1,1
1773 | 0.703125,0.859375,1,1
1774 | 0.703125,0.859375,1,1
1775 | 0.734375,0.859375,1,1
1776 | 0.734375,0.859375,1,1
1777 | 0.765625,0.859375,1,1
1778 | 0.765625,0.859375,1,1
1779 | 0.796875,0.859375,1,1
1780 | 0.796875,0.859375,1,1
1781 | 0.828125,0.859375,1,1
1782 | 0.828125,0.859375,1,1
1783 | 0.859375,0.859375,1,1
1784 | 0.859375,0.859375,1,1
1785 | 0.890625,0.859375,1,1
1786 | 0.890625,0.859375,1,1
1787 | 0.921875,0.859375,1,1
1788 | 0.921875,0.859375,1,1
1789 | 0.953125,0.859375,1,1
1790 | 0.953125,0.859375,1,1
1791 | 0.984375,0.859375,1,1
1792 | 0.984375,0.859375,1,1
1793 | 0.015625,0.890625,1,1
1794 | 0.015625,0.890625,1,1
1795 | 0.046875,0.890625,1,1
1796 | 0.046875,0.890625,1,1
1797 | 0.078125,0.890625,1,1
1798 | 0.078125,0.890625,1,1
1799 | 0.109375,0.890625,1,1
1800 | 0.109375,0.890625,1,1
1801 | 0.140625,0.890625,1,1
1802 | 0.140625,0.890625,1,1
1803 | 0.171875,0.890625,1,1
1804 | 0.171875,0.890625,1,1
1805 | 0.203125,0.890625,1,1
1806 | 0.203125,0.890625,1,1
1807 | 0.234375,0.890625,1,1
1808 | 0.234375,0.890625,1,1
1809 | 0.265625,0.890625,1,1
1810 | 0.265625,0.890625,1,1
1811 | 0.296875,0.890625,1,1
1812 | 0.296875,0.890625,1,1
1813 | 0.328125,0.890625,1,1
1814 | 0.328125,0.890625,1,1
1815 | 0.359375,0.890625,1,1
1816 | 0.359375,0.890625,1,1
1817 | 0.390625,0.890625,1,1
1818 | 0.390625,0.890625,1,1
1819 | 0.421875,0.890625,1,1
1820 | 0.421875,0.890625,1,1
1821 | 0.453125,0.890625,1,1
1822 | 0.453125,0.890625,1,1
1823 | 0.484375,0.890625,1,1
1824 | 0.484375,0.890625,1,1
1825 | 0.515625,0.890625,1,1
1826 | 0.515625,0.890625,1,1
1827 | 0.546875,0.890625,1,1
1828 | 0.546875,0.890625,1,1
1829 | 0.578125,0.890625,1,1
1830 | 0.578125,0.890625,1,1
1831 | 0.609375,0.890625,1,1
1832 | 0.609375,0.890625,1,1
1833 | 0.640625,0.890625,1,1
1834 | 0.640625,0.890625,1,1
1835 | 0.671875,0.890625,1,1
1836 | 0.671875,0.890625,1,1
1837 | 0.703125,0.890625,1,1
1838 | 0.703125,0.890625,1,1
1839 | 0.734375,0.890625,1,1
1840 | 0.734375,0.890625,1,1
1841 | 0.765625,0.890625,1,1
1842 | 0.765625,0.890625,1,1
1843 | 0.796875,0.890625,1,1
1844 | 0.796875,0.890625,1,1
1845 | 0.828125,0.890625,1,1
1846 | 0.828125,0.890625,1,1
1847 | 0.859375,0.890625,1,1
1848 | 0.859375,0.890625,1,1
1849 | 0.890625,0.890625,1,1
1850 | 0.890625,0.890625,1,1
1851 | 0.921875,0.890625,1,1
1852 | 0.921875,0.890625,1,1
1853 | 0.953125,0.890625,1,1
1854 | 0.953125,0.890625,1,1
1855 | 0.984375,0.890625,1,1
1856 | 0.984375,0.890625,1,1
1857 | 0.015625,0.921875,1,1
1858 | 0.015625,0.921875,1,1
1859 | 0.046875,0.921875,1,1
1860 | 0.046875,0.921875,1,1
1861 | 0.078125,0.921875,1,1
1862 | 0.078125,0.921875,1,1
1863 | 0.109375,0.921875,1,1
1864 | 0.109375,0.921875,1,1
1865 | 0.140625,0.921875,1,1
1866 | 0.140625,0.921875,1,1
1867 | 0.171875,0.921875,1,1
1868 | 0.171875,0.921875,1,1
1869 | 0.203125,0.921875,1,1
1870 | 0.203125,0.921875,1,1
1871 | 0.234375,0.921875,1,1
1872 | 0.234375,0.921875,1,1
1873 | 0.265625,0.921875,1,1
1874 | 0.265625,0.921875,1,1
1875 | 0.296875,0.921875,1,1
1876 | 0.296875,0.921875,1,1
1877 | 0.328125,0.921875,1,1
1878 | 0.328125,0.921875,1,1
1879 | 0.359375,0.921875,1,1
1880 | 0.359375,0.921875,1,1
1881 | 0.390625,0.921875,1,1
1882 | 0.390625,0.921875,1,1
1883 | 0.421875,0.921875,1,1
1884 | 0.421875,0.921875,1,1
1885 | 0.453125,0.921875,1,1
1886 | 0.453125,0.921875,1,1
1887 | 0.484375,0.921875,1,1
1888 | 0.484375,0.921875,1,1
1889 | 0.515625,0.921875,1,1
1890 | 0.515625,0.921875,1,1
1891 | 0.546875,0.921875,1,1
1892 | 0.546875,0.921875,1,1
1893 | 0.578125,0.921875,1,1
1894 | 0.578125,0.921875,1,1
1895 | 0.609375,0.921875,1,1
1896 | 0.609375,0.921875,1,1
1897 | 0.640625,0.921875,1,1
1898 | 0.640625,0.921875,1,1
1899 | 0.671875,0.921875,1,1
1900 | 0.671875,0.921875,1,1
1901 | 0.703125,0.921875,1,1
1902 | 0.703125,0.921875,1,1
1903 | 0.734375,0.921875,1,1
1904 | 0.734375,0.921875,1,1
1905 | 0.765625,0.921875,1,1
1906 | 0.765625,0.921875,1,1
1907 | 0.796875,0.921875,1,1
1908 | 0.796875,0.921875,1,1
1909 | 0.828125,0.921875,1,1
1910 | 0.828125,0.921875,1,1
1911 | 0.859375,0.921875,1,1
1912 | 0.859375,0.921875,1,1
1913 | 0.890625,0.921875,1,1
1914 | 0.890625,0.921875,1,1
1915 | 0.921875,0.921875,1,1
1916 | 0.921875,0.921875,1,1
1917 | 0.953125,0.921875,1,1
1918 | 0.953125,0.921875,1,1
1919 | 0.984375,0.921875,1,1
1920 | 0.984375,0.921875,1,1
1921 | 0.015625,0.953125,1,1
1922 | 0.015625,0.953125,1,1
1923 | 0.046875,0.953125,1,1
1924 | 0.046875,0.953125,1,1
1925 | 0.078125,0.953125,1,1
1926 | 0.078125,0.953125,1,1
1927 | 0.109375,0.953125,1,1
1928 | 0.109375,0.953125,1,1
1929 | 0.140625,0.953125,1,1
1930 | 0.140625,0.953125,1,1
1931 | 0.171875,0.953125,1,1
1932 | 0.171875,0.953125,1,1
1933 | 0.203125,0.953125,1,1
1934 | 0.203125,0.953125,1,1
1935 | 0.234375,0.953125,1,1
1936 | 0.234375,0.953125,1,1
1937 | 0.265625,0.953125,1,1
1938 | 0.265625,0.953125,1,1
1939 | 0.296875,0.953125,1,1
1940 | 0.296875,0.953125,1,1
1941 | 0.328125,0.953125,1,1
1942 | 0.328125,0.953125,1,1
1943 | 0.359375,0.953125,1,1
1944 | 0.359375,0.953125,1,1
1945 | 0.390625,0.953125,1,1
1946 | 0.390625,0.953125,1,1
1947 | 0.421875,0.953125,1,1
1948 | 0.421875,0.953125,1,1
1949 | 0.453125,0.953125,1,1
1950 | 0.453125,0.953125,1,1
1951 | 0.484375,0.953125,1,1
1952 | 0.484375,0.953125,1,1
1953 | 0.515625,0.953125,1,1
1954 | 0.515625,0.953125,1,1
1955 | 0.546875,0.953125,1,1
1956 | 0.546875,0.953125,1,1
1957 | 0.578125,0.953125,1,1
1958 | 0.578125,0.953125,1,1
1959 | 0.609375,0.953125,1,1
1960 | 0.609375,0.953125,1,1
1961 | 0.640625,0.953125,1,1
1962 | 0.640625,0.953125,1,1
1963 | 0.671875,0.953125,1,1
1964 | 0.671875,0.953125,1,1
1965 | 0.703125,0.953125,1,1
1966 | 0.703125,0.953125,1,1
1967 | 0.734375,0.953125,1,1
1968 | 0.734375,0.953125,1,1
1969 | 0.765625,0.953125,1,1
1970 | 0.765625,0.953125,1,1
1971 | 0.796875,0.953125,1,1
1972 | 0.796875,0.953125,1,1
1973 | 0.828125,0.953125,1,1
1974 | 0.828125,0.953125,1,1
1975 | 0.859375,0.953125,1,1
1976 | 0.859375,0.953125,1,1
1977 | 0.890625,0.953125,1,1
1978 | 0.890625,0.953125,1,1
1979 | 0.921875,0.953125,1,1
1980 | 0.921875,0.953125,1,1
1981 | 0.953125,0.953125,1,1
1982 | 0.953125,0.953125,1,1
1983 | 0.984375,0.953125,1,1
1984 | 0.984375,0.953125,1,1
1985 | 0.015625,0.984375,1,1
1986 | 0.015625,0.984375,1,1
1987 | 0.046875,0.984375,1,1
1988 | 0.046875,0.984375,1,1
1989 | 0.078125,0.984375,1,1
1990 | 0.078125,0.984375,1,1
1991 | 0.109375,0.984375,1,1
1992 | 0.109375,0.984375,1,1
1993 | 0.140625,0.984375,1,1
1994 | 0.140625,0.984375,1,1
1995 | 0.171875,0.984375,1,1
1996 | 0.171875,0.984375,1,1
1997 | 0.203125,0.984375,1,1
1998 | 0.203125,0.984375,1,1
1999 | 0.234375,0.984375,1,1
2000 | 0.234375,0.984375,1,1
2001 | 0.265625,0.984375,1,1
2002 | 0.265625,0.984375,1,1
2003 | 0.296875,0.984375,1,1
2004 | 0.296875,0.984375,1,1
2005 | 0.328125,0.984375,1,1
2006 | 0.328125,0.984375,1,1
2007 | 0.359375,0.984375,1,1
2008 | 0.359375,0.984375,1,1
2009 | 0.390625,0.984375,1,1
2010 | 0.390625,0.984375,1,1
2011 | 0.421875,0.984375,1,1
2012 | 0.421875,0.984375,1,1
2013 | 0.453125,0.984375,1,1
2014 | 0.453125,0.984375,1,1
2015 | 0.484375,0.984375,1,1
2016 | 0.484375,0.984375,1,1
2017 | 0.515625,0.984375,1,1
2018 | 0.515625,0.984375,1,1
2019 | 0.546875,0.984375,1,1
2020 | 0.546875,0.984375,1,1
2021 | 0.578125,0.984375,1,1
2022 | 0.578125,0.984375,1,1
2023 | 0.609375,0.984375,1,1
2024 | 0.609375,0.984375,1,1
2025 | 0.640625,0.984375,1,1
2026 | 0.640625,0.984375,1,1
2027 | 0.671875,0.984375,1,1
2028 | 0.671875,0.984375,1,1
2029 | 0.703125,0.984375,1,1
2030 | 0.703125,0.984375,1,1
2031 | 0.734375,0.984375,1,1
2032 | 0.734375,0.984375,1,1
2033 | 0.765625,0.984375,1,1
2034 | 0.765625,0.984375,1,1
2035 | 0.796875,0.984375,1,1
2036 | 0.796875,0.984375,1,1
2037 | 0.828125,0.984375,1,1
2038 | 0.828125,0.984375,1,1
2039 | 0.859375,0.984375,1,1
2040 | 0.859375,0.984375,1,1
2041 | 0.890625,0.984375,1,1
2042 | 0.890625,0.984375,1,1
2043 | 0.921875,0.984375,1,1
2044 | 0.921875,0.984375,1,1
2045 | 0.953125,0.984375,1,1
2046 | 0.953125,0.984375,1,1
2047 | 0.984375,0.984375,1,1
2048 | 0.984375,0.984375,1,1
2049 | 0.03125,0.03125,1,1
2050 | 0.03125,0.03125,1,1
2051 | 0.09375,0.03125,1,1
2052 | 0.09375,0.03125,1,1
2053 | 0.15625,0.03125,1,1
2054 | 0.15625,0.03125,1,1
2055 | 0.21875,0.03125,1,1
2056 | 0.21875,0.03125,1,1
2057 | 0.28125,0.03125,1,1
2058 | 0.28125,0.03125,1,1
2059 | 0.34375,0.03125,1,1
2060 | 0.34375,0.03125,1,1
2061 | 0.40625,0.03125,1,1
2062 | 0.40625,0.03125,1,1
2063 | 0.46875,0.03125,1,1
2064 | 0.46875,0.03125,1,1
2065 | 0.53125,0.03125,1,1
2066 | 0.53125,0.03125,1,1
2067 | 0.59375,0.03125,1,1
2068 | 0.59375,0.03125,1,1
2069 | 0.65625,0.03125,1,1
2070 | 0.65625,0.03125,1,1
2071 | 0.71875,0.03125,1,1
2072 | 0.71875,0.03125,1,1
2073 | 0.78125,0.03125,1,1
2074 | 0.78125,0.03125,1,1
2075 | 0.84375,0.03125,1,1
2076 | 0.84375,0.03125,1,1
2077 | 0.90625,0.03125,1,1
2078 | 0.90625,0.03125,1,1
2079 | 0.96875,0.03125,1,1
2080 | 0.96875,0.03125,1,1
2081 | 0.03125,0.09375,1,1
2082 | 0.03125,0.09375,1,1
2083 | 0.09375,0.09375,1,1
2084 | 0.09375,0.09375,1,1
2085 | 0.15625,0.09375,1,1
2086 | 0.15625,0.09375,1,1
2087 | 0.21875,0.09375,1,1
2088 | 0.21875,0.09375,1,1
2089 | 0.28125,0.09375,1,1
2090 | 0.28125,0.09375,1,1
2091 | 0.34375,0.09375,1,1
2092 | 0.34375,0.09375,1,1
2093 | 0.40625,0.09375,1,1
2094 | 0.40625,0.09375,1,1
2095 | 0.46875,0.09375,1,1
2096 | 0.46875,0.09375,1,1
2097 | 0.53125,0.09375,1,1
2098 | 0.53125,0.09375,1,1
2099 | 0.59375,0.09375,1,1
2100 | 0.59375,0.09375,1,1
2101 | 0.65625,0.09375,1,1
2102 | 0.65625,0.09375,1,1
2103 | 0.71875,0.09375,1,1
2104 | 0.71875,0.09375,1,1
2105 | 0.78125,0.09375,1,1
2106 | 0.78125,0.09375,1,1
2107 | 0.84375,0.09375,1,1
2108 | 0.84375,0.09375,1,1
2109 | 0.90625,0.09375,1,1
2110 | 0.90625,0.09375,1,1
2111 | 0.96875,0.09375,1,1
2112 | 0.96875,0.09375,1,1
2113 | 0.03125,0.15625,1,1
2114 | 0.03125,0.15625,1,1
2115 | 0.09375,0.15625,1,1
2116 | 0.09375,0.15625,1,1
2117 | 0.15625,0.15625,1,1
2118 | 0.15625,0.15625,1,1
2119 | 0.21875,0.15625,1,1
2120 | 0.21875,0.15625,1,1
2121 | 0.28125,0.15625,1,1
2122 | 0.28125,0.15625,1,1
2123 | 0.34375,0.15625,1,1
2124 | 0.34375,0.15625,1,1
2125 | 0.40625,0.15625,1,1
2126 | 0.40625,0.15625,1,1
2127 | 0.46875,0.15625,1,1
2128 | 0.46875,0.15625,1,1
2129 | 0.53125,0.15625,1,1
2130 | 0.53125,0.15625,1,1
2131 | 0.59375,0.15625,1,1
2132 | 0.59375,0.15625,1,1
2133 | 0.65625,0.15625,1,1
2134 | 0.65625,0.15625,1,1
2135 | 0.71875,0.15625,1,1
2136 | 0.71875,0.15625,1,1
2137 | 0.78125,0.15625,1,1
2138 | 0.78125,0.15625,1,1
2139 | 0.84375,0.15625,1,1
2140 | 0.84375,0.15625,1,1
2141 | 0.90625,0.15625,1,1
2142 | 0.90625,0.15625,1,1
2143 | 0.96875,0.15625,1,1
2144 | 0.96875,0.15625,1,1
2145 | 0.03125,0.21875,1,1
2146 | 0.03125,0.21875,1,1
2147 | 0.09375,0.21875,1,1
2148 | 0.09375,0.21875,1,1
2149 | 0.15625,0.21875,1,1
2150 | 0.15625,0.21875,1,1
2151 | 0.21875,0.21875,1,1
2152 | 0.21875,0.21875,1,1
2153 | 0.28125,0.21875,1,1
2154 | 0.28125,0.21875,1,1
2155 | 0.34375,0.21875,1,1
2156 | 0.34375,0.21875,1,1
2157 | 0.40625,0.21875,1,1
2158 | 0.40625,0.21875,1,1
2159 | 0.46875,0.21875,1,1
2160 | 0.46875,0.21875,1,1
2161 | 0.53125,0.21875,1,1
2162 | 0.53125,0.21875,1,1
2163 | 0.59375,0.21875,1,1
2164 | 0.59375,0.21875,1,1
2165 | 0.65625,0.21875,1,1
2166 | 0.65625,0.21875,1,1
2167 | 0.71875,0.21875,1,1
2168 | 0.71875,0.21875,1,1
2169 | 0.78125,0.21875,1,1
2170 | 0.78125,0.21875,1,1
2171 | 0.84375,0.21875,1,1
2172 | 0.84375,0.21875,1,1
2173 | 0.90625,0.21875,1,1
2174 | 0.90625,0.21875,1,1
2175 | 0.96875,0.21875,1,1
2176 | 0.96875,0.21875,1,1
2177 | 0.03125,0.28125,1,1
2178 | 0.03125,0.28125,1,1
2179 | 0.09375,0.28125,1,1
2180 | 0.09375,0.28125,1,1
2181 | 0.15625,0.28125,1,1
2182 | 0.15625,0.28125,1,1
2183 | 0.21875,0.28125,1,1
2184 | 0.21875,0.28125,1,1
2185 | 0.28125,0.28125,1,1
2186 | 0.28125,0.28125,1,1
2187 | 0.34375,0.28125,1,1
2188 | 0.34375,0.28125,1,1
2189 | 0.40625,0.28125,1,1
2190 | 0.40625,0.28125,1,1
2191 | 0.46875,0.28125,1,1
2192 | 0.46875,0.28125,1,1
2193 | 0.53125,0.28125,1,1
2194 | 0.53125,0.28125,1,1
2195 | 0.59375,0.28125,1,1
2196 | 0.59375,0.28125,1,1
2197 | 0.65625,0.28125,1,1
2198 | 0.65625,0.28125,1,1
2199 | 0.71875,0.28125,1,1
2200 | 0.71875,0.28125,1,1
2201 | 0.78125,0.28125,1,1
2202 | 0.78125,0.28125,1,1
2203 | 0.84375,0.28125,1,1
2204 | 0.84375,0.28125,1,1
2205 | 0.90625,0.28125,1,1
2206 | 0.90625,0.28125,1,1
2207 | 0.96875,0.28125,1,1
2208 | 0.96875,0.28125,1,1
2209 | 0.03125,0.34375,1,1
2210 | 0.03125,0.34375,1,1
2211 | 0.09375,0.34375,1,1
2212 | 0.09375,0.34375,1,1
2213 | 0.15625,0.34375,1,1
2214 | 0.15625,0.34375,1,1
2215 | 0.21875,0.34375,1,1
2216 | 0.21875,0.34375,1,1
2217 | 0.28125,0.34375,1,1
2218 | 0.28125,0.34375,1,1
2219 | 0.34375,0.34375,1,1
2220 | 0.34375,0.34375,1,1
2221 | 0.40625,0.34375,1,1
2222 | 0.40625,0.34375,1,1
2223 | 0.46875,0.34375,1,1
2224 | 0.46875,0.34375,1,1
2225 | 0.53125,0.34375,1,1
2226 | 0.53125,0.34375,1,1
2227 | 0.59375,0.34375,1,1
2228 | 0.59375,0.34375,1,1
2229 | 0.65625,0.34375,1,1
2230 | 0.65625,0.34375,1,1
2231 | 0.71875,0.34375,1,1
2232 | 0.71875,0.34375,1,1
2233 | 0.78125,0.34375,1,1
2234 | 0.78125,0.34375,1,1
2235 | 0.84375,0.34375,1,1
2236 | 0.84375,0.34375,1,1
2237 | 0.90625,0.34375,1,1
2238 | 0.90625,0.34375,1,1
2239 | 0.96875,0.34375,1,1
2240 | 0.96875,0.34375,1,1
2241 | 0.03125,0.40625,1,1
2242 | 0.03125,0.40625,1,1
2243 | 0.09375,0.40625,1,1
2244 | 0.09375,0.40625,1,1
2245 | 0.15625,0.40625,1,1
2246 | 0.15625,0.40625,1,1
2247 | 0.21875,0.40625,1,1
2248 | 0.21875,0.40625,1,1
2249 | 0.28125,0.40625,1,1
2250 | 0.28125,0.40625,1,1
2251 | 0.34375,0.40625,1,1
2252 | 0.34375,0.40625,1,1
2253 | 0.40625,0.40625,1,1
2254 | 0.40625,0.40625,1,1
2255 | 0.46875,0.40625,1,1
2256 | 0.46875,0.40625,1,1
2257 | 0.53125,0.40625,1,1
2258 | 0.53125,0.40625,1,1
2259 | 0.59375,0.40625,1,1
2260 | 0.59375,0.40625,1,1
2261 | 0.65625,0.40625,1,1
2262 | 0.65625,0.40625,1,1
2263 | 0.71875,0.40625,1,1
2264 | 0.71875,0.40625,1,1
2265 | 0.78125,0.40625,1,1
2266 | 0.78125,0.40625,1,1
2267 | 0.84375,0.40625,1,1
2268 | 0.84375,0.40625,1,1
2269 | 0.90625,0.40625,1,1
2270 | 0.90625,0.40625,1,1
2271 | 0.96875,0.40625,1,1
2272 | 0.96875,0.40625,1,1
2273 | 0.03125,0.46875,1,1
2274 | 0.03125,0.46875,1,1
2275 | 0.09375,0.46875,1,1
2276 | 0.09375,0.46875,1,1
2277 | 0.15625,0.46875,1,1
2278 | 0.15625,0.46875,1,1
2279 | 0.21875,0.46875,1,1
2280 | 0.21875,0.46875,1,1
2281 | 0.28125,0.46875,1,1
2282 | 0.28125,0.46875,1,1
2283 | 0.34375,0.46875,1,1
2284 | 0.34375,0.46875,1,1
2285 | 0.40625,0.46875,1,1
2286 | 0.40625,0.46875,1,1
2287 | 0.46875,0.46875,1,1
2288 | 0.46875,0.46875,1,1
2289 | 0.53125,0.46875,1,1
2290 | 0.53125,0.46875,1,1
2291 | 0.59375,0.46875,1,1
2292 | 0.59375,0.46875,1,1
2293 | 0.65625,0.46875,1,1
2294 | 0.65625,0.46875,1,1
2295 | 0.71875,0.46875,1,1
2296 | 0.71875,0.46875,1,1
2297 | 0.78125,0.46875,1,1
2298 | 0.78125,0.46875,1,1
2299 | 0.84375,0.46875,1,1
2300 | 0.84375,0.46875,1,1
2301 | 0.90625,0.46875,1,1
2302 | 0.90625,0.46875,1,1
2303 | 0.96875,0.46875,1,1
2304 | 0.96875,0.46875,1,1
2305 | 0.03125,0.53125,1,1
2306 | 0.03125,0.53125,1,1
2307 | 0.09375,0.53125,1,1
2308 | 0.09375,0.53125,1,1
2309 | 0.15625,0.53125,1,1
2310 | 0.15625,0.53125,1,1
2311 | 0.21875,0.53125,1,1
2312 | 0.21875,0.53125,1,1
2313 | 0.28125,0.53125,1,1
2314 | 0.28125,0.53125,1,1
2315 | 0.34375,0.53125,1,1
2316 | 0.34375,0.53125,1,1
2317 | 0.40625,0.53125,1,1
2318 | 0.40625,0.53125,1,1
2319 | 0.46875,0.53125,1,1
2320 | 0.46875,0.53125,1,1
2321 | 0.53125,0.53125,1,1
2322 | 0.53125,0.53125,1,1
2323 | 0.59375,0.53125,1,1
2324 | 0.59375,0.53125,1,1
2325 | 0.65625,0.53125,1,1
2326 | 0.65625,0.53125,1,1
2327 | 0.71875,0.53125,1,1
2328 | 0.71875,0.53125,1,1
2329 | 0.78125,0.53125,1,1
2330 | 0.78125,0.53125,1,1
2331 | 0.84375,0.53125,1,1
2332 | 0.84375,0.53125,1,1
2333 | 0.90625,0.53125,1,1
2334 | 0.90625,0.53125,1,1
2335 | 0.96875,0.53125,1,1
2336 | 0.96875,0.53125,1,1
2337 | 0.03125,0.59375,1,1
2338 | 0.03125,0.59375,1,1
2339 | 0.09375,0.59375,1,1
2340 | 0.09375,0.59375,1,1
2341 | 0.15625,0.59375,1,1
2342 | 0.15625,0.59375,1,1
2343 | 0.21875,0.59375,1,1
2344 | 0.21875,0.59375,1,1
2345 | 0.28125,0.59375,1,1
2346 | 0.28125,0.59375,1,1
2347 | 0.34375,0.59375,1,1
2348 | 0.34375,0.59375,1,1
2349 | 0.40625,0.59375,1,1
2350 | 0.40625,0.59375,1,1
2351 | 0.46875,0.59375,1,1
2352 | 0.46875,0.59375,1,1
2353 | 0.53125,0.59375,1,1
2354 | 0.53125,0.59375,1,1
2355 | 0.59375,0.59375,1,1
2356 | 0.59375,0.59375,1,1
2357 | 0.65625,0.59375,1,1
2358 | 0.65625,0.59375,1,1
2359 | 0.71875,0.59375,1,1
2360 | 0.71875,0.59375,1,1
2361 | 0.78125,0.59375,1,1
2362 | 0.78125,0.59375,1,1
2363 | 0.84375,0.59375,1,1
2364 | 0.84375,0.59375,1,1
2365 | 0.90625,0.59375,1,1
2366 | 0.90625,0.59375,1,1
2367 | 0.96875,0.59375,1,1
2368 | 0.96875,0.59375,1,1
2369 | 0.03125,0.65625,1,1
2370 | 0.03125,0.65625,1,1
2371 | 0.09375,0.65625,1,1
2372 | 0.09375,0.65625,1,1
2373 | 0.15625,0.65625,1,1
2374 | 0.15625,0.65625,1,1
2375 | 0.21875,0.65625,1,1
2376 | 0.21875,0.65625,1,1
2377 | 0.28125,0.65625,1,1
2378 | 0.28125,0.65625,1,1
2379 | 0.34375,0.65625,1,1
2380 | 0.34375,0.65625,1,1
2381 | 0.40625,0.65625,1,1
2382 | 0.40625,0.65625,1,1
2383 | 0.46875,0.65625,1,1
2384 | 0.46875,0.65625,1,1
2385 | 0.53125,0.65625,1,1
2386 | 0.53125,0.65625,1,1
2387 | 0.59375,0.65625,1,1
2388 | 0.59375,0.65625,1,1
2389 | 0.65625,0.65625,1,1
2390 | 0.65625,0.65625,1,1
2391 | 0.71875,0.65625,1,1
2392 | 0.71875,0.65625,1,1
2393 | 0.78125,0.65625,1,1
2394 | 0.78125,0.65625,1,1
2395 | 0.84375,0.65625,1,1
2396 | 0.84375,0.65625,1,1
2397 | 0.90625,0.65625,1,1
2398 | 0.90625,0.65625,1,1
2399 | 0.96875,0.65625,1,1
2400 | 0.96875,0.65625,1,1
2401 | 0.03125,0.71875,1,1
2402 | 0.03125,0.71875,1,1
2403 | 0.09375,0.71875,1,1
2404 | 0.09375,0.71875,1,1
2405 | 0.15625,0.71875,1,1
2406 | 0.15625,0.71875,1,1
2407 | 0.21875,0.71875,1,1
2408 | 0.21875,0.71875,1,1
2409 | 0.28125,0.71875,1,1
2410 | 0.28125,0.71875,1,1
2411 | 0.34375,0.71875,1,1
2412 | 0.34375,0.71875,1,1
2413 | 0.40625,0.71875,1,1
2414 | 0.40625,0.71875,1,1
2415 | 0.46875,0.71875,1,1
2416 | 0.46875,0.71875,1,1
2417 | 0.53125,0.71875,1,1
2418 | 0.53125,0.71875,1,1
2419 | 0.59375,0.71875,1,1
2420 | 0.59375,0.71875,1,1
2421 | 0.65625,0.71875,1,1
2422 | 0.65625,0.71875,1,1
2423 | 0.71875,0.71875,1,1
2424 | 0.71875,0.71875,1,1
2425 | 0.78125,0.71875,1,1
2426 | 0.78125,0.71875,1,1
2427 | 0.84375,0.71875,1,1
2428 | 0.84375,0.71875,1,1
2429 | 0.90625,0.71875,1,1
2430 | 0.90625,0.71875,1,1
2431 | 0.96875,0.71875,1,1
2432 | 0.96875,0.71875,1,1
2433 | 0.03125,0.78125,1,1
2434 | 0.03125,0.78125,1,1
2435 | 0.09375,0.78125,1,1
2436 | 0.09375,0.78125,1,1
2437 | 0.15625,0.78125,1,1
2438 | 0.15625,0.78125,1,1
2439 | 0.21875,0.78125,1,1
2440 | 0.21875,0.78125,1,1
2441 | 0.28125,0.78125,1,1
2442 | 0.28125,0.78125,1,1
2443 | 0.34375,0.78125,1,1
2444 | 0.34375,0.78125,1,1
2445 | 0.40625,0.78125,1,1
2446 | 0.40625,0.78125,1,1
2447 | 0.46875,0.78125,1,1
2448 | 0.46875,0.78125,1,1
2449 | 0.53125,0.78125,1,1
2450 | 0.53125,0.78125,1,1
2451 | 0.59375,0.78125,1,1
2452 | 0.59375,0.78125,1,1
2453 | 0.65625,0.78125,1,1
2454 | 0.65625,0.78125,1,1
2455 | 0.71875,0.78125,1,1
2456 | 0.71875,0.78125,1,1
2457 | 0.78125,0.78125,1,1
2458 | 0.78125,0.78125,1,1
2459 | 0.84375,0.78125,1,1
2460 | 0.84375,0.78125,1,1
2461 | 0.90625,0.78125,1,1
2462 | 0.90625,0.78125,1,1
2463 | 0.96875,0.78125,1,1
2464 | 0.96875,0.78125,1,1
2465 | 0.03125,0.84375,1,1
2466 | 0.03125,0.84375,1,1
2467 | 0.09375,0.84375,1,1
2468 | 0.09375,0.84375,1,1
2469 | 0.15625,0.84375,1,1
2470 | 0.15625,0.84375,1,1
2471 | 0.21875,0.84375,1,1
2472 | 0.21875,0.84375,1,1
2473 | 0.28125,0.84375,1,1
2474 | 0.28125,0.84375,1,1
2475 | 0.34375,0.84375,1,1
2476 | 0.34375,0.84375,1,1
2477 | 0.40625,0.84375,1,1
2478 | 0.40625,0.84375,1,1
2479 | 0.46875,0.84375,1,1
2480 | 0.46875,0.84375,1,1
2481 | 0.53125,0.84375,1,1
2482 | 0.53125,0.84375,1,1
2483 | 0.59375,0.84375,1,1
2484 | 0.59375,0.84375,1,1
2485 | 0.65625,0.84375,1,1
2486 | 0.65625,0.84375,1,1
2487 | 0.71875,0.84375,1,1
2488 | 0.71875,0.84375,1,1
2489 | 0.78125,0.84375,1,1
2490 | 0.78125,0.84375,1,1
2491 | 0.84375,0.84375,1,1
2492 | 0.84375,0.84375,1,1
2493 | 0.90625,0.84375,1,1
2494 | 0.90625,0.84375,1,1
2495 | 0.96875,0.84375,1,1
2496 | 0.96875,0.84375,1,1
2497 | 0.03125,0.90625,1,1
2498 | 0.03125,0.90625,1,1
2499 | 0.09375,0.90625,1,1
2500 | 0.09375,0.90625,1,1
2501 | 0.15625,0.90625,1,1
2502 | 0.15625,0.90625,1,1
2503 | 0.21875,0.90625,1,1
2504 | 0.21875,0.90625,1,1
2505 | 0.28125,0.90625,1,1
2506 | 0.28125,0.90625,1,1
2507 | 0.34375,0.90625,1,1
2508 | 0.34375,0.90625,1,1
2509 | 0.40625,0.90625,1,1
2510 | 0.40625,0.90625,1,1
2511 | 0.46875,0.90625,1,1
2512 | 0.46875,0.90625,1,1
2513 | 0.53125,0.90625,1,1
2514 | 0.53125,0.90625,1,1
2515 | 0.59375,0.90625,1,1
2516 | 0.59375,0.90625,1,1
2517 | 0.65625,0.90625,1,1
2518 | 0.65625,0.90625,1,1
2519 | 0.71875,0.90625,1,1
2520 | 0.71875,0.90625,1,1
2521 | 0.78125,0.90625,1,1
2522 | 0.78125,0.90625,1,1
2523 | 0.84375,0.90625,1,1
2524 | 0.84375,0.90625,1,1
2525 | 0.90625,0.90625,1,1
2526 | 0.90625,0.90625,1,1
2527 | 0.96875,0.90625,1,1
2528 | 0.96875,0.90625,1,1
2529 | 0.03125,0.96875,1,1
2530 | 0.03125,0.96875,1,1
2531 | 0.09375,0.96875,1,1
2532 | 0.09375,0.96875,1,1
2533 | 0.15625,0.96875,1,1
2534 | 0.15625,0.96875,1,1
2535 | 0.21875,0.96875,1,1
2536 | 0.21875,0.96875,1,1
2537 | 0.28125,0.96875,1,1
2538 | 0.28125,0.96875,1,1
2539 | 0.34375,0.96875,1,1
2540 | 0.34375,0.96875,1,1
2541 | 0.40625,0.96875,1,1
2542 | 0.40625,0.96875,1,1
2543 | 0.46875,0.96875,1,1
2544 | 0.46875,0.96875,1,1
2545 | 0.53125,0.96875,1,1
2546 | 0.53125,0.96875,1,1
2547 | 0.59375,0.96875,1,1
2548 | 0.59375,0.96875,1,1
2549 | 0.65625,0.96875,1,1
2550 | 0.65625,0.96875,1,1
2551 | 0.71875,0.96875,1,1
2552 | 0.71875,0.96875,1,1
2553 | 0.78125,0.96875,1,1
2554 | 0.78125,0.96875,1,1
2555 | 0.84375,0.96875,1,1
2556 | 0.84375,0.96875,1,1
2557 | 0.90625,0.96875,1,1
2558 | 0.90625,0.96875,1,1
2559 | 0.96875,0.96875,1,1
2560 | 0.96875,0.96875,1,1
2561 | 0.0625,0.0625,1,1
2562 | 0.0625,0.0625,1,1
2563 | 0.0625,0.0625,1,1
2564 | 0.0625,0.0625,1,1
2565 | 0.0625,0.0625,1,1
2566 | 0.0625,0.0625,1,1
2567 | 0.1875,0.0625,1,1
2568 | 0.1875,0.0625,1,1
2569 | 0.1875,0.0625,1,1
2570 | 0.1875,0.0625,1,1
2571 | 0.1875,0.0625,1,1
2572 | 0.1875,0.0625,1,1
2573 | 0.3125,0.0625,1,1
2574 | 0.3125,0.0625,1,1
2575 | 0.3125,0.0625,1,1
2576 | 0.3125,0.0625,1,1
2577 | 0.3125,0.0625,1,1
2578 | 0.3125,0.0625,1,1
2579 | 0.4375,0.0625,1,1
2580 | 0.4375,0.0625,1,1
2581 | 0.4375,0.0625,1,1
2582 | 0.4375,0.0625,1,1
2583 | 0.4375,0.0625,1,1
2584 | 0.4375,0.0625,1,1
2585 | 0.5625,0.0625,1,1
2586 | 0.5625,0.0625,1,1
2587 | 0.5625,0.0625,1,1
2588 | 0.5625,0.0625,1,1
2589 | 0.5625,0.0625,1,1
2590 | 0.5625,0.0625,1,1
2591 | 0.6875,0.0625,1,1
2592 | 0.6875,0.0625,1,1
2593 | 0.6875,0.0625,1,1
2594 | 0.6875,0.0625,1,1
2595 | 0.6875,0.0625,1,1
2596 | 0.6875,0.0625,1,1
2597 | 0.8125,0.0625,1,1
2598 | 0.8125,0.0625,1,1
2599 | 0.8125,0.0625,1,1
2600 | 0.8125,0.0625,1,1
2601 | 0.8125,0.0625,1,1
2602 | 0.8125,0.0625,1,1
2603 | 0.9375,0.0625,1,1
2604 | 0.9375,0.0625,1,1
2605 | 0.9375,0.0625,1,1
2606 | 0.9375,0.0625,1,1
2607 | 0.9375,0.0625,1,1
2608 | 0.9375,0.0625,1,1
2609 | 0.0625,0.1875,1,1
2610 | 0.0625,0.1875,1,1
2611 | 0.0625,0.1875,1,1
2612 | 0.0625,0.1875,1,1
2613 | 0.0625,0.1875,1,1
2614 | 0.0625,0.1875,1,1
2615 | 0.1875,0.1875,1,1
2616 | 0.1875,0.1875,1,1
2617 | 0.1875,0.1875,1,1
2618 | 0.1875,0.1875,1,1
2619 | 0.1875,0.1875,1,1
2620 | 0.1875,0.1875,1,1
2621 | 0.3125,0.1875,1,1
2622 | 0.3125,0.1875,1,1
2623 | 0.3125,0.1875,1,1
2624 | 0.3125,0.1875,1,1
2625 | 0.3125,0.1875,1,1
2626 | 0.3125,0.1875,1,1
2627 | 0.4375,0.1875,1,1
2628 | 0.4375,0.1875,1,1
2629 | 0.4375,0.1875,1,1
2630 | 0.4375,0.1875,1,1
2631 | 0.4375,0.1875,1,1
2632 | 0.4375,0.1875,1,1
2633 | 0.5625,0.1875,1,1
2634 | 0.5625,0.1875,1,1
2635 | 0.5625,0.1875,1,1
2636 | 0.5625,0.1875,1,1
2637 | 0.5625,0.1875,1,1
2638 | 0.5625,0.1875,1,1
2639 | 0.6875,0.1875,1,1
2640 | 0.6875,0.1875,1,1
2641 | 0.6875,0.1875,1,1
2642 | 0.6875,0.1875,1,1
2643 | 0.6875,0.1875,1,1
2644 | 0.6875,0.1875,1,1
2645 | 0.8125,0.1875,1,1
2646 | 0.8125,0.1875,1,1
2647 | 0.8125,0.1875,1,1
2648 | 0.8125,0.1875,1,1
2649 | 0.8125,0.1875,1,1
2650 | 0.8125,0.1875,1,1
2651 | 0.9375,0.1875,1,1
2652 | 0.9375,0.1875,1,1
2653 | 0.9375,0.1875,1,1
2654 | 0.9375,0.1875,1,1
2655 | 0.9375,0.1875,1,1
2656 | 0.9375,0.1875,1,1
2657 | 0.0625,0.3125,1,1
2658 | 0.0625,0.3125,1,1
2659 | 0.0625,0.3125,1,1
2660 | 0.0625,0.3125,1,1
2661 | 0.0625,0.3125,1,1
2662 | 0.0625,0.3125,1,1
2663 | 0.1875,0.3125,1,1
2664 | 0.1875,0.3125,1,1
2665 | 0.1875,0.3125,1,1
2666 | 0.1875,0.3125,1,1
2667 | 0.1875,0.3125,1,1
2668 | 0.1875,0.3125,1,1
2669 | 0.3125,0.3125,1,1
2670 | 0.3125,0.3125,1,1
2671 | 0.3125,0.3125,1,1
2672 | 0.3125,0.3125,1,1
2673 | 0.3125,0.3125,1,1
2674 | 0.3125,0.3125,1,1
2675 | 0.4375,0.3125,1,1
2676 | 0.4375,0.3125,1,1
2677 | 0.4375,0.3125,1,1
2678 | 0.4375,0.3125,1,1
2679 | 0.4375,0.3125,1,1
2680 | 0.4375,0.3125,1,1
2681 | 0.5625,0.3125,1,1
2682 | 0.5625,0.3125,1,1
2683 | 0.5625,0.3125,1,1
2684 | 0.5625,0.3125,1,1
2685 | 0.5625,0.3125,1,1
2686 | 0.5625,0.3125,1,1
2687 | 0.6875,0.3125,1,1
2688 | 0.6875,0.3125,1,1
2689 | 0.6875,0.3125,1,1
2690 | 0.6875,0.3125,1,1
2691 | 0.6875,0.3125,1,1
2692 | 0.6875,0.3125,1,1
2693 | 0.8125,0.3125,1,1
2694 | 0.8125,0.3125,1,1
2695 | 0.8125,0.3125,1,1
2696 | 0.8125,0.3125,1,1
2697 | 0.8125,0.3125,1,1
2698 | 0.8125,0.3125,1,1
2699 | 0.9375,0.3125,1,1
2700 | 0.9375,0.3125,1,1
2701 | 0.9375,0.3125,1,1
2702 | 0.9375,0.3125,1,1
2703 | 0.9375,0.3125,1,1
2704 | 0.9375,0.3125,1,1
2705 | 0.0625,0.4375,1,1
2706 | 0.0625,0.4375,1,1
2707 | 0.0625,0.4375,1,1
2708 | 0.0625,0.4375,1,1
2709 | 0.0625,0.4375,1,1
2710 | 0.0625,0.4375,1,1
2711 | 0.1875,0.4375,1,1
2712 | 0.1875,0.4375,1,1
2713 | 0.1875,0.4375,1,1
2714 | 0.1875,0.4375,1,1
2715 | 0.1875,0.4375,1,1
2716 | 0.1875,0.4375,1,1
2717 | 0.3125,0.4375,1,1
2718 | 0.3125,0.4375,1,1
2719 | 0.3125,0.4375,1,1
2720 | 0.3125,0.4375,1,1
2721 | 0.3125,0.4375,1,1
2722 | 0.3125,0.4375,1,1
2723 | 0.4375,0.4375,1,1
2724 | 0.4375,0.4375,1,1
2725 | 0.4375,0.4375,1,1
2726 | 0.4375,0.4375,1,1
2727 | 0.4375,0.4375,1,1
2728 | 0.4375,0.4375,1,1
2729 | 0.5625,0.4375,1,1
2730 | 0.5625,0.4375,1,1
2731 | 0.5625,0.4375,1,1
2732 | 0.5625,0.4375,1,1
2733 | 0.5625,0.4375,1,1
2734 | 0.5625,0.4375,1,1
2735 | 0.6875,0.4375,1,1
2736 | 0.6875,0.4375,1,1
2737 | 0.6875,0.4375,1,1
2738 | 0.6875,0.4375,1,1
2739 | 0.6875,0.4375,1,1
2740 | 0.6875,0.4375,1,1
2741 | 0.8125,0.4375,1,1
2742 | 0.8125,0.4375,1,1
2743 | 0.8125,0.4375,1,1
2744 | 0.8125,0.4375,1,1
2745 | 0.8125,0.4375,1,1
2746 | 0.8125,0.4375,1,1
2747 | 0.9375,0.4375,1,1
2748 | 0.9375,0.4375,1,1
2749 | 0.9375,0.4375,1,1
2750 | 0.9375,0.4375,1,1
2751 | 0.9375,0.4375,1,1
2752 | 0.9375,0.4375,1,1
2753 | 0.0625,0.5625,1,1
2754 | 0.0625,0.5625,1,1
2755 | 0.0625,0.5625,1,1
2756 | 0.0625,0.5625,1,1
2757 | 0.0625,0.5625,1,1
2758 | 0.0625,0.5625,1,1
2759 | 0.1875,0.5625,1,1
2760 | 0.1875,0.5625,1,1
2761 | 0.1875,0.5625,1,1
2762 | 0.1875,0.5625,1,1
2763 | 0.1875,0.5625,1,1
2764 | 0.1875,0.5625,1,1
2765 | 0.3125,0.5625,1,1
2766 | 0.3125,0.5625,1,1
2767 | 0.3125,0.5625,1,1
2768 | 0.3125,0.5625,1,1
2769 | 0.3125,0.5625,1,1
2770 | 0.3125,0.5625,1,1
2771 | 0.4375,0.5625,1,1
2772 | 0.4375,0.5625,1,1
2773 | 0.4375,0.5625,1,1
2774 | 0.4375,0.5625,1,1
2775 | 0.4375,0.5625,1,1
2776 | 0.4375,0.5625,1,1
2777 | 0.5625,0.5625,1,1
2778 | 0.5625,0.5625,1,1
2779 | 0.5625,0.5625,1,1
2780 | 0.5625,0.5625,1,1
2781 | 0.5625,0.5625,1,1
2782 | 0.5625,0.5625,1,1
2783 | 0.6875,0.5625,1,1
2784 | 0.6875,0.5625,1,1
2785 | 0.6875,0.5625,1,1
2786 | 0.6875,0.5625,1,1
2787 | 0.6875,0.5625,1,1
2788 | 0.6875,0.5625,1,1
2789 | 0.8125,0.5625,1,1
2790 | 0.8125,0.5625,1,1
2791 | 0.8125,0.5625,1,1
2792 | 0.8125,0.5625,1,1
2793 | 0.8125,0.5625,1,1
2794 | 0.8125,0.5625,1,1
2795 | 0.9375,0.5625,1,1
2796 | 0.9375,0.5625,1,1
2797 | 0.9375,0.5625,1,1
2798 | 0.9375,0.5625,1,1
2799 | 0.9375,0.5625,1,1
2800 | 0.9375,0.5625,1,1
2801 | 0.0625,0.6875,1,1
2802 | 0.0625,0.6875,1,1
2803 | 0.0625,0.6875,1,1
2804 | 0.0625,0.6875,1,1
2805 | 0.0625,0.6875,1,1
2806 | 0.0625,0.6875,1,1
2807 | 0.1875,0.6875,1,1
2808 | 0.1875,0.6875,1,1
2809 | 0.1875,0.6875,1,1
2810 | 0.1875,0.6875,1,1
2811 | 0.1875,0.6875,1,1
2812 | 0.1875,0.6875,1,1
2813 | 0.3125,0.6875,1,1
2814 | 0.3125,0.6875,1,1
2815 | 0.3125,0.6875,1,1
2816 | 0.3125,0.6875,1,1
2817 | 0.3125,0.6875,1,1
2818 | 0.3125,0.6875,1,1
2819 | 0.4375,0.6875,1,1
2820 | 0.4375,0.6875,1,1
2821 | 0.4375,0.6875,1,1
2822 | 0.4375,0.6875,1,1
2823 | 0.4375,0.6875,1,1
2824 | 0.4375,0.6875,1,1
2825 | 0.5625,0.6875,1,1
2826 | 0.5625,0.6875,1,1
2827 | 0.5625,0.6875,1,1
2828 | 0.5625,0.6875,1,1
2829 | 0.5625,0.6875,1,1
2830 | 0.5625,0.6875,1,1
2831 | 0.6875,0.6875,1,1
2832 | 0.6875,0.6875,1,1
2833 | 0.6875,0.6875,1,1
2834 | 0.6875,0.6875,1,1
2835 | 0.6875,0.6875,1,1
2836 | 0.6875,0.6875,1,1
2837 | 0.8125,0.6875,1,1
2838 | 0.8125,0.6875,1,1
2839 | 0.8125,0.6875,1,1
2840 | 0.8125,0.6875,1,1
2841 | 0.8125,0.6875,1,1
2842 | 0.8125,0.6875,1,1
2843 | 0.9375,0.6875,1,1
2844 | 0.9375,0.6875,1,1
2845 | 0.9375,0.6875,1,1
2846 | 0.9375,0.6875,1,1
2847 | 0.9375,0.6875,1,1
2848 | 0.9375,0.6875,1,1
2849 | 0.0625,0.8125,1,1
2850 | 0.0625,0.8125,1,1
2851 | 0.0625,0.8125,1,1
2852 | 0.0625,0.8125,1,1
2853 | 0.0625,0.8125,1,1
2854 | 0.0625,0.8125,1,1
2855 | 0.1875,0.8125,1,1
2856 | 0.1875,0.8125,1,1
2857 | 0.1875,0.8125,1,1
2858 | 0.1875,0.8125,1,1
2859 | 0.1875,0.8125,1,1
2860 | 0.1875,0.8125,1,1
2861 | 0.3125,0.8125,1,1
2862 | 0.3125,0.8125,1,1
2863 | 0.3125,0.8125,1,1
2864 | 0.3125,0.8125,1,1
2865 | 0.3125,0.8125,1,1
2866 | 0.3125,0.8125,1,1
2867 | 0.4375,0.8125,1,1
2868 | 0.4375,0.8125,1,1
2869 | 0.4375,0.8125,1,1
2870 | 0.4375,0.8125,1,1
2871 | 0.4375,0.8125,1,1
2872 | 0.4375,0.8125,1,1
2873 | 0.5625,0.8125,1,1
2874 | 0.5625,0.8125,1,1
2875 | 0.5625,0.8125,1,1
2876 | 0.5625,0.8125,1,1
2877 | 0.5625,0.8125,1,1
2878 | 0.5625,0.8125,1,1
2879 | 0.6875,0.8125,1,1
2880 | 0.6875,0.8125,1,1
2881 | 0.6875,0.8125,1,1
2882 | 0.6875,0.8125,1,1
2883 | 0.6875,0.8125,1,1
2884 | 0.6875,0.8125,1,1
2885 | 0.8125,0.8125,1,1
2886 | 0.8125,0.8125,1,1
2887 | 0.8125,0.8125,1,1
2888 | 0.8125,0.8125,1,1
2889 | 0.8125,0.8125,1,1
2890 | 0.8125,0.8125,1,1
2891 | 0.9375,0.8125,1,1
2892 | 0.9375,0.8125,1,1
2893 | 0.9375,0.8125,1,1
2894 | 0.9375,0.8125,1,1
2895 | 0.9375,0.8125,1,1
2896 | 0.9375,0.8125,1,1
2897 | 0.0625,0.9375,1,1
2898 | 0.0625,0.9375,1,1
2899 | 0.0625,0.9375,1,1
2900 | 0.0625,0.9375,1,1
2901 | 0.0625,0.9375,1,1
2902 | 0.0625,0.9375,1,1
2903 | 0.1875,0.9375,1,1
2904 | 0.1875,0.9375,1,1
2905 | 0.1875,0.9375,1,1
2906 | 0.1875,0.9375,1,1
2907 | 0.1875,0.9375,1,1
2908 | 0.1875,0.9375,1,1
2909 | 0.3125,0.9375,1,1
2910 | 0.3125,0.9375,1,1
2911 | 0.3125,0.9375,1,1
2912 | 0.3125,0.9375,1,1
2913 | 0.3125,0.9375,1,1
2914 | 0.3125,0.9375,1,1
2915 | 0.4375,0.9375,1,1
2916 | 0.4375,0.9375,1,1
2917 | 0.4375,0.9375,1,1
2918 | 0.4375,0.9375,1,1
2919 | 0.4375,0.9375,1,1
2920 | 0.4375,0.9375,1,1
2921 | 0.5625,0.9375,1,1
2922 | 0.5625,0.9375,1,1
2923 | 0.5625,0.9375,1,1
2924 | 0.5625,0.9375,1,1
2925 | 0.5625,0.9375,1,1
2926 | 0.5625,0.9375,1,1
2927 | 0.6875,0.9375,1,1
2928 | 0.6875,0.9375,1,1
2929 | 0.6875,0.9375,1,1
2930 | 0.6875,0.9375,1,1
2931 | 0.6875,0.9375,1,1
2932 | 0.6875,0.9375,1,1
2933 | 0.8125,0.9375,1,1
2934 | 0.8125,0.9375,1,1
2935 | 0.8125,0.9375,1,1
2936 | 0.8125,0.9375,1,1
2937 | 0.8125,0.9375,1,1
2938 | 0.8125,0.9375,1,1
2939 | 0.9375,0.9375,1,1
2940 | 0.9375,0.9375,1,1
2941 | 0.9375,0.9375,1,1
2942 | 0.9375,0.9375,1,1
2943 | 0.9375,0.9375,1,1
2944 | 0.9375,0.9375,1,1
2945 |
--------------------------------------------------------------------------------
/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JuliaPoo/MultiHand-Tracking/78b817591eaac9e31645f0e0d63560248b040f78/demo.gif
--------------------------------------------------------------------------------
/demo_3D.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JuliaPoo/MultiHand-Tracking/78b817591eaac9e31645f0e0d63560248b040f78/demo_3D.gif
--------------------------------------------------------------------------------
/demo_process_video.py:
--------------------------------------------------------------------------------
1 | from PIL import Image
2 | import imageio
3 | import numpy as np
4 | from threading import Thread
5 |
6 | import os
7 | import shutil
8 | import sys
9 |
10 | import time
11 |
12 | sys.path.insert(0, "src/")
13 |
14 | import multi_hand_tracker as mht
15 | import plot_hand
16 |
17 | TEMP_FOLDER = "TEMP"
18 | N_THREADS = 8
19 |
20 | palm_model_path = "./models/palm_detection_without_custom_op.tflite"
21 | landmark_model_path = "./models/hand_landmark.tflite"
22 | anchors_path = "./data/anchors.csv"
23 |
24 |
25 | def GetImageList(filename, crop=1):
26 | reader = imageio.get_reader(filename)
27 | images = []
28 | for index, img in enumerate(reader):
29 | img = Image.fromarray(img)
30 | w,h = img.size
31 | img = img.crop((w*(1-crop)/2, 0, w*(1+crop)/2, h))
32 | images.append(np.array(img))
33 |
34 | fps = reader.get_meta_data()['fps']
35 | return images, fps
36 |
37 | def Process_Img_List(img_idx_list, thread_idx):
38 |
39 | detector = mht.MultiHandTracker(palm_model_path, landmark_model_path, anchors_path)
40 |
41 | L = len(img_idx_list)
42 | for c, i in enumerate(img_idx_list):
43 | img = img_list[i]
44 | kp_list, box_list = detector(img)
45 | ALL_KP[i] = kp_list
46 | ALL_BB[i] = box_list
47 | print ("Thread {2}: [*] Processing image {0}/{1} \r".format(c+1, L, thread_idx), end = "")
48 | print ("Thread {2}: [*] Done!".format(c+1, L, thread_idx) + " "*30 + "\n", end = "")
49 |
50 | def chunks(lst, n):
51 | """Yield successive n-sized chunks from lst."""
52 | for i in range(0, len(lst), n):
53 | yield lst[i:i + n]
54 |
55 | def main(filename):
56 |
57 | # Initialise images
58 | global img_list, ALL_KP, ALL_BB
59 | img_list, fps = GetImageList(filename, crop=0.8)
60 | L = len(img_list)
61 | ALL_KP = [None]*L
62 | ALL_BB = [None]*L
63 |
64 | # Create TEMP folder
65 | if not os.path.isdir(TEMP_FOLDER): os.mkdir(TEMP_FOLDER)
66 |
67 | # Analyse images
68 | t = time.time()
69 |
70 | img_list_chunks = chunks(list(range(L)), L // N_THREADS)
71 |
72 | threads = []
73 | for i, chunk in enumerate(img_list_chunks):
74 | threads.append(Thread(target = Process_Img_List, args = (chunk, i)))
75 | for thread in threads: thread.start()
76 | for thread in threads: thread.join()
77 |
78 | print ("\n[+] Done!")
79 | print ("Time taken: {}s".format(time.time() - t))
80 | t = time.time()
81 |
82 | # Saving images
83 | print("\n[*] Saving images")
84 | count = 0
85 | for img, kp_list, box_list in zip(img_list, ALL_KP, ALL_BB):
86 | plot_hand.plot_img(img, kp_list, box_list, save=TEMP_FOLDER + r"/{}.png".format(count))
87 | count += 1
88 | print("[*] Saving image {0}/{1} \r".format(count, L), end = "")
89 |
90 | print ("\n[+] Done!")
91 | print ("Time taken: {}s".format(time.time() - t))
92 |
93 | # Creating GIF
94 | print ("[*] Saving to GIF")
95 | images_save = []
96 | for i in range(L):
97 | images_save.append(Image.fromarray(imageio.imread(TEMP_FOLDER + r"/{}.png".format(i))))
98 |
99 | gif_save = images_save[0]
100 | gif_save.info['duration'] = 1./fps
101 | gif_save.save('DEMO.gif', save_all=True, append_images=images_save[1:], loop=0)
102 |
103 | shutil.rmtree(TEMP_FOLDER)
104 | print ("[+] Done!")
105 |
106 | if __name__ == "__main__":
107 |
108 | print (" Input filename or url of video to process")
109 | print (" E.g. https://www.signingsavvy.com/media/mp4-hd/6/6990.mp4")
110 | filename = input(">>>>> filename/url: ")
111 | main(filename)
--------------------------------------------------------------------------------
/demo_process_video_3D.py:
--------------------------------------------------------------------------------
1 | from PIL import Image
2 | import imageio
3 | import numpy as np
4 | from threading import Thread
5 |
6 | import os
7 | import shutil
8 | import sys
9 |
10 | import time
11 |
12 | sys.path.insert(0, "src/")
13 |
14 | import multi_hand_tracker as mht
15 | import plot_hand
16 |
17 | TEMP_FOLDER = "TEMP"
18 | N_THREADS = 8
19 |
20 | palm_model_path = "./models/palm_detection_without_custom_op.tflite"
21 | landmark_model_path = "./models/hand_landmark_3D.tflite"
22 | anchors_path = "./data/anchors.csv"
23 |
24 | def GetImageList(filename, crop=1):
25 | reader = imageio.get_reader(filename)
26 | images = []
27 | for index, img in enumerate(reader):
28 | img = Image.fromarray(img)
29 | w,h = img.size
30 | img = img.crop((w*(1-crop)/2, 0, w*(1+crop)/2, h))
31 | images.append(np.array(img))
32 |
33 | fps = reader.get_meta_data()['fps']
34 | return images, fps
35 |
36 | def Process_Img_List(img_idx_list, thread_idx):
37 |
38 | # Initialise detector
39 | detector = mht.MultiHandTracker3D(palm_model_path, landmark_model_path, anchors_path)
40 |
41 | L = len(img_idx_list)
42 | for c, i in enumerate(img_idx_list):
43 | img = img_list[i]
44 |
45 | # Make background black cuz its wayy cooler
46 | img1 = img[:,:,:]
47 | img1[img > 240] = 0
48 |
49 | # Get predictions
50 | kp_list, box_list = detector(img1)
51 | ALL_KP[i] = kp_list
52 | ALL_BB[i] = box_list
53 |
54 | # Determine handedness of predictions
55 | ALL_ISRIGHT[i] = [mht.is_right_hand(kp) for kp in kp_list]
56 |
57 | print ("Thread {2}: [*] Processing image {0}/{1} \r".format(c+1, L, thread_idx), end = "")
58 | print ("Thread {2}: [*] Done!".format(c+1, L, thread_idx) + " "*30 + "\n", end = "")
59 |
60 | def chunks(lst, n):
61 | """Yield successive n-sized chunks from lst."""
62 | for i in range(0, len(lst), n):
63 | yield lst[i:i + n]
64 |
65 | def main(filename):
66 |
67 | # Initialise images
68 | global img_list, ALL_KP, ALL_BB, ALL_ISRIGHT
69 | img_list, fps = GetImageList(filename, crop=0.8)
70 | L = len(img_list)
71 | ALL_KP = [None]*L
72 | ALL_BB = [None]*L
73 | ALL_ISRIGHT = [None]*L
74 |
75 | # Create TEMP folder
76 | if not os.path.isdir(TEMP_FOLDER): os.mkdir(TEMP_FOLDER)
77 |
78 | # Analyse images
79 | t = time.time()
80 |
81 | img_list_chunks = chunks(list(range(L)), L // N_THREADS)
82 |
83 | threads = []
84 | for i, chunk in enumerate(img_list_chunks):
85 | threads.append(Thread(target = Process_Img_List, args = (chunk, i)))
86 | for thread in threads: thread.start()
87 | for thread in threads: thread.join()
88 |
89 | timetaken = time.time() - t
90 | print ("\n[+] Done!")
91 | print ("Time taken: {}s".format(timetaken))
92 | print ("Frames per sec: {}s".format(timetaken/L))
93 | t = time.time()
94 |
95 | # Saving images
96 | print("\n[*] Saving images")
97 | count = 0
98 | for img, kp_list, box_list, is_right in zip(img_list, ALL_KP, ALL_BB, ALL_ISRIGHT):
99 | plot_hand.plot_img(img, kp_list, box_list, save=TEMP_FOLDER + r"/{}.png".format(count), size=6, is_right=is_right)
100 | count += 1
101 | print("[*] Saving image {0}/{1} \r".format(count, L), end = "")
102 |
103 | print ("\n[+] Done!")
104 | print ("Time taken: {}s".format(time.time() - t))
105 |
106 | # Creating GIF
107 | print ("[*] Saving to GIF")
108 | images_save = []
109 | for i in range(L):
110 | images_save.append(Image.fromarray(imageio.imread(TEMP_FOLDER + r"/{}.png".format(i))))
111 |
112 | gif_save = images_save[0]
113 | gif_save.info['duration'] = 1./fps
114 | gif_save.save('DEMO_3D.gif', save_all=True, append_images=images_save[1:], loop=0)
115 |
116 | shutil.rmtree(TEMP_FOLDER)
117 | print ("[+] Done!")
118 |
119 | if __name__ == "__main__":
120 |
121 | print (" Input filename or url of video to process")
122 | print (" E.g. https://www.signingsavvy.com/media/mp4-hd/24/24526.mp4")
123 | filename = input(">>>>> filename/url: ")
124 | main(filename)
--------------------------------------------------------------------------------
/models/hand_landmark.tflite:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JuliaPoo/MultiHand-Tracking/78b817591eaac9e31645f0e0d63560248b040f78/models/hand_landmark.tflite
--------------------------------------------------------------------------------
/models/hand_landmark_3d.tflite:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JuliaPoo/MultiHand-Tracking/78b817591eaac9e31645f0e0d63560248b040f78/models/hand_landmark_3d.tflite
--------------------------------------------------------------------------------
/models/palm_detection_without_custom_op.tflite:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JuliaPoo/MultiHand-Tracking/78b817591eaac9e31645f0e0d63560248b040f78/models/palm_detection_without_custom_op.tflite
--------------------------------------------------------------------------------
/src/multi_hand_tracker.py:
--------------------------------------------------------------------------------
1 | import csv
2 | import cv2
3 | import numpy as np
4 | import tensorflow as tf
5 | from shapely.geometry import Polygon
6 | from scipy.spatial.distance import pdist, squareform
7 |
8 | # TODO:
9 | # Make camera demo
10 |
11 | class MultiHandTracker():
12 |
13 | r"""
14 | Class to use Google's Mediapipe MultiHandTracking pipeline from Python for 2D predictions.
15 | Any any image size and aspect ratio supported.
16 |
17 | Args:
18 | palm_model: path to the palm_detection.tflite
19 | joint_model: path to the hand_landmark.tflite
20 | anchors_path: path to the csv containing SSD anchors
21 |
22 | Optional_Args:
23 | box_enlarge: bbox will be scalled by box_enlarge. Default 1.5
24 | box_shift: bbox will be shifted downwards by box_shift. Default 0.4
25 | max_hands: The maximum number of hands to detect. Default 2
26 | detect_hand_thres: Threshold for hand detections. Default 0.7
27 | detect_keypoints_thres: Threshold whereby keypoints detected will be considered a hand. Default 0.2
28 | iou_thres: non-maximum suppression threshold. Default 0.6
29 | independent: If True, each image will be processed independent of the previous frame
30 |
31 | Output:
32 | Tuple (keypoints list, bounding box list)
33 | -- keypoints list is a list of (21,2) array each representing the coordinates of keypoints for each hand
34 | -- bounding box list is a list of (4,2) array each representing the bounding box for each hand
35 | -- If hand instance does not exist, its entry in keypoints list and bounding box list will be empty
36 |
37 |
38 | Examples::
39 | >>> det = HandTracker(path1, path2, path3)
40 | >>> input_img = np.random.randint(0,255, 256*256*3).reshape(256,256,3)
41 | >>> keypoints, bbox = det(input_img)
42 | """
43 |
44 | def __init__(self,
45 | palm_model,
46 | joint_model,
47 | anchors_path,
48 | box_enlarge = 1.5,
49 | box_shift = 0.4,
50 | max_hands = 2,
51 | detect_hand_thres = 0.7,
52 | detect_keypoints_thres = 0.2,
53 | iou_thres = 0.6,
54 | independent = False
55 | ):
56 |
57 | # Flags
58 | self.independent = independent
59 |
60 | # BBox predictions parameters
61 | self.box_shift = box_shift
62 | self.box_enlarge = box_enlarge
63 |
64 | # HandLanmarks parameters (not used for now)
65 | self.max_hands = max_hands
66 | self.is_hands_list = [False]*max_hands
67 |
68 | # Initialise previous frame buffers
69 | self.bb_prev = [None]*max_hands
70 | self.kp_prev = [None]*max_hands
71 |
72 | # Thresholds init
73 | self.detect_hand_thres = detect_hand_thres
74 | self.detect_keypoints_thres = detect_keypoints_thres
75 | self.iou_thres = iou_thres
76 |
77 | # Initialise models
78 | self.interp_palm = tf.lite.Interpreter(palm_model)
79 | self.interp_palm.allocate_tensors()
80 | self.interp_joint = tf.lite.Interpreter(joint_model)
81 | self.interp_joint.allocate_tensors()
82 |
83 | # reading the SSD anchors
84 | with open(anchors_path, "r") as csv_f:
85 | self.anchors = np.r_[
86 | [x for x in csv.reader(csv_f, quoting=csv.QUOTE_NONNUMERIC)]
87 | ]
88 | # reading tflite model paramteres
89 | output_details = self.interp_palm.get_output_details()
90 | input_details = self.interp_palm.get_input_details()
91 |
92 | # Getting tensor index for palm detection
93 | self.in_idx = input_details[0]['index']
94 | self.out_reg_idx = output_details[0]['index']
95 | self.out_clf_idx = output_details[1]['index']
96 |
97 | # Getting tensor index for hand landmarks
98 | self.in_idx_joint = self.interp_joint.get_input_details()[0]['index']
99 | self.out_idx_joint = self.interp_joint.get_output_details()[0]['index']
100 | self.out_idx_is_hand = self.interp_joint.get_output_details()[1]['index']
101 |
102 | # 90° rotation matrix used to create the alignment trianlge
103 | self.R90 = np.r_[[[0,1],[-1,0]]]
104 |
105 | # trianlge target coordinates used to move the detected hand
106 | # into the right position
107 | self._target_triangle = np.float32([
108 | [128, 128],
109 | [128, 0],
110 | [ 0, 128]
111 | ])
112 | self._target_box = np.float32([
113 | [ 0, 0, 1],
114 | [256, 0, 1],
115 | [256, 256, 1],
116 | [ 0, 256, 1],
117 | ])
118 |
119 | def _get_triangle(self, kp0, kp2, dist=1):
120 | """get a triangle used to calculate Affine transformation matrix"""
121 |
122 | dir_v = kp2 - kp0
123 | dir_v /= np.linalg.norm(dir_v)
124 |
125 | dir_v_r = dir_v @ self.R90.T
126 | return np.float32([kp2, kp2+dir_v*dist, kp2 + dir_v_r*dist])
127 |
128 | @staticmethod
129 | def _triangle_to_bbox(source):
130 | # plain old vector arithmetics
131 | bbox = np.c_[
132 | [source[2] - source[0] + source[1]],
133 | [source[1] + source[0] - source[2]],
134 | [3 * source[0] - source[1] - source[2]],
135 | [source[2] - source[1] + source[0]],
136 | ].reshape(-1,2)
137 | return bbox
138 |
139 | @staticmethod
140 | def _im_normalize(img):
141 | return np.ascontiguousarray(
142 | 2 * ((img / 255) - 0.5
143 | ).astype('float32'))
144 |
145 | @staticmethod
146 | def _sigm(x):
147 | return 1 / (1 + np.exp(-x) )
148 |
149 | @staticmethod
150 | def _pad1(x):
151 | return np.pad(x, ((0,0),(0,1)), constant_values=1, mode='constant')
152 |
153 | @staticmethod
154 | def _IOU(poly1, poly2):
155 | return poly1.intersection(poly2).area / poly1.union(poly2).area
156 |
157 | @staticmethod
158 | def _max_dist(points):
159 | '''Find maximum distance between 2 points in a set of points'''
160 | D = pdist(points)
161 | D = squareform(D);
162 | return np.nanmax(D)
163 |
164 | def _predict_bbox(self, kp, bbox):
165 | '''Predicts bbox from previous keypoints and bbox'''
166 |
167 | #kp_C = kp.sum(axis = 0)/len(kp)
168 | kp_C = kp[9]
169 | bb_C = bbox.sum(axis = 0)/len(bbox)
170 | bbox_pred = bbox + (kp_C - bb_C)
171 |
172 | # 12 is the kp for the tip of the middle finger
173 | # 9 is the knuckle of the middle finger
174 | # I'm not sure which is better
175 | line = np.array([kp[0], kp[9]])
176 | bbox_side = bbox[1] - bbox[2]
177 | line_vec = line[1] - line[0]
178 | cangle = np.dot(line_vec, bbox_side)/(np.linalg.norm(line_vec) * np.linalg.norm(bbox_side))
179 | sangle = np.sqrt(1 - cangle*cangle)
180 |
181 | scale = self.box_enlarge * self._max_dist(kp)/np.linalg.norm(bbox_side)
182 | rot = np.r_[[[cangle,-sangle],[sangle,cangle]]]
183 | bbox_pred = (bbox - bb_C) @ rot * scale + bb_C
184 |
185 | return bbox_pred
186 |
187 | def _GetCandidateIdx(self, box_list, max_hands = 2, iou_thres = 0.45):
188 | '''Perform non max suppression'''
189 |
190 | box_groups = [[(box_list[0], 0)]]
191 |
192 | # Group BBOX according to IOU
193 | for idx, box in enumerate(box_list[1:]):
194 | idx += 1
195 | pbox = Polygon(box)
196 | new_group = True
197 | for group in box_groups:
198 | if self._IOU(pbox, Polygon(group[0][0])) > iou_thres:
199 | group.append((box, idx))
200 | new_group = False
201 | break
202 | if new_group:
203 | box_groups.append([(box, idx)])
204 |
205 | # Sort bbox groups according to number of elements in group
206 | len_groups = [(len(group), idx) for idx, group in enumerate(box_groups)]
207 | len_groups = sorted(len_groups, reverse = True, key = lambda x: x[0])
208 |
209 | # Return candidate bbox groups (max max_hands groups)
210 | candidate_groups_idx = [len_idx[-1] for len_idx in len_groups[:max_hands]]
211 | candidate_groups = [box_groups[idx] for idx in candidate_groups_idx]
212 |
213 | # Return candidate bbox index based on maximum area
214 | candidate_groups_area = [[(Polygon(box).area, idx) for box, idx in group] for group in candidate_groups]
215 | candidate_idx = [max(group, key=lambda x: x[0])[-1] for group in candidate_groups_area]
216 |
217 | return candidate_idx
218 |
219 | def _source_to_bbox(self, scale, pad, source):
220 | '''
221 | From output of palm detections to bbox
222 | Also returns parameters used for transforming the
223 | handlandmarks to prevent repeated computation
224 | '''
225 |
226 | Mtr = cv2.getAffineTransform(
227 | source * scale,
228 | self._target_triangle
229 | )
230 |
231 | Mtr_temp = self._pad1(Mtr.T).T
232 | Mtr_temp[2,:2] = 0
233 | Minv = np.linalg.inv(Mtr_temp)
234 |
235 | box_orig = (self._target_box @ Minv.T)[:,:2]
236 | box_orig -= pad[::-1]
237 |
238 | return box_orig, Mtr, Minv
239 |
240 | def _bbox_to_source(self, bbox, pad):
241 |
242 | '''
243 | Obtain the transformation matrix and its inverse from bbox to source
244 | '''
245 |
246 | src_tri = np.array(bbox[:3] + pad[::-1], dtype=np.float32)
247 | dst_tri = self._target_box[:3,:2].copy(order='C')
248 | Mtr = cv2.getAffineTransform(src_tri, dst_tri)
249 |
250 | Mtr_temp = self._pad1(Mtr.T).T
251 | Mtr_temp[2,:2] = 0
252 | Minv = np.linalg.inv(Mtr_temp)
253 |
254 | return Mtr, Minv
255 |
256 | def _get_bbox_Mtr_Minv(self, img, img_norm):
257 | source_list = self.detect_hand(img_norm)
258 | if len(source_list) == 0:
259 | return [], []
260 |
261 | scale = max(img.shape) / 256
262 | bbox_Mtr_Minv_list = [self._source_to_bbox(scale, self.pad, source) for source in source_list]
263 | box_orig_list = [ele[0] for ele in bbox_Mtr_Minv_list]
264 |
265 | box_valid_idx = self._GetCandidateIdx(box_orig_list, max_hands = self.max_hands, iou_thres = self.iou_thres)
266 | box_orig_list = [box_orig_list[i] for i in box_valid_idx]
267 | Mtr_Minv_list = [bbox_Mtr_Minv_list[i][1:] for i in box_valid_idx]
268 |
269 | box_orig_list += [None] * (self.max_hands - len(box_orig_list))
270 | Mtr_Minv_list += [(None, None)] * (self.max_hands - len(Mtr_Minv_list))
271 |
272 | return box_orig_list, Mtr_Minv_list
273 |
274 | def _merge_bbox_predicts(self, bbox_list, bbox_params):
275 | '''
276 | Primitive instance tracking
277 | Not part of the mediapipe pipeline
278 | '''
279 |
280 | prev_poly = [Polygon(box) for box in self.bb_prev]
281 | curr_poly = [Polygon(box) for box in bbox_list]
282 |
283 | rearranged_box = [None]*self.max_hands
284 | rearranged_params = [None]*self.max_hands
285 | leftover = curr_poly[:]
286 | for idx1, ppoly in enumerate(prev_poly):
287 | for idx2, cpoly in enumerate(curr_poly):
288 | if cpoly in leftover: continue
289 | if self._IOU(ppoly, cpoly) > self.iou_thres:
290 | rearranged_box[idx1] = self.bb_prev[idx2]
291 | rearranged_params[idx1] = tuple(_bbox_to_source(bbox, self.pad))
292 | leftover[idx2] = None
293 | break
294 |
295 | leftover = [i for i in leftover if type(i) != type(None)]
296 |
297 | for idx1, cpoly in enumerate(leftover):
298 | for idx2 in range(len(rearranged_box)):
299 | if type(rearranged_box[idx2]) == type(None):
300 | rearranged_box[idx2] = bbox_list[idx1]
301 | rearranged_params[idx2] = bbox_params[idx1]
302 | break
303 |
304 | return rearranged_box, rearranged_params
305 |
306 |
307 | def predict_joints(self, img_norm, hand_thres = 0.):
308 | '''Returns the joints output and if a hand is present in img_norm'''
309 |
310 | self.interp_joint.set_tensor(
311 | self.in_idx_joint, img_norm.reshape(1,256,256,3))
312 | self.interp_joint.invoke()
313 |
314 | joints = self.interp_joint.get_tensor(self.out_idx_joint)
315 | is_hand = self.interp_joint.get_tensor(self.out_idx_is_hand)[0][0]*10**11
316 |
317 | return joints.reshape(-1,2), is_hand > hand_thres
318 |
319 | def detect_hand(self, img_norm):
320 | '''Perform palm hand detection'''
321 |
322 | assert -1 <= img_norm.min() and img_norm.max() <= 1,\
323 | "img_norm should be in range [-1, 1]"
324 | assert img_norm.shape == (256, 256, 3),\
325 | "img_norm shape must be (256, 256, 3)"
326 |
327 | # predict hand location and 7 initial landmarks
328 | self.interp_palm.set_tensor(self.in_idx, img_norm[None])
329 | self.interp_palm.invoke()
330 |
331 | out_reg = self.interp_palm.get_tensor(self.out_reg_idx)[0]
332 | out_clf = self.interp_palm.get_tensor(self.out_clf_idx)[0,:,0]
333 |
334 | # finding the best prediction
335 | detecion_mask = self._sigm(out_clf) > self.detect_hand_thres
336 | candidate_detect = out_reg[detecion_mask]
337 | candidate_anchors = self.anchors[detecion_mask]
338 |
339 | if candidate_detect.shape[0] == 0:
340 | return []
341 |
342 | candidate_idx = list(range(candidate_detect.shape[0]))
343 |
344 | # bounding box offsets, width and height
345 | bbox_dets_list = []
346 | center_wo_offst_list = []
347 | for idx in candidate_idx:
348 | dx,dy,w,h = candidate_detect[idx, :4]
349 | bbox_dets_list.append((dx,dy,w,h))
350 |
351 | center_wo_offst_list.append(candidate_anchors[idx,:2] * 256)
352 |
353 | # 7 initial keypoints
354 | keypoints_list = [center_wo_offst_list[i] + candidate_detect[idx,4:].reshape(-1,2) for i,idx in enumerate(candidate_idx)]
355 | side_list = [max(w,h) * self.box_enlarge for _,_,w,h in bbox_dets_list]
356 |
357 | # now we need to move and rotate the detected hand for it to occupy a
358 | # 256x256 square
359 | # line from wrist keypoint to middle finger keypoint
360 | # should point straight up
361 | # I'm sorry for the list comprehensions
362 | source_list = [self._get_triangle(keypoints[0], keypoints[2], side) for keypoints, side in zip(keypoints_list, side_list)]
363 | source_list = [source - (keypoints[0] - keypoints[2]) * self.box_shift for source, keypoints in zip(source_list, keypoints_list)]
364 | source_list = [np.array(source, dtype="float32") for source in source_list]
365 |
366 | return source_list
367 |
368 | def preprocess_img(self, img):
369 | # fit the image into a 256x256 square
370 | shape = np.r_[img.shape]
371 | pad = (shape.max() - shape[:2]).astype('uint32') // 2
372 | img_pad = np.pad(
373 | img,
374 | ((pad[0],pad[0]), (pad[1],pad[1]), (0,0)),
375 | mode='constant')
376 | img_small = cv2.resize(img_pad, (256, 256))
377 | img_small = np.ascontiguousarray(img_small)
378 |
379 | img_norm = self._im_normalize(img_small)
380 | return img_pad, img_norm, pad
381 |
382 |
383 | def __call__(self, img, get_kp = True):
384 |
385 | '''
386 | img is the image to be processed (np.array)
387 | if get_kp is False, only the bounding box is returned. Keypoints will return an empty list
388 | '''
389 |
390 | # Process image
391 | img_pad, img_norm, pad = self.preprocess_img(img)
392 | self.pad = pad
393 |
394 | # Checks whether to recompute palm detection or use previous frame's bounding box
395 | if len([1 for i in self.bb_prev if type(i) == type(None)]) > 0:
396 | box_orig_list, Mtr_Minv_list = self._get_bbox_Mtr_Minv(img, img_norm)
397 | box_orig_list, Mtr_Minv_list = self._merge_bbox_predicts(box_orig_list, Mtr_Minv_list)
398 |
399 | if not get_kp: return [], box_orig_list
400 | else:
401 | box_orig_list = [self._predict_bbox(kp, bbox) for kp, bbox in zip(self.kp_prev, self.bb_prev)]
402 | Mtr_Minv_list = [self._bbox_to_source(bbox, pad) for bbox in box_orig_list]
403 |
404 |
405 | # Initialise buffers
406 | is_hands_list_prev = self.is_hands_list
407 | kp_orig_list = []
408 | self.is_hands_list = []
409 | index = 0
410 |
411 | kp_orig_list = []
412 |
413 | # Iterate across all palm detections
414 | for Mtr, Minv in Mtr_Minv_list:
415 |
416 | # Check if palm instance exist
417 | if type(Mtr) == type(None):
418 | self.is_hands_list.append(False)
419 | kp_orig_list.append(None)
420 | continue
421 |
422 | # Crop image according to bounding box
423 | img_landmark = cv2.warpAffine(
424 | self._im_normalize(img_pad), Mtr, (256,256)
425 | )
426 |
427 | # Get hand keypoints. is_hand is to detect if hand is present within bounding box
428 | joints, is_hand = self.predict_joints(img_landmark, hand_thres = self.detect_keypoints_thres)
429 | if not is_hand:
430 | self.is_hands_list.append(False)
431 | box_orig_list[index] = None
432 | kp_orig_list.append(None)
433 | is_recall = True
434 | continue
435 |
436 | # projecting keypoints back into original image coordinate space
437 | kp_orig = (self._pad1(joints) @ Minv.T)[:,:2]
438 | kp_orig -= pad[::-1]
439 |
440 | kp_orig_list.append(kp_orig)
441 | self.is_hands_list.append(is_hand)
442 |
443 | index += 1
444 |
445 | # Store previous frame bbox and kp
446 | if not self.independent:
447 | self.bb_prev = box_orig_list
448 | self.kp_prev = kp_orig_list
449 |
450 | # Recall if is_hands has changed (The number of palm instances decreased)
451 | if (len([1 for i,j in zip(is_hands_list_prev, self.is_hands_list) if (i==True and j==False)]) != 0):
452 | return self.__call__(img, get_kp = get_kp)
453 |
454 | return kp_orig_list, box_orig_list
455 |
456 |
457 | # Plenty of repeated code, but it works I guess
458 | class MultiHandTracker3D():
459 |
460 | r"""
461 | Class to use Google's Mediapipe MultiHandTracking pipeline from Python for 3D predictions.
462 | Any any image size and aspect ratio supported.
463 | 3D predictions enables differentiation between left and right hand using is_right_hand(keypoints).
464 |
465 | Args:
466 | palm_model: path to the palm_detection.tflite
467 | joint_model: path to the hand_landmark_3D.tflite
468 | anchors_path: path to the csv containing SSD anchors
469 |
470 | Optional_Args:
471 | box_enlarge: bbox will be scaled by box_enlarge. Default 1.5
472 | box_shift: bbox will be shifted downwards by box_shift. Default 0.2
473 | max_hands: The maximum number of hands to detect. Default 2
474 | detect_hand_thres: Threshold for hand detections. Default 0.5
475 | detect_keypoints_thres: Threshold whereby keypoints detected will be considered a hand. Default 0.3
476 | iou_thres: non-maximum suppression threshold. Default 0.4
477 |
478 | Output:
479 | Tuple (keypoints list, bounding box list)
480 | -- keypoints list is a list of (21,3) array each representing the coordinates of keypoints for each hand
481 | -- bounding box list is a list of (4,2) array each representing the bounding box for each hand
482 | -- If hand instance does not exist, its entry in keypoints list and bounding box list will be empty
483 |
484 |
485 | Examples::
486 | >>> det = HandTracker(path1, path2, path3)
487 | >>> input_img = np.random.randint(0,255, 256*256*3).reshape(256,256,3)
488 | >>> keypoints, bbox = det(input_img)
489 |
490 | """
491 |
492 | def __init__(self,
493 | palm_model,
494 | joint_model,
495 | anchors_path,
496 | box_enlarge = 1.5,
497 | box_shift = 0.2,
498 | max_hands = 2,
499 | detect_hand_thres = 0.5,
500 | detect_keypoints_thres = 0.3,
501 | iou_thres = 0.4,
502 | ):
503 |
504 | # Flags
505 | self.independent = True
506 |
507 | # BBox predictions parameters
508 | self.box_shift = box_shift
509 | self.box_enlarge = box_enlarge
510 |
511 | # HandLanmarks parameters (not used for now)
512 | self.max_hands = max_hands
513 | self.is_hands_list = [False]*max_hands
514 |
515 | # Initialise previous frame buffers
516 | self.bb_prev = [None]*max_hands
517 | self.kp_prev = [None]*max_hands
518 |
519 | # Thresholds init
520 | self.detect_hand_thres = detect_hand_thres
521 | self.detect_keypoints_thres = detect_keypoints_thres
522 | self.iou_thres = iou_thres
523 |
524 | # Initialise models
525 | self.interp_palm = tf.lite.Interpreter(palm_model)
526 | self.interp_palm.allocate_tensors()
527 | self.interp_joint = tf.lite.Interpreter(joint_model)
528 | self.interp_joint.allocate_tensors()
529 |
530 | # reading the SSD anchors
531 | with open(anchors_path, "r") as csv_f:
532 | self.anchors = np.r_[
533 | [x for x in csv.reader(csv_f, quoting=csv.QUOTE_NONNUMERIC)]
534 | ]
535 | # reading tflite model paramteres
536 | output_details = self.interp_palm.get_output_details()
537 | input_details = self.interp_palm.get_input_details()
538 |
539 | # Getting tensor index for palm detection
540 | self.in_idx = input_details[0]['index']
541 | self.out_reg_idx = output_details[0]['index']
542 | self.out_clf_idx = output_details[1]['index']
543 |
544 | # Getting tensor index for hand landmarks
545 | self.in_idx_joint = self.interp_joint.get_input_details()[0]['index']
546 | self.out_idx_joint = self.interp_joint.get_output_details()[0]['index']
547 | self.out_idx_is_hand = self.interp_joint.get_output_details()[1]['index']
548 |
549 | # 90° rotation matrix used to create the alignment trianlge
550 | self.R90 = np.r_[[[0,1],[-1,0]]]
551 |
552 | # trianlge target coordinates used to move the detected hand
553 | # into the right position
554 | self._target_triangle = np.float32([
555 | [128, 128],
556 | [128, 0],
557 | [ 0, 128]
558 | ])
559 | self._target_box = np.float32([
560 | [ 0, 0, 1],
561 | [256, 0, 1],
562 | [256, 256, 1],
563 | [ 0, 256, 1],
564 | ])
565 |
566 | def _get_triangle(self, kp0, kp2, dist=1):
567 | """get a triangle used to calculate Affine transformation matrix"""
568 |
569 | dir_v = kp2 - kp0
570 | dir_v /= np.linalg.norm(dir_v)
571 |
572 | dir_v_r = dir_v @ self.R90.T
573 | return np.float32([kp2, kp2+dir_v*dist, kp2 + dir_v_r*dist])
574 |
575 | @staticmethod
576 | def _triangle_to_bbox(source):
577 | # plain old vector arithmetics
578 | bbox = np.c_[
579 | [source[2] - source[0] + source[1]],
580 | [source[1] + source[0] - source[2]],
581 | [3 * source[0] - source[1] - source[2]],
582 | [source[2] - source[1] + source[0]],
583 | ].reshape(-1,2)
584 | return bbox
585 |
586 | @staticmethod
587 | def _im_normalize(img):
588 | return np.ascontiguousarray(
589 | 2 * ((img / 255) - 0.5
590 | ).astype('float32'))
591 |
592 | @staticmethod
593 | def _sigm(x):
594 | return 1 / (1 + np.exp(-x) )
595 |
596 | @staticmethod
597 | def _pad1(x):
598 | return np.pad(x, ((0,0),(0,1)), constant_values=1, mode='constant')
599 |
600 | @staticmethod
601 | def _IOU(poly1, poly2):
602 | return poly1.intersection(poly2).area / poly1.union(poly2).area
603 |
604 | @staticmethod
605 | def _max_dist(points):
606 | '''Find maximum distance between 2 points in a set of points'''
607 | D = pdist(points)
608 | D = squareform(D);
609 | return np.nanmax(D)
610 |
611 | def _predict_bbox(self, kp, bbox):
612 | '''Predicts bbox from previous keypoints and bbox'''
613 |
614 | #kp_C = kp.sum(axis = 0)/len(kp)
615 | kp_C = kp[9]
616 | bb_C = bbox.sum(axis = 0)/len(bbox)
617 | bbox_pred = bbox + (kp_C - bb_C)
618 |
619 | # 12 is the kp for the tip of the middle finger
620 | # 9 is the knuckle of the middle finger
621 | # I'm not sure which is better
622 | line = np.array([kp[0], kp[9]])
623 | bbox_side = bbox[1] - bbox[2]
624 | line_vec = line[1] - line[0]
625 | cangle = np.dot(line_vec, bbox_side)/(np.linalg.norm(line_vec) * np.linalg.norm(bbox_side))
626 | sangle = np.sqrt(1 - cangle*cangle)
627 |
628 | scale = self.box_enlarge * self._max_dist(kp)/np.linalg.norm(bbox_side)
629 | rot = np.r_[[[cangle,-sangle],[sangle,cangle]]]
630 | bbox_pred = (bbox - bb_C) @ rot * scale + bb_C
631 |
632 | return bbox_pred
633 |
634 | def _GetCandidateIdx(self, box_list, max_hands = 2, iou_thres = 0.45):
635 | '''Perform non max suppression'''
636 |
637 | box_groups = [[(box_list[0], 0)]]
638 |
639 | # Group BBOX according to IOU
640 | for idx, box in enumerate(box_list[1:]):
641 | idx += 1
642 | pbox = Polygon(box)
643 | new_group = True
644 | for group in box_groups:
645 | if self._IOU(pbox, Polygon(group[0][0])) > iou_thres:
646 | group.append((box, idx))
647 | new_group = False
648 | break
649 | if new_group:
650 | box_groups.append([(box, idx)])
651 |
652 | # Sort bbox groups according to number of elements in group
653 | len_groups = [(len(group), idx) for idx, group in enumerate(box_groups)]
654 | len_groups = sorted(len_groups, reverse = True, key = lambda x: x[0])
655 |
656 | # Return candidate bbox groups (max max_hands groups)
657 | candidate_groups_idx = [len_idx[-1] for len_idx in len_groups[:max_hands]]
658 | candidate_groups = [box_groups[idx] for idx in candidate_groups_idx]
659 |
660 | # Return candidate bbox index based on maximum area
661 | candidate_groups_area = [[(Polygon(box).area, idx) for box, idx in group] for group in candidate_groups]
662 | candidate_idx = [max(group, key=lambda x: x[0])[-1] for group in candidate_groups_area]
663 |
664 | return candidate_idx
665 |
666 | def _source_to_bbox(self, scale, pad, source):
667 | '''
668 | From output of palm detections to bbox
669 | Also returns parameters used for transforming the
670 | handlandmarks to prevent repeated computation
671 | '''
672 |
673 | Mtr = cv2.getAffineTransform(
674 | source * scale,
675 | self._target_triangle
676 | )
677 |
678 | Mtr_temp = self._pad1(Mtr.T).T
679 | Mtr_temp[2,:2] = 0
680 | Minv = np.linalg.inv(Mtr_temp)
681 |
682 | box_orig = (self._target_box @ Minv.T)[:,:2]
683 | box_orig -= pad[::-1]
684 |
685 | return box_orig, Mtr, Minv
686 |
687 | def _bbox_to_source(self, bbox, pad):
688 |
689 | '''
690 | Obtain the transformation matrix and its inverse from bbox to source
691 | '''
692 |
693 | src_tri = np.array(bbox[:3] + pad[::-1], dtype=np.float32)
694 | dst_tri = self._target_box[:3,:2].copy(order='C')
695 | Mtr = cv2.getAffineTransform(src_tri, dst_tri)
696 |
697 | Mtr_temp = self._pad1(Mtr.T).T
698 | Mtr_temp[2,:2] = 0
699 | Minv = np.linalg.inv(Mtr_temp)
700 |
701 | return Mtr, Minv
702 |
703 | def _get_bbox_Mtr_Minv(self, img, img_norm):
704 | source_list = self.detect_hand(img_norm)
705 | if len(source_list) == 0:
706 | return [], []
707 |
708 | scale = max(img.shape) / 256
709 | bbox_Mtr_Minv_list = [self._source_to_bbox(scale, self.pad, source) for source in source_list]
710 | box_orig_list = [ele[0] for ele in bbox_Mtr_Minv_list]
711 |
712 | box_valid_idx = self._GetCandidateIdx(box_orig_list, max_hands = self.max_hands, iou_thres = self.iou_thres)
713 | box_orig_list = [box_orig_list[i] for i in box_valid_idx]
714 | Mtr_Minv_list = [bbox_Mtr_Minv_list[i][1:] for i in box_valid_idx]
715 |
716 | box_orig_list += [None] * (self.max_hands - len(box_orig_list))
717 | Mtr_Minv_list += [(None, None)] * (self.max_hands - len(Mtr_Minv_list))
718 |
719 | return box_orig_list, Mtr_Minv_list
720 |
721 | def _merge_bbox_predicts(self, bbox_list, bbox_params):
722 | '''
723 | Primitive instance tracking
724 | Not part of the mediapipe pipeline
725 | '''
726 |
727 | prev_poly = [Polygon(box) for box in self.bb_prev]
728 | curr_poly = [Polygon(box) for box in bbox_list]
729 |
730 | rearranged_box = [None]*self.max_hands
731 | rearranged_params = [None]*self.max_hands
732 | leftover = curr_poly[:]
733 | for idx1, ppoly in enumerate(prev_poly):
734 | for idx2, cpoly in enumerate(curr_poly):
735 | if cpoly in leftover: continue
736 | if self._IOU(ppoly, cpoly) > self.iou_thres:
737 | rearranged_box[idx1] = self.bb_prev[idx2]
738 | rearranged_params[idx1] = tuple(_bbox_to_source(bbox, self.pad))
739 | leftover[idx2] = None
740 | break
741 |
742 | leftover = [i for i in leftover if type(i) != type(None)]
743 |
744 | for idx1, cpoly in enumerate(leftover):
745 | for idx2 in range(len(rearranged_box)):
746 | if type(rearranged_box[idx2]) == type(None):
747 | rearranged_box[idx2] = bbox_list[idx1]
748 | rearranged_params[idx2] = bbox_params[idx1]
749 | break
750 |
751 | return rearranged_box, rearranged_params
752 |
753 |
754 | def predict_joints(self, img_norm, hand_thres = 0.):
755 | '''Returns the joints output and if a hand is present in img_norm'''
756 |
757 | self.interp_joint.set_tensor(
758 | self.in_idx_joint, img_norm.reshape(1,256,256,3))
759 | self.interp_joint.invoke()
760 |
761 | joints = self.interp_joint.get_tensor(self.out_idx_joint)
762 | is_hand = self.interp_joint.get_tensor(self.out_idx_is_hand)[0][0]*10**11
763 |
764 | return joints.reshape(-1,3), is_hand > hand_thres
765 |
766 | def detect_hand(self, img_norm):
767 | '''Perform palm hand detection'''
768 |
769 | assert -1 <= img_norm.min() and img_norm.max() <= 1,\
770 | "img_norm should be in range [-1, 1]"
771 | assert img_norm.shape == (256, 256, 3),\
772 | "img_norm shape must be (256, 256, 3)"
773 |
774 | # predict hand location and 7 initial landmarks
775 | self.interp_palm.set_tensor(self.in_idx, img_norm[None])
776 | self.interp_palm.invoke()
777 |
778 | out_reg = self.interp_palm.get_tensor(self.out_reg_idx)[0]
779 | out_clf = self.interp_palm.get_tensor(self.out_clf_idx)[0,:,0]
780 |
781 | # finding the best prediction
782 | detecion_mask = self._sigm(out_clf) > self.detect_hand_thres
783 | candidate_detect = out_reg[detecion_mask]
784 | candidate_anchors = self.anchors[detecion_mask]
785 |
786 | if candidate_detect.shape[0] == 0:
787 | return []
788 |
789 | candidate_idx = list(range(candidate_detect.shape[0]))
790 |
791 | # bounding box offsets, width and height
792 | bbox_dets_list = []
793 | center_wo_offst_list = []
794 | for idx in candidate_idx:
795 | dx,dy,w,h = candidate_detect[idx, :4]
796 | bbox_dets_list.append((dx,dy,w,h))
797 |
798 | center_wo_offst_list.append(candidate_anchors[idx,:2] * 256)
799 |
800 | # 7 initial keypoints
801 | keypoints_list = [center_wo_offst_list[i] + candidate_detect[idx,4:].reshape(-1,2) for i,idx in enumerate(candidate_idx)]
802 | side_list = [max(w,h) * self.box_enlarge for _,_,w,h in bbox_dets_list]
803 |
804 | # now we need to move and rotate the detected hand for it to occupy a
805 | # 256x256 square
806 | # line from wrist keypoint to middle finger keypoint
807 | # should point straight up
808 | # I'm sorry for the list comprehensions
809 | source_list = [self._get_triangle(keypoints[0], keypoints[2], side) for keypoints, side in zip(keypoints_list, side_list)]
810 | source_list = [source - (keypoints[0] - keypoints[2]) * self.box_shift for source, keypoints in zip(source_list, keypoints_list)]
811 | source_list = [np.array(source, dtype="float32") for source in source_list]
812 |
813 | return source_list
814 |
815 | def preprocess_img(self, img):
816 | # fit the image into a 256x256 square
817 | shape = np.r_[img.shape]
818 | pad = (shape.max() - shape[:2]).astype('uint32') // 2
819 | img_pad = np.pad(
820 | img,
821 | ((pad[0],pad[0]), (pad[1],pad[1]), (0,0)),
822 | mode='constant')
823 | img_small = cv2.resize(img_pad, (256, 256))
824 | img_small = np.ascontiguousarray(img_small)
825 |
826 | img_norm = self._im_normalize(img_small)
827 | return img_pad, img_norm, pad
828 |
829 |
830 | def __call__(self, img, get_kp = True):
831 |
832 | '''
833 | img is the image to be processed (np.array)
834 | if get_kp is False, only the bounding box is returned. Keypoints will return an empty list
835 | '''
836 |
837 | # Process image
838 | img_pad, img_norm, pad = self.preprocess_img(img)
839 | self.pad = pad
840 |
841 | # Checks whether to recompute palm detection or use previous frame's bounding box
842 | if len([1 for i in self.bb_prev if type(i) == type(None)]) > 0:
843 | box_orig_list, Mtr_Minv_list = self._get_bbox_Mtr_Minv(img, img_norm)
844 | box_orig_list, Mtr_Minv_list = self._merge_bbox_predicts(box_orig_list, Mtr_Minv_list)
845 |
846 | if not get_kp: return [], box_orig_list
847 | else:
848 | box_orig_list = [self._predict_bbox(kp[:,:2], bbox) for kp, bbox in zip(self.kp_prev, self.bb_prev)]
849 | Mtr_Minv_list = [self._bbox_to_source(bbox, pad) for bbox in box_orig_list]
850 |
851 |
852 | # Initialise buffers
853 | is_hands_list_prev = self.is_hands_list
854 | kp_orig_list = []
855 | self.is_hands_list = []
856 | index = 0
857 |
858 | kp_orig_list = []
859 |
860 | # Iterate across all palm detections
861 | for Mtr, Minv in Mtr_Minv_list:
862 |
863 | # Check if palm instance exist
864 | if type(Mtr) == type(None):
865 | self.is_hands_list.append(False)
866 | kp_orig_list.append(None)
867 | continue
868 |
869 | # Crop image according to bounding box
870 | img_landmark = cv2.warpAffine(
871 | self._im_normalize(img_pad), Mtr, (256,256)
872 | )
873 |
874 | # Get hand keypoints. is_hand is to detect if hand is present within bounding box
875 | joints, is_hand = self.predict_joints(img_landmark, hand_thres = self.detect_keypoints_thres)
876 | if not is_hand:
877 | self.is_hands_list.append(False)
878 | box_orig_list[index] = None
879 | kp_orig_list.append(None)
880 | is_recall = True
881 | continue
882 |
883 | # projecting keypoints back into original image coordinate space
884 | kp_orig_0 = (self._pad1(joints[:,:2]) @ Minv.T)[:,:2]
885 | kp_orig_0 -= pad[::-1]
886 |
887 | # Add back the 3D data
888 | kp_orig = joints[:,:]
889 | kp_orig[:,:2] = kp_orig_0[:,:2]
890 |
891 | kp_orig_list.append(kp_orig)
892 | self.is_hands_list.append(is_hand)
893 |
894 | index += 1
895 |
896 | # Store previous frame bbox and kp
897 | if not self.independent:
898 | self.bb_prev = box_orig_list
899 | self.kp_prev = kp_orig_list
900 |
901 | # Recall if is_hands has changed (The number of palm instances decreased)
902 | if (len([1 for i,j in zip(is_hands_list_prev, self.is_hands_list) if (i==True and j==False)]) != 0):
903 | return self.__call__(img, get_kp = get_kp)
904 |
905 | return kp_orig_list, box_orig_list
906 |
907 | def is_right_hand(kp):
908 |
909 | '''
910 | kp: 3D keypoints list. Output by MultiHandTracker3D.__call__
911 |
912 | Returns True if kp is right hand and False if left hand.
913 | If kp is None, returns None
914 | If kp is not 3D (Say because kp is the output of MultiHandTracker instead of MultiHandTracker3D), returns None
915 | '''
916 |
917 | digitgroups = [
918 | (17,18,19,20),
919 | (13,14,15,16),
920 | (9,10,11,12),
921 | (5,6,7,8),
922 | (2,3,4) # Thumb
923 | ]
924 |
925 | if type(kp) == type(None): return None
926 | if len(kp[0]) != 3: return None
927 |
928 | palm_dir_vec = np.array([0,0,0], dtype=np.float64)
929 | for digit in digitgroups:
930 | for idx in digit[1:]:
931 | palm_dir_vec += kp[idx] - kp[digit[0]]
932 |
933 | palm_pos_vec = np.array([0,0,0], dtype=np.float64)
934 | for digit in digitgroups:
935 | palm_pos_vec += kp[digit[0]]
936 | palm_pos_vec /= len(digitgroups)
937 |
938 | top_palm_pos_vec = kp[9]
939 |
940 | val = np.dot(np.cross(kp[2] - palm_pos_vec, palm_dir_vec), top_palm_pos_vec - palm_pos_vec)
941 |
942 | if val < 0: return True
943 |
944 | return False
--------------------------------------------------------------------------------
/src/plot_hand.py:
--------------------------------------------------------------------------------
1 | import matplotlib.pyplot as plt
2 | import numpy as np
3 |
4 | HAND_GRAPH = {
5 | 0:[1,17],
6 | 1:[2,5],
7 | 2:[3],
8 | 3:[4],
9 | 4:[],
10 | 5:[6,9],
11 | 6:[7],
12 | 7:[8],
13 | 8:[],
14 | 9:[10,13],
15 | 10:[11],
16 | 11:[12],
17 | 12:[],
18 | 13:[14,17],
19 | 14:[15],
20 | 15:[16],
21 | 16:[],
22 | 17:[18],
23 | 18:[19],
24 | 19:[20],
25 | 20:[]
26 | }
27 | flatten = lambda l: [item for sublist in l for item in sublist]
28 | def plot_img(img, kp_list, box_list, save=None, size=10, line = [], is_right = None):
29 |
30 | plt.figure(figsize=(size,size*img.shape[0]/img.shape[1]))
31 | plt.xlim((0,img.shape[1]))
32 | plt.ylim((img.shape[0],0))
33 | plt.imshow(img)
34 |
35 | mode_3D = False
36 | if len(kp_list[0][0]) == 3: mode_3D = True
37 |
38 | plot_kp = True
39 | if len(kp_list) == 0:
40 | kp_list = [None]*len(box_list)
41 | plot_kp = False
42 |
43 | plot_bb = True
44 | if len(box_list) == 0:
45 | box_list = [None]*len(kp_list)
46 | plot_bb = False
47 |
48 | for kp, box, idx in zip(kp_list, box_list, range(len(kp_list))):
49 | if type(kp) == type(None): continue
50 |
51 | if plot_bb:
52 |
53 | box_plot = np.append(box, box[0]).reshape(-1,2)
54 | plt.plot(box_plot[:,0], box_plot[:,1], c="cyan")
55 | plt.plot([box_plot[3,0], box_plot[2,0]], [box_plot[3,1], box_plot[2,1]], c="red")
56 |
57 | if type(is_right) == type(None):
58 | plt.annotate(str(idx), box[0])
59 | else:
60 | leftright = "left"
61 | if is_right[idx]: leftright = "right"
62 | plt.annotate(leftright, kp[12][:2], c="cyan")
63 |
64 | if not plot_kp: continue
65 |
66 | lines_x = []
67 | lines_y = []
68 | for i in range(20):
69 | lines_x += flatten([[kp[i,0], kp[j,0], None] for j in HAND_GRAPH[i]])
70 | lines_y += flatten([[kp[i,1], kp[j,1], None] for j in HAND_GRAPH[i]])
71 | plt.plot(lines_x, lines_y, c="white")
72 |
73 | if mode_3D:
74 | s = kp[:,2] - min(kp[:,2])
75 | s = max(s) - s + 5
76 | plt.scatter(kp[:,0], kp[:,1], s=s, c="white", alpha=.6)
77 | else:
78 | plt.scatter(kp[:,0], kp[:,1], s=5, c='white', alpha=.6)
79 |
80 | plt.axis("off")
81 |
82 | if save:
83 | plt.savefig(save, bbox_inches='tight', pad_inches=0)
84 | else:
85 | plt.show()
86 |
87 | plt.close()
--------------------------------------------------------------------------------