├── 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 | Process video result 85 | 86 | Video from [Signing Savvy](https://www.signingsavvy.com/sign/HAVE%20A%20GOOD%20DAY/8194/1). 87 | 88 | Predictions from ```MultiHandTracker3D```: 89 | 90 | Process video result 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() --------------------------------------------------------------------------------