├── .gitignore ├── custom ├── __init__.py ├── core.py ├── face_geometry.py └── iris_lm_depth.py ├── face_detection.py ├── face_mesh.py ├── facial_expression.py ├── hands.py ├── head_posture.py ├── holistic.py ├── iris.py ├── objectron.py ├── pose.py ├── readme.MD ├── requirements.txt ├── selfie_segmentation.py ├── setup.cfg └── videosource.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 98 | __pypackages__/ 99 | 100 | # Celery stuff 101 | celerybeat-schedule 102 | celerybeat.pid 103 | 104 | # SageMath parsed files 105 | *.sage.py 106 | 107 | # Environments 108 | .env 109 | .venv 110 | env/ 111 | venv/ 112 | ENV/ 113 | env.bak/ 114 | venv.bak/ 115 | 116 | # Spyder project settings 117 | .spyderproject 118 | .spyproject 119 | 120 | # Rope project settings 121 | .ropeproject 122 | 123 | # mkdocs documentation 124 | /site 125 | 126 | # mypy 127 | .mypy_cache/ 128 | .dmypy.json 129 | dmypy.json 130 | 131 | # Pyre type checker 132 | .pyre/ 133 | 134 | # pytype static type analyzer 135 | .pytype/ 136 | 137 | # Cython debug symbols 138 | cython_debug/ 139 | 140 | # ignore tf models 141 | models/* -------------------------------------------------------------------------------- /custom/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rassibassi/mediapipeDemos/47c6330227c88ca02e32deb47b150aa8391306a4/custom/__init__.py -------------------------------------------------------------------------------- /custom/core.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import tensorflow as tf 3 | 4 | 5 | def tflite_inference(inputs, model_path, dtype=np.float32): 6 | 7 | if not isinstance(inputs, (list, tuple)): 8 | inputs = (inputs,) 9 | 10 | # Load the TFLite model and allocate tensors. 11 | interpreter = tf.lite.Interpreter(model_path=model_path) 12 | interpreter.allocate_tensors() 13 | 14 | # Get input and output tensors. 15 | input_details = interpreter.get_input_details() 16 | output_details = interpreter.get_output_details() 17 | 18 | # Test the model on random input data. 19 | for inp, inp_det in zip(inputs, input_details): 20 | interpreter.set_tensor(inp_det["index"], np.array(inp[None, ...], dtype=dtype)) 21 | 22 | interpreter.invoke() 23 | 24 | # The function `get_tensor()` returns a copy of the tensor data. 25 | # Use `tensor()` in order to get a pointer to the tensor. 26 | outputs = [interpreter.get_tensor(out["index"]) for out in output_details] 27 | 28 | return outputs 29 | 30 | 31 | def landmarks_to_detections(landmarks): 32 | """ 33 | landmarks: (3, N) landmarks 34 | """ 35 | x_min = np.amin(landmarks[0, :]) 36 | x_max = np.amax(landmarks[0, :]) 37 | y_min = np.amin(landmarks[1, :]) 38 | y_max = np.amax(landmarks[1, :]) 39 | 40 | bbox = dict() 41 | bbox["x_min"] = x_min 42 | bbox["y_min"] = y_min 43 | bbox["width"] = x_max - x_min 44 | bbox["height"] = y_max - y_min 45 | 46 | detections = dict() 47 | detections["bboxs"] = bbox 48 | detections["keypoints"] = landmarks[:2, :] 49 | 50 | return detections 51 | 52 | 53 | def detections_to_rect( 54 | detections, 55 | image_size, 56 | rotation_vector_start_end=None, 57 | rotation_vector_target_angle=0, 58 | ): 59 | 60 | keypoints = detections["keypoints"] 61 | x_min = np.amin(keypoints[0, :]) 62 | x_max = np.amax(keypoints[0, :]) 63 | y_min = np.amin(keypoints[1, :]) 64 | y_max = np.amax(keypoints[1, :]) 65 | 66 | rect = dict() 67 | rect["x_center"] = (x_min + x_max) / 2 68 | rect["y_center"] = (y_min + y_max) / 2 69 | rect["width"] = x_max - x_min 70 | rect["height"] = y_max - y_min 71 | 72 | if rotation_vector_start_end is not None: 73 | rect["rotation"] = compute_rotation( 74 | detections, 75 | image_size, 76 | rotation_vector_start_end, 77 | rotation_vector_target_angle, 78 | ) 79 | else: 80 | rect["rotation"] = None 81 | 82 | return rect 83 | 84 | 85 | def compute_rotation(detections, image_size, rotation_vector_start_end, target_angle): 86 | 87 | keypoints = detections["keypoints"] 88 | 89 | x0 = keypoints[0, rotation_vector_start_end[0]] * image_size[0] 90 | y0 = keypoints[1, rotation_vector_start_end[0]] * image_size[1] 91 | x1 = keypoints[0, rotation_vector_start_end[1]] * image_size[0] 92 | y1 = keypoints[1, rotation_vector_start_end[1]] * image_size[1] 93 | 94 | rotation = normalize_radians(target_angle - np.arctan2(-(y1 - y0), x1 - x0)) 95 | 96 | return rotation 97 | 98 | 99 | def normalize_radians(angle): 100 | return angle - 2 * np.pi * np.floor((angle - (-np.pi)) / (2 * np.pi)) 101 | 102 | 103 | def transform_rect( 104 | rect, 105 | image_size, 106 | scale_x=1, 107 | scale_y=1, 108 | shift_x=0, 109 | shift_y=0, 110 | square_long=True, 111 | square_short=False, 112 | opt_rotation=None, 113 | ): 114 | width = rect["width"] 115 | height = rect["height"] 116 | rotation = rect["rotation"] 117 | image_width = image_size[0] 118 | image_height = image_size[1] 119 | 120 | if rotation is not None and opt_rotation is not None: 121 | rotation += opt_rotation 122 | rotation = normalize_radians(rotation) 123 | 124 | if rotation is None: 125 | rect["x_center"] = rect["x_center"] + width * shift_x 126 | rect["y_center"] = rect["y_center"] + height * shift_y 127 | else: 128 | x_shift = ( 129 | image_width * width * shift_x * np.cos(rotation) 130 | - image_height * height * shift_y * np.sin(rotation) 131 | ) / image_width 132 | y_shift = ( 133 | image_width * width * shift_x * np.sin(rotation) 134 | + image_height * height * shift_y * np.cos(rotation) 135 | ) / image_height 136 | 137 | rect["x_center"] = rect["x_center"] + x_shift 138 | rect["y_center"] = rect["y_center"] + y_shift 139 | 140 | if square_long: 141 | long_side = np.max((width * image_width, height * image_height)) 142 | width = long_side / image_width 143 | height = long_side / image_height 144 | elif square_short: 145 | short_side = np.min((width * image_width, height * image_height)) 146 | width = short_side / image_width 147 | height = short_side / image_height 148 | 149 | rect["width"] = width * scale_x 150 | rect["height"] = height * scale_y 151 | 152 | return rect 153 | 154 | 155 | def slice_from_roi(roi, image_size, horizontal_side=True): 156 | if horizontal_side: 157 | center = roi["x_center"] 158 | norm_side = roi["width"] 159 | image_side = image_size[0] 160 | else: 161 | center = roi["y_center"] 162 | norm_side = roi["height"] 163 | image_side = image_size[1] 164 | 165 | first_id = int((center - norm_side / 2) * image_side) 166 | second_id = int((center + norm_side / 2) * image_side) 167 | 168 | return (first_id, second_id) 169 | 170 | 171 | def extract_faces(raw_frame, results, x_scale=1.0, y_scale=1.0): 172 | frames = [] 173 | if results.detections is None: 174 | return frames 175 | for detection in results.detections: 176 | image_size = raw_frame.shape[1::-1] 177 | x_min = detection.location_data.relative_bounding_box.xmin 178 | y_min = detection.location_data.relative_bounding_box.ymin 179 | width = detection.location_data.relative_bounding_box.width 180 | height = detection.location_data.relative_bounding_box.height 181 | 182 | x_min = image_size[0] * x_min 183 | y_min = image_size[1] * y_min 184 | width = image_size[0] * width 185 | height = image_size[1] * height 186 | x_max = x_min + width 187 | y_max = y_min + height 188 | 189 | x_center = (x_min + x_max) / 2 190 | y_center = (y_min + y_max) / 2 191 | 192 | width = x_scale * width 193 | height = y_scale * height 194 | 195 | x_min = x_center - width / 2 196 | y_min = y_center - height / 2 197 | 198 | x_max = x_min + width 199 | y_max = y_min + height 200 | 201 | x_min, x_max, y_min, y_max = map(int, [x_min, x_max, y_min, y_max]) 202 | 203 | frame = raw_frame[y_min:y_max, x_min:x_max] 204 | 205 | if frame.any(): 206 | frames.append(frame) 207 | 208 | return frames 209 | -------------------------------------------------------------------------------- /custom/face_geometry.py: -------------------------------------------------------------------------------- 1 | # Many parts taken from the cpp implementation from github.com/google/mediapipe 2 | # 3 | # Copyright 2020 The MediaPipe Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | 17 | import numpy as np 18 | 19 | 20 | class Singleton(type): 21 | _instances = {} 22 | 23 | def __call__(cls, *args, **kwargs): 24 | if cls not in cls._instances: 25 | cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) 26 | return cls._instances[cls] 27 | 28 | 29 | class Debugger(metaclass=Singleton): 30 | def set_debug(self, debug): 31 | self.debug = debug 32 | 33 | def toggle(self): 34 | self.debug = not self.debug 35 | 36 | def get_debug(self): 37 | return self.debug 38 | 39 | 40 | DEBUG = Debugger() 41 | DEBUG.set_debug(False) 42 | 43 | 44 | class PCF: 45 | def __init__( 46 | self, 47 | near=1, 48 | far=10000, 49 | frame_height=1920, 50 | frame_width=1080, 51 | fy=1074.520446598223, 52 | ): 53 | 54 | self.near = near 55 | self.far = far 56 | self.frame_height = frame_height 57 | self.frame_width = frame_width 58 | self.fy = fy 59 | 60 | fov_y = 2 * np.arctan(frame_height / (2 * fy)) 61 | # kDegreesToRadians = np.pi / 180.0 # never used 62 | height_at_near = 2 * near * np.tan(0.5 * fov_y) 63 | width_at_near = frame_width * height_at_near / frame_height 64 | 65 | self.fov_y = fov_y 66 | self.left = -0.5 * width_at_near 67 | self.right = 0.5 * width_at_near 68 | self.bottom = -0.5 * height_at_near 69 | self.top = 0.5 * height_at_near 70 | 71 | 72 | canonical_metric_landmarks = np.array( 73 | [ 74 | 0.000000, 75 | -3.406404, 76 | 5.979507, 77 | 0.499977, 78 | 0.652534, 79 | 0.000000, 80 | -1.126865, 81 | 7.475604, 82 | 0.500026, 83 | 0.547487, 84 | 0.000000, 85 | -2.089024, 86 | 6.058267, 87 | 0.499974, 88 | 0.602372, 89 | -0.463928, 90 | 0.955357, 91 | 6.633583, 92 | 0.482113, 93 | 0.471979, 94 | 0.000000, 95 | -0.463170, 96 | 7.586580, 97 | 0.500151, 98 | 0.527156, 99 | 0.000000, 100 | 0.365669, 101 | 7.242870, 102 | 0.499910, 103 | 0.498253, 104 | 0.000000, 105 | 2.473255, 106 | 5.788627, 107 | 0.499523, 108 | 0.401062, 109 | -4.253081, 110 | 2.577646, 111 | 3.279702, 112 | 0.289712, 113 | 0.380764, 114 | 0.000000, 115 | 4.019042, 116 | 5.284764, 117 | 0.499955, 118 | 0.312398, 119 | 0.000000, 120 | 4.885979, 121 | 5.385258, 122 | 0.499987, 123 | 0.269919, 124 | 0.000000, 125 | 8.261778, 126 | 4.481535, 127 | 0.500023, 128 | 0.107050, 129 | 0.000000, 130 | -3.706811, 131 | 5.864924, 132 | 0.500023, 133 | 0.666234, 134 | 0.000000, 135 | -3.918301, 136 | 5.569430, 137 | 0.500016, 138 | 0.679224, 139 | 0.000000, 140 | -3.994436, 141 | 5.219482, 142 | 0.500023, 143 | 0.692348, 144 | 0.000000, 145 | -4.542400, 146 | 5.404754, 147 | 0.499977, 148 | 0.695278, 149 | 0.000000, 150 | -4.745577, 151 | 5.529457, 152 | 0.499977, 153 | 0.705934, 154 | 0.000000, 155 | -5.019567, 156 | 5.601448, 157 | 0.499977, 158 | 0.719385, 159 | 0.000000, 160 | -5.365123, 161 | 5.535441, 162 | 0.499977, 163 | 0.737019, 164 | 0.000000, 165 | -6.149624, 166 | 5.071372, 167 | 0.499968, 168 | 0.781371, 169 | 0.000000, 170 | -1.501095, 171 | 7.112196, 172 | 0.499816, 173 | 0.562981, 174 | -0.416106, 175 | -1.466449, 176 | 6.447657, 177 | 0.473773, 178 | 0.573910, 179 | -7.087960, 180 | 5.434801, 181 | 0.099620, 182 | 0.104907, 183 | 0.254141, 184 | -2.628639, 185 | 2.035898, 186 | 3.848121, 187 | 0.365930, 188 | 0.409576, 189 | -3.198363, 190 | 1.985815, 191 | 3.796952, 192 | 0.338758, 193 | 0.413025, 194 | -3.775151, 195 | 2.039402, 196 | 3.646194, 197 | 0.311120, 198 | 0.409460, 199 | -4.465819, 200 | 2.422950, 201 | 3.155168, 202 | 0.274658, 203 | 0.389131, 204 | -2.164289, 205 | 2.189867, 206 | 3.851822, 207 | 0.393362, 208 | 0.403706, 209 | -3.208229, 210 | 3.223926, 211 | 4.115822, 212 | 0.345234, 213 | 0.344011, 214 | -2.673803, 215 | 3.205337, 216 | 4.092203, 217 | 0.370094, 218 | 0.346076, 219 | -3.745193, 220 | 3.165286, 221 | 3.972409, 222 | 0.319322, 223 | 0.347265, 224 | -4.161018, 225 | 3.059069, 226 | 3.719554, 227 | 0.297903, 228 | 0.353591, 229 | -5.062006, 230 | 1.934418, 231 | 2.776093, 232 | 0.247792, 233 | 0.410810, 234 | -2.266659, 235 | -7.425768, 236 | 4.389812, 237 | 0.396889, 238 | 0.842755, 239 | -4.445859, 240 | 2.663991, 241 | 3.173422, 242 | 0.280098, 243 | 0.375600, 244 | -7.214530, 245 | 2.263009, 246 | 0.073150, 247 | 0.106310, 248 | 0.399956, 249 | -5.799793, 250 | 2.349546, 251 | 2.204059, 252 | 0.209925, 253 | 0.391353, 254 | -2.844939, 255 | -0.720868, 256 | 4.433130, 257 | 0.355808, 258 | 0.534406, 259 | -0.711452, 260 | -3.329355, 261 | 5.877044, 262 | 0.471751, 263 | 0.650404, 264 | -0.606033, 265 | -3.924562, 266 | 5.444923, 267 | 0.474155, 268 | 0.680192, 269 | -1.431615, 270 | -3.500953, 271 | 5.496189, 272 | 0.439785, 273 | 0.657229, 274 | -1.914910, 275 | -3.803146, 276 | 5.028930, 277 | 0.414617, 278 | 0.666541, 279 | -1.131043, 280 | -3.973937, 281 | 5.189648, 282 | 0.450374, 283 | 0.680861, 284 | -1.563548, 285 | -4.082763, 286 | 4.842263, 287 | 0.428771, 288 | 0.682691, 289 | -2.650112, 290 | -5.003649, 291 | 4.188483, 292 | 0.374971, 293 | 0.727805, 294 | -0.427049, 295 | -1.094134, 296 | 7.360529, 297 | 0.486717, 298 | 0.547629, 299 | -0.496396, 300 | -0.475659, 301 | 7.440358, 302 | 0.485301, 303 | 0.527395, 304 | -5.253307, 305 | 3.881582, 306 | 3.363159, 307 | 0.257765, 308 | 0.314490, 309 | -1.718698, 310 | 0.974609, 311 | 4.558359, 312 | 0.401223, 313 | 0.455172, 314 | -1.608635, 315 | -0.942516, 316 | 5.814193, 317 | 0.429819, 318 | 0.548615, 319 | -1.651267, 320 | -0.610868, 321 | 5.581319, 322 | 0.421352, 323 | 0.533741, 324 | -4.765501, 325 | -0.701554, 326 | 3.534632, 327 | 0.276896, 328 | 0.532057, 329 | -0.478306, 330 | 0.295766, 331 | 7.101013, 332 | 0.483370, 333 | 0.499587, 334 | -3.734964, 335 | 4.508230, 336 | 4.550454, 337 | 0.337212, 338 | 0.282883, 339 | -4.588603, 340 | 4.302037, 341 | 4.048484, 342 | 0.296392, 343 | 0.293243, 344 | -6.279331, 345 | 6.615427, 346 | 1.425850, 347 | 0.169295, 348 | 0.193814, 349 | -1.220941, 350 | 4.142165, 351 | 5.106035, 352 | 0.447580, 353 | 0.302610, 354 | -2.193489, 355 | 3.100317, 356 | 4.000575, 357 | 0.392390, 358 | 0.353888, 359 | -3.102642, 360 | -4.352984, 361 | 4.095905, 362 | 0.354490, 363 | 0.696784, 364 | -6.719682, 365 | -4.788645, 366 | -1.745401, 367 | 0.067305, 368 | 0.730105, 369 | -1.193824, 370 | -1.306795, 371 | 5.737747, 372 | 0.442739, 373 | 0.572826, 374 | -0.729766, 375 | -1.593712, 376 | 5.833208, 377 | 0.457098, 378 | 0.584792, 379 | -2.456206, 380 | -4.342621, 381 | 4.283884, 382 | 0.381974, 383 | 0.694711, 384 | -2.204823, 385 | -4.304508, 386 | 4.162499, 387 | 0.392389, 388 | 0.694203, 389 | -4.985894, 390 | 4.802461, 391 | 3.751977, 392 | 0.277076, 393 | 0.271932, 394 | -1.592294, 395 | -1.257709, 396 | 5.456949, 397 | 0.422552, 398 | 0.563233, 399 | -2.644548, 400 | 4.524654, 401 | 4.921559, 402 | 0.385919, 403 | 0.281364, 404 | -2.760292, 405 | 5.100971, 406 | 5.015990, 407 | 0.383103, 408 | 0.255840, 409 | -3.523964, 410 | 8.005976, 411 | 3.729163, 412 | 0.331431, 413 | 0.119714, 414 | -5.599763, 415 | 5.715470, 416 | 2.724259, 417 | 0.229924, 418 | 0.232003, 419 | -3.063932, 420 | 6.566144, 421 | 4.529981, 422 | 0.364501, 423 | 0.189114, 424 | -5.720968, 425 | 4.254584, 426 | 2.830852, 427 | 0.229622, 428 | 0.299541, 429 | -6.374393, 430 | 4.785590, 431 | 1.591691, 432 | 0.173287, 433 | 0.278748, 434 | -0.672728, 435 | -3.688016, 436 | 5.737804, 437 | 0.472879, 438 | 0.666198, 439 | -1.262560, 440 | -3.787691, 441 | 5.417779, 442 | 0.446828, 443 | 0.668527, 444 | -1.732553, 445 | -3.952767, 446 | 5.000579, 447 | 0.422762, 448 | 0.673890, 449 | -1.043625, 450 | -1.464973, 451 | 5.662455, 452 | 0.445308, 453 | 0.580066, 454 | -2.321234, 455 | -4.329069, 456 | 4.258156, 457 | 0.388103, 458 | 0.693961, 459 | -2.056846, 460 | -4.477671, 461 | 4.520883, 462 | 0.403039, 463 | 0.706540, 464 | -2.153084, 465 | -4.276322, 466 | 4.038093, 467 | 0.403629, 468 | 0.693953, 469 | -0.946874, 470 | -1.035249, 471 | 6.512274, 472 | 0.460042, 473 | 0.557139, 474 | -1.469132, 475 | -4.036351, 476 | 4.604908, 477 | 0.431158, 478 | 0.692366, 479 | -1.024340, 480 | -3.989851, 481 | 4.926693, 482 | 0.452182, 483 | 0.692366, 484 | -0.533422, 485 | -3.993222, 486 | 5.138202, 487 | 0.475387, 488 | 0.692366, 489 | -0.769720, 490 | -6.095394, 491 | 4.985883, 492 | 0.465828, 493 | 0.779190, 494 | -0.699606, 495 | -5.291850, 496 | 5.448304, 497 | 0.472329, 498 | 0.736226, 499 | -0.669687, 500 | -4.949770, 501 | 5.509612, 502 | 0.473087, 503 | 0.717857, 504 | -0.630947, 505 | -4.695101, 506 | 5.449371, 507 | 0.473122, 508 | 0.704626, 509 | -0.583218, 510 | -4.517982, 511 | 5.339869, 512 | 0.473033, 513 | 0.695278, 514 | -1.537170, 515 | -4.423206, 516 | 4.745470, 517 | 0.427942, 518 | 0.695278, 519 | -1.615600, 520 | -4.475942, 521 | 4.813632, 522 | 0.426479, 523 | 0.703540, 524 | -1.729053, 525 | -4.618680, 526 | 4.854463, 527 | 0.423162, 528 | 0.711846, 529 | -1.838624, 530 | -4.828746, 531 | 4.823737, 532 | 0.418309, 533 | 0.720063, 534 | -2.368250, 535 | -3.106237, 536 | 4.868096, 537 | 0.390095, 538 | 0.639573, 539 | -7.542244, 540 | -1.049282, 541 | -2.431321, 542 | 0.013954, 543 | 0.560034, 544 | 0.000000, 545 | -1.724003, 546 | 6.601390, 547 | 0.499914, 548 | 0.580147, 549 | -1.826614, 550 | -4.399531, 551 | 4.399021, 552 | 0.413200, 553 | 0.695400, 554 | -1.929558, 555 | -4.411831, 556 | 4.497052, 557 | 0.409626, 558 | 0.701823, 559 | -0.597442, 560 | -2.013686, 561 | 5.866456, 562 | 0.468080, 563 | 0.601535, 564 | -1.405627, 565 | -1.714196, 566 | 5.241087, 567 | 0.422729, 568 | 0.585985, 569 | -0.662449, 570 | -1.819321, 571 | 5.863759, 572 | 0.463080, 573 | 0.593784, 574 | -2.342340, 575 | 0.572222, 576 | 4.294303, 577 | 0.372120, 578 | 0.473414, 579 | -3.327324, 580 | 0.104863, 581 | 4.113860, 582 | 0.334562, 583 | 0.496073, 584 | -1.726175, 585 | -0.919165, 586 | 5.273355, 587 | 0.411671, 588 | 0.546965, 589 | -5.133204, 590 | 7.485602, 591 | 2.660442, 592 | 0.242176, 593 | 0.147676, 594 | -4.538641, 595 | 6.319907, 596 | 3.683424, 597 | 0.290777, 598 | 0.201446, 599 | -3.986562, 600 | 5.109487, 601 | 4.466315, 602 | 0.327338, 603 | 0.256527, 604 | -2.169681, 605 | -5.440433, 606 | 4.455874, 607 | 0.399510, 608 | 0.748921, 609 | -1.395634, 610 | 5.011963, 611 | 5.316032, 612 | 0.441728, 613 | 0.261676, 614 | -1.619500, 615 | 6.599217, 616 | 4.921106, 617 | 0.429765, 618 | 0.187834, 619 | -1.891399, 620 | 8.236377, 621 | 4.274997, 622 | 0.412198, 623 | 0.108901, 624 | -4.195832, 625 | 2.235205, 626 | 3.375099, 627 | 0.288955, 628 | 0.398952, 629 | -5.733342, 630 | 1.411738, 631 | 2.431726, 632 | 0.218937, 633 | 0.435411, 634 | -1.859887, 635 | 2.355757, 636 | 3.843181, 637 | 0.412782, 638 | 0.398970, 639 | -4.988612, 640 | 3.074654, 641 | 3.083858, 642 | 0.257135, 643 | 0.355440, 644 | -1.303263, 645 | 1.416453, 646 | 4.831091, 647 | 0.427685, 648 | 0.437961, 649 | -1.305757, 650 | -0.672779, 651 | 6.415959, 652 | 0.448340, 653 | 0.536936, 654 | -6.465170, 655 | 0.937119, 656 | 1.689873, 657 | 0.178560, 658 | 0.457554, 659 | -5.258659, 660 | 0.945811, 661 | 2.974312, 662 | 0.247308, 663 | 0.457194, 664 | -4.432338, 665 | 0.722096, 666 | 3.522615, 667 | 0.286267, 668 | 0.467675, 669 | -3.300681, 670 | 0.861641, 671 | 3.872784, 672 | 0.332828, 673 | 0.460712, 674 | -2.430178, 675 | 1.131492, 676 | 4.039035, 677 | 0.368756, 678 | 0.447207, 679 | -1.820731, 680 | 1.467954, 681 | 4.224124, 682 | 0.398964, 683 | 0.432655, 684 | -0.563221, 685 | 2.307693, 686 | 5.566789, 687 | 0.476410, 688 | 0.405806, 689 | -6.338145, 690 | -0.529279, 691 | 1.881175, 692 | 0.189241, 693 | 0.523924, 694 | -5.587698, 695 | 3.208071, 696 | 2.687839, 697 | 0.228962, 698 | 0.348951, 699 | -0.242624, 700 | -1.462857, 701 | 7.071491, 702 | 0.490726, 703 | 0.562401, 704 | -1.611251, 705 | 0.339326, 706 | 4.895421, 707 | 0.404670, 708 | 0.485133, 709 | -7.743095, 710 | 2.364999, 711 | -2.005167, 712 | 0.019469, 713 | 0.401564, 714 | -1.391142, 715 | 1.851048, 716 | 4.448999, 717 | 0.426243, 718 | 0.420431, 719 | -1.785794, 720 | -0.978284, 721 | 4.850470, 722 | 0.396993, 723 | 0.548797, 724 | -4.670959, 725 | 2.664461, 726 | 3.084075, 727 | 0.266470, 728 | 0.376977, 729 | -1.333970, 730 | -0.283761, 731 | 6.097047, 732 | 0.439121, 733 | 0.518958, 734 | -7.270895, 735 | -2.890917, 736 | -2.252455, 737 | 0.032314, 738 | 0.644357, 739 | -1.856432, 740 | 2.585245, 741 | 3.757904, 742 | 0.419054, 743 | 0.387155, 744 | -0.923388, 745 | 0.073076, 746 | 6.671944, 747 | 0.462783, 748 | 0.505747, 749 | -5.000589, 750 | -6.135128, 751 | 1.892523, 752 | 0.238979, 753 | 0.779745, 754 | -5.085276, 755 | -7.178590, 756 | 0.714711, 757 | 0.198221, 758 | 0.831938, 759 | -7.159291, 760 | -0.811820, 761 | -0.072044, 762 | 0.107550, 763 | 0.540755, 764 | -5.843051, 765 | -5.248023, 766 | 0.924091, 767 | 0.183610, 768 | 0.740257, 769 | -6.847258, 770 | 3.662916, 771 | 0.724695, 772 | 0.134410, 773 | 0.333683, 774 | -2.412942, 775 | -8.258853, 776 | 4.119213, 777 | 0.385764, 778 | 0.883154, 779 | -0.179909, 780 | -1.689864, 781 | 6.573301, 782 | 0.490967, 783 | 0.579378, 784 | -2.103655, 785 | -0.163946, 786 | 4.566119, 787 | 0.382385, 788 | 0.508573, 789 | -6.407571, 790 | 2.236021, 791 | 1.560843, 792 | 0.174399, 793 | 0.397671, 794 | -3.670075, 795 | 2.360153, 796 | 3.635230, 797 | 0.318785, 798 | 0.396235, 799 | -3.177186, 800 | 2.294265, 801 | 3.775704, 802 | 0.343364, 803 | 0.400597, 804 | -2.196121, 805 | -4.598322, 806 | 4.479786, 807 | 0.396100, 808 | 0.710217, 809 | -6.234883, 810 | -1.944430, 811 | 1.663542, 812 | 0.187885, 813 | 0.588538, 814 | -1.292924, 815 | -9.295920, 816 | 4.094063, 817 | 0.430987, 818 | 0.944065, 819 | -3.210651, 820 | -8.533278, 821 | 2.802001, 822 | 0.318993, 823 | 0.898285, 824 | -4.068926, 825 | -7.993109, 826 | 1.925119, 827 | 0.266248, 828 | 0.869701, 829 | 0.000000, 830 | 6.545390, 831 | 5.027311, 832 | 0.500023, 833 | 0.190576, 834 | 0.000000, 835 | -9.403378, 836 | 4.264492, 837 | 0.499977, 838 | 0.954453, 839 | -2.724032, 840 | 2.315802, 841 | 3.777151, 842 | 0.366170, 843 | 0.398822, 844 | -2.288460, 845 | 2.398891, 846 | 3.697603, 847 | 0.393207, 848 | 0.395537, 849 | -1.998311, 850 | 2.496547, 851 | 3.689148, 852 | 0.410373, 853 | 0.391080, 854 | -6.130040, 855 | 3.399261, 856 | 2.038516, 857 | 0.194993, 858 | 0.342102, 859 | -2.288460, 860 | 2.886504, 861 | 3.775031, 862 | 0.388665, 863 | 0.362284, 864 | -2.724032, 865 | 2.961810, 866 | 3.871767, 867 | 0.365962, 868 | 0.355971, 869 | -3.177186, 870 | 2.964136, 871 | 3.876973, 872 | 0.343364, 873 | 0.355357, 874 | -3.670075, 875 | 2.927714, 876 | 3.724325, 877 | 0.318785, 878 | 0.358340, 879 | -4.018389, 880 | 2.857357, 881 | 3.482983, 882 | 0.301415, 883 | 0.363156, 884 | -7.555811, 885 | 4.106811, 886 | -0.991917, 887 | 0.058133, 888 | 0.319076, 889 | -4.018389, 890 | 2.483695, 891 | 3.440898, 892 | 0.301415, 893 | 0.387449, 894 | 0.000000, 895 | -2.521945, 896 | 5.932265, 897 | 0.499988, 898 | 0.618434, 899 | -1.776217, 900 | -2.683946, 901 | 5.213116, 902 | 0.415838, 903 | 0.624196, 904 | -1.222237, 905 | -1.182444, 906 | 5.952465, 907 | 0.445682, 908 | 0.566077, 909 | -0.731493, 910 | -2.536683, 911 | 5.815343, 912 | 0.465844, 913 | 0.620641, 914 | 0.000000, 915 | 3.271027, 916 | 5.236015, 917 | 0.499923, 918 | 0.351524, 919 | -4.135272, 920 | -6.996638, 921 | 2.671970, 922 | 0.288719, 923 | 0.819946, 924 | -3.311811, 925 | -7.660815, 926 | 3.382963, 927 | 0.335279, 928 | 0.852820, 929 | -1.313701, 930 | -8.639995, 931 | 4.702456, 932 | 0.440512, 933 | 0.902419, 934 | -5.940524, 935 | -6.223629, 936 | -0.631468, 937 | 0.128294, 938 | 0.791941, 939 | -1.998311, 940 | 2.743838, 941 | 3.744030, 942 | 0.408772, 943 | 0.373894, 944 | -0.901447, 945 | 1.236992, 946 | 5.754256, 947 | 0.455607, 948 | 0.451801, 949 | 0.000000, 950 | -8.765243, 951 | 4.891441, 952 | 0.499877, 953 | 0.908990, 954 | -2.308977, 955 | -8.974196, 956 | 3.609070, 957 | 0.375437, 958 | 0.924192, 959 | -6.954154, 960 | -2.439843, 961 | -0.131163, 962 | 0.114210, 963 | 0.615022, 964 | -1.098819, 965 | -4.458788, 966 | 5.120727, 967 | 0.448662, 968 | 0.695278, 969 | -1.181124, 970 | -4.579996, 971 | 5.189564, 972 | 0.448020, 973 | 0.704632, 974 | -1.255818, 975 | -4.787901, 976 | 5.237051, 977 | 0.447112, 978 | 0.715808, 979 | -1.325085, 980 | -5.106507, 981 | 5.205010, 982 | 0.444832, 983 | 0.730794, 984 | -1.546388, 985 | -5.819392, 986 | 4.757893, 987 | 0.430012, 988 | 0.766809, 989 | -1.953754, 990 | -4.183892, 991 | 4.431713, 992 | 0.406787, 993 | 0.685673, 994 | -2.117802, 995 | -4.137093, 996 | 4.555096, 997 | 0.400738, 998 | 0.681069, 999 | -2.285339, 1000 | -4.051196, 1001 | 4.582438, 1002 | 0.392400, 1003 | 0.677703, 1004 | -2.850160, 1005 | -3.665720, 1006 | 4.484994, 1007 | 0.367856, 1008 | 0.663919, 1009 | -5.278538, 1010 | -2.238942, 1011 | 2.861224, 1012 | 0.247923, 1013 | 0.601333, 1014 | -0.946709, 1015 | 1.907628, 1016 | 5.196779, 1017 | 0.452770, 1018 | 0.420850, 1019 | -1.314173, 1020 | 3.104912, 1021 | 4.231404, 1022 | 0.436392, 1023 | 0.359887, 1024 | -1.780000, 1025 | 2.860000, 1026 | 3.881555, 1027 | 0.416164, 1028 | 0.368714, 1029 | -1.845110, 1030 | -4.098880, 1031 | 4.247264, 1032 | 0.413386, 1033 | 0.692366, 1034 | -5.436187, 1035 | -4.030482, 1036 | 2.109852, 1037 | 0.228018, 1038 | 0.683572, 1039 | -0.766444, 1040 | 3.182131, 1041 | 4.861453, 1042 | 0.468268, 1043 | 0.352671, 1044 | -1.938616, 1045 | -6.614410, 1046 | 4.521085, 1047 | 0.411362, 1048 | 0.804327, 1049 | 0.000000, 1050 | 1.059413, 1051 | 6.774605, 1052 | 0.499989, 1053 | 0.469825, 1054 | -0.516573, 1055 | 1.583572, 1056 | 6.148363, 1057 | 0.479154, 1058 | 0.442654, 1059 | 0.000000, 1060 | 1.728369, 1061 | 6.316750, 1062 | 0.499974, 1063 | 0.439637, 1064 | -1.246815, 1065 | 0.230297, 1066 | 5.681036, 1067 | 0.432112, 1068 | 0.493589, 1069 | 0.000000, 1070 | -7.942194, 1071 | 5.181173, 1072 | 0.499886, 1073 | 0.866917, 1074 | 0.000000, 1075 | -6.991499, 1076 | 5.153478, 1077 | 0.499913, 1078 | 0.821729, 1079 | -0.997827, 1080 | -6.930921, 1081 | 4.979576, 1082 | 0.456549, 1083 | 0.819201, 1084 | -3.288807, 1085 | -5.382514, 1086 | 3.795752, 1087 | 0.344549, 1088 | 0.745439, 1089 | -2.311631, 1090 | -1.566237, 1091 | 4.590085, 1092 | 0.378909, 1093 | 0.574010, 1094 | -2.680250, 1095 | -6.111567, 1096 | 4.096152, 1097 | 0.374293, 1098 | 0.780185, 1099 | -3.832928, 1100 | -1.537326, 1101 | 4.137731, 1102 | 0.319688, 1103 | 0.570738, 1104 | -2.961860, 1105 | -2.274215, 1106 | 4.440943, 1107 | 0.357155, 1108 | 0.604270, 1109 | -4.386901, 1110 | -2.683286, 1111 | 3.643886, 1112 | 0.295284, 1113 | 0.621581, 1114 | -1.217295, 1115 | -7.834465, 1116 | 4.969286, 1117 | 0.447750, 1118 | 0.862477, 1119 | -1.542374, 1120 | -0.136843, 1121 | 5.201008, 1122 | 0.410986, 1123 | 0.508723, 1124 | -3.878377, 1125 | -6.041764, 1126 | 3.311079, 1127 | 0.313951, 1128 | 0.775308, 1129 | -3.084037, 1130 | -6.809842, 1131 | 3.814195, 1132 | 0.354128, 1133 | 0.812553, 1134 | -3.747321, 1135 | -4.503545, 1136 | 3.726453, 1137 | 0.324548, 1138 | 0.703993, 1139 | -6.094129, 1140 | -3.205991, 1141 | 1.473482, 1142 | 0.189096, 1143 | 0.646300, 1144 | -4.588995, 1145 | -4.728726, 1146 | 2.983221, 1147 | 0.279777, 1148 | 0.714658, 1149 | -6.583231, 1150 | -3.941269, 1151 | 0.070268, 1152 | 0.133823, 1153 | 0.682701, 1154 | -3.492580, 1155 | -3.195820, 1156 | 4.130198, 1157 | 0.336768, 1158 | 0.644733, 1159 | -1.255543, 1160 | 0.802341, 1161 | 5.307551, 1162 | 0.429884, 1163 | 0.466522, 1164 | -1.126122, 1165 | -0.933602, 1166 | 6.538785, 1167 | 0.455528, 1168 | 0.548623, 1169 | -1.443109, 1170 | -1.142774, 1171 | 5.905127, 1172 | 0.437114, 1173 | 0.558896, 1174 | -0.923043, 1175 | -0.529042, 1176 | 7.003423, 1177 | 0.467288, 1178 | 0.529925, 1179 | -1.755386, 1180 | 3.529117, 1181 | 4.327696, 1182 | 0.414712, 1183 | 0.335220, 1184 | -2.632589, 1185 | 3.713828, 1186 | 4.364629, 1187 | 0.377046, 1188 | 0.322778, 1189 | -3.388062, 1190 | 3.721976, 1191 | 4.309028, 1192 | 0.344108, 1193 | 0.320151, 1194 | -4.075766, 1195 | 3.675413, 1196 | 4.076063, 1197 | 0.312876, 1198 | 0.322332, 1199 | -4.622910, 1200 | 3.474691, 1201 | 3.646321, 1202 | 0.283526, 1203 | 0.333190, 1204 | -5.171755, 1205 | 2.535753, 1206 | 2.670867, 1207 | 0.241246, 1208 | 0.382786, 1209 | -7.297331, 1210 | 0.763172, 1211 | -0.048769, 1212 | 0.102986, 1213 | 0.468763, 1214 | -4.706828, 1215 | 1.651000, 1216 | 3.109532, 1217 | 0.267612, 1218 | 0.424560, 1219 | -4.071712, 1220 | 1.476821, 1221 | 3.476944, 1222 | 0.297879, 1223 | 0.433176, 1224 | -3.269817, 1225 | 1.470659, 1226 | 3.731945, 1227 | 0.333434, 1228 | 0.433878, 1229 | -2.527572, 1230 | 1.617311, 1231 | 3.865444, 1232 | 0.366427, 1233 | 0.426116, 1234 | -1.970894, 1235 | 1.858505, 1236 | 3.961782, 1237 | 0.396012, 1238 | 0.416696, 1239 | -1.579543, 1240 | 2.097941, 1241 | 4.084996, 1242 | 0.420121, 1243 | 0.410228, 1244 | -7.664182, 1245 | 0.673132, 1246 | -2.435867, 1247 | 0.007561, 1248 | 0.480777, 1249 | -1.397041, 1250 | -1.340139, 1251 | 5.630378, 1252 | 0.432949, 1253 | 0.569518, 1254 | -0.884838, 1255 | 0.658740, 1256 | 6.233232, 1257 | 0.458639, 1258 | 0.479089, 1259 | -0.767097, 1260 | -0.968035, 1261 | 7.077932, 1262 | 0.473466, 1263 | 0.545744, 1264 | -0.460213, 1265 | -1.334106, 1266 | 6.787447, 1267 | 0.476088, 1268 | 0.563830, 1269 | -0.748618, 1270 | -1.067994, 1271 | 6.798303, 1272 | 0.468472, 1273 | 0.555057, 1274 | -1.236408, 1275 | -1.585568, 1276 | 5.480490, 1277 | 0.433991, 1278 | 0.582362, 1279 | -0.387306, 1280 | -1.409990, 1281 | 6.957705, 1282 | 0.483518, 1283 | 0.562984, 1284 | -0.319925, 1285 | -1.607931, 1286 | 6.508676, 1287 | 0.482483, 1288 | 0.577849, 1289 | -1.639633, 1290 | 2.556298, 1291 | 3.863736, 1292 | 0.426450, 1293 | 0.389799, 1294 | -1.255645, 1295 | 2.467144, 1296 | 4.203800, 1297 | 0.438999, 1298 | 0.396495, 1299 | -1.031362, 1300 | 2.382663, 1301 | 4.615849, 1302 | 0.450067, 1303 | 0.400434, 1304 | -4.253081, 1305 | 2.772296, 1306 | 3.315305, 1307 | 0.289712, 1308 | 0.368253, 1309 | -4.530000, 1310 | 2.910000, 1311 | 3.339685, 1312 | 0.276670, 1313 | 0.363373, 1314 | 0.463928, 1315 | 0.955357, 1316 | 6.633583, 1317 | 0.517862, 1318 | 0.471948, 1319 | 4.253081, 1320 | 2.577646, 1321 | 3.279702, 1322 | 0.710288, 1323 | 0.380764, 1324 | 0.416106, 1325 | -1.466449, 1326 | 6.447657, 1327 | 0.526227, 1328 | 0.573910, 1329 | 7.087960, 1330 | 5.434801, 1331 | 0.099620, 1332 | 0.895093, 1333 | 0.254141, 1334 | 2.628639, 1335 | 2.035898, 1336 | 3.848121, 1337 | 0.634070, 1338 | 0.409576, 1339 | 3.198363, 1340 | 1.985815, 1341 | 3.796952, 1342 | 0.661242, 1343 | 0.413025, 1344 | 3.775151, 1345 | 2.039402, 1346 | 3.646194, 1347 | 0.688880, 1348 | 0.409460, 1349 | 4.465819, 1350 | 2.422950, 1351 | 3.155168, 1352 | 0.725342, 1353 | 0.389131, 1354 | 2.164289, 1355 | 2.189867, 1356 | 3.851822, 1357 | 0.606630, 1358 | 0.403705, 1359 | 3.208229, 1360 | 3.223926, 1361 | 4.115822, 1362 | 0.654766, 1363 | 0.344011, 1364 | 2.673803, 1365 | 3.205337, 1366 | 4.092203, 1367 | 0.629906, 1368 | 0.346076, 1369 | 3.745193, 1370 | 3.165286, 1371 | 3.972409, 1372 | 0.680678, 1373 | 0.347265, 1374 | 4.161018, 1375 | 3.059069, 1376 | 3.719554, 1377 | 0.702097, 1378 | 0.353591, 1379 | 5.062006, 1380 | 1.934418, 1381 | 2.776093, 1382 | 0.752212, 1383 | 0.410805, 1384 | 2.266659, 1385 | -7.425768, 1386 | 4.389812, 1387 | 0.602918, 1388 | 0.842863, 1389 | 4.445859, 1390 | 2.663991, 1391 | 3.173422, 1392 | 0.719902, 1393 | 0.375600, 1394 | 7.214530, 1395 | 2.263009, 1396 | 0.073150, 1397 | 0.893693, 1398 | 0.399960, 1399 | 5.799793, 1400 | 2.349546, 1401 | 2.204059, 1402 | 0.790082, 1403 | 0.391354, 1404 | 2.844939, 1405 | -0.720868, 1406 | 4.433130, 1407 | 0.643998, 1408 | 0.534488, 1409 | 0.711452, 1410 | -3.329355, 1411 | 5.877044, 1412 | 0.528249, 1413 | 0.650404, 1414 | 0.606033, 1415 | -3.924562, 1416 | 5.444923, 1417 | 0.525850, 1418 | 0.680191, 1419 | 1.431615, 1420 | -3.500953, 1421 | 5.496189, 1422 | 0.560215, 1423 | 0.657229, 1424 | 1.914910, 1425 | -3.803146, 1426 | 5.028930, 1427 | 0.585384, 1428 | 0.666541, 1429 | 1.131043, 1430 | -3.973937, 1431 | 5.189648, 1432 | 0.549626, 1433 | 0.680861, 1434 | 1.563548, 1435 | -4.082763, 1436 | 4.842263, 1437 | 0.571228, 1438 | 0.682692, 1439 | 2.650112, 1440 | -5.003649, 1441 | 4.188483, 1442 | 0.624852, 1443 | 0.728099, 1444 | 0.427049, 1445 | -1.094134, 1446 | 7.360529, 1447 | 0.513050, 1448 | 0.547282, 1449 | 0.496396, 1450 | -0.475659, 1451 | 7.440358, 1452 | 0.515097, 1453 | 0.527252, 1454 | 5.253307, 1455 | 3.881582, 1456 | 3.363159, 1457 | 0.742247, 1458 | 0.314507, 1459 | 1.718698, 1460 | 0.974609, 1461 | 4.558359, 1462 | 0.598631, 1463 | 0.454979, 1464 | 1.608635, 1465 | -0.942516, 1466 | 5.814193, 1467 | 0.570338, 1468 | 0.548575, 1469 | 1.651267, 1470 | -0.610868, 1471 | 5.581319, 1472 | 0.578632, 1473 | 0.533623, 1474 | 4.765501, 1475 | -0.701554, 1476 | 3.534632, 1477 | 0.723087, 1478 | 0.532054, 1479 | 0.478306, 1480 | 0.295766, 1481 | 7.101013, 1482 | 0.516446, 1483 | 0.499639, 1484 | 3.734964, 1485 | 4.508230, 1486 | 4.550454, 1487 | 0.662801, 1488 | 0.282918, 1489 | 4.588603, 1490 | 4.302037, 1491 | 4.048484, 1492 | 0.703624, 1493 | 0.293271, 1494 | 6.279331, 1495 | 6.615427, 1496 | 1.425850, 1497 | 0.830705, 1498 | 0.193814, 1499 | 1.220941, 1500 | 4.142165, 1501 | 5.106035, 1502 | 0.552386, 1503 | 0.302568, 1504 | 2.193489, 1505 | 3.100317, 1506 | 4.000575, 1507 | 0.607610, 1508 | 0.353888, 1509 | 3.102642, 1510 | -4.352984, 1511 | 4.095905, 1512 | 0.645429, 1513 | 0.696707, 1514 | 6.719682, 1515 | -4.788645, 1516 | -1.745401, 1517 | 0.932695, 1518 | 0.730105, 1519 | 1.193824, 1520 | -1.306795, 1521 | 5.737747, 1522 | 0.557261, 1523 | 0.572826, 1524 | 0.729766, 1525 | -1.593712, 1526 | 5.833208, 1527 | 0.542902, 1528 | 0.584792, 1529 | 2.456206, 1530 | -4.342621, 1531 | 4.283884, 1532 | 0.618026, 1533 | 0.694711, 1534 | 2.204823, 1535 | -4.304508, 1536 | 4.162499, 1537 | 0.607591, 1538 | 0.694203, 1539 | 4.985894, 1540 | 4.802461, 1541 | 3.751977, 1542 | 0.722943, 1543 | 0.271963, 1544 | 1.592294, 1545 | -1.257709, 1546 | 5.456949, 1547 | 0.577414, 1548 | 0.563167, 1549 | 2.644548, 1550 | 4.524654, 1551 | 4.921559, 1552 | 0.614083, 1553 | 0.281387, 1554 | 2.760292, 1555 | 5.100971, 1556 | 5.015990, 1557 | 0.616907, 1558 | 0.255886, 1559 | 3.523964, 1560 | 8.005976, 1561 | 3.729163, 1562 | 0.668509, 1563 | 0.119914, 1564 | 5.599763, 1565 | 5.715470, 1566 | 2.724259, 1567 | 0.770092, 1568 | 0.232021, 1569 | 3.063932, 1570 | 6.566144, 1571 | 4.529981, 1572 | 0.635536, 1573 | 0.189249, 1574 | 5.720968, 1575 | 4.254584, 1576 | 2.830852, 1577 | 0.770391, 1578 | 0.299556, 1579 | 6.374393, 1580 | 4.785590, 1581 | 1.591691, 1582 | 0.826722, 1583 | 0.278755, 1584 | 0.672728, 1585 | -3.688016, 1586 | 5.737804, 1587 | 0.527121, 1588 | 0.666198, 1589 | 1.262560, 1590 | -3.787691, 1591 | 5.417779, 1592 | 0.553172, 1593 | 0.668527, 1594 | 1.732553, 1595 | -3.952767, 1596 | 5.000579, 1597 | 0.577238, 1598 | 0.673890, 1599 | 1.043625, 1600 | -1.464973, 1601 | 5.662455, 1602 | 0.554692, 1603 | 0.580066, 1604 | 2.321234, 1605 | -4.329069, 1606 | 4.258156, 1607 | 0.611897, 1608 | 0.693961, 1609 | 2.056846, 1610 | -4.477671, 1611 | 4.520883, 1612 | 0.596961, 1613 | 0.706540, 1614 | 2.153084, 1615 | -4.276322, 1616 | 4.038093, 1617 | 0.596371, 1618 | 0.693953, 1619 | 0.946874, 1620 | -1.035249, 1621 | 6.512274, 1622 | 0.539958, 1623 | 0.557139, 1624 | 1.469132, 1625 | -4.036351, 1626 | 4.604908, 1627 | 0.568842, 1628 | 0.692366, 1629 | 1.024340, 1630 | -3.989851, 1631 | 4.926693, 1632 | 0.547818, 1633 | 0.692366, 1634 | 0.533422, 1635 | -3.993222, 1636 | 5.138202, 1637 | 0.524613, 1638 | 0.692366, 1639 | 0.769720, 1640 | -6.095394, 1641 | 4.985883, 1642 | 0.534090, 1643 | 0.779141, 1644 | 0.699606, 1645 | -5.291850, 1646 | 5.448304, 1647 | 0.527671, 1648 | 0.736226, 1649 | 0.669687, 1650 | -4.949770, 1651 | 5.509612, 1652 | 0.526913, 1653 | 0.717857, 1654 | 0.630947, 1655 | -4.695101, 1656 | 5.449371, 1657 | 0.526878, 1658 | 0.704626, 1659 | 0.583218, 1660 | -4.517982, 1661 | 5.339869, 1662 | 0.526967, 1663 | 0.695278, 1664 | 1.537170, 1665 | -4.423206, 1666 | 4.745470, 1667 | 0.572058, 1668 | 0.695278, 1669 | 1.615600, 1670 | -4.475942, 1671 | 4.813632, 1672 | 0.573521, 1673 | 0.703540, 1674 | 1.729053, 1675 | -4.618680, 1676 | 4.854463, 1677 | 0.576838, 1678 | 0.711846, 1679 | 1.838624, 1680 | -4.828746, 1681 | 4.823737, 1682 | 0.581691, 1683 | 0.720063, 1684 | 2.368250, 1685 | -3.106237, 1686 | 4.868096, 1687 | 0.609945, 1688 | 0.639910, 1689 | 7.542244, 1690 | -1.049282, 1691 | -2.431321, 1692 | 0.986046, 1693 | 0.560034, 1694 | 1.826614, 1695 | -4.399531, 1696 | 4.399021, 1697 | 0.586800, 1698 | 0.695400, 1699 | 1.929558, 1700 | -4.411831, 1701 | 4.497052, 1702 | 0.590372, 1703 | 0.701823, 1704 | 0.597442, 1705 | -2.013686, 1706 | 5.866456, 1707 | 0.531915, 1708 | 0.601537, 1709 | 1.405627, 1710 | -1.714196, 1711 | 5.241087, 1712 | 0.577268, 1713 | 0.585935, 1714 | 0.662449, 1715 | -1.819321, 1716 | 5.863759, 1717 | 0.536915, 1718 | 0.593786, 1719 | 2.342340, 1720 | 0.572222, 1721 | 4.294303, 1722 | 0.627543, 1723 | 0.473352, 1724 | 3.327324, 1725 | 0.104863, 1726 | 4.113860, 1727 | 0.665586, 1728 | 0.495951, 1729 | 1.726175, 1730 | -0.919165, 1731 | 5.273355, 1732 | 0.588354, 1733 | 0.546862, 1734 | 5.133204, 1735 | 7.485602, 1736 | 2.660442, 1737 | 0.757824, 1738 | 0.147676, 1739 | 4.538641, 1740 | 6.319907, 1741 | 3.683424, 1742 | 0.709250, 1743 | 0.201508, 1744 | 3.986562, 1745 | 5.109487, 1746 | 4.466315, 1747 | 0.672684, 1748 | 0.256581, 1749 | 2.169681, 1750 | -5.440433, 1751 | 4.455874, 1752 | 0.600409, 1753 | 0.749005, 1754 | 1.395634, 1755 | 5.011963, 1756 | 5.316032, 1757 | 0.558266, 1758 | 0.261672, 1759 | 1.619500, 1760 | 6.599217, 1761 | 4.921106, 1762 | 0.570304, 1763 | 0.187871, 1764 | 1.891399, 1765 | 8.236377, 1766 | 4.274997, 1767 | 0.588166, 1768 | 0.109044, 1769 | 4.195832, 1770 | 2.235205, 1771 | 3.375099, 1772 | 0.711045, 1773 | 0.398952, 1774 | 5.733342, 1775 | 1.411738, 1776 | 2.431726, 1777 | 0.781070, 1778 | 0.435405, 1779 | 1.859887, 1780 | 2.355757, 1781 | 3.843181, 1782 | 0.587247, 1783 | 0.398932, 1784 | 4.988612, 1785 | 3.074654, 1786 | 3.083858, 1787 | 0.742870, 1788 | 0.355446, 1789 | 1.303263, 1790 | 1.416453, 1791 | 4.831091, 1792 | 0.572156, 1793 | 0.437652, 1794 | 1.305757, 1795 | -0.672779, 1796 | 6.415959, 1797 | 0.551868, 1798 | 0.536570, 1799 | 6.465170, 1800 | 0.937119, 1801 | 1.689873, 1802 | 0.821442, 1803 | 0.457556, 1804 | 5.258659, 1805 | 0.945811, 1806 | 2.974312, 1807 | 0.752702, 1808 | 0.457182, 1809 | 4.432338, 1810 | 0.722096, 1811 | 3.522615, 1812 | 0.713757, 1813 | 0.467627, 1814 | 3.300681, 1815 | 0.861641, 1816 | 3.872784, 1817 | 0.667113, 1818 | 0.460673, 1819 | 2.430178, 1820 | 1.131492, 1821 | 4.039035, 1822 | 0.631101, 1823 | 0.447154, 1824 | 1.820731, 1825 | 1.467954, 1826 | 4.224124, 1827 | 0.600862, 1828 | 0.432473, 1829 | 0.563221, 1830 | 2.307693, 1831 | 5.566789, 1832 | 0.523481, 1833 | 0.405627, 1834 | 6.338145, 1835 | -0.529279, 1836 | 1.881175, 1837 | 0.810748, 1838 | 0.523926, 1839 | 5.587698, 1840 | 3.208071, 1841 | 2.687839, 1842 | 0.771046, 1843 | 0.348959, 1844 | 0.242624, 1845 | -1.462857, 1846 | 7.071491, 1847 | 0.509127, 1848 | 0.562718, 1849 | 1.611251, 1850 | 0.339326, 1851 | 4.895421, 1852 | 0.595293, 1853 | 0.485024, 1854 | 7.743095, 1855 | 2.364999, 1856 | -2.005167, 1857 | 0.980531, 1858 | 0.401564, 1859 | 1.391142, 1860 | 1.851048, 1861 | 4.448999, 1862 | 0.573500, 1863 | 0.420000, 1864 | 1.785794, 1865 | -0.978284, 1866 | 4.850470, 1867 | 0.602995, 1868 | 0.548688, 1869 | 4.670959, 1870 | 2.664461, 1871 | 3.084075, 1872 | 0.733530, 1873 | 0.376977, 1874 | 1.333970, 1875 | -0.283761, 1876 | 6.097047, 1877 | 0.560611, 1878 | 0.519017, 1879 | 7.270895, 1880 | -2.890917, 1881 | -2.252455, 1882 | 0.967686, 1883 | 0.644357, 1884 | 1.856432, 1885 | 2.585245, 1886 | 3.757904, 1887 | 0.580985, 1888 | 0.387160, 1889 | 0.923388, 1890 | 0.073076, 1891 | 6.671944, 1892 | 0.537728, 1893 | 0.505385, 1894 | 5.000589, 1895 | -6.135128, 1896 | 1.892523, 1897 | 0.760966, 1898 | 0.779753, 1899 | 5.085276, 1900 | -7.178590, 1901 | 0.714711, 1902 | 0.801779, 1903 | 0.831938, 1904 | 7.159291, 1905 | -0.811820, 1906 | -0.072044, 1907 | 0.892441, 1908 | 0.540761, 1909 | 5.843051, 1910 | -5.248023, 1911 | 0.924091, 1912 | 0.816351, 1913 | 0.740260, 1914 | 6.847258, 1915 | 3.662916, 1916 | 0.724695, 1917 | 0.865595, 1918 | 0.333687, 1919 | 2.412942, 1920 | -8.258853, 1921 | 4.119213, 1922 | 0.614074, 1923 | 0.883246, 1924 | 0.179909, 1925 | -1.689864, 1926 | 6.573301, 1927 | 0.508953, 1928 | 0.579438, 1929 | 2.103655, 1930 | -0.163946, 1931 | 4.566119, 1932 | 0.617942, 1933 | 0.508316, 1934 | 6.407571, 1935 | 2.236021, 1936 | 1.560843, 1937 | 0.825608, 1938 | 0.397675, 1939 | 3.670075, 1940 | 2.360153, 1941 | 3.635230, 1942 | 0.681215, 1943 | 0.396235, 1944 | 3.177186, 1945 | 2.294265, 1946 | 3.775704, 1947 | 0.656636, 1948 | 0.400597, 1949 | 2.196121, 1950 | -4.598322, 1951 | 4.479786, 1952 | 0.603900, 1953 | 0.710217, 1954 | 6.234883, 1955 | -1.944430, 1956 | 1.663542, 1957 | 0.812086, 1958 | 0.588539, 1959 | 1.292924, 1960 | -9.295920, 1961 | 4.094063, 1962 | 0.568013, 1963 | 0.944565, 1964 | 3.210651, 1965 | -8.533278, 1966 | 2.802001, 1967 | 0.681008, 1968 | 0.898285, 1969 | 4.068926, 1970 | -7.993109, 1971 | 1.925119, 1972 | 0.733752, 1973 | 0.869701, 1974 | 2.724032, 1975 | 2.315802, 1976 | 3.777151, 1977 | 0.633830, 1978 | 0.398822, 1979 | 2.288460, 1980 | 2.398891, 1981 | 3.697603, 1982 | 0.606793, 1983 | 0.395537, 1984 | 1.998311, 1985 | 2.496547, 1986 | 3.689148, 1987 | 0.589660, 1988 | 0.391062, 1989 | 6.130040, 1990 | 3.399261, 1991 | 2.038516, 1992 | 0.805016, 1993 | 0.342108, 1994 | 2.288460, 1995 | 2.886504, 1996 | 3.775031, 1997 | 0.611335, 1998 | 0.362284, 1999 | 2.724032, 2000 | 2.961810, 2001 | 3.871767, 2002 | 0.634038, 2003 | 0.355971, 2004 | 3.177186, 2005 | 2.964136, 2006 | 3.876973, 2007 | 0.656636, 2008 | 0.355357, 2009 | 3.670075, 2010 | 2.927714, 2011 | 3.724325, 2012 | 0.681215, 2013 | 0.358340, 2014 | 4.018389, 2015 | 2.857357, 2016 | 3.482983, 2017 | 0.698585, 2018 | 0.363156, 2019 | 7.555811, 2020 | 4.106811, 2021 | -0.991917, 2022 | 0.941867, 2023 | 0.319076, 2024 | 4.018389, 2025 | 2.483695, 2026 | 3.440898, 2027 | 0.698585, 2028 | 0.387449, 2029 | 1.776217, 2030 | -2.683946, 2031 | 5.213116, 2032 | 0.584177, 2033 | 0.624107, 2034 | 1.222237, 2035 | -1.182444, 2036 | 5.952465, 2037 | 0.554318, 2038 | 0.566077, 2039 | 0.731493, 2040 | -2.536683, 2041 | 5.815343, 2042 | 0.534154, 2043 | 0.620640, 2044 | 4.135272, 2045 | -6.996638, 2046 | 2.671970, 2047 | 0.711218, 2048 | 0.819975, 2049 | 3.311811, 2050 | -7.660815, 2051 | 3.382963, 2052 | 0.664630, 2053 | 0.852871, 2054 | 1.313701, 2055 | -8.639995, 2056 | 4.702456, 2057 | 0.559100, 2058 | 0.902632, 2059 | 5.940524, 2060 | -6.223629, 2061 | -0.631468, 2062 | 0.871706, 2063 | 0.791941, 2064 | 1.998311, 2065 | 2.743838, 2066 | 3.744030, 2067 | 0.591234, 2068 | 0.373894, 2069 | 0.901447, 2070 | 1.236992, 2071 | 5.754256, 2072 | 0.544341, 2073 | 0.451584, 2074 | 2.308977, 2075 | -8.974196, 2076 | 3.609070, 2077 | 0.624563, 2078 | 0.924192, 2079 | 6.954154, 2080 | -2.439843, 2081 | -0.131163, 2082 | 0.885770, 2083 | 0.615029, 2084 | 1.098819, 2085 | -4.458788, 2086 | 5.120727, 2087 | 0.551338, 2088 | 0.695278, 2089 | 1.181124, 2090 | -4.579996, 2091 | 5.189564, 2092 | 0.551980, 2093 | 0.704632, 2094 | 1.255818, 2095 | -4.787901, 2096 | 5.237051, 2097 | 0.552888, 2098 | 0.715808, 2099 | 1.325085, 2100 | -5.106507, 2101 | 5.205010, 2102 | 0.555168, 2103 | 0.730794, 2104 | 1.546388, 2105 | -5.819392, 2106 | 4.757893, 2107 | 0.569944, 2108 | 0.767035, 2109 | 1.953754, 2110 | -4.183892, 2111 | 4.431713, 2112 | 0.593203, 2113 | 0.685676, 2114 | 2.117802, 2115 | -4.137093, 2116 | 4.555096, 2117 | 0.599262, 2118 | 0.681069, 2119 | 2.285339, 2120 | -4.051196, 2121 | 4.582438, 2122 | 0.607600, 2123 | 0.677703, 2124 | 2.850160, 2125 | -3.665720, 2126 | 4.484994, 2127 | 0.631938, 2128 | 0.663500, 2129 | 5.278538, 2130 | -2.238942, 2131 | 2.861224, 2132 | 0.752033, 2133 | 0.601315, 2134 | 0.946709, 2135 | 1.907628, 2136 | 5.196779, 2137 | 0.547226, 2138 | 0.420395, 2139 | 1.314173, 2140 | 3.104912, 2141 | 4.231404, 2142 | 0.563544, 2143 | 0.359828, 2144 | 1.780000, 2145 | 2.860000, 2146 | 3.881555, 2147 | 0.583841, 2148 | 0.368714, 2149 | 1.845110, 2150 | -4.098880, 2151 | 4.247264, 2152 | 0.586614, 2153 | 0.692366, 2154 | 5.436187, 2155 | -4.030482, 2156 | 2.109852, 2157 | 0.771915, 2158 | 0.683578, 2159 | 0.766444, 2160 | 3.182131, 2161 | 4.861453, 2162 | 0.531597, 2163 | 0.352483, 2164 | 1.938616, 2165 | -6.614410, 2166 | 4.521085, 2167 | 0.588371, 2168 | 0.804441, 2169 | 0.516573, 2170 | 1.583572, 2171 | 6.148363, 2172 | 0.520797, 2173 | 0.442565, 2174 | 1.246815, 2175 | 0.230297, 2176 | 5.681036, 2177 | 0.567985, 2178 | 0.493479, 2179 | 0.997827, 2180 | -6.930921, 2181 | 4.979576, 2182 | 0.543283, 2183 | 0.819255, 2184 | 3.288807, 2185 | -5.382514, 2186 | 3.795752, 2187 | 0.655317, 2188 | 0.745515, 2189 | 2.311631, 2190 | -1.566237, 2191 | 4.590085, 2192 | 0.621009, 2193 | 0.574018, 2194 | 2.680250, 2195 | -6.111567, 2196 | 4.096152, 2197 | 0.625560, 2198 | 0.780312, 2199 | 3.832928, 2200 | -1.537326, 2201 | 4.137731, 2202 | 0.680198, 2203 | 0.570719, 2204 | 2.961860, 2205 | -2.274215, 2206 | 4.440943, 2207 | 0.642764, 2208 | 0.604338, 2209 | 4.386901, 2210 | -2.683286, 2211 | 3.643886, 2212 | 0.704663, 2213 | 0.621530, 2214 | 1.217295, 2215 | -7.834465, 2216 | 4.969286, 2217 | 0.552012, 2218 | 0.862592, 2219 | 1.542374, 2220 | -0.136843, 2221 | 5.201008, 2222 | 0.589072, 2223 | 0.508637, 2224 | 3.878377, 2225 | -6.041764, 2226 | 3.311079, 2227 | 0.685945, 2228 | 0.775357, 2229 | 3.084037, 2230 | -6.809842, 2231 | 3.814195, 2232 | 0.645735, 2233 | 0.812640, 2234 | 3.747321, 2235 | -4.503545, 2236 | 3.726453, 2237 | 0.675343, 2238 | 0.703978, 2239 | 6.094129, 2240 | -3.205991, 2241 | 1.473482, 2242 | 0.810858, 2243 | 0.646305, 2244 | 4.588995, 2245 | -4.728726, 2246 | 2.983221, 2247 | 0.720122, 2248 | 0.714667, 2249 | 6.583231, 2250 | -3.941269, 2251 | 0.070268, 2252 | 0.866152, 2253 | 0.682705, 2254 | 3.492580, 2255 | -3.195820, 2256 | 4.130198, 2257 | 0.663187, 2258 | 0.644597, 2259 | 1.255543, 2260 | 0.802341, 2261 | 5.307551, 2262 | 0.570082, 2263 | 0.466326, 2264 | 1.126122, 2265 | -0.933602, 2266 | 6.538785, 2267 | 0.544562, 2268 | 0.548376, 2269 | 1.443109, 2270 | -1.142774, 2271 | 5.905127, 2272 | 0.562759, 2273 | 0.558785, 2274 | 0.923043, 2275 | -0.529042, 2276 | 7.003423, 2277 | 0.531987, 2278 | 0.530140, 2279 | 1.755386, 2280 | 3.529117, 2281 | 4.327696, 2282 | 0.585271, 2283 | 0.335177, 2284 | 2.632589, 2285 | 3.713828, 2286 | 4.364629, 2287 | 0.622953, 2288 | 0.322779, 2289 | 3.388062, 2290 | 3.721976, 2291 | 4.309028, 2292 | 0.655896, 2293 | 0.320163, 2294 | 4.075766, 2295 | 3.675413, 2296 | 4.076063, 2297 | 0.687132, 2298 | 0.322346, 2299 | 4.622910, 2300 | 3.474691, 2301 | 3.646321, 2302 | 0.716482, 2303 | 0.333201, 2304 | 5.171755, 2305 | 2.535753, 2306 | 2.670867, 2307 | 0.758757, 2308 | 0.382787, 2309 | 7.297331, 2310 | 0.763172, 2311 | -0.048769, 2312 | 0.897013, 2313 | 0.468769, 2314 | 4.706828, 2315 | 1.651000, 2316 | 3.109532, 2317 | 0.732392, 2318 | 0.424547, 2319 | 4.071712, 2320 | 1.476821, 2321 | 3.476944, 2322 | 0.702114, 2323 | 0.433163, 2324 | 3.269817, 2325 | 1.470659, 2326 | 3.731945, 2327 | 0.666525, 2328 | 0.433866, 2329 | 2.527572, 2330 | 1.617311, 2331 | 3.865444, 2332 | 0.633505, 2333 | 0.426088, 2334 | 1.970894, 2335 | 1.858505, 2336 | 3.961782, 2337 | 0.603876, 2338 | 0.416587, 2339 | 1.579543, 2340 | 2.097941, 2341 | 4.084996, 2342 | 0.579658, 2343 | 0.409945, 2344 | 7.664182, 2345 | 0.673132, 2346 | -2.435867, 2347 | 0.992440, 2348 | 0.480777, 2349 | 1.397041, 2350 | -1.340139, 2351 | 5.630378, 2352 | 0.567192, 2353 | 0.569420, 2354 | 0.884838, 2355 | 0.658740, 2356 | 6.233232, 2357 | 0.541366, 2358 | 0.478899, 2359 | 0.767097, 2360 | -0.968035, 2361 | 7.077932, 2362 | 0.526564, 2363 | 0.546118, 2364 | 0.460213, 2365 | -1.334106, 2366 | 6.787447, 2367 | 0.523913, 2368 | 0.563830, 2369 | 0.748618, 2370 | -1.067994, 2371 | 6.798303, 2372 | 0.531529, 2373 | 0.555057, 2374 | 1.236408, 2375 | -1.585568, 2376 | 5.480490, 2377 | 0.566036, 2378 | 0.582329, 2379 | 0.387306, 2380 | -1.409990, 2381 | 6.957705, 2382 | 0.516311, 2383 | 0.563054, 2384 | 0.319925, 2385 | -1.607931, 2386 | 6.508676, 2387 | 0.517472, 2388 | 0.577877, 2389 | 1.639633, 2390 | 2.556298, 2391 | 3.863736, 2392 | 0.573595, 2393 | 0.389807, 2394 | 1.255645, 2395 | 2.467144, 2396 | 4.203800, 2397 | 0.560698, 2398 | 0.395332, 2399 | 1.031362, 2400 | 2.382663, 2401 | 4.615849, 2402 | 0.549756, 2403 | 0.399751, 2404 | 4.253081, 2405 | 2.772296, 2406 | 3.315305, 2407 | 0.710288, 2408 | 0.368253, 2409 | 4.530000, 2410 | 2.910000, 2411 | 3.339685, 2412 | 0.723330, 2413 | 0.363373, 2414 | ] 2415 | ) 2416 | canonical_metric_landmarks = np.reshape( 2417 | canonical_metric_landmarks, (canonical_metric_landmarks.shape[0] // 5, 5) 2418 | ).T 2419 | canonical_metric_landmarks = canonical_metric_landmarks[:3, :] 2420 | 2421 | procrustes_landmark_basis = [ 2422 | (4, 0.070909939706326), 2423 | (6, 0.032100144773722), 2424 | (10, 0.008446550928056), 2425 | (33, 0.058724168688059), 2426 | (54, 0.007667080033571), 2427 | (67, 0.009078059345484), 2428 | (117, 0.009791937656701), 2429 | (119, 0.014565368182957), 2430 | (121, 0.018591361120343), 2431 | (127, 0.005197994410992), 2432 | (129, 0.120625205338001), 2433 | (132, 0.005560018587857), 2434 | (133, 0.05328618362546), 2435 | (136, 0.066890455782413), 2436 | (143, 0.014816547743976), 2437 | (147, 0.014262833632529), 2438 | (198, 0.025462191551924), 2439 | (205, 0.047252278774977), 2440 | (263, 0.058724168688059), 2441 | (284, 0.007667080033571), 2442 | (297, 0.009078059345484), 2443 | (346, 0.009791937656701), 2444 | (348, 0.014565368182957), 2445 | (350, 0.018591361120343), 2446 | (356, 0.005197994410992), 2447 | (358, 0.120625205338001), 2448 | (361, 0.005560018587857), 2449 | (362, 0.05328618362546), 2450 | (365, 0.066890455782413), 2451 | (372, 0.014816547743976), 2452 | (376, 0.014262833632529), 2453 | (420, 0.025462191551924), 2454 | (425, 0.047252278774977), 2455 | ] 2456 | landmark_weights = np.zeros((canonical_metric_landmarks.shape[1],)) 2457 | for idx, weight in procrustes_landmark_basis: 2458 | landmark_weights[idx] = weight 2459 | 2460 | 2461 | def log(name, f): 2462 | if DEBUG.get_debug(): 2463 | print(f"{name} logged:", f) 2464 | print() 2465 | 2466 | 2467 | def cpp_compare(name, np_matrix): 2468 | if DEBUG.get_debug(): 2469 | # reorder cpp matrix as memory alignment is not correct 2470 | cpp_matrix = np.load(f"{name}_cpp.npy") 2471 | rows, cols = cpp_matrix.shape 2472 | cpp_matrix = np.split(np.reshape(cpp_matrix, -1), cols) 2473 | cpp_matrix = np.stack(cpp_matrix, 1) 2474 | 2475 | print(f"{name}:", np.sum(np.abs(cpp_matrix - np_matrix[:rows, :cols]) ** 2)) 2476 | print() 2477 | 2478 | 2479 | def get_metric_landmarks(screen_landmarks, pcf): 2480 | screen_landmarks = project_xy(screen_landmarks, pcf) 2481 | depth_offset = np.mean(screen_landmarks[2, :]) 2482 | 2483 | intermediate_landmarks = screen_landmarks.copy() 2484 | intermediate_landmarks = change_handedness(intermediate_landmarks) 2485 | first_iteration_scale = estimate_scale(intermediate_landmarks) 2486 | 2487 | intermediate_landmarks = screen_landmarks.copy() 2488 | intermediate_landmarks = move_and_rescale_z( 2489 | pcf, depth_offset, first_iteration_scale, intermediate_landmarks 2490 | ) 2491 | intermediate_landmarks = unproject_xy(pcf, intermediate_landmarks) 2492 | intermediate_landmarks = change_handedness(intermediate_landmarks) 2493 | second_iteration_scale = estimate_scale(intermediate_landmarks) 2494 | 2495 | metric_landmarks = screen_landmarks.copy() 2496 | total_scale = first_iteration_scale * second_iteration_scale 2497 | metric_landmarks = move_and_rescale_z( 2498 | pcf, depth_offset, total_scale, metric_landmarks 2499 | ) 2500 | metric_landmarks = unproject_xy(pcf, metric_landmarks) 2501 | metric_landmarks = change_handedness(metric_landmarks) 2502 | 2503 | pose_transform_mat = solve_weighted_orthogonal_problem( 2504 | canonical_metric_landmarks, metric_landmarks, landmark_weights 2505 | ) 2506 | cpp_compare("pose_transform_mat", pose_transform_mat) 2507 | 2508 | inv_pose_transform_mat = np.linalg.inv(pose_transform_mat) 2509 | inv_pose_rotation = inv_pose_transform_mat[:3, :3] 2510 | inv_pose_translation = inv_pose_transform_mat[:3, 3] 2511 | 2512 | metric_landmarks = ( 2513 | inv_pose_rotation @ metric_landmarks + inv_pose_translation[:, None] 2514 | ) 2515 | 2516 | return metric_landmarks, pose_transform_mat 2517 | 2518 | 2519 | def project_xy(landmarks, pcf): 2520 | x_scale = pcf.right - pcf.left 2521 | y_scale = pcf.top - pcf.bottom 2522 | x_translation = pcf.left 2523 | y_translation = pcf.bottom 2524 | 2525 | landmarks[1, :] = 1.0 - landmarks[1, :] 2526 | 2527 | landmarks = landmarks * np.array([[x_scale, y_scale, x_scale]]).T 2528 | landmarks = landmarks + np.array([[x_translation, y_translation, 0]]).T 2529 | 2530 | return landmarks 2531 | 2532 | 2533 | def change_handedness(landmarks): 2534 | landmarks[2, :] *= -1.0 2535 | 2536 | return landmarks 2537 | 2538 | 2539 | def move_and_rescale_z(pcf, depth_offset, scale, landmarks): 2540 | landmarks[2, :] = (landmarks[2, :] - depth_offset + pcf.near) / scale 2541 | 2542 | return landmarks 2543 | 2544 | 2545 | def unproject_xy(pcf, landmarks): 2546 | landmarks[0, :] = landmarks[0, :] * landmarks[2, :] / pcf.near 2547 | landmarks[1, :] = landmarks[1, :] * landmarks[2, :] / pcf.near 2548 | 2549 | return landmarks 2550 | 2551 | 2552 | def estimate_scale(landmarks): 2553 | transform_mat = solve_weighted_orthogonal_problem( 2554 | canonical_metric_landmarks, landmarks, landmark_weights 2555 | ) 2556 | 2557 | return np.linalg.norm(transform_mat[:, 0]) 2558 | 2559 | 2560 | def extract_square_root(point_weights): 2561 | return np.sqrt(point_weights) 2562 | 2563 | 2564 | def solve_weighted_orthogonal_problem(source_points, target_points, point_weights): 2565 | sqrt_weights = extract_square_root(point_weights) 2566 | transform_mat = internal_solve_weighted_orthogonal_problem( 2567 | source_points, target_points, sqrt_weights 2568 | ) 2569 | return transform_mat 2570 | 2571 | 2572 | def internal_solve_weighted_orthogonal_problem(sources, targets, sqrt_weights): 2573 | cpp_compare("sources", sources) 2574 | cpp_compare("targets", targets) 2575 | 2576 | # tranposed(A_w). 2577 | weighted_sources = sources * sqrt_weights[None, :] 2578 | # tranposed(B_w). 2579 | weighted_targets = targets * sqrt_weights[None, :] 2580 | 2581 | cpp_compare("weighted_sources", weighted_sources) 2582 | cpp_compare("weighted_targets", weighted_targets) 2583 | 2584 | # w = tranposed(j_w) j_w. 2585 | total_weight = np.sum(sqrt_weights * sqrt_weights) 2586 | log("total_weight", total_weight) 2587 | 2588 | # Let C = (j_w tranposed(j_w)) / (tranposed(j_w) j_w). 2589 | # Note that C = tranposed(C), hence (I - C) = tranposed(I - C). 2590 | # 2591 | # tranposed(A_w) C = tranposed(A_w) j_w tranposed(j_w) / w = 2592 | # (tranposed(A_w) j_w) tranposed(j_w) / w = c_w tranposed(j_w), 2593 | # 2594 | # where c_w = tranposed(A_w) j_w / w is a k x 1 vector calculated here: 2595 | twice_weighted_sources = weighted_sources * sqrt_weights[None, :] 2596 | source_center_of_mass = np.sum(twice_weighted_sources, axis=1) / total_weight 2597 | log("source_center_of_mass", source_center_of_mass) 2598 | 2599 | # tranposed((I - C) A_w) = tranposed(A_w) (I - C) = 2600 | # tranposed(A_w) - tranposed(A_w) C = tranposed(A_w) - c_w tranposed(j_w). 2601 | centered_weighted_sources = weighted_sources - np.matmul( 2602 | source_center_of_mass[:, None], sqrt_weights[None, :] 2603 | ) 2604 | cpp_compare("centered_weighted_sources", centered_weighted_sources) 2605 | 2606 | design_matrix = np.matmul(weighted_targets, centered_weighted_sources.T) 2607 | cpp_compare("design_matrix", design_matrix) 2608 | log("design_matrix_norm", np.linalg.norm(design_matrix)) 2609 | 2610 | rotation = compute_optimal_rotation(design_matrix) 2611 | 2612 | scale = compute_optimal_scale( 2613 | centered_weighted_sources, weighted_sources, weighted_targets, rotation 2614 | ) 2615 | log("scale", scale) 2616 | 2617 | rotation_and_scale = scale * rotation 2618 | 2619 | pointwise_diffs = weighted_targets - np.matmul(rotation_and_scale, weighted_sources) 2620 | cpp_compare("pointwise_diffs", pointwise_diffs) 2621 | 2622 | weighted_pointwise_diffs = pointwise_diffs * sqrt_weights[None, :] 2623 | cpp_compare("weighted_pointwise_diffs", weighted_pointwise_diffs) 2624 | 2625 | translation = np.sum(weighted_pointwise_diffs, axis=1) / total_weight 2626 | log("translation", translation) 2627 | 2628 | transform_mat = combine_transform_matrix(rotation_and_scale, translation) 2629 | cpp_compare("transform_mat", transform_mat) 2630 | 2631 | return transform_mat 2632 | 2633 | 2634 | def compute_optimal_rotation(design_matrix): 2635 | if np.linalg.norm(design_matrix) < 1e-9: 2636 | print("Design matrix norm is too small!") 2637 | 2638 | u, _, vh = np.linalg.svd(design_matrix, full_matrices=True) 2639 | 2640 | postrotation = u 2641 | prerotation = vh 2642 | 2643 | if np.linalg.det(postrotation) * np.linalg.det(prerotation) < 0: 2644 | postrotation[:, 2] = -1 * postrotation[:, 2] 2645 | 2646 | cpp_compare("postrotation", postrotation) 2647 | cpp_compare("prerotation", prerotation) 2648 | 2649 | rotation = np.matmul(postrotation, prerotation) 2650 | 2651 | cpp_compare("rotation", rotation) 2652 | 2653 | return rotation 2654 | 2655 | 2656 | def compute_optimal_scale( 2657 | centered_weighted_sources, weighted_sources, weighted_targets, rotation 2658 | ): 2659 | rotated_centered_weighted_sources = np.matmul(rotation, centered_weighted_sources) 2660 | 2661 | numerator = np.sum(rotated_centered_weighted_sources * weighted_targets) 2662 | denominator = np.sum(centered_weighted_sources * weighted_sources) 2663 | 2664 | if denominator < 1e-9: 2665 | print("Scale expression denominator is too small!") 2666 | if numerator / denominator < 1e-9: 2667 | print("Scale is too small!") 2668 | 2669 | return numerator / denominator 2670 | 2671 | 2672 | def combine_transform_matrix(r_and_s, t): 2673 | result = np.eye(4) 2674 | result[:3, :3] = r_and_s 2675 | result[:3, 3] = t 2676 | return result 2677 | -------------------------------------------------------------------------------- /custom/iris_lm_depth.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | from custom.core import ( # isort:skip 5 | detections_to_rect, 6 | landmarks_to_detections, 7 | slice_from_roi, 8 | tflite_inference, 9 | transform_rect, 10 | ) 11 | 12 | 13 | def from_landmarks_to_depth( 14 | frame_rgb, eye_landmarks, image_size, is_right_eye=False, focal_length=None 15 | ): 16 | if focal_length is None: 17 | focal_length = frame_rgb.shape[1] 18 | detections = landmarks_to_detections(eye_landmarks) 19 | rect = detections_to_rect(detections, image_size, rotation_vector_start_end=(0, 1)) 20 | roi = transform_rect(rect, image_size, scale_x=2.3, scale_y=2.3) 21 | 22 | slice_y = slice_from_roi(roi, image_size, False) 23 | slice_x = slice_from_roi(roi, image_size, True) 24 | eye_image = frame_rgb[slice(*slice_y), slice(*slice_x), :] 25 | position_in_frame = np.array((slice_x[0], slice_y[0], 0)) 26 | 27 | eye_contours, iris_landmarks = detect_iris( 28 | eye_image.copy(), is_right_eye=is_right_eye 29 | ) 30 | 31 | eye_contours[:, 0] = eye_contours[:, 0] * eye_image.shape[0] 32 | eye_contours[:, 1] = eye_contours[:, 1] * eye_image.shape[1] 33 | eye_contours = eye_contours + position_in_frame 34 | 35 | eye_contours[:, 0] = eye_contours[:, 0] / frame_rgb.shape[1] 36 | eye_contours[:, 1] = eye_contours[:, 1] / frame_rgb.shape[0] 37 | 38 | iris_landmarks[:, 0] = iris_landmarks[:, 0] * eye_image.shape[0] 39 | iris_landmarks[:, 1] = iris_landmarks[:, 1] * eye_image.shape[1] 40 | iris_landmarks = iris_landmarks + position_in_frame 41 | 42 | iris_landmarks[:, 0] = iris_landmarks[:, 0] / frame_rgb.shape[1] 43 | iris_landmarks[:, 1] = iris_landmarks[:, 1] / frame_rgb.shape[0] 44 | 45 | depth, iris_size = calculate_iris_depth(iris_landmarks, image_size, focal_length) 46 | 47 | return depth, iris_size, iris_landmarks, eye_contours 48 | 49 | 50 | def detect_iris(eye_frame, is_right_eye=False): 51 | side_low = 64 52 | eye_frame_low = cv2.resize( 53 | eye_frame, (side_low, side_low), interpolation=cv2.INTER_AREA 54 | ) 55 | 56 | model_path = "models/iris_landmark.tflite" 57 | 58 | if is_right_eye: 59 | eye_frame_low = np.fliplr(eye_frame_low) 60 | 61 | outputs = tflite_inference(eye_frame_low / 127.5 - 1.0, model_path) 62 | eye_contours_low = np.reshape(outputs[0], (71, 3)) 63 | iris_landmarks_low = np.reshape(outputs[1], (5, 3)) 64 | 65 | eye_contours = eye_contours_low / side_low 66 | iris_landmarks = iris_landmarks_low / side_low 67 | 68 | if is_right_eye: 69 | eye_contours[:, 0] = 1 - eye_contours[:, 0] 70 | iris_landmarks[:, 0] = 1 - iris_landmarks[:, 0] 71 | 72 | return eye_contours, iris_landmarks 73 | 74 | 75 | def calculate_iris_depth(iris_landmarks, image_size, focal_length_pixel): 76 | """ 77 | iris_landmarks should be normalized to the complete image frame 78 | depth in mm 79 | """ 80 | iris_size = calculate_iris_diameter(iris_landmarks, image_size) 81 | depth = calculate_depth( 82 | iris_landmarks[0, :], focal_length_pixel, iris_size, image_size 83 | ) 84 | 85 | return depth, iris_size 86 | 87 | 88 | def get_depth(x0, y0, x1, y1): 89 | return np.sqrt((x0 - x1) ** 2 + (y0 - y1) ** 2) 90 | 91 | 92 | def get_landmark_depth(ld0, ld1, image_size): 93 | return get_depth( 94 | ld0[0] * image_size[0], 95 | ld0[1] * image_size[1], 96 | ld1[0] * image_size[0], 97 | ld1[1] * image_size[1], 98 | ) 99 | 100 | 101 | def calculate_iris_diameter(iris_landmarks, image_size): 102 | dist_vert = get_landmark_depth( 103 | iris_landmarks[1, :], iris_landmarks[3, :], image_size 104 | ) 105 | dist_hori = get_landmark_depth( 106 | iris_landmarks[2, :], iris_landmarks[4, :], image_size 107 | ) 108 | 109 | return (dist_hori + dist_vert) / 2.0 110 | 111 | 112 | def calculate_depth(center_landmark, focal_length_pixel, iris_size, image_size): 113 | # Average fixed iris size across human beings. 114 | human_iris_size_in_mm = 11.8 115 | origin = np.array(image_size) / 2.0 116 | center_landmark_pixel = center_landmark[:2] * np.array(image_size) 117 | y = get_depth( 118 | origin[0], origin[1], center_landmark_pixel[0], center_landmark_pixel[1] 119 | ) 120 | x = np.sqrt(focal_length_pixel ** 2 + y ** 2) 121 | depth = human_iris_size_in_mm * x / iris_size 122 | 123 | return depth 124 | -------------------------------------------------------------------------------- /face_detection.py: -------------------------------------------------------------------------------- 1 | import mediapipe as mp 2 | 3 | from videosource import WebcamSource 4 | 5 | mp_drawing = mp.solutions.drawing_utils 6 | mp_face_detection = mp.solutions.face_detection 7 | 8 | 9 | def main(): 10 | source = WebcamSource() 11 | 12 | with mp_face_detection.FaceDetection( 13 | model_selection=0, min_detection_confidence=0.5 14 | ) as face_detection: 15 | 16 | for idx, (frame, frame_rgb) in enumerate(source): 17 | 18 | results = face_detection.process(frame_rgb) 19 | 20 | if results.detections: 21 | for detection in results.detections: 22 | mp_drawing.draw_detection(frame, detection) 23 | 24 | source.show(frame) 25 | 26 | 27 | if __name__ == "__main__": 28 | main() 29 | -------------------------------------------------------------------------------- /face_mesh.py: -------------------------------------------------------------------------------- 1 | import mediapipe as mp 2 | 3 | from videosource import WebcamSource 4 | 5 | mp_drawing = mp.solutions.drawing_utils 6 | mp_face_mesh = mp.solutions.face_mesh 7 | mp_face_mesh_connections = mp.solutions.face_mesh_connections 8 | drawing_spec = mp_drawing.DrawingSpec(thickness=1, circle_radius=3) 9 | 10 | 11 | def main(): 12 | source = WebcamSource() 13 | 14 | refine_landmarks = False 15 | 16 | with mp_face_mesh.FaceMesh( 17 | static_image_mode=False, 18 | refine_landmarks=refine_landmarks, 19 | min_detection_confidence=0.5, 20 | min_tracking_confidence=0.5, 21 | ) as face_mesh: 22 | 23 | for idx, (frame, frame_rgb) in enumerate(source): 24 | 25 | results = face_mesh.process(frame_rgb) 26 | 27 | if results.multi_face_landmarks: 28 | for face_landmarks in results.multi_face_landmarks: 29 | mp_drawing.draw_landmarks( 30 | image=frame, 31 | landmark_list=face_landmarks, 32 | connections=mp_face_mesh_connections.FACEMESH_TESSELATION, 33 | landmark_drawing_spec=drawing_spec, 34 | connection_drawing_spec=drawing_spec, 35 | ) 36 | 37 | source.show(frame) 38 | 39 | 40 | if __name__ == "__main__": 41 | main() 42 | -------------------------------------------------------------------------------- /facial_expression.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import mediapipe as mp 3 | import numpy as np 4 | 5 | from custom.core import extract_faces, tflite_inference 6 | from videosource import WebcamSource 7 | 8 | mp_drawing = mp.solutions.drawing_utils 9 | mp_face_detection = mp.solutions.face_detection 10 | 11 | labels = ["Neutral", "Happiness", "Sadness", "Surprise", "Fear", "Disgust", "Anger"] 12 | 13 | fast_model = True 14 | slow_model_every_x = 5 15 | 16 | 17 | def main(): 18 | source = WebcamSource() 19 | 20 | mean = np.array([0.57535914, 0.44928582, 0.40079932]) 21 | std = np.array([0.20735591, 0.18981615, 0.18132027]) 22 | 23 | if fast_model: 24 | # from https://github.com/zengqunzhao/EfficientFace 25 | model_path = "models/efficient_face_model.tflite" 26 | else: 27 | # from https://github.com/zengqunzhao/EfficientFace 28 | model_path = "models/dlg_model.tflite" 29 | 30 | with mp_face_detection.FaceDetection( 31 | model_selection=0, min_detection_confidence=0.5 32 | ) as face_detection: 33 | 34 | for idx, (frame, frame_rgb) in enumerate(source): 35 | 36 | results = face_detection.process(frame_rgb) 37 | 38 | face_frames = extract_faces(frame_rgb, results, x_scale=1.2, y_scale=1.2) 39 | 40 | if face_frames: 41 | face_frame = cv2.resize(face_frames[0], (224, 224)) 42 | frame[0:224, 0:224, :] = cv2.cvtColor(face_frame, cv2.COLOR_RGB2BGR) 43 | 44 | if fast_model or (idx % slow_model_every_x == 0): 45 | face_frame = face_frame / 255 46 | face_frame -= mean 47 | face_frame /= std 48 | face_frame = np.moveaxis(face_frame, -1, 0) 49 | 50 | outputs = tflite_inference(face_frame, model_path) 51 | outputs = outputs[0] 52 | expression_id = np.argmax(outputs) 53 | 54 | # write expression over head 55 | detection = results.detections[0] 56 | relative_keypoints = detection.location_data.relative_keypoints 57 | landmarks = np.stack([(rk.x, rk.y) for rk in relative_keypoints]) 58 | 59 | image_size = frame_rgb.shape[1::-1] 60 | pos = landmarks[2, :] 61 | pos = image_size * pos 62 | text_size = cv2.getTextSize( 63 | labels[expression_id], cv2.FONT_HERSHEY_SIMPLEX, 1.2, 2 64 | ) 65 | text_size = text_size[0] 66 | pos[0] -= text_size[0] / 2 67 | pos[1] -= 150 68 | 69 | pos = tuple(pos.astype(np.int32).tolist()) 70 | cv2.putText( 71 | frame, 72 | labels[expression_id], 73 | pos, 74 | cv2.FONT_HERSHEY_SIMPLEX, 75 | 1.2, 76 | (57, 255, 20), 77 | 2, 78 | ) 79 | 80 | source.show(frame) 81 | 82 | 83 | if __name__ == "__main__": 84 | main() 85 | -------------------------------------------------------------------------------- /hands.py: -------------------------------------------------------------------------------- 1 | import mediapipe as mp 2 | 3 | from videosource import WebcamSource 4 | 5 | mp_drawing = mp.solutions.drawing_utils 6 | mp_hands = mp.solutions.hands 7 | drawing_spec = mp_drawing.DrawingSpec(thickness=1, circle_radius=3) 8 | 9 | 10 | def main(): 11 | source = WebcamSource() 12 | 13 | with mp_hands.Hands( 14 | min_detection_confidence=0.5, min_tracking_confidence=0.5 15 | ) as hands: 16 | 17 | for idx, (frame, frame_rgb) in enumerate(source): 18 | 19 | results = hands.process(frame_rgb) 20 | 21 | if results.multi_hand_landmarks: 22 | for hand_landmarks in results.multi_hand_landmarks: 23 | mp_drawing.draw_landmarks( 24 | frame, 25 | hand_landmarks, 26 | mp_hands.HAND_CONNECTIONS, 27 | landmark_drawing_spec=drawing_spec, 28 | connection_drawing_spec=drawing_spec, 29 | ) 30 | 31 | source.show(frame) 32 | 33 | 34 | if __name__ == "__main__": 35 | main() 36 | -------------------------------------------------------------------------------- /head_posture.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import mediapipe as mp 3 | import numpy as np 4 | 5 | from videosource import WebcamSource 6 | 7 | from custom.face_geometry import ( # isort:skip 8 | PCF, 9 | get_metric_landmarks, 10 | procrustes_landmark_basis, 11 | ) 12 | 13 | mp_drawing = mp.solutions.drawing_utils 14 | mp_face_mesh = mp.solutions.face_mesh 15 | mp_face_mesh_connections = mp.solutions.face_mesh_connections 16 | drawing_spec = mp_drawing.DrawingSpec(thickness=1, circle_radius=3) 17 | 18 | points_idx = [33, 263, 61, 291, 199] 19 | points_idx = points_idx + [key for (key, val) in procrustes_landmark_basis] 20 | points_idx = list(set(points_idx)) 21 | points_idx.sort() 22 | 23 | # uncomment next line to use all points for PnP algorithm 24 | # points_idx = list(range(0,468)); points_idx[0:2] = points_idx[0:2:-1]; 25 | 26 | frame_height, frame_width, channels = (720, 1280, 3) 27 | 28 | # pseudo camera internals 29 | focal_length = frame_width 30 | center = (frame_width / 2, frame_height / 2) 31 | camera_matrix = np.array( 32 | [[focal_length, 0, center[0]], [0, focal_length, center[1]], [0, 0, 1]], 33 | dtype="double", 34 | ) 35 | 36 | dist_coeff = np.zeros((4, 1)) 37 | 38 | 39 | def main(): 40 | source = WebcamSource() 41 | 42 | refine_landmarks = True 43 | 44 | pcf = PCF( 45 | near=1, 46 | far=10000, 47 | frame_height=frame_height, 48 | frame_width=frame_width, 49 | fy=camera_matrix[1, 1], 50 | ) 51 | 52 | with mp_face_mesh.FaceMesh( 53 | static_image_mode=False, 54 | refine_landmarks=refine_landmarks, 55 | min_detection_confidence=0.5, 56 | min_tracking_confidence=0.5, 57 | ) as face_mesh: 58 | 59 | for idx, (frame, frame_rgb) in enumerate(source): 60 | results = face_mesh.process(frame_rgb) 61 | multi_face_landmarks = results.multi_face_landmarks 62 | 63 | if multi_face_landmarks: 64 | face_landmarks = multi_face_landmarks[0] 65 | landmarks = np.array( 66 | [(lm.x, lm.y, lm.z) for lm in face_landmarks.landmark] 67 | ) 68 | # print(landmarks.shape) 69 | landmarks = landmarks.T 70 | 71 | if refine_landmarks: 72 | landmarks = landmarks[:, :468] 73 | 74 | metric_landmarks, pose_transform_mat = get_metric_landmarks( 75 | landmarks.copy(), pcf 76 | ) 77 | 78 | image_points = ( 79 | landmarks[0:2, points_idx].T 80 | * np.array([frame_width, frame_height])[None, :] 81 | ) 82 | model_points = metric_landmarks[0:3, points_idx].T 83 | 84 | # see here: 85 | # https://github.com/google/mediapipe/issues/1379#issuecomment-752534379 86 | pose_transform_mat[1:3, :] = -pose_transform_mat[1:3, :] 87 | mp_rotation_vector, _ = cv2.Rodrigues(pose_transform_mat[:3, :3]) 88 | mp_translation_vector = pose_transform_mat[:3, 3, None] 89 | 90 | if False: 91 | # sanity check 92 | # get same result with solvePnP 93 | 94 | success, rotation_vector, translation_vector = cv2.solvePnP( 95 | model_points, 96 | image_points, 97 | camera_matrix, 98 | dist_coeff, 99 | flags=cv2.cv2.SOLVEPNP_ITERATIVE, 100 | ) 101 | 102 | np.testing.assert_almost_equal(mp_rotation_vector, rotation_vector) 103 | np.testing.assert_almost_equal( 104 | mp_translation_vector, translation_vector 105 | ) 106 | 107 | for face_landmarks in multi_face_landmarks: 108 | mp_drawing.draw_landmarks( 109 | image=frame, 110 | landmark_list=face_landmarks, 111 | connections=mp_face_mesh_connections.FACEMESH_TESSELATION, 112 | landmark_drawing_spec=drawing_spec, 113 | connection_drawing_spec=drawing_spec, 114 | ) 115 | 116 | nose_tip = model_points[0] 117 | nose_tip_extended = 2.5 * model_points[0] 118 | (nose_pointer2D, jacobian) = cv2.projectPoints( 119 | np.array([nose_tip, nose_tip_extended]), 120 | mp_rotation_vector, 121 | mp_translation_vector, 122 | camera_matrix, 123 | dist_coeff, 124 | ) 125 | 126 | nose_tip_2D, nose_tip_2D_extended = nose_pointer2D.squeeze().astype(int) 127 | frame = cv2.line( 128 | frame, nose_tip_2D, nose_tip_2D_extended, (255, 0, 0), 2 129 | ) 130 | 131 | source.show(frame) 132 | 133 | 134 | if __name__ == "__main__": 135 | main() 136 | -------------------------------------------------------------------------------- /holistic.py: -------------------------------------------------------------------------------- 1 | import mediapipe as mp 2 | 3 | from videosource import WebcamSource 4 | 5 | mp_drawing = mp.solutions.drawing_utils 6 | mp_holistic = mp.solutions.holistic 7 | mp_face_mesh_connections = mp.solutions.face_mesh_connections 8 | drawing_spec = mp_drawing.DrawingSpec(thickness=1, circle_radius=3) 9 | 10 | 11 | def main(): 12 | source = WebcamSource() 13 | 14 | with mp_holistic.Holistic( 15 | min_detection_confidence=0.5, min_tracking_confidence=0.5 16 | ) as holistic: 17 | 18 | for idx, (frame, frame_rgb) in enumerate(source): 19 | 20 | results = holistic.process(frame_rgb) 21 | 22 | mp_drawing.draw_landmarks( 23 | frame, 24 | results.face_landmarks, 25 | connections=mp_face_mesh_connections.FACEMESH_TESSELATION, 26 | landmark_drawing_spec=drawing_spec, 27 | connection_drawing_spec=drawing_spec, 28 | ) 29 | mp_drawing.draw_landmarks( 30 | frame, 31 | results.left_hand_landmarks, 32 | mp_holistic.HAND_CONNECTIONS, 33 | landmark_drawing_spec=drawing_spec, 34 | connection_drawing_spec=drawing_spec, 35 | ) 36 | mp_drawing.draw_landmarks( 37 | frame, 38 | results.right_hand_landmarks, 39 | mp_holistic.HAND_CONNECTIONS, 40 | landmark_drawing_spec=drawing_spec, 41 | connection_drawing_spec=drawing_spec, 42 | ) 43 | mp_drawing.draw_landmarks( 44 | frame, 45 | results.pose_landmarks, 46 | mp_holistic.POSE_CONNECTIONS, 47 | landmark_drawing_spec=drawing_spec, 48 | connection_drawing_spec=drawing_spec, 49 | ) 50 | 51 | source.show(frame) 52 | 53 | 54 | if __name__ == "__main__": 55 | main() 56 | -------------------------------------------------------------------------------- /iris.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | 3 | import cv2 4 | import mediapipe as mp 5 | import numpy as np 6 | 7 | from custom.iris_lm_depth import from_landmarks_to_depth 8 | from videosource import FileSource, WebcamSource 9 | 10 | mp_face_mesh = mp.solutions.face_mesh 11 | 12 | points_idx = [33, 133, 362, 263, 61, 291, 199] 13 | points_idx = list(set(points_idx)) 14 | points_idx.sort() 15 | 16 | left_eye_landmarks_id = np.array([33, 133]) 17 | right_eye_landmarks_id = np.array([362, 263]) 18 | 19 | dist_coeff = np.zeros((4, 1)) 20 | 21 | YELLOW = (0, 255, 255) 22 | GREEN = (0, 255, 0) 23 | BLUE = (255, 0, 0) 24 | RED = (0, 0, 255) 25 | SMALL_CIRCLE_SIZE = 1 26 | LARGE_CIRCLE_SIZE = 2 27 | 28 | 29 | def main(inp): 30 | if inp is None: 31 | frame_height, frame_width = (720, 1280) 32 | source = WebcamSource(width=frame_width, height=frame_height) 33 | else: 34 | source = FileSource(inp) 35 | frame_width, frame_height = (int(i) for i in source.get_image_size()) 36 | 37 | image_size = (frame_width, frame_height) 38 | 39 | # pseudo camera internals 40 | focal_length = frame_width 41 | 42 | landmarks = None 43 | smooth_left_depth = -1 44 | smooth_right_depth = -1 45 | smooth_factor = 0.1 46 | 47 | with mp_face_mesh.FaceMesh( 48 | static_image_mode=False, 49 | min_detection_confidence=0.5, 50 | min_tracking_confidence=0.5, 51 | ) as face_mesh: 52 | 53 | for idx, (frame, frame_rgb) in enumerate(source): 54 | results = face_mesh.process(frame_rgb) 55 | multi_face_landmarks = results.multi_face_landmarks 56 | 57 | if multi_face_landmarks: 58 | face_landmarks = results.multi_face_landmarks[0] 59 | landmarks = np.array( 60 | [(lm.x, lm.y, lm.z) for lm in face_landmarks.landmark] 61 | ) 62 | landmarks = landmarks.T 63 | 64 | ( 65 | left_depth, 66 | left_iris_size, 67 | left_iris_landmarks, 68 | left_eye_contours, 69 | ) = from_landmarks_to_depth( 70 | frame_rgb, 71 | landmarks[:, left_eye_landmarks_id], 72 | image_size, 73 | is_right_eye=False, 74 | focal_length=focal_length, 75 | ) 76 | 77 | ( 78 | right_depth, 79 | right_iris_size, 80 | right_iris_landmarks, 81 | right_eye_contours, 82 | ) = from_landmarks_to_depth( 83 | frame_rgb, 84 | landmarks[:, right_eye_landmarks_id], 85 | image_size, 86 | is_right_eye=True, 87 | focal_length=focal_length, 88 | ) 89 | 90 | if smooth_right_depth < 0: 91 | smooth_right_depth = right_depth 92 | else: 93 | smooth_right_depth = ( 94 | smooth_right_depth * (1 - smooth_factor) 95 | + right_depth * smooth_factor 96 | ) 97 | 98 | if smooth_left_depth < 0: 99 | smooth_left_depth = left_depth 100 | else: 101 | smooth_left_depth = ( 102 | smooth_left_depth * (1 - smooth_factor) 103 | + left_depth * smooth_factor 104 | ) 105 | 106 | print( 107 | f"depth in cm: {smooth_left_depth / 10:.2f}, {smooth_right_depth / 10:.2f}" 108 | ) 109 | print(f"size: {left_iris_size:.2f}, {right_iris_size:.2f}") 110 | 111 | if landmarks is not None: 112 | 113 | # draw subset of facemesh 114 | for ii in points_idx: 115 | pos = (np.array(image_size) * landmarks[:2, ii]).astype(np.int32) 116 | frame = cv2.circle(frame, tuple(pos), LARGE_CIRCLE_SIZE, GREEN, -1) 117 | 118 | # draw eye contours 119 | eye_landmarks = np.concatenate( 120 | [ 121 | right_eye_contours, 122 | left_eye_contours, 123 | ] 124 | ) 125 | for landmark in eye_landmarks: 126 | pos = (np.array(image_size) * landmark[:2]).astype(np.int32) 127 | frame = cv2.circle(frame, tuple(pos), SMALL_CIRCLE_SIZE, RED, -1) 128 | 129 | # draw iris landmarks 130 | iris_landmarks = np.concatenate( 131 | [ 132 | right_iris_landmarks, 133 | left_iris_landmarks, 134 | ] 135 | ) 136 | for landmark in iris_landmarks: 137 | pos = (np.array(image_size) * landmark[:2]).astype(np.int32) 138 | frame = cv2.circle(frame, tuple(pos), SMALL_CIRCLE_SIZE, YELLOW, -1) 139 | 140 | # write depth values into frame 141 | depth_string = "{:.2f}cm, {:.2f}cm".format( 142 | smooth_left_depth / 10, smooth_right_depth / 10 143 | ) 144 | frame = cv2.putText( 145 | frame, 146 | depth_string, 147 | (50, 50), 148 | cv2.FONT_HERSHEY_SIMPLEX, 149 | 1, 150 | GREEN, 151 | 2, 152 | cv2.LINE_AA, 153 | ) 154 | 155 | source.show(frame) 156 | 157 | 158 | if __name__ == "__main__": 159 | parser = argparse.ArgumentParser( 160 | description="Choose video file otherwise webcam is used." 161 | ) 162 | parser.add_argument( 163 | "-i", metavar="path-to-file", type=str, help="Path to video file" 164 | ) 165 | 166 | args = parser.parse_args() 167 | main(args.i) 168 | -------------------------------------------------------------------------------- /objectron.py: -------------------------------------------------------------------------------- 1 | import mediapipe as mp 2 | 3 | from videosource import WebcamSource 4 | 5 | mp_drawing = mp.solutions.drawing_utils 6 | mp_objectron = mp.solutions.objectron 7 | 8 | 9 | def main(): 10 | source = WebcamSource() 11 | 12 | with mp_objectron.Objectron( 13 | static_image_mode=False, 14 | max_num_objects=5, 15 | min_detection_confidence=0.5, 16 | min_tracking_confidence=0.99, 17 | model_name="Shoe", # {'Shoe', 'Chair', 'Cup', 'Camera'} 18 | ) as objectron: 19 | 20 | for idx, (frame, frame_rgb) in enumerate(source): 21 | 22 | results = objectron.process(frame_rgb) 23 | 24 | if results.detected_objects: 25 | for detected_object in results.detected_objects: 26 | mp_drawing.draw_landmarks( 27 | frame, 28 | detected_object.landmarks_2d, 29 | mp_objectron.BOX_CONNECTIONS, 30 | ) 31 | mp_drawing.draw_axis( 32 | frame, detected_object.rotation, detected_object.translation 33 | ) 34 | 35 | source.show(frame) 36 | 37 | 38 | if __name__ == "__main__": 39 | main() 40 | -------------------------------------------------------------------------------- /pose.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | 3 | import mediapipe as mp 4 | import numpy as np 5 | 6 | from videosource import FileSource, WebcamSource 7 | 8 | mp_drawing = mp.solutions.drawing_utils 9 | mp_pose = mp.solutions.pose 10 | drawing_spec = mp_drawing.DrawingSpec(thickness=1, circle_radius=3) 11 | 12 | 13 | def main(inp): 14 | if inp is None: 15 | source = WebcamSource() 16 | else: 17 | source = FileSource(inp) 18 | 19 | with mp_pose.Pose( 20 | min_detection_confidence=0.5, min_tracking_confidence=0.5 21 | ) as pose: 22 | 23 | for idx, (frame, frame_rgb) in enumerate(source): 24 | 25 | results = pose.process(frame_rgb) 26 | 27 | if results.pose_landmarks: 28 | mp_drawing.draw_landmarks( 29 | frame, 30 | results.pose_landmarks, 31 | mp_pose.POSE_CONNECTIONS, 32 | landmark_drawing_spec=drawing_spec, 33 | connection_drawing_spec=drawing_spec, 34 | ) 35 | 36 | # get landmarks as numpy 37 | landmarks = results.pose_landmarks.landmark 38 | np_landmarks = np.array( 39 | [(lm.x, lm.y, lm.z, lm.visibility) for lm in landmarks] 40 | ) 41 | print(np_landmarks.shape) 42 | 43 | source.show(frame) 44 | 45 | 46 | if __name__ == "__main__": 47 | parser = argparse.ArgumentParser( 48 | description="Choose video file otherwise webcam is used." 49 | ) 50 | parser.add_argument( 51 | "-i", metavar="path-to-file", type=str, help="Path to video file" 52 | ) 53 | 54 | args = parser.parse_args() 55 | main(args.i) 56 | -------------------------------------------------------------------------------- /readme.MD: -------------------------------------------------------------------------------- 1 | # Mediapipe examples 2 | 3 | From: 4 | https://google.github.io/mediapipe/ 5 | 6 | 7 | ## Installation 8 | 9 | ``` 10 | python -m venv env 11 | source env/bin/activate 12 | pip install -r requirements.txt 13 | ``` 14 | 15 | For the iris example, put `iris_landmark.tflite` into `models` directory, by unpacking following zip file: 16 | ``` 17 | https://github.com/google/mediapipe/files/10012191/iris_landmark.zip 18 | ``` 19 | 20 | The facial expression example uses the trained weights from [github.com/zengqunzhao/EfficientFace](https://github.com/zengqunzhao/EfficientFace), but converted to tflite. 21 | For the facial expression example download both models (fast and slow) into the `models` directory: 22 | 23 | ``` 24 | wget -P models https://rassibassi-mediapipedemos.s3.eu-central-1.amazonaws.com/efficient_face_model.tflite 25 | wget -P models https://rassibassi-mediapipedemos.s3.eu-central-1.amazonaws.com/dlg_model.tflite 26 | ``` 27 | 28 | ## How to run 29 | 30 | One of the following: 31 | 32 | ``` 33 | python facial_expression.py 34 | python face_detection.py 35 | python face_mesh.py 36 | python hands.py 37 | python head_posture.py 38 | python holistic.py 39 | python iris.py 40 | python objectron.py 41 | python pose.py 42 | python selfie_segmentation.py 43 | ``` 44 | 45 | `pose.py` and `iris.py` include the possibility to process a video file instead of the webcam input stream. Run like this: 46 | 47 | ``` 48 | python iris.py -i /path/to/some/file/i-am-a-video-file.mp4 49 | python pose.py -i /path/to/some/file/i-am-a-video-file.mp4 50 | ``` 51 | 52 | ## Numpy 53 | 54 | See example `python pose.py` for how to extract numpy array from the mediapipe landmark objects. 55 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | numpy==1.19.2 2 | tensorflow==2.5.0 3 | Pillow==8.2.0 4 | mediapipe==0.8.10.1 5 | opencv-python==4.5.2.54 -------------------------------------------------------------------------------- /selfie_segmentation.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import mediapipe as mp 3 | import numpy as np 4 | 5 | from videosource import WebcamSource 6 | 7 | mp_drawing = mp.solutions.drawing_utils 8 | mp_selfie_segmentation = mp.solutions.selfie_segmentation 9 | 10 | 11 | def main(): 12 | source = WebcamSource() 13 | 14 | with mp_selfie_segmentation.SelfieSegmentation( 15 | model_selection=1 16 | ) as selfie_segmentation: 17 | 18 | for idx, (frame, frame_rgb) in enumerate(source): 19 | 20 | results = selfie_segmentation.process(frame_rgb) 21 | 22 | # Draw selfie segmentation on the background image. 23 | # To improve segmentation around boundaries, consider applying a joint 24 | # bilateral filter to "results.segmentation_mask" with "image". 25 | condition = np.stack((results.segmentation_mask,) * 3, axis=-1) > 0.1 26 | 27 | bg_image = None 28 | 29 | # The background can be customized. 30 | # a) Load an image (with the same width and height of the input image) to 31 | # be the background, e.g., bg_image = cv2.imread('/path/to/image/file') 32 | # b) Blur the input image by applying image filtering, e.g., 33 | # bg_image = cv2.GaussianBlur(image,(55,55),0) 34 | 35 | bg_image = cv2.GaussianBlur(frame, (55, 55), 0) 36 | 37 | if bg_image is None: 38 | bg_image = np.zeros(frame.shape, dtype=np.uint8) 39 | 40 | output_image = np.where(condition, frame, bg_image) 41 | 42 | source.show(output_image) 43 | 44 | 45 | if __name__ == "__main__": 46 | main() 47 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [flake8] 2 | max-line-length = 119 -------------------------------------------------------------------------------- /videosource.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | from PIL import Image 4 | 5 | 6 | class VideoSource: 7 | def __init__(self, flip=False, display=False, dtype=np.uint8): 8 | self._name = "VideoSource" 9 | self._capture = None 10 | self._display = display 11 | self._dtype = dtype 12 | self._flip = flip 13 | 14 | def get_fps(self): 15 | return self._capture.get(cv2.CAP_PROP_FPS) 16 | 17 | def get_frame_count(self): 18 | return int(self._capture.get(cv2.CAP_PROP_FRAME_COUNT)) 19 | 20 | def get_image_size(self): 21 | width = self._capture.get(cv2.CAP_PROP_FRAME_WIDTH) 22 | height = self._capture.get(cv2.CAP_PROP_FRAME_HEIGHT) 23 | return width, height 24 | 25 | def release(self): 26 | self._capture.release() 27 | cv2.destroyAllWindows() 28 | 29 | def __iter__(self): 30 | self._capture.isOpened() 31 | return self 32 | 33 | def __next__(self): 34 | ret, frame = self._capture.read() 35 | 36 | if self._flip: 37 | frame = cv2.flip(frame, 3) 38 | 39 | if self._display: 40 | cv2.imshow(f"{self._name} - FPS: {self.get_fps()}", frame) 41 | 42 | if not ret: 43 | raise StopIteration 44 | 45 | if cv2.waitKey(1) & 0xFF == ord("q"): 46 | raise StopIteration 47 | 48 | cv2_im_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) 49 | frame_rgb = np.asarray(Image.fromarray(cv2_im_rgb), dtype=self._dtype) 50 | 51 | return frame, frame_rgb 52 | 53 | def __del__(self): 54 | self.release() 55 | 56 | def show(self, frame): 57 | cv2.imshow(f"{self._name} - FPS: {self.get_fps()}", frame) 58 | 59 | 60 | class WebcamSource(VideoSource): 61 | def __init__( 62 | self, 63 | camera_id=0, 64 | width=1280, 65 | height=720, 66 | fps=30, 67 | autofocus=0, 68 | absolute_focus=75, 69 | flip=True, 70 | display=False, 71 | ): 72 | super().__init__(flip, display) 73 | self._capture = cv2.VideoCapture(camera_id) 74 | self._capture.set(cv2.CAP_PROP_FRAME_WIDTH, width) 75 | self._capture.set(cv2.CAP_PROP_FRAME_HEIGHT, height) 76 | self._capture.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc(*"MJPG")) 77 | self._capture.set(cv2.CAP_PROP_FPS, fps) 78 | self._capture.set(cv2.CAP_PROP_AUTOFOCUS, autofocus) 79 | self._capture.set(cv2.CAP_PROP_FOCUS, absolute_focus / 255) 80 | 81 | 82 | class FileSource(VideoSource): 83 | def __init__(self, file_path, flip=False, display=False): 84 | super().__init__(flip, display) 85 | self._capture = cv2.VideoCapture(str(file_path)) 86 | --------------------------------------------------------------------------------