Download face_detect/LandmarksProcessor.py from GuijiAI/ReHiFace-S: direct link, hf CLI and curl.
- Browser
- Download file 55.5 kB
-
https://huggingface.co/GuijiAI/ReHiFace-S/resolve/refs%2Fpr%2F2/face_detect/LandmarksProcessor.py
- Command line
-
hf download hf://GuijiAI/ReHiFace-S@refs/pr/2/face_detect/LandmarksProcessor.py
-
curl -L -o LandmarksProcessor.py https://huggingface.co/GuijiAI/ReHiFace-S/resolve/refs%2Fpr%2F2/face_detect/LandmarksProcessor.py
55.5 kB
| import colorsys | |
| import math | |
| from enum import IntEnum | |
| import cv2 | |
| import numpy as np | |
| import numpy.linalg as npla | |
| from face_detect.core import imagelib | |
| from face_detect.core import mathlib | |
| from face_detect.core.mathlib.umeyama import umeyama | |
| from face_detect.FaceType import FaceType | |
| mesh_33=[70,63,105,66,107,336,296,334,293,300,168,197,5,4,240,99,2,328,460,33,160,158,133,153,144,362,385,387,263,373,380,57,287] | |
| landmarks_2D_4=np.array([ | |
| [0.224152 , 0.2119465], #left iris mean 37 38 40 41 | |
| [0.75610125, 0.2119465],#right iris mean 43 44 46 47 | |
| [0.490127, 0.515625], # nose 30 | |
| [0.4901265, 0.780233] #mouth mean 48 54 | |
| ]) | |
| landmarks_2D_4_bottom=np.array([ | |
| [0.2218305, 0.244588 ], #left iris mean 40 41 | |
| [0.7584225, 0.244588],#right iris mean 46 47 | |
| [0.490127, 0.515625], # nose 30 | |
| [0.4901265, 0.780233] #mouth mean 48 54 | |
| ]) | |
| landmarks_2D = np.array([ | |
| [0.000213256, 0.106454], # 17 | |
| [0.0752622, 0.038915], # 18 | |
| [0.18113, 0.0187482], # 19 | |
| [0.29077, 0.0344891], # 20 | |
| [0.393397, 0.0773906], # 21 | |
| [0.586856, 0.0773906], # 22 | |
| [0.689483, 0.0344891], # 23 | |
| [0.799124, 0.0187482], # 24 | |
| [0.904991, 0.038915], # 25 | |
| [0.98004, 0.106454], # 26 | |
| [0.490127, 0.203352], # 27 | |
| [0.490127, 0.307009], # 28 | |
| [0.490127, 0.409805], # 29 | |
| [0.490127, 0.515625], # 30 | |
| [0.36688, 0.587326], # 31 | |
| [0.426036, 0.609345], # 32 | |
| [0.490127, 0.628106], # 33 | |
| [0.554217, 0.609345], # 34 | |
| [0.613373, 0.587326], # 35 | |
| [0.121737, 0.216423], # 36 | |
| [0.187122, 0.178758], # 37 | |
| [0.265825, 0.179852], # 38 | |
| [0.334606, 0.231733], # 39 | |
| [0.260918, 0.245099], # 40 | |
| [0.182743, 0.244077], # 41 | |
| [0.645647, 0.231733], # 42 | |
| [0.714428, 0.179852], # 43 | |
| [0.793132, 0.178758], # 44 | |
| [0.858516, 0.216423], # 45 | |
| [0.79751, 0.244077], # 46 | |
| [0.719335, 0.245099], # 47 | |
| [0.254149, 0.780233], # 48 | |
| [0.340985, 0.745405], # 49 | |
| [0.428858, 0.727388], # 50 | |
| [0.490127, 0.742578], # 51 | |
| [0.551395, 0.727388], # 52 | |
| [0.639268, 0.745405], # 53 | |
| [0.726104, 0.780233], # 54 | |
| [0.642159, 0.864805], # 55 | |
| [0.556721, 0.902192], # 56 | |
| [0.490127, 0.909281], # 57 | |
| [0.423532, 0.902192], # 58 | |
| [0.338094, 0.864805], # 59 | |
| [0.290379, 0.784792], # 60 | |
| [0.428096, 0.778746], # 61 | |
| [0.490127, 0.785343], # 62 | |
| [0.552157, 0.778746], # 63 | |
| [0.689874, 0.784792], # 64 | |
| [0.553364, 0.824182], # 65 | |
| [0.490127, 0.831803], # 66 | |
| [0.42689, 0.824182] # 67 | |
| ], dtype=np.float32) | |
| landmarks_2D_new = np.array([ | |
| [0.000213256, 0.106454], # 17 | |
| [0.0752622, 0.038915], # 18 | |
| [0.18113, 0.0187482], # 19 | |
| [0.29077, 0.0344891], # 20 | |
| [0.393397, 0.0773906], # 21 | |
| [0.586856, 0.0773906], # 22 | |
| [0.689483, 0.0344891], # 23 | |
| [0.799124, 0.0187482], # 24 | |
| [0.904991, 0.038915], # 25 | |
| [0.98004, 0.106454], # 26 | |
| [0.490127, 0.203352], # 27 | |
| [0.490127, 0.307009], # 28 | |
| [0.490127, 0.409805], # 29 | |
| [0.490127, 0.515625], # 30 | |
| [0.36688, 0.587326], # 31 | |
| [0.426036, 0.609345], # 32 | |
| [0.490127, 0.628106], # 33 | |
| [0.554217, 0.609345], # 34 | |
| [0.613373, 0.587326], # 35 | |
| [0.121737, 0.216423], # 36 | |
| [0.187122, 0.178758], # 37 | |
| [0.265825, 0.179852], # 38 | |
| [0.334606, 0.231733], # 39 | |
| [0.260918, 0.245099], # 40 | |
| [0.182743, 0.244077], # 41 | |
| [0.645647, 0.231733], # 42 | |
| [0.714428, 0.179852], # 43 | |
| [0.793132, 0.178758], # 44 | |
| [0.858516, 0.216423], # 45 | |
| [0.79751, 0.244077], # 46 | |
| [0.719335, 0.245099], # 47 | |
| [0.254149, 0.780233], # 48 | |
| [0.726104, 0.780233], # 54 | |
| ], dtype=np.float32) | |
| landmarks_2D_new_mesh = np.array([ | |
| [ 0.000213256, 0.106454 ], #17 | |
| [ 0.0752622, 0.038915 ], #18 | |
| [0.1281961, 0.0288316], #19[ 0.18113, 0.0187482 ] | |
| [ 0.29077, 0.0144891 ], #20 | |
| [ 0.393397, 0.0773906 ], #21 | |
| [ 0.586856, 0.0773906 ], #22 | |
| [ 0.689483, 0.0144891 ], #23 | |
| [0.8520575, 0.0288316], #24[ 0.799124, 0.0187482 ] | |
| [ 0.904991, 0.038915 ], #25 | |
| [ 0.98004, 0.106454 ], #26 | |
| [ 0.490127, 0.203352 ], #27 | |
| [ 0.490127, 0.307009 ], #28 | |
| [ 0.490127, 0.409805 ], #29 | |
| [ 0.490127, 0.515625 ], #30 | |
| [0.396458 , 0.5983355], #31 [ 0.36688, 0.587326 ] | |
| [ 0.426036, 0.609345 ], #32 | |
| [ 0.490127, 0.628106 ], #33 | |
| [ 0.554217, 0.609345 ], #34 | |
| [ 0.613373, 0.587326 ], #35 | |
| [ 0.071737, 0.136423 ], #36 | |
| [ 0.137122, 0.118758 ], #37 | |
| [ 0.215825, 0.119852 ], #38 | |
| [ 0.334606, 0.151733 ], #39 | |
| [ 0.210918, 0.165099 ], #40 | |
| [ 0.132743, 0.164077 ], #41 | |
| [ 0.645647, 0.151733 ], #42 | |
| [ 0.764428, 0.119852 ], #43 | |
| [ 0.743132, 0.118758 ], #44 | |
| [ 0.908516, 0.136423 ], #45 | |
| [ 0.84751, 0.164077 ], #46 | |
| [ 0.769335, 0.165099 ], #47 | |
| [ 0.254149, 0.780233 ], #48 | |
| [ 0.726104, 0.780233 ], #54 | |
| ], dtype=np.float32) | |
| # landmarks_468_moving_parts_indexes = [0, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 37, 38, 39, 40, 41, 42, 43, 46, 52, 53, 54, 55, 56, 57, 58, 61, 62, 63, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 76, 77, 78, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 95, 96, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 117, 118, 124, 130, 132, 133, 135, 136, 138, 139, 140, 143, 144, 145, 146, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 168, 169, 170, 171, 172, 173, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 189, 190, 191, 192, 193, 194, 199, 200, 201, 202, 204, 208, 210, 211, 212, 213, 214, 215, 221, 222, 223, 224, 225, 226, 228, 229, 230, 231, 232, 233, 243, 244, 245, 246, 247, 249, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 267, 268, 269, 270, 271, 272, 273, 276, 282, 283, 284, 285, 286, 287, 288, 291, 292, 293, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 306, 307, 308, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 324, 325, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 346, 347, 353, 359, 361, 362, 364, 365, 367, 368, 369, 372, 373, 374, 375, 377, 378, 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 394, 395, 396, 397, 398, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 413, 414, 415, 416, 417, 418, 421, 422, 424, 428, 430, 431, 432, 433, 434, 435, 441, 442, 443, 444, 445, 446, 448, 449, 450, 451, 452, 453, 463, 464, 465, 466, 467] | |
| # uni_landmarks_468 = np.array( | |
| # [[ 0.49066195, 0.7133885 ], | |
| # [ 0.49042386, 0.52723485], | |
| # [ 0.49050152, 0.6244965 ], | |
| # [ 0.45844677, 0.39348277], | |
| # [ 0.4905825 , 0.49120593], | |
| # [ 0.49006602, 0.43998772], | |
| # [ 0.48907965, 0.26775706], | |
| # [ 0.11721139, 0.23243594], | |
| # [ 0.48957095, 0.11063451], | |
| # [ 0.48949632, 0.03535742], | |
| # [ 0.48905632, -0.25326234], | |
| # [ 0.4907858 , 0.73766613], | |
| # [ 0.49081355, 0.7606857 ], | |
| # [ 0.4908666 , 0.7839426 ], | |
| # [ 0.49079415, 0.78913504], | |
| # [ 0.4908271 , 0.80801845], | |
| # [ 0.49086872, 0.831855 ], | |
| # [ 0.49092326, 0.8631041 ], | |
| # [ 0.49104446, 0.94170016], | |
| # [ 0.49009967, 0.5546924 ], | |
| # [ 0.44398275, 0.5741402 ], | |
| # [-0.2106727 , 0.00861922], | |
| # [ 0.2523662 , 0.2832579 ], | |
| # [ 0.2042254 , 0.28945392], | |
| # [ 0.1552372 , 0.28322184], | |
| # [ 0.09056008, 0.24730967], | |
| # [ 0.30096018, 0.27277085], | |
| # [ 0.21548809, 0.16713436], | |
| # [ 0.2595488 , 0.17071684], | |
| # [ 0.16957955, 0.17298089], | |
| # [ 0.13164258, 0.18425746], | |
| # [ 0.043018 , 0.28581 ], | |
| # [ 0.30856833, 1.0507976 ], | |
| # [ 0.10015843, 0.22331452], | |
| # [-0.20773543, 0.26701325], | |
| # [-0.02414621, 0.25144747], | |
| # [ 0.23481508, 0.5045001 ], | |
| # [ 0.44063616, 0.7097012 ], | |
| # [ 0.4449884 , 0.762481 ], | |
| # [ 0.3840104 , 0.7218947 ], | |
| # [ 0.33943903, 0.73847425], | |
| # [ 0.40284824, 0.76374006], | |
| # [ 0.36457124, 0.76704985], | |
| # [ 0.26937196, 0.84716266], | |
| # [ 0.46683946, 0.5275276 ], | |
| # [ 0.4642676 , 0.49167544], | |
| # [ 0.06039319, 0.11509081], | |
| # [ 0.31504983, 0.36394927], | |
| # [ 0.3660137 , 0.52945083], | |
| # [ 0.3509634 , 0.50311893], | |
| # [ 0.09496811, 0.5005815 ], | |
| # [ 0.46075967, 0.4424029 ], | |
| # [ 0.20108324, 0.05883435], | |
| # [ 0.12877828, 0.07731954], | |
| # [-0.09675749, -0.09848522], | |
| # [ 0.39672711, 0.09345116], | |
| # [ 0.29908365, 0.18449144], | |
| # [ 0.23298171, 0.7922538 ], | |
| # [-0.27583498, 0.85219014], | |
| # [ 0.38898414, 0.5723152 ], | |
| # [ 0.41446668, 0.59347576], | |
| # [ 0.28167963, 0.7884952 ], | |
| # [ 0.30013445, 0.7875627 ], | |
| # [ 0.09448256, 0.03961415], | |
| # [ 0.3531811 , 0.5553779 ], | |
| # [ 0.2873921 , 0.05599196], | |
| # [ 0.28232294, 0.01076962], | |
| # [ 0.1903341 , -0.23029903], | |
| # [ 0.0108011 , -0.03099815], | |
| # [ 0.24915197, -0.10741784], | |
| # [ 0.01047484, 0.08868673], | |
| # [-0.08942058, 0.05201372], | |
| # [ 0.44268388, 0.7376863 ], | |
| # [ 0.39652622, 0.741894 ], | |
| # [ 0.35389552, 0.7514722 ], | |
| # [ 0.393559 , 0.5851372 ], | |
| # [ 0.2925385 , 0.7871472 ], | |
| # [ 0.31904542, 0.80939215], | |
| # [ 0.32005206, 0.787085 ], | |
| # [ 0.4195982 , 0.5444628 ], | |
| # [ 0.3688312 , 0.78418756], | |
| # [ 0.40608776, 0.7841225 ], | |
| # [ 0.4472093 , 0.78405076], | |
| # [ 0.43053833, 0.9379409 ], | |
| # [ 0.44192585, 0.8617842 ], | |
| # [ 0.44321233, 0.82923037], | |
| # [ 0.4432334 , 0.80578357], | |
| # [ 0.44304678, 0.78921837], | |
| # [ 0.36314115, 0.7893578 ], | |
| # [ 0.36057413, 0.8040033 ], | |
| # [ 0.35472178, 0.8187327 ], | |
| # [ 0.34614718, 0.83330894], | |
| # [ 0.2959003 , 0.69076014], | |
| # [-0.37090415, 0.5509728 ], | |
| # [ 0.4903264 , 0.5851119 ], | |
| # [ 0.3370172 , 0.78961957], | |
| # [ 0.33070365, 0.8010128 ], | |
| # [ 0.43397966, 0.6231119 ], | |
| # [ 0.35356513, 0.59569615], | |
| # [ 0.42509514, 0.6093918 ], | |
| # [ 0.2635329 , 0.39636588], | |
| # [ 0.19704658, 0.43663597], | |
| # [ 0.33384863, 0.52658314], | |
| # [ 0.03225203, -0.18047164], | |
| # [ 0.11854403, -0.08533629], | |
| # [ 0.18350407, 0.01215954], | |
| # [ 0.31292278, 0.8845064 ], | |
| # [ 0.3862302 , 0.02093028], | |
| # [ 0.36480215, -0.1098879 ], | |
| # [ 0.33342764, -0.2497105 ], | |
| # [ 0.11592615, 0.2646692 ], | |
| # [-0.00803981, 0.3294946 ], | |
| # [ 0.33535972, 0.26431814], | |
| # [ 0.05940344, 0.18766014], | |
| # [ 0.36188984, 0.33336782], | |
| # [ 0.39879864, 0.50869733], | |
| # [-0.07952328, 0.36885905], | |
| # [ 0.04230375, 0.36800843], | |
| # [ 0.11137532, 0.3864613 ], | |
| # [ 0.19386435, 0.37397826], | |
| # [ 0.25749052, 0.34993485], | |
| # [ 0.310977 , 0.3240539 ], | |
| # [ 0.44813582, 0.2762354 ], | |
| # [-0.06039021, 0.4864401 ], | |
| # [ 0.00945808, 0.17624807], | |
| # [ 0.4739895 , 0.55369264], | |
| # [ 0.32125092, 0.4170324 ], | |
| # [-0.36162117, 0.27013144], | |
| # [ 0.3592803 , 0.3023075 ], | |
| # [ 0.30784345, 0.529875 ], | |
| # [ 0.07601253, 0.22579695], | |
| # [ 0.3824061 , 0.47686696], | |
| # [-0.33810768, 0.70034444], | |
| # [ 0.34643772, 0.24336138], | |
| # [ 0.42429656, 0.45338264], | |
| # [ 0.02854156, 0.939626 ], | |
| # [-0.04352415, 1.0322431 ], | |
| # [-0.20510256, 0.51651907], | |
| # [-0.06969981, 0.8698207 ], | |
| # [-0.1581445 , 0.14948419], | |
| # [ 0.2889787 , 1.1224228 ], | |
| # [ 0.47446907, 0.58377683], | |
| # [ 0.2818322 , 0.4586393 ], | |
| # [-0.08708218, 0.2627534 ], | |
| # [ 0.16877942, 0.25976214], | |
| # [ 0.21234928, 0.267416 ], | |
| # [ 0.30676025, 0.81592965], | |
| # [-0.06259334, 0.6009466 ], | |
| # [ 0.36930662, 1.2302231 ], | |
| # [ 0.17070079, 1.149443 ], | |
| # [ 0.07714309, 1.0989524 ], | |
| # [ 0.48931465, -0.1052461 ], | |
| # [ 0.49159575, 1.2484183 ], | |
| # [ 0.2527582 , 0.26420003], | |
| # [ 0.30066028, 0.25829503], | |
| # [ 0.3310663 , 0.25034374], | |
| # [-0.05075949, 0.16421606], | |
| # [ 0.29250854, 0.19938153], | |
| # [ 0.2522571 , 0.18826446], | |
| # [ 0.21220936, 0.18724632], | |
| # [ 0.16866222, 0.19260857], | |
| # [ 0.13789575, 0.2011967 ], | |
| # [-0.29335994, 0.12383505], | |
| # [ 0.1379709 , 0.24424627], | |
| # [ 0.49057597, 0.65296 ], | |
| # [ 0.34147182, 0.663431 ], | |
| # [ 0.3941785 , 0.5603462 ], | |
| # [ 0.43007633, 0.6569765 ], | |
| # [ 0.48963526, 0.17996965], | |
| # [ 0.11681002, 1.0107123 ], | |
| # [ 0.19942053, 1.068824 ], | |
| # [ 0.38605705, 1.1563928 ], | |
| # [-0.16756529, 0.9615808 ], | |
| # [ 0.32817602, 0.21989337], | |
| # [ 0.41141313, 0.3578073 ], | |
| # [ 0.49127796, 1.1678538 ], | |
| # [ 0.27080515, 1.195178 ], | |
| # [-0.19307071, 0.6481067 ], | |
| # [ 0.399859 , 0.7892937 ], | |
| # [ 0.39875022, 0.80587196], | |
| # [ 0.39717573, 0.8256797 ], | |
| # [ 0.3931817 , 0.85224336], | |
| # [ 0.3670306 , 0.9161113 ], | |
| # [ 0.3256227 , 0.7724022 ], | |
| # [ 0.31488904, 0.76426226], | |
| # [ 0.3001029 , 0.7583232 ], | |
| # [ 0.2565659 , 0.73397243], | |
| # [ 0.0438394 , 0.6234349 ], | |
| # [ 0.40628996, 0.30296788], | |
| # [ 0.37707803, 0.19498621], | |
| # [ 0.34125936, 0.21069102], | |
| # [ 0.33733743, 0.7842425 ], | |
| # [ 0.00882016, 0.769232 ], | |
| # [ 0.4335431 , 0.1821002 ], | |
| # [ 0.33409703, 0.9826546 ], | |
| # [ 0.49011812, 0.3896104 ], | |
| # [ 0.45311242, 0.34152514], | |
| # [ 0.4899982 , 0.33611432], | |
| # [ 0.369907 , 0.43193236], | |
| # [ 0.49116373, 1.0932964 ], | |
| # [ 0.49107185, 1.0132186 ], | |
| # [ 0.41421878, 1.008873 ], | |
| # [ 0.21551576, 0.8785059 ], | |
| # [ 0.27587482, 0.57461077], | |
| # [ 0.2683325 , 0.9399872 ], | |
| # [ 0.17091931, 0.56899554], | |
| # [ 0.23741819, 0.6283017 ], | |
| # [ 0.12783033, 0.65916985], | |
| # [ 0.39875996, 1.0855893 ], | |
| # [ 0.33251646, 0.45881665], | |
| # [ 0.16138549, 0.93153137], | |
| # [ 0.23269826, 0.99740875], | |
| # [ 0.17994387, 0.8051213 ], | |
| # [-0.06026869, 0.7033027 ], | |
| # [ 0.10063827, 0.8241594 ], | |
| # [-0.15810522, 0.7679798 ], | |
| # [ 0.2014156 , 0.7000692 ], | |
| # [ 0.365875 , 0.3839739 ], | |
| # [ 0.4115726 , 0.5293855 ], | |
| # [ 0.378973 , 0.5476473 ], | |
| # [ 0.43235463, 0.49621448], | |
| # [ 0.3385827 , 0.15134089], | |
| # [ 0.27179635, 0.12940899], | |
| # [ 0.21341887, 0.12485553], | |
| # [ 0.15807948, 0.12881717], | |
| # [ 0.10610204, 0.14814937], | |
| # [ 0.03133116, 0.236169 ], | |
| # [-0.21341309, 0.38895622], | |
| # [ 0.07818349, 0.3101151 ], | |
| # [ 0.1318462 , 0.32528982], | |
| # [ 0.19485526, 0.32642388], | |
| # [ 0.25329807, 0.31256682], | |
| # [ 0.30569646, 0.29578218], | |
| # [ 0.34839994, 0.2842457 ], | |
| # [-0.3824783 , 0.41054142], | |
| # [ 0.37162504, 0.5664833 ], | |
| # [ 0.41687053, 0.40615496], | |
| # [ 0.4433516 , 0.5242282 ], | |
| # [ 0.44805393, 0.5562703 ], | |
| # [ 0.43453053, 0.5407472 ], | |
| # [ 0.37351128, 0.58924097], | |
| # [ 0.46121803, 0.55474806], | |
| # [ 0.45942986, 0.5810936 ], | |
| # [ 0.35955238, 0.24802393], | |
| # [ 0.38181108, 0.25985107], | |
| # [ 0.40143687, 0.26679716], | |
| # [ 0.11717269, 0.2102652 ], | |
| # [ 0.0940459 , 0.2016577 ], | |
| # [ 0.5217974 , 0.39331725], | |
| # [ 0.8625129 , 0.23113514], | |
| # [ 0.5369363 , 0.57397795], | |
| # [ 1.1896138 , 0.00617525], | |
| # [ 0.7275363 , 0.28242856], | |
| # [ 0.7756985 , 0.2884565 ], | |
| # [ 0.82466465, 0.28205347], | |
| # [ 0.88921595, 0.24591576], | |
| # [ 0.6788919 , 0.27210945], | |
| # [ 0.7640089 , 0.166177 ], | |
| # [ 0.7199609 , 0.16991326], | |
| # [ 0.8099376 , 0.17186326], | |
| # [ 0.8479136 , 0.18300733], | |
| # [ 0.9368992 , 0.28424102], | |
| # [ 0.67367214, 1.0503516 ], | |
| # [ 0.8795338 , 0.22195426], | |
| # [ 1.1875838 , 0.26458502], | |
| # [ 1.0039485 , 0.24965489], | |
| # [ 0.74551606, 0.50375396], | |
| # [ 0.54075617, 0.7095265 ], | |
| # [ 0.5365969 , 0.76231945], | |
| # [ 0.59742403, 0.7215222 ], | |
| # [ 0.6420548 , 0.7379461 ], | |
| # [ 0.5787324 , 0.7634331 ], | |
| # [ 0.617019 , 0.766611 ], | |
| # [ 0.71218634, 0.8469107 ], | |
| # [ 0.513503 , 0.52683127], | |
| # [ 0.5170686 , 0.49132976], | |
| # [ 0.91894245, 0.11362247], | |
| # [ 0.66487545, 0.36299667], | |
| # [ 0.61502695, 0.52894545], | |
| # [ 0.6296784 , 0.50242335], | |
| # [ 0.88566196, 0.49919614], | |
| # [ 0.5193738 , 0.4423927 ], | |
| # [ 0.7780587 , 0.05788935], | |
| # [ 0.8504331 , 0.07610969], | |
| # [ 1.0753254 , -0.1005309 ], | |
| # [ 0.5824533 , 0.09305263], | |
| # [ 0.6804744 , 0.18382579], | |
| # [ 0.7485537 , 0.79121745], | |
| # [ 1.2577202 , 0.8495136 ], | |
| # [ 0.59192824, 0.57196105], | |
| # [ 0.5665197 , 0.59321034], | |
| # [ 0.6999867 , 0.7877651 ], | |
| # [ 0.6814933 , 0.7868972 ], | |
| # [ 0.8846023 , 0.03829005], | |
| # [ 0.62761134, 0.5547819 ], | |
| # [ 0.6917209 , 0.05532694], | |
| # [ 0.6966465 , 0.01012804], | |
| # [ 0.7876697 , -0.2309872 ], | |
| # [ 0.9680314 , -0.03263693], | |
| # [ 0.7294528 , -0.1080169 ], | |
| # [ 0.96877015, 0.08704082], | |
| # [ 1.0685298 , 0.05000517], | |
| # [ 0.538806 , 0.7375185 ], | |
| # [ 0.5849781 , 0.7415651 ], | |
| # [ 0.62764204, 0.7509944 ], | |
| # [ 0.58739805, 0.5847989 ], | |
| # [ 0.68912315, 0.78645504], | |
| # [ 0.6626941 , 0.8087924 ], | |
| # [ 0.6616096 , 0.7864889 ], | |
| # [ 0.5612171 , 0.5442156 ], | |
| # [ 0.61282057, 0.7837617 ], | |
| # [ 0.575564 , 0.7838267 ], | |
| # [ 0.5344426 , 0.7838985 ], | |
| # [ 0.551505 , 0.93764293], | |
| # [ 0.5399973 , 0.8616131 ], | |
| # [ 0.53859717, 0.8290639 ], | |
| # [ 0.5384943 , 0.8056173 ], | |
| # [ 0.53862303, 0.78905153], | |
| # [ 0.6185288 , 0.78891206], | |
| # [ 0.62114686, 0.8035485 ], | |
| # [ 0.62705064, 0.81825733], | |
| # [ 0.635676 , 0.8328036 ], | |
| # [ 0.6854969 , 0.69067734], | |
| # [ 1.3517375 , 0.54796624], | |
| # [ 0.64465326, 0.78908265], | |
| # [ 0.6510032 , 0.8004538 ], | |
| # [ 0.5471015 , 0.62291807], | |
| # [ 0.62742317, 0.59512955], | |
| # [ 0.55593795, 0.6091671 ], | |
| # [ 0.7161671 , 0.39546603], | |
| # [ 0.7836529 , 0.435396 ], | |
| # [ 0.64694774, 0.5258542 ], | |
| # [ 0.94603044, -0.1820665 ], | |
| # [ 0.86011904, -0.08652072], | |
| # [ 0.79549086, 0.01118712], | |
| # [ 0.66893554, 0.8840338 ], | |
| # [ 0.59274685, 0.02056277], | |
| # [ 0.613851 , -0.11025709], | |
| # [ 0.64526045, -0.25000137], | |
| # [ 0.8639107 , 0.26336375], | |
| # [ 0.9881146 , 0.3277454 ], | |
| # [ 0.6445285 , 0.26371115], | |
| # [ 0.92017305, 0.18616839], | |
| # [ 0.61790556, 0.3323734 ], | |
| # [ 0.58225924, 0.5077285 ], | |
| # [ 1.0597262 , 0.36687428], | |
| # [ 0.93791103, 0.36642405], | |
| # [ 0.86892897, 0.38505408], | |
| # [ 0.78624976, 0.37287512], | |
| # [ 0.7223912 , 0.34902957], | |
| # [ 0.6687594 , 0.32310694], | |
| # [ 0.5315497 , 0.2757726 ], | |
| # [ 1.0409807 , 0.48452145], | |
| # [ 0.9700836 , 0.17458573], | |
| # [ 0.5065989 , 0.55419755], | |
| # [ 0.6590531 , 0.41624966], | |
| # [ 1.3414742 , 0.26715896], | |
| # [ 0.62023264, 0.30108824], | |
| # [ 0.67289865, 0.5290446 ], | |
| # [ 0.9036883 , 0.22435239], | |
| # [ 0.59769833, 0.47659585], | |
| # [ 1.3194624 , 0.6974514 ], | |
| # [ 0.63339525, 0.24286939], | |
| # [ 0.5571053 , 0.45250946], | |
| # [ 0.9535533 , 0.9380257 ], | |
| # [ 1.0260391 , 1.0303764 ], | |
| # [ 1.1858007 , 0.51410204], | |
| # [ 1.0515786 , 0.867869 ], | |
| # [ 1.1375865 , 0.14722979], | |
| # [ 0.6935665 , 1.1218798 ], | |
| # [ 0.5063422 , 0.58382744], | |
| # [ 0.69926125, 0.45745537], | |
| # [ 1.0669235 , 0.26074636], | |
| # [ 0.8110406 , 0.25864118], | |
| # [ 0.7674977 , 0.26644707], | |
| # [ 0.67500204, 0.81528693], | |
| # [ 1.0435516 , 0.5990178 ], | |
| # [ 0.6121316 , 1.2306852 ], | |
| # [ 0.81222653, 1.1483234 ], | |
| # [ 0.9056057 , 1.0975065 ], | |
| # [ 0.7270778 , 0.26337218], | |
| # [ 0.6791554 , 0.25763443], | |
| # [ 0.6487802 , 0.24975733], | |
| # [ 1.0302606 , 0.16233999], | |
| # [ 0.68710136, 0.19869283], | |
| # [ 0.72731376, 0.18743533], | |
| # [ 0.7673578 , 0.1862774 ], | |
| # [ 0.81092334, 0.1914876 ], | |
| # [ 0.84171957, 0.1999683 ], | |
| # [ 1.2727026 , 0.12110176], | |
| # [ 0.8417947 , 0.24301787], | |
| # [ 0.63978463, 0.6627527 ], | |
| # [ 0.5866921 , 0.5600102 ], | |
| # [ 0.5511283 , 0.6567636 ], | |
| # [ 0.8655194 , 1.009457 ], | |
| # [ 0.78306264, 1.0678959 ], | |
| # [ 0.59620714, 1.1564037 ], | |
| # [ 1.149833 , 0.9592815 ], | |
| # [ 0.65151644, 0.21932903], | |
| # [ 0.56865776, 0.3571483 ], | |
| # [ 0.71228063, 1.1944076 ], | |
| # [ 1.1742088 , 0.6457327 ], | |
| # [ 0.5818109 , 0.78897613], | |
| # [ 0.5829775 , 0.80555046], | |
| # [ 0.5846211 , 0.82535255], | |
| # [ 0.5887078 , 0.8519021 ], | |
| # [ 0.6150045 , 0.916079 ], | |
| # [ 0.65597004, 0.771831 ], | |
| # [ 0.66669285, 0.7636482 ], | |
| # [ 0.6814582 , 0.7576576 ], | |
| # [ 0.7245435 , 0.73241323], | |
| # [ 0.9371713 , 0.62184393], | |
| # [ 0.5736738 , 0.30186948], | |
| # [ 0.60240346, 0.19448838], | |
| # [ 0.6383993 , 0.21017241], | |
| # [ 0.64431435, 0.7837067 ], | |
| # [ 0.9726586 , 0.7675604 ], | |
| # [ 0.54576766, 0.18157108], | |
| # [ 0.6477745 , 0.98230904], | |
| # [ 0.5269076 , 0.34123868], | |
| # [ 0.61068684, 0.43131724], | |
| # [ 0.56792 , 1.0087004 ], | |
| # [ 0.7662271 , 0.8776794 ], | |
| # [ 0.7048996 , 0.57387614], | |
| # [ 0.7136024 , 0.9394351 ], | |
| # [ 0.8097781 , 0.56784695], | |
| # [ 0.7435453 , 0.62753886], | |
| # [ 0.85328954, 0.6578133 ], | |
| # [ 0.5835228 , 1.0854707 ], | |
| # [ 0.64810187, 0.45811343], | |
| # [ 0.82059515, 0.9304676 ], | |
| # [ 0.7494546 , 0.9966611 ], | |
| # [ 0.8015866 , 0.80400985], | |
| # [ 1.0415541 , 0.70138854], | |
| # [ 0.8809724 , 0.8228132 ], | |
| # [ 1.1396528 , 0.7657218 ], | |
| # [ 0.7798614 , 0.69881856], | |
| # [ 0.6143189 , 0.383193 ], | |
| # [ 0.56934875, 0.52867246], | |
| # [ 0.60162777, 0.54706186], | |
| # [ 0.5470082 , 0.4963955 ], | |
| # [ 0.6408297 , 0.15073723], | |
| # [ 0.7075675 , 0.12865019], | |
| # [ 0.76593757, 0.12391254], | |
| # [ 0.8212976 , 0.12768434], | |
| # [ 0.87334216, 0.14682971], | |
| # [ 0.948411 , 0.23457018], | |
| # [ 1.1936799 , 0.38651106], | |
| # [ 0.90181875, 0.30865455], | |
| # [ 0.84818983, 0.3240165 ], | |
| # [ 0.7851249 , 0.32537246], | |
| # [ 0.72658616, 0.3116911 ], | |
| # [ 0.6740513 , 0.2949461 ], | |
| # [ 0.63111407, 0.28325075], | |
| # [ 1.362823 , 0.4074953 ], | |
| # [ 0.60951644, 0.5658945 ], | |
| # [ 0.5634702 , 0.4055624 ], | |
| # [ 0.5374476 , 0.5247268 ], | |
| # [ 0.53280455, 0.5561224 ], | |
| # [ 0.5462737 , 0.5405522 ], | |
| # [ 0.6075077 , 0.58877414], | |
| # [ 0.51933056, 0.55477065], | |
| # [ 0.52143395, 0.58103496], | |
| # [ 0.62030756, 0.24758299], | |
| # [ 0.59746987, 0.2574137 ], | |
| # [ 0.5780933 , 0.2652785 ], | |
| # [ 0.8624742 , 0.2089644 ], | |
| # [ 0.8855709 , 0.20027623]], dtype=np.float32) | |
| # mesh_33 = np.arange(468) | |
| # mask = np.ones(len(mesh_33), dtype=bool) | |
| # mask[landmarks_468_moving_parts_indexes]=False | |
| # mesh_33=mesh_33[mask,...] | |
| # landmarks_2D_new_mesh=uni_landmarks_468[mask,...] | |
| # mouth_center_landmarks_2D = np.array([ | |
| # [-4.4202591e-07, 4.4916576e-01], # 48 | |
| # [1.8399176e-01, 3.7537053e-01], # 49 | |
| # [3.7018123e-01, 3.3719531e-01], # 50 | |
| # [5.0000089e-01, 3.6938059e-01], # 51 | |
| # [6.2981832e-01, 3.3719531e-01], # 52 | |
| # [8.1600773e-01, 3.7537053e-01], # 53 | |
| # [1.0000000e+00, 4.4916576e-01], # 54 | |
| # [8.2213330e-01, 6.2836081e-01], # 55 | |
| # [6.4110327e-01, 7.0757812e-01], # 56 | |
| # [5.0000089e-01, 7.2259867e-01], # 57 | |
| # [3.5889623e-01, 7.0757812e-01], # 58 | |
| # [1.7786618e-01, 6.2836081e-01], # 59 | |
| # [7.6765373e-02, 4.5882553e-01], # 60 | |
| # [3.6856663e-01, 4.4601500e-01], # 61 | |
| # [5.0000089e-01, 4.5999300e-01], # 62 | |
| # [6.3143289e-01, 4.4601500e-01], # 63 | |
| # [9.2323411e-01, 4.5882553e-01], # 64 | |
| # [6.3399029e-01, 5.4228687e-01], # 65 | |
| # [5.0000089e-01, 5.5843467e-01], # 66 | |
| # [3.6601129e-01, 5.4228687e-01] # 67 | |
| # ], dtype=np.float32) | |
| # 68 point landmark definitions | |
| landmarks_68_pt = {"mouth": (48, 68), | |
| "right_eyebrow": (17, 22), | |
| "left_eyebrow": (22, 27), | |
| "right_eye": (36, 42), | |
| "left_eye": (42, 48), | |
| "nose": (27, 36), # missed one point | |
| "jaw": (0, 17)} | |
| landmarks_68_3D = np.array([ | |
| [-73.393523, -29.801432, 47.667532], # 00 | |
| [-72.775014, -10.949766, 45.909403], # 01 | |
| [-70.533638, 7.929818, 44.842580], # 02 | |
| [-66.850058, 26.074280, 43.141114], # 03 | |
| [-59.790187, 42.564390, 38.635298], # 04 | |
| [-48.368973, 56.481080, 30.750622], # 05 | |
| [-34.121101, 67.246992, 18.456453], # 06 | |
| [-17.875411, 75.056892, 3.609035], # 07 | |
| [0.098749, 77.061286, -0.881698], # 08 | |
| [17.477031, 74.758448, 5.181201], # 09 | |
| [32.648966, 66.929021, 19.176563], # 10 | |
| [46.372358, 56.311389, 30.770570], # 11 | |
| [57.343480, 42.419126, 37.628629], # 12 | |
| [64.388482, 25.455880, 40.886309], # 13 | |
| [68.212038, 6.990805, 42.281449], # 14 | |
| [70.486405, -11.666193, 44.142567], # 15 | |
| [71.375822, -30.365191, 47.140426], # 16 | |
| [-61.119406, -49.361602, 14.254422], # 17 | |
| [-51.287588, -58.769795, 7.268147], # 18 | |
| [-37.804800, -61.996155, 0.442051], # 19 | |
| [-24.022754, -61.033399, -6.606501], # 20 | |
| [-11.635713, -56.686759, -11.967398], # 21 | |
| [12.056636, -57.391033, -12.051204], # 22 | |
| [25.106256, -61.902186, -7.315098], # 23 | |
| [38.338588, -62.777713, -1.022953], # 24 | |
| [51.191007, -59.302347, 5.349435], # 25 | |
| [60.053851, -50.190255, 11.615746], # 26 | |
| [0.653940, -42.193790, -13.380835], # 27 | |
| [0.804809, -30.993721, -21.150853], # 28 | |
| [0.992204, -19.944596, -29.284036], # 29 | |
| [1.226783, -8.414541, -36.948060], # 00 | |
| [-14.772472, 2.598255, -20.132003], # 01 | |
| [-7.180239, 4.751589, -23.536684], # 02 | |
| [0.555920, 6.562900, -25.944448], # 03 | |
| [8.272499, 4.661005, -23.695741], # 04 | |
| [15.214351, 2.643046, -20.858157], # 05 | |
| [-46.047290, -37.471411, 7.037989], # 06 | |
| [-37.674688, -42.730510, 3.021217], # 07 | |
| [-27.883856, -42.711517, 1.353629], # 08 | |
| [-19.648268, -36.754742, -0.111088], # 09 | |
| [-28.272965, -35.134493, -0.147273], # 10 | |
| [-38.082418, -34.919043, 1.476612], # 11 | |
| [19.265868, -37.032306, -0.665746], # 12 | |
| [27.894191, -43.342445, 0.247660], # 13 | |
| [37.437529, -43.110822, 1.696435], # 14 | |
| [45.170805, -38.086515, 4.894163], # 15 | |
| [38.196454, -35.532024, 0.282961], # 16 | |
| [28.764989, -35.484289, -1.172675], # 17 | |
| [-28.916267, 28.612716, -2.240310], # 18 | |
| [-17.533194, 22.172187, -15.934335], # 19 | |
| [-6.684590, 19.029051, -22.611355], # 20 | |
| [0.381001, 20.721118, -23.748437], # 21 | |
| [8.375443, 19.035460, -22.721995], # 22 | |
| [18.876618, 22.394109, -15.610679], # 23 | |
| [28.794412, 28.079924, -3.217393], # 24 | |
| [19.057574, 36.298248, -14.987997], # 25 | |
| [8.956375, 39.634575, -22.554245], # 26 | |
| [0.381549, 40.395647, -23.591626], # 27 | |
| [-7.428895, 39.836405, -22.406106], # 28 | |
| [-18.160634, 36.677899, -15.121907], # 29 | |
| [-24.377490, 28.677771, -4.785684], # 30 | |
| [-6.897633, 25.475976, -20.893742], # 31 | |
| [0.340663, 26.014269, -22.220479], # 32 | |
| [8.444722, 25.326198, -21.025520], # 33 | |
| [24.474473, 28.323008, -5.712776], # 34 | |
| [8.449166, 30.596216, -20.671489], # 35 | |
| [0.205322, 31.408738, -21.903670], # 36 | |
| [-7.198266, 30.844876, -20.328022] # 37 | |
| ], dtype=np.float32) | |
| FaceType_to_padding_remove_align = { | |
| FaceType.HALF: (0.0, False), | |
| FaceType.MID_FULL: (0.0675, False), | |
| FaceType.FULL: (0.2109375, False), | |
| FaceType.FULL_NO_ALIGN: (0.2109375, True), | |
| FaceType.WHOLE_FACE: (0.40, False), | |
| FaceType.HEAD: (0.70, False), | |
| FaceType.HEAD_NO_ALIGN: (0.70, True), | |
| } | |
| def convert_98_to_68(lmrks): | |
| # jaw | |
| result = [lmrks[0]] | |
| for i in range(2, 16, 2): | |
| result += [(lmrks[i] + (lmrks[i - 1] + lmrks[i + 1]) / 2) / 2] | |
| result += [lmrks[16]] | |
| for i in range(18, 32, 2): | |
| result += [(lmrks[i] + (lmrks[i - 1] + lmrks[i + 1]) / 2) / 2] | |
| result += [lmrks[32]] | |
| # eyebrows averaging | |
| result += [lmrks[33], | |
| (lmrks[34] + lmrks[41]) / 2, | |
| (lmrks[35] + lmrks[40]) / 2, | |
| (lmrks[36] + lmrks[39]) / 2, | |
| (lmrks[37] + lmrks[38]) / 2, | |
| ] | |
| result += [(lmrks[42] + lmrks[50]) / 2, | |
| (lmrks[43] + lmrks[49]) / 2, | |
| (lmrks[44] + lmrks[48]) / 2, | |
| (lmrks[45] + lmrks[47]) / 2, | |
| lmrks[46] | |
| ] | |
| # nose | |
| result += list(lmrks[51:60]) | |
| # left eye (from our view) | |
| result += [lmrks[60], | |
| lmrks[61], | |
| lmrks[63], | |
| lmrks[64], | |
| lmrks[65], | |
| lmrks[67]] | |
| # right eye | |
| result += [lmrks[68], | |
| lmrks[69], | |
| lmrks[71], | |
| lmrks[72], | |
| lmrks[73], | |
| lmrks[75]] | |
| # mouth | |
| result += list(lmrks[76:96]) | |
| return np.concatenate(result).reshape((68, 2)) | |
| def transform_points(points, mat, invert=False): | |
| if invert: | |
| mat = cv2.invertAffineTransform(mat) | |
| points = np.expand_dims(points, axis=1) | |
| points = cv2.transform(points, mat, points.shape) | |
| points = np.squeeze(points) | |
| return points | |
| def get_transform_mat(image_landmarks, output_size, face_type, scale=1.0): | |
| if not isinstance(image_landmarks, np.ndarray): | |
| image_landmarks = np.array(image_landmarks) | |
| # estimate landmarks transform from global space to local aligned space with bounds [0..1] | |
| mat = umeyama(np.concatenate([image_landmarks[17:49], image_landmarks[54:55]]), landmarks_2D_new, True)[0:2] | |
| # get corner points in global space | |
| g_p = transform_points(np.float32([(0, 0), (1, 0), (1, 1), (0, 1), (0.5, 0.5)]), mat, True) | |
| g_c = g_p[4] | |
| # calc diagonal vectors between corners in global space | |
| tb_diag_vec = (g_p[2] - g_p[0]).astype(np.float32) | |
| tb_diag_vec /= npla.norm(tb_diag_vec) | |
| bt_diag_vec = (g_p[1] - g_p[3]).astype(np.float32) | |
| bt_diag_vec /= npla.norm(bt_diag_vec) | |
| # calc modifier of diagonal vectors for scale and padding value | |
| # print(face_type) | |
| padding, remove_align = FaceType_to_padding_remove_align.get(face_type, 0.0) | |
| mod = (1.0 / scale) * (npla.norm(g_p[0] - g_p[2]) * (padding * np.sqrt(2.0) + 0.5)) | |
| if face_type == FaceType.WHOLE_FACE: | |
| # adjust vertical offset for WHOLE_FACE, 7% below in order to cover more forehead | |
| vec = (g_p[0] - g_p[3]).astype(np.float32) | |
| vec_len = npla.norm(vec) | |
| vec /= vec_len | |
| g_c += vec * vec_len * 0.07 | |
| # calc 3 points in global space to estimate 2d affine transform | |
| if not remove_align: | |
| l_t = np.array([g_c - tb_diag_vec * mod, | |
| g_c + bt_diag_vec * mod, | |
| g_c + tb_diag_vec * mod]) | |
| else: | |
| # remove_align - face will be centered in the frame but not aligned | |
| l_t = np.array([g_c - tb_diag_vec * mod, | |
| g_c + bt_diag_vec * mod, | |
| g_c + tb_diag_vec * mod, | |
| g_c - bt_diag_vec * mod, | |
| ]) | |
| # get area of face square in global space | |
| area = mathlib.polygon_area(l_t[:, 0], l_t[:, 1]) | |
| # calc side of square | |
| side = np.float32(math.sqrt(area) / 2) | |
| # calc 3 points with unrotated square | |
| l_t = np.array([g_c + [-side, -side], | |
| g_c + [side, -side], | |
| g_c + [side, side]]) | |
| # calc affine transform from 3 global space points to 3 local space points size of 'output_size' | |
| pts2 = np.float32(((0, 0), (output_size, 0), (output_size, output_size))) | |
| mat = cv2.getAffineTransform(l_t, pts2) | |
| return mat | |
| def get_rect_from_landmarks(image_landmarks): | |
| mat = get_transform_mat(image_landmarks, 256, FaceType.FULL_NO_ALIGN) | |
| g_p = transform_points(np.float32([(0, 0), (255, 255)]), mat, True) | |
| (l, t, r, b) = g_p[0][0], g_p[0][1], g_p[1][0], g_p[1][1] | |
| return (l, t, r, b) | |
| def get_transform_mat_all(image_landmarks,uni_landmarks,output_size,scale=1,gcx=-0.02,gcy=0.15,face_type=FaceType.WHOLE_FACE): | |
| if not isinstance(image_landmarks, np.ndarray): | |
| image_landmarks = np.array (image_landmarks) | |
| # estimate landmarks transform from global space to local aligned space with bounds [0..1] | |
| mat = umeyama(image_landmarks, uni_landmarks, True)[0:2] | |
| # get corner points in global space | |
| g_p = transform_points ( np.float32([(0,0),(1,0),(1,1),(0,1),(0.5,0.5) ]) , mat, True) | |
| g_c = g_p[4] | |
| # calc diagonal vectors between corners in global space | |
| tb_diag_vec = (g_p[2] - g_p[0]).astype(np.float32) | |
| tb_diag_vec /= npla.norm(tb_diag_vec) | |
| bt_diag_vec = (g_p[1] - g_p[3]).astype(np.float32) | |
| bt_diag_vec /= npla.norm(bt_diag_vec) | |
| # calc modifier of diagonal vectors for scale and padding value | |
| padding, remove_align = FaceType_to_padding_remove_align.get(face_type, 0.0) | |
| mod = (1.0 / scale) * (npla.norm(g_p[0] - g_p[2]) * (padding * np.sqrt(2.0) + 0.5)) | |
| vec = (g_p[0]-g_p[3]).astype(np.float32) | |
| vec_len = npla.norm(vec) | |
| vec /= vec_len | |
| g_c += vec*vec_len*[gcx,gcy] | |
| # calc 3 points in global space to estimate 2d affine transform | |
| if not remove_align: | |
| l_t = np.array([g_c - tb_diag_vec * mod, | |
| g_c + bt_diag_vec * mod, | |
| g_c + tb_diag_vec * mod]) | |
| else: | |
| # remove_align - face will be centered in the frame but not aligned | |
| l_t = np.array([g_c - tb_diag_vec * mod, | |
| g_c + bt_diag_vec * mod, | |
| g_c + tb_diag_vec * mod, | |
| g_c - bt_diag_vec * mod, | |
| ]) | |
| # get area of face square in global space | |
| area = mathlib.polygon_area(l_t[:, 0], l_t[:, 1]) | |
| # calc side of square | |
| side = np.float32(math.sqrt(area) / 2) | |
| # calc 3 points with unrotated square | |
| l_t = np.array([g_c + [-side, -side], | |
| g_c + [side, -side], | |
| g_c + [side, side]]) | |
| # calc affine transform from 3 global space points to 3 local space points size of 'output_size' | |
| pts2 = np.float32(((0, 0), (output_size, 0), (output_size, output_size))) | |
| mat = cv2.getAffineTransform(l_t, pts2) | |
| return mat | |
| def expand_eyebrows(lmrks, eyebrows_expand_mod=1.0): | |
| if len(lmrks) != 68: | |
| raise Exception('works only with 68 landmarks') | |
| lmrks = np.array(lmrks.copy(), dtype=np.int) | |
| # #nose | |
| ml_pnt = (lmrks[36] + lmrks[0]) // 2 | |
| mr_pnt = (lmrks[16] + lmrks[45]) // 2 | |
| # mid points between the mid points and eye | |
| ql_pnt = (lmrks[36] + ml_pnt) // 2 | |
| qr_pnt = (lmrks[45] + mr_pnt) // 2 | |
| # Top of the eye arrays | |
| bot_l = np.array((ql_pnt, lmrks[36], lmrks[37], lmrks[38], lmrks[39])) | |
| bot_r = np.array((lmrks[42], lmrks[43], lmrks[44], lmrks[45], qr_pnt)) | |
| # Eyebrow arrays | |
| top_l = lmrks[17:22] | |
| top_r = lmrks[22:27] | |
| # Adjust eyebrow arrays | |
| lmrks[17:22] = top_l + eyebrows_expand_mod * 0.5 * (top_l - bot_l) | |
| lmrks[22:27] = top_r + eyebrows_expand_mod * 0.5 * (top_r - bot_r) | |
| return lmrks | |
| def get_image_hull_mask(image_shape, image_landmarks, eyebrows_expand_mod=1.0): | |
| hull_mask = np.zeros(image_shape[0:2] + (1,), dtype=np.float32) | |
| lmrks = expand_eyebrows(image_landmarks, eyebrows_expand_mod) | |
| r_jaw = (lmrks[0:9], lmrks[17:18]) | |
| l_jaw = (lmrks[8:17], lmrks[26:27]) | |
| r_cheek = (lmrks[17:20], lmrks[8:9]) | |
| l_cheek = (lmrks[24:27], lmrks[8:9]) | |
| nose_ridge = (lmrks[19:25], lmrks[8:9],) | |
| r_eye = (lmrks[17:22], lmrks[27:28], lmrks[31:36], lmrks[8:9]) | |
| l_eye = (lmrks[22:27], lmrks[27:28], lmrks[31:36], lmrks[8:9]) | |
| nose = (lmrks[27:31], lmrks[31:36]) | |
| parts = [r_jaw, l_jaw, r_cheek, l_cheek, nose_ridge, r_eye, l_eye, nose] | |
| for item in parts: | |
| merged = np.concatenate(item) | |
| cv2.fillConvexPoly(hull_mask, cv2.convexHull(merged), (1,)) | |
| return hull_mask | |
| def get_image_eye_mask(image_shape, image_landmarks): | |
| if len(image_landmarks) != 68: | |
| raise Exception('get_image_eye_mask works only with 68 landmarks') | |
| h, w, c = image_shape | |
| hull_mask = np.zeros((h, w, 1), dtype=np.float32) | |
| image_landmarks = image_landmarks.astype(np.int) | |
| cv2.fillConvexPoly(hull_mask, cv2.convexHull(image_landmarks[36:42]), (1,)) | |
| cv2.fillConvexPoly(hull_mask, cv2.convexHull(image_landmarks[42:48]), (1,)) | |
| dilate = h // 32 | |
| hull_mask = cv2.dilate(hull_mask, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (dilate, dilate)), iterations=1) | |
| blur = h // 16 | |
| blur = blur + (1 - blur % 2) | |
| hull_mask = cv2.GaussianBlur(hull_mask, (blur, blur), 0) | |
| hull_mask = hull_mask[..., None] | |
| return hull_mask | |
| def get_image_mouth_mask(image_shape, image_landmarks): | |
| if len(image_landmarks) != 68: | |
| raise Exception('get_image_eye_mask works only with 68 landmarks') | |
| h, w, c = image_shape | |
| hull_mask = np.zeros((h, w, 1), dtype=np.float32) | |
| image_landmarks = image_landmarks.astype(np.int) | |
| cv2.fillConvexPoly(hull_mask, cv2.convexHull(image_landmarks[60:]), (1,)) | |
| dilate = h // 32 | |
| hull_mask = cv2.dilate(hull_mask, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (dilate, dilate)), iterations=1) | |
| blur = h // 16 | |
| blur = blur + (1 - blur % 2) | |
| hull_mask = cv2.GaussianBlur(hull_mask, (blur, blur), 0) | |
| hull_mask = hull_mask[..., None] | |
| return hull_mask | |
| def alpha_to_color(img_alpha, color): | |
| if len(img_alpha.shape) == 2: | |
| img_alpha = img_alpha[..., None] | |
| h, w, c = img_alpha.shape | |
| result = np.zeros((h, w, len(color)), dtype=np.float32) | |
| result[:, :] = color | |
| return result * img_alpha | |
| def get_cmask(image_shape, lmrks, eyebrows_expand_mod=1.0): | |
| h, w, c = image_shape | |
| hull = get_image_hull_mask(image_shape, lmrks, eyebrows_expand_mod) | |
| result = np.zeros((h, w, 3), dtype=np.float32) | |
| def process(w, h, data): | |
| d = {} | |
| cur_lc = 0 | |
| all_lines = [] | |
| for s, pts_loop_ar in data: | |
| lines = [] | |
| for pts, loop in pts_loop_ar: | |
| pts_len = len(pts) | |
| lines.append([[pts[i], pts[(i + 1) % pts_len]] for i in range(pts_len - (0 if loop else 1))]) | |
| lines = np.concatenate(lines) | |
| lc = lines.shape[0] | |
| all_lines.append(lines) | |
| d[s] = cur_lc, cur_lc + lc | |
| cur_lc += lc | |
| all_lines = np.concatenate(all_lines, 0) | |
| # calculate signed distance for all points and lines | |
| line_count = all_lines.shape[0] | |
| pts_count = w * h | |
| all_lines = np.repeat(all_lines[None, ...], pts_count, axis=0).reshape((pts_count * line_count, 2, 2)) | |
| pts = np.empty((h, w, line_count, 2), dtype=np.float32) | |
| pts[..., 1] = np.arange(h)[:, None, None] | |
| pts[..., 0] = np.arange(w)[:, None] | |
| pts = pts.reshape((h * w * line_count, -1)) | |
| a = all_lines[:, 0, :] | |
| b = all_lines[:, 1, :] | |
| pa = pts - a | |
| ba = b - a | |
| ph = np.clip(np.einsum('ij,ij->i', pa, ba) / np.einsum('ij,ij->i', ba, ba), 0, 1) | |
| dists = npla.norm(pa - ba * ph[..., None], axis=1).reshape((h, w, line_count)) | |
| def get_dists(name, thickness=0): | |
| s, e = d[name] | |
| result = dists[..., s:e] | |
| if thickness != 0: | |
| result = np.abs(result) - thickness | |
| return np.min(result, axis=-1) | |
| return get_dists | |
| l_eye = lmrks[42:48] | |
| r_eye = lmrks[36:42] | |
| l_brow = lmrks[22:27] | |
| r_brow = lmrks[17:22] | |
| mouth = lmrks[48:60] | |
| up_nose = np.concatenate((lmrks[27:31], lmrks[33:34])) | |
| down_nose = lmrks[31:36] | |
| nose = np.concatenate((up_nose, down_nose)) | |
| gdf = process(w, h, | |
| ( | |
| ('eyes', ((l_eye, True), (r_eye, True))), | |
| ('brows', ((l_brow, False), (r_brow, False))), | |
| ('up_nose', ((up_nose, False),)), | |
| ('down_nose', ((down_nose, False),)), | |
| ('mouth', ((mouth, True),)), | |
| ) | |
| ) | |
| eyes_fall_dist = w // 32 | |
| eyes_thickness = max(w // 64, 1) | |
| brows_fall_dist = w // 32 | |
| brows_thickness = max(w // 256, 1) | |
| nose_fall_dist = w / 12 | |
| nose_thickness = max(w // 96, 1) | |
| mouth_fall_dist = w // 32 | |
| mouth_thickness = max(w // 64, 1) | |
| eyes_mask = gdf('eyes', eyes_thickness) | |
| eyes_mask = 1 - np.clip(eyes_mask / eyes_fall_dist, 0, 1) | |
| # eyes_mask = np.clip ( 1- ( np.sqrt( np.maximum(eyes_mask,0) ) / eyes_fall_dist ), 0, 1) | |
| # eyes_mask = np.clip ( 1- ( np.cbrt( np.maximum(eyes_mask,0) ) / eyes_fall_dist ), 0, 1) | |
| brows_mask = gdf('brows', brows_thickness) | |
| brows_mask = 1 - np.clip(brows_mask / brows_fall_dist, 0, 1) | |
| # brows_mask = np.clip ( 1- ( np.sqrt( np.maximum(brows_mask,0) ) / brows_fall_dist ), 0, 1) | |
| mouth_mask = gdf('mouth', mouth_thickness) | |
| mouth_mask = 1 - np.clip(mouth_mask / mouth_fall_dist, 0, 1) | |
| # mouth_mask = np.clip ( 1- ( np.sqrt( np.maximum(mouth_mask,0) ) / mouth_fall_dist ), 0, 1) | |
| def blend(a, b, k): | |
| x = np.clip(0.5 + 0.5 * (b - a) / k, 0.0, 1.0) | |
| return (a - b) * x + b - k * x * (1.0 - x) | |
| # nose_mask = (a-b)*x+b - k*x*(1.0-x) | |
| # nose_mask = np.minimum (up_nose_mask , down_nose_mask ) | |
| # nose_mask = 1-np.clip( nose_mask / nose_fall_dist, 0, 1) | |
| nose_mask = blend(gdf('up_nose', nose_thickness), gdf('down_nose', nose_thickness), nose_thickness * 3) | |
| nose_mask = 1 - np.clip(nose_mask / nose_fall_dist, 0, 1) | |
| up_nose_mask = gdf('up_nose', nose_thickness) | |
| up_nose_mask = 1 - np.clip(up_nose_mask / nose_fall_dist, 0, 1) | |
| # up_nose_mask = np.clip ( 1- ( np.cbrt( np.maximum(up_nose_mask,0) ) / nose_fall_dist ), 0, 1) | |
| down_nose_mask = gdf('down_nose', nose_thickness) | |
| down_nose_mask = 1 - np.clip(down_nose_mask / nose_fall_dist, 0, 1) | |
| # down_nose_mask = np.clip ( 1- ( np.cbrt( np.maximum(down_nose_mask,0) ) / nose_fall_dist ), 0, 1) | |
| # nose_mask = np.clip( up_nose_mask + down_nose_mask, 0, 1 ) | |
| # nose_mask /= np.max(nose_mask) | |
| # nose_mask = np.maximum (up_nose_mask , down_nose_mask ) | |
| # nose_mask = down_nose_mask | |
| # nose_mask = np.zeros_like(nose_mask) | |
| eyes_mask = eyes_mask * (1 - mouth_mask) | |
| nose_mask = nose_mask * (1 - eyes_mask) | |
| hull_mask = hull[..., 0].copy() | |
| hull_mask = hull_mask * (1 - eyes_mask) * (1 - brows_mask) * (1 - nose_mask) * (1 - mouth_mask) | |
| # eyes_mask = eyes_mask * (1-nose_mask) | |
| mouth_mask = mouth_mask * (1 - nose_mask) | |
| brows_mask = brows_mask * (1 - nose_mask) * (1 - eyes_mask) | |
| hull_mask = alpha_to_color(hull_mask, (0, 1, 0)) | |
| eyes_mask = alpha_to_color(eyes_mask, (1, 0, 0)) | |
| brows_mask = alpha_to_color(brows_mask, (0, 0, 1)) | |
| nose_mask = alpha_to_color(nose_mask, (0, 1, 1)) | |
| mouth_mask = alpha_to_color(mouth_mask, (0, 0, 1)) | |
| # nose_mask = np.maximum( up_nose_mask, down_nose_mask ) | |
| result = hull_mask + mouth_mask + nose_mask + brows_mask + eyes_mask | |
| result *= hull | |
| # result = np.clip (result, 0, 1) | |
| return result | |
| def blur_image_hull_mask(hull_mask): | |
| maxregion = np.argwhere(hull_mask == 1.0) | |
| miny, minx = maxregion.min(axis=0)[:2] | |
| maxy, maxx = maxregion.max(axis=0)[:2] | |
| lenx = maxx - minx; | |
| leny = maxy - miny; | |
| masky = int(minx + (lenx // 2)) | |
| maskx = int(miny + (leny // 2)) | |
| lowest_len = min(lenx, leny) | |
| ero = int(lowest_len * 0.085) | |
| blur = int(lowest_len * 0.10) | |
| hull_mask = cv2.erode(hull_mask, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (ero, ero)), iterations=1) | |
| hull_mask = cv2.blur(hull_mask, (blur, blur)) | |
| hull_mask = np.expand_dims(hull_mask, -1) | |
| return hull_mask | |
| mirror_idxs = [ | |
| [0, 16], | |
| [1, 15], | |
| [2, 14], | |
| [3, 13], | |
| [4, 12], | |
| [5, 11], | |
| [6, 10], | |
| [7, 9], | |
| [17, 26], | |
| [18, 25], | |
| [19, 24], | |
| [20, 23], | |
| [21, 22], | |
| [36, 45], | |
| [37, 44], | |
| [38, 43], | |
| [39, 42], | |
| [40, 47], | |
| [41, 46], | |
| [31, 35], | |
| [32, 34], | |
| [50, 52], | |
| [49, 53], | |
| [48, 54], | |
| [59, 55], | |
| [58, 56], | |
| [67, 65], | |
| [60, 64], | |
| [61, 63]] | |
| def mirror_landmarks(landmarks, val): | |
| result = landmarks.copy() | |
| for idx in mirror_idxs: | |
| result[idx] = result[idx[::-1]] | |
| result[:, 0] = val - result[:, 0] - 1 | |
| return result | |
| def get_face_struct_mask(image_shape, image_landmarks, eyebrows_expand_mod=1.0, color=(1,)): | |
| mask = np.zeros(image_shape[0:2] + (len(color),), dtype=np.float32) | |
| lmrks = expand_eyebrows(image_landmarks, eyebrows_expand_mod) | |
| draw_landmarks(mask, image_landmarks, color=color, draw_circles=False, thickness=2) | |
| return mask | |
| def draw_landmarks(image, image_landmarks, color=(0, 255, 0), draw_circles=True, thickness=1, transparent_mask=False): | |
| if len(image_landmarks) != 68: | |
| raise Exception('get_image_eye_mask works only with 68 landmarks') | |
| int_lmrks = np.array(image_landmarks, dtype=np.int) | |
| jaw = int_lmrks[slice(*landmarks_68_pt["jaw"])] | |
| right_eyebrow = int_lmrks[slice(*landmarks_68_pt["right_eyebrow"])] | |
| left_eyebrow = int_lmrks[slice(*landmarks_68_pt["left_eyebrow"])] | |
| mouth = int_lmrks[slice(*landmarks_68_pt["mouth"])] | |
| right_eye = int_lmrks[slice(*landmarks_68_pt["right_eye"])] | |
| left_eye = int_lmrks[slice(*landmarks_68_pt["left_eye"])] | |
| nose = int_lmrks[slice(*landmarks_68_pt["nose"])] | |
| # open shapes | |
| cv2.polylines(image, | |
| tuple(np.array([v]) for v in (right_eyebrow, jaw, left_eyebrow, np.concatenate((nose, [nose[-6]])))), | |
| False, color, thickness=thickness, lineType=cv2.LINE_AA) | |
| # closed shapes | |
| cv2.polylines(image, tuple(np.array([v]) for v in (right_eye, left_eye, mouth)), | |
| True, color, thickness=thickness, lineType=cv2.LINE_AA) | |
| if draw_circles: | |
| # the rest of the cicles | |
| for x, y in np.concatenate((right_eyebrow, left_eyebrow, mouth, right_eye, left_eye, nose), axis=0): | |
| cv2.circle(image, (x, y), 1, color, 1, lineType=cv2.LINE_AA) | |
| # jaw big circles | |
| for x, y in jaw: | |
| cv2.circle(image, (x, y), 2, color, lineType=cv2.LINE_AA) | |
| if transparent_mask: | |
| mask = get_image_hull_mask(image.shape, image_landmarks) | |
| image[...] = (image * (1 - mask) + image * mask / 2)[...] | |
| def draw_rect_landmarks(image, rect, image_landmarks, face_type, face_size=256, transparent_mask=False, | |
| landmarks_color=(0, 255, 0)): | |
| draw_landmarks(image, image_landmarks, color=landmarks_color, transparent_mask=transparent_mask) | |
| imagelib.draw_rect(image, rect, (255, 0, 0), 2) | |
| image_to_face_mat = get_transform_mat(image_landmarks, face_size, face_type) | |
| points = transform_points([(0, 0), (0, face_size - 1), (face_size - 1, face_size - 1), (face_size - 1, 0)], | |
| image_to_face_mat, True) | |
| imagelib.draw_polygon(image, points, (0, 0, 255), 2) | |
| points = transform_points( | |
| [(int(face_size * 0.05), 0), (int(face_size * 0.1), int(face_size * 0.1)), (0, int(face_size * 0.1))], | |
| image_to_face_mat, True) | |
| imagelib.draw_polygon(image, points, (0, 0, 255), 2) | |
| def calc_face_pitch(landmarks): | |
| if not isinstance(landmarks, np.ndarray): | |
| landmarks = np.array(landmarks) | |
| t = ((landmarks[6][1] - landmarks[8][1]) + (landmarks[10][1] - landmarks[8][1])) / 2.0 | |
| b = landmarks[8][1] | |
| return float(b - t) | |
| def estimate_averaged_yaw(landmarks): | |
| # Works much better than solvePnP if landmarks from "3DFAN" | |
| if not isinstance(landmarks, np.ndarray): | |
| landmarks = np.array(landmarks) | |
| l = ((landmarks[27][0] - landmarks[0][0]) + (landmarks[28][0] - landmarks[1][0]) + ( | |
| landmarks[29][0] - landmarks[2][0])) / 3.0 | |
| r = ((landmarks[16][0] - landmarks[27][0]) + (landmarks[15][0] - landmarks[28][0]) + ( | |
| landmarks[14][0] - landmarks[29][0])) / 3.0 | |
| return float(r - l) | |
| def estimate_pitch_yaw_roll(aligned_landmarks, size=256): | |
| """ | |
| returns pitch,yaw,roll [-pi/2...+pi/2] | |
| """ | |
| shape = (size, size) | |
| focal_length = shape[1] | |
| camera_center = (shape[1] / 2, shape[0] / 2) | |
| camera_matrix = np.array( | |
| [[focal_length, 0, camera_center[0]], | |
| [0, focal_length, camera_center[1]], | |
| [0, 0, 1]], dtype=np.float32) | |
| (_, rotation_vector, _) = cv2.solvePnP( | |
| np.concatenate((landmarks_68_3D[:27], landmarks_68_3D[30:36]), axis=0), | |
| np.concatenate((aligned_landmarks[:27], aligned_landmarks[30:36]), axis=0).astype(np.float32), | |
| camera_matrix, | |
| np.zeros((4, 1))) | |
| pitch, yaw, roll = mathlib.rotationMatrixToEulerAngles(cv2.Rodrigues(rotation_vector)[0]) | |
| half_pi = math.pi / 2.0 | |
| pitch = np.clip(pitch, -half_pi, half_pi) | |
| yaw = np.clip(yaw, -half_pi, half_pi) | |
| roll = np.clip(roll, -half_pi, half_pi) | |
| return -pitch, yaw, roll | |
| # if remove_align: | |
| # bbox = transform_points ( [ (0,0), (0,output_size), (output_size, output_size), (output_size,0) ], mat, True) | |
| # #import code | |
| # #code.interact(local=dict(globals(), **locals())) | |
| # area = mathlib.polygon_area(bbox[:,0], bbox[:,1] ) | |
| # side = math.sqrt(area) / 2 | |
| # center = transform_points ( [(output_size/2,output_size/2)], mat, True) | |
| # pts1 = np.float32(( center+[-side,-side], center+[side,-side], center+[side,-side] )) | |
| # pts2 = np.float32([[0,0],[output_size,0],[0,output_size]]) | |
| # mat = cv2.getAffineTransform(pts1,pts2) | |
| # if full_face_align_top and (face_type == FaceType.FULL or face_type == FaceType.FULL_NO_ALIGN): | |
| # #lmrks2 = expand_eyebrows(image_landmarks) | |
| # #lmrks2_ = transform_points( [ lmrks2[19], lmrks2[24] ], mat, False ) | |
| # #y_diff = np.float32( (0,np.min(lmrks2_[:,1])) ) | |
| # #y_diff = transform_points( [ np.float32( (0,0) ), y_diff], mat, True) | |
| # #y_diff = y_diff[1]-y_diff[0] | |
| # | |
| # x_diff = np.float32((0,0)) | |
| # | |
| # lmrks2_ = transform_points( [ image_landmarks[0], image_landmarks[16] ], mat, False ) | |
| # if lmrks2_[0,0] < 0: | |
| # x_diff = lmrks2_[0,0] | |
| # x_diff = transform_points( [ np.float32( (0,0) ), np.float32((x_diff,0)) ], mat, True) | |
| # x_diff = x_diff[1]-x_diff[0] | |
| # elif lmrks2_[1,0] >= output_size: | |
| # x_diff = lmrks2_[1,0]-(output_size-1) | |
| # x_diff = transform_points( [ np.float32( (0,0) ), np.float32((x_diff,0)) ], mat, True) | |
| # x_diff = x_diff[1]-x_diff[0] | |
| # | |
| # mat = cv2.getAffineTransform( l_t+y_diff+x_diff ,pts2) | |
| """ | |
| def get_averaged_transform_mat (img_landmarks, | |
| img_landmarks_prev, | |
| img_landmarks_next, | |
| average_frame_count, | |
| average_center_frame_count, | |
| output_size, face_type, scale=1.0): | |
| l_c_list = [] | |
| tb_diag_vec_list = [] | |
| bt_diag_vec_list = [] | |
| mod_list = [] | |
| count = max(average_frame_count,average_center_frame_count) | |
| for i in range ( -count, count+1, 1 ): | |
| if i < 0: | |
| lmrks = img_landmarks_prev[i] if -i < len(img_landmarks_prev) else None | |
| elif i > 0: | |
| lmrks = img_landmarks_next[i] if i < len(img_landmarks_next) else None | |
| else: | |
| lmrks = img_landmarks | |
| if lmrks is None: | |
| continue | |
| l_c, tb_diag_vec, bt_diag_vec, mod = get_transform_mat_data (lmrks, face_type, scale=scale) | |
| if i >= -average_frame_count and i <= average_frame_count: | |
| tb_diag_vec_list.append(tb_diag_vec) | |
| bt_diag_vec_list.append(bt_diag_vec) | |
| mod_list.append(mod) | |
| if i >= -average_center_frame_count and i <= average_center_frame_count: | |
| l_c_list.append(l_c) | |
| tb_diag_vec = np.mean( np.array(tb_diag_vec_list), axis=0 ) | |
| bt_diag_vec = np.mean( np.array(bt_diag_vec_list), axis=0 ) | |
| mod = np.mean( np.array(mod_list), axis=0 ) | |
| l_c = np.mean( np.array(l_c_list), axis=0 ) | |
| return get_transform_mat_by_data (l_c, tb_diag_vec, bt_diag_vec, mod, output_size, face_type) | |
| def get_transform_mat (image_landmarks, output_size, face_type, scale=1.0): | |
| if not isinstance(image_landmarks, np.ndarray): | |
| image_landmarks = np.array (image_landmarks) | |
| # get face padding value for FaceType | |
| padding, remove_align = FaceType_to_padding_remove_align.get(face_type, 0.0) | |
| # estimate landmarks transform from global space to local aligned space with bounds [0..1] | |
| mat = umeyama( np.concatenate ( [ image_landmarks[17:49] , image_landmarks[54:55] ] ) , landmarks_2D_new, True)[0:2] | |
| # get corner points in global space | |
| l_p = transform_points ( np.float32([(0,0),(1,0),(1,1),(0,1),(0.5,0.5)]) , mat, True) | |
| l_c = l_p[4] | |
| # calc diagonal vectors between corners in global space | |
| tb_diag_vec = (l_p[2]-l_p[0]).astype(np.float32) | |
| tb_diag_vec /= npla.norm(tb_diag_vec) | |
| bt_diag_vec = (l_p[1]-l_p[3]).astype(np.float32) | |
| bt_diag_vec /= npla.norm(bt_diag_vec) | |
| # calc modifier of diagonal vectors for scale and padding value | |
| mod = (1.0 / scale)* ( npla.norm(l_p[0]-l_p[2])*(padding*np.sqrt(2.0) + 0.5) ) | |
| # calc 3 points in global space to estimate 2d affine transform | |
| if not remove_align: | |
| l_t = np.array( [ np.round( l_c - tb_diag_vec*mod ), | |
| np.round( l_c + bt_diag_vec*mod ), | |
| np.round( l_c + tb_diag_vec*mod ) ] ) | |
| else: | |
| # remove_align - face will be centered in the frame but not aligned | |
| l_t = np.array( [ np.round( l_c - tb_diag_vec*mod ), | |
| np.round( l_c + bt_diag_vec*mod ), | |
| np.round( l_c + tb_diag_vec*mod ), | |
| np.round( l_c - bt_diag_vec*mod ), | |
| ] ) | |
| # get area of face square in global space | |
| area = mathlib.polygon_area(l_t[:,0], l_t[:,1] ) | |
| # calc side of square | |
| side = np.float32(math.sqrt(area) / 2) | |
| # calc 3 points with unrotated square | |
| l_t = np.array( [ np.round( l_c + [-side,-side] ), | |
| np.round( l_c + [ side,-side] ), | |
| np.round( l_c + [ side, side] ) ] ) | |
| # calc affine transform from 3 global space points to 3 local space points size of 'output_size' | |
| pts2 = np.float32(( (0,0),(output_size,0),(output_size,output_size) )) | |
| mat = cv2.getAffineTransform(l_t,pts2) | |
| return mat | |
| """ | |