From ce1ee32fde8700303e8a7da0cc24a82c2f1e4da1 Mon Sep 17 00:00:00 2001 From: gylcalex1314 <154417289+gylcalex1314@users.noreply.github.com> Date: Sun, 1 Sep 2024 19:53:18 +0800 Subject: [PATCH] add facial 68 landmark detection model (#964) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 敛沧 --- modelscope/metainfo.py | 2 + .../facial_68ldk_detection/conf/__init__.py | 1 + .../facial_68ldk_detection/conf/alignment.py | 239 +++++++++++++ .../cv/facial_68ldk_detection/conf/base.py | 94 ++++++ .../models/cv/facial_68ldk_detection/infer.py | 182 ++++++++++ .../cv/facial_68ldk_detection/lib/__init__.py | 2 + .../lib/backbone/__init__.py | 5 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 246 bytes .../__pycache__/__init__.cpython-37.pyc | Bin 0 -> 235 bytes .../__pycache__/__init__.cpython-39.pyc | Bin 0 -> 230 bytes .../stackedHGNetV1.cpython-312.pyc | Bin 0 -> 15490 bytes .../__pycache__/stackedHGNetV1.cpython-37.pyc | Bin 0 -> 9196 bytes .../__pycache__/stackedHGNetV1.cpython-39.pyc | Bin 0 -> 9067 bytes .../__pycache__/coord_conv.cpython-312.pyc | Bin 0 -> 8615 bytes .../__pycache__/coord_conv.cpython-37.pyc | Bin 0 -> 4379 bytes .../__pycache__/coord_conv.cpython-39.pyc | Bin 0 -> 4366 bytes .../lib/backbone/core/coord_conv.py | 157 +++++++++ .../lib/backbone/stackedHGNetV1.py | 307 +++++++++++++++++ .../lib/dataset/__init__.py | 10 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 360 bytes .../__pycache__/__init__.cpython-37.pyc | Bin 0 -> 348 bytes .../__pycache__/__init__.cpython-39.pyc | Bin 0 -> 385 bytes .../alignmentDataset.cpython-312.pyc | Bin 0 -> 18430 bytes .../alignmentDataset.cpython-37.pyc | Bin 0 -> 9469 bytes .../alignmentDataset.cpython-39.pyc | Bin 0 -> 9541 bytes .../__pycache__/augmentation.cpython-37.pyc | Bin 0 -> 10362 bytes .../__pycache__/augmentation.cpython-39.pyc | Bin 0 -> 10248 bytes .../lib/dataset/alignmentDataset.py | 314 ++++++++++++++++++ .../lib/dataset/decoder/__init__.py | 8 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 447 bytes .../__pycache__/__init__.cpython-37.pyc | Bin 0 -> 399 bytes .../__pycache__/__init__.cpython-39.pyc | Bin 0 -> 396 bytes .../decoder_default.cpython-312.pyc | Bin 0 -> 2391 bytes .../decoder_default.cpython-37.pyc | Bin 0 -> 1514 bytes .../decoder_default.cpython-39.pyc | Bin 0 -> 1525 bytes .../lib/dataset/decoder/decoder_default.py | 38 +++ .../lib/dataset/encoder/__init__.py | 8 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 526 bytes .../__pycache__/__init__.cpython-37.pyc | Bin 0 -> 476 bytes .../__pycache__/__init__.cpython-39.pyc | Bin 0 -> 473 bytes .../encoder_default.cpython-312.pyc | Bin 0 -> 4343 bytes .../encoder_default.cpython-37.pyc | Bin 0 -> 2296 bytes .../encoder_default.cpython-39.pyc | Bin 0 -> 2305 bytes .../lib/dataset/encoder/encoder_default.py | 63 ++++ .../cv/facial_68ldk_detection/lib/utility.py | 52 +++ .../cv/facial_68ldk_detection/star_model.py | 34 ++ .../cv/facial_68ldk_detection_pipeline.py | 87 +++++ modelscope/utils/constant.py | 1 + 48 files changed, 1604 insertions(+) create mode 100644 modelscope/models/cv/facial_68ldk_detection/conf/__init__.py create mode 100644 modelscope/models/cv/facial_68ldk_detection/conf/alignment.py create mode 100644 modelscope/models/cv/facial_68ldk_detection/conf/base.py create mode 100644 modelscope/models/cv/facial_68ldk_detection/infer.py create mode 100644 modelscope/models/cv/facial_68ldk_detection/lib/__init__.py create mode 100644 modelscope/models/cv/facial_68ldk_detection/lib/backbone/__init__.py create mode 100644 modelscope/models/cv/facial_68ldk_detection/lib/backbone/__pycache__/__init__.cpython-312.pyc create mode 100644 modelscope/models/cv/facial_68ldk_detection/lib/backbone/__pycache__/__init__.cpython-37.pyc create mode 100644 modelscope/models/cv/facial_68ldk_detection/lib/backbone/__pycache__/__init__.cpython-39.pyc create mode 100644 modelscope/models/cv/facial_68ldk_detection/lib/backbone/__pycache__/stackedHGNetV1.cpython-312.pyc create mode 100644 modelscope/models/cv/facial_68ldk_detection/lib/backbone/__pycache__/stackedHGNetV1.cpython-37.pyc create mode 100644 modelscope/models/cv/facial_68ldk_detection/lib/backbone/__pycache__/stackedHGNetV1.cpython-39.pyc create mode 100644 modelscope/models/cv/facial_68ldk_detection/lib/backbone/core/__pycache__/coord_conv.cpython-312.pyc create mode 100644 modelscope/models/cv/facial_68ldk_detection/lib/backbone/core/__pycache__/coord_conv.cpython-37.pyc create mode 100644 modelscope/models/cv/facial_68ldk_detection/lib/backbone/core/__pycache__/coord_conv.cpython-39.pyc create mode 100644 modelscope/models/cv/facial_68ldk_detection/lib/backbone/core/coord_conv.py create mode 100644 modelscope/models/cv/facial_68ldk_detection/lib/backbone/stackedHGNetV1.py create mode 100644 modelscope/models/cv/facial_68ldk_detection/lib/dataset/__init__.py create mode 100644 modelscope/models/cv/facial_68ldk_detection/lib/dataset/__pycache__/__init__.cpython-312.pyc create mode 100644 modelscope/models/cv/facial_68ldk_detection/lib/dataset/__pycache__/__init__.cpython-37.pyc create mode 100644 modelscope/models/cv/facial_68ldk_detection/lib/dataset/__pycache__/__init__.cpython-39.pyc create mode 100644 modelscope/models/cv/facial_68ldk_detection/lib/dataset/__pycache__/alignmentDataset.cpython-312.pyc create mode 100644 modelscope/models/cv/facial_68ldk_detection/lib/dataset/__pycache__/alignmentDataset.cpython-37.pyc create mode 100644 modelscope/models/cv/facial_68ldk_detection/lib/dataset/__pycache__/alignmentDataset.cpython-39.pyc create mode 100644 modelscope/models/cv/facial_68ldk_detection/lib/dataset/__pycache__/augmentation.cpython-37.pyc create mode 100644 modelscope/models/cv/facial_68ldk_detection/lib/dataset/__pycache__/augmentation.cpython-39.pyc create mode 100644 modelscope/models/cv/facial_68ldk_detection/lib/dataset/alignmentDataset.py create mode 100644 modelscope/models/cv/facial_68ldk_detection/lib/dataset/decoder/__init__.py create mode 100644 modelscope/models/cv/facial_68ldk_detection/lib/dataset/decoder/__pycache__/__init__.cpython-312.pyc create mode 100644 modelscope/models/cv/facial_68ldk_detection/lib/dataset/decoder/__pycache__/__init__.cpython-37.pyc create mode 100644 modelscope/models/cv/facial_68ldk_detection/lib/dataset/decoder/__pycache__/__init__.cpython-39.pyc create mode 100644 modelscope/models/cv/facial_68ldk_detection/lib/dataset/decoder/__pycache__/decoder_default.cpython-312.pyc create mode 100644 modelscope/models/cv/facial_68ldk_detection/lib/dataset/decoder/__pycache__/decoder_default.cpython-37.pyc create mode 100644 modelscope/models/cv/facial_68ldk_detection/lib/dataset/decoder/__pycache__/decoder_default.cpython-39.pyc create mode 100644 modelscope/models/cv/facial_68ldk_detection/lib/dataset/decoder/decoder_default.py create mode 100644 modelscope/models/cv/facial_68ldk_detection/lib/dataset/encoder/__init__.py create mode 100644 modelscope/models/cv/facial_68ldk_detection/lib/dataset/encoder/__pycache__/__init__.cpython-312.pyc create mode 100644 modelscope/models/cv/facial_68ldk_detection/lib/dataset/encoder/__pycache__/__init__.cpython-37.pyc create mode 100644 modelscope/models/cv/facial_68ldk_detection/lib/dataset/encoder/__pycache__/__init__.cpython-39.pyc create mode 100644 modelscope/models/cv/facial_68ldk_detection/lib/dataset/encoder/__pycache__/encoder_default.cpython-312.pyc create mode 100644 modelscope/models/cv/facial_68ldk_detection/lib/dataset/encoder/__pycache__/encoder_default.cpython-37.pyc create mode 100644 modelscope/models/cv/facial_68ldk_detection/lib/dataset/encoder/__pycache__/encoder_default.cpython-39.pyc create mode 100644 modelscope/models/cv/facial_68ldk_detection/lib/dataset/encoder/encoder_default.py create mode 100644 modelscope/models/cv/facial_68ldk_detection/lib/utility.py create mode 100644 modelscope/models/cv/facial_68ldk_detection/star_model.py create mode 100644 modelscope/pipelines/cv/facial_68ldk_detection_pipeline.py diff --git a/modelscope/metainfo.py b/modelscope/metainfo.py index 28aea889..c9ce5cb7 100644 --- a/modelscope/metainfo.py +++ b/modelscope/metainfo.py @@ -39,6 +39,7 @@ class Models(object): body_3d_keypoints_hdformer = 'hdformer' crowd_counting = 'HRNetCrowdCounting' face_2d_keypoints = 'face-2d-keypoints' + star_68ldk_detection = 'star-68ldk-detection' panoptic_segmentation = 'swinL-panoptic-segmentation' r50_panoptic_segmentation = 'r50-panoptic-segmentation' image_reid_person = 'passvitb' @@ -343,6 +344,7 @@ class Pipelines(object): tinymog_face_detection = 'manual-face-detection-tinymog' facial_expression_recognition = 'vgg19-facial-expression-recognition-fer' facial_landmark_confidence = 'manual-facial-landmark-confidence-flcm' + facial_68ldk_detection = 'facial-68ldk-detection' face_attribute_recognition = 'resnet34-face-attribute-recognition-fairface' retina_face_detection = 'resnet50-face-detection-retinaface' mog_face_detection = 'resnet101-face-detection-cvpr22papermogface' diff --git a/modelscope/models/cv/facial_68ldk_detection/conf/__init__.py b/modelscope/models/cv/facial_68ldk_detection/conf/__init__.py new file mode 100644 index 00000000..2f92d0e8 --- /dev/null +++ b/modelscope/models/cv/facial_68ldk_detection/conf/__init__.py @@ -0,0 +1 @@ +from .alignment import Alignment \ No newline at end of file diff --git a/modelscope/models/cv/facial_68ldk_detection/conf/alignment.py b/modelscope/models/cv/facial_68ldk_detection/conf/alignment.py new file mode 100644 index 00000000..eebaa1d7 --- /dev/null +++ b/modelscope/models/cv/facial_68ldk_detection/conf/alignment.py @@ -0,0 +1,239 @@ +import os.path as osp +from .base import Base + + +class Alignment(Base): + """ + Alignment configure file, which contains training parameters of alignment. + """ + + def __init__(self, args): + super(Alignment, self).__init__('alignment') + self.ckpt_dir = '/mnt/workspace/humanAIGC/project/STAR/weights' + self.net = "stackedHGnet_v1" + self.nstack = 4 + self.loader_type = "alignment" + self.data_definition = "300W" # COFW, 300W, WFLW + self.test_file = "test.tsv" + + # image + self.channels = 3 + self.width = 256 + self.height = 256 + self.means = (127.5, 127.5, 127.5) + self.scale = 1 / 127.5 + self.aug_prob = 1.0 + + self.display_iteration = 10 + self.val_epoch = 1 + self.valset = "test.tsv" + self.norm_type = 'default' + self.encoder_type = 'default' + self.decoder_type = 'default' + + # scheduler & optimizer + self.milestones = [200, 350, 450] + self.max_epoch = 260 + self.optimizer = "adam" + self.learn_rate = 0.001 + self.weight_decay = 0.00001 + self.betas = [0.9, 0.999] + self.gamma = 0.1 + + # batch_size & workers + self.batch_size = 32 + self.train_num_workers = 16 + self.val_batch_size = 32 + self.val_num_workers = 16 + self.test_batch_size = 16 + self.test_num_workers = 0 + + # tricks + self.ema = True + self.add_coord = True + self.use_AAM = True + + # loss + self.loss_func = "STARLoss_v2" + + # STAR Loss paras + self.star_w = 1 + self.star_dist = 'smoothl1' + + self.init_from_args(args) + + # COFW + if self.data_definition == "COFW": + self.edge_info = ( + (True, (0, 4, 2, 5)), # RightEyebrow + (True, (1, 6, 3, 7)), # LeftEyebrow + (True, (8, 12, 10, 13)), # RightEye + (False, (9, 14, 11, 15)), # LeftEye + (True, (18, 20, 19, 21)), # Nose + (True, (22, 26, 23, 27)), # LowerLip + (True, (22, 24, 23, 25)), # UpperLip + ) + if self.norm_type == 'ocular': + self.nme_left_index = 8 # ocular + self.nme_right_index = 9 # ocular + elif self.norm_type in ['pupil', 'default']: + self.nme_left_index = 16 # pupil + self.nme_right_index = 17 # pupil + else: + raise NotImplementedError + self.classes_num = [29, 7, 29] + self.crop_op = True + self.flip_mapping = ( + [0, 1], [4, 6], [2, 3], [5, 7], [8, 9], [10, 11], [12, 14], [16, 17], [13, 15], [18, 19], [22, 23], + ) + self.image_dir = osp.join(self.image_dir, 'COFW') + # 300W + elif self.data_definition == "300W": + self.edge_info = ( + (False, (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)), # FaceContour + (False, (17, 18, 19, 20, 21)), # RightEyebrow + (False, (22, 23, 24, 25, 26)), # LeftEyebrow + (False, (27, 28, 29, 30)), # NoseLine + (False, (31, 32, 33, 34, 35)), # Nose + (True, (36, 37, 38, 39, 40, 41)), # RightEye + (True, (42, 43, 44, 45, 46, 47)), # LeftEye + (True, (48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59)), # OuterLip + (True, (60, 61, 62, 63, 64, 65, 66, 67)), # InnerLip + ) + if self.norm_type in ['ocular', 'default']: + self.nme_left_index = 36 # ocular + self.nme_right_index = 45 # ocular + elif self.norm_type == 'pupil': + self.nme_left_index = [36, 37, 38, 39, 40, 41] # pupil + self.nme_right_index = [42, 43, 44, 45, 46, 47] # pupil + else: + raise NotImplementedError + self.classes_num = [68, 9, 68] + self.crop_op = True + self.flip_mapping = ( + [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], + [31, 35], [32, 34], + [36, 45], [37, 44], [38, 43], [39, 42], [40, 47], [41, 46], + [48, 54], [49, 53], [50, 52], [61, 63], [60, 64], [67, 65], [58, 56], [59, 55], + ) + self.image_dir = osp.join(self.image_dir, '300W') + # self.image_dir = osp.join(self.image_dir, '300VW_images') + # 300VW + elif self.data_definition == "300VW": + self.edge_info = ( + (False, (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)), # FaceContour + (False, (17, 18, 19, 20, 21)), # RightEyebrow + (False, (22, 23, 24, 25, 26)), # LeftEyebrow + (False, (27, 28, 29, 30)), # NoseLine + (False, (31, 32, 33, 34, 35)), # Nose + (True, (36, 37, 38, 39, 40, 41)), # RightEye + (True, (42, 43, 44, 45, 46, 47)), # LeftEye + (True, (48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59)), # OuterLip + (True, (60, 61, 62, 63, 64, 65, 66, 67)), # InnerLip + ) + if self.norm_type in ['ocular', 'default']: + self.nme_left_index = 36 # ocular + self.nme_right_index = 45 # ocular + elif self.norm_type == 'pupil': + self.nme_left_index = [36, 37, 38, 39, 40, 41] # pupil + self.nme_right_index = [42, 43, 44, 45, 46, 47] # pupil + else: + raise NotImplementedError + self.classes_num = [68, 9, 68] + self.crop_op = True + self.flip_mapping = ( + [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], + [31, 35], [32, 34], + [36, 45], [37, 44], [38, 43], [39, 42], [40, 47], [41, 46], + [48, 54], [49, 53], [50, 52], [61, 63], [60, 64], [67, 65], [58, 56], [59, 55], + ) + self.image_dir = osp.join(self.image_dir, '300VW_Dataset_2015_12_14') + # WFLW + elif self.data_definition == "WFLW": + self.edge_info = ( + (False, ( + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, + 28, 29, 30, 31, 32)), # FaceContour + (True, (33, 34, 35, 36, 37, 38, 39, 40, 41)), # RightEyebrow + (True, (42, 43, 44, 45, 46, 47, 48, 49, 50)), # LeftEyebrow + (False, (51, 52, 53, 54)), # NoseLine + (False, (55, 56, 57, 58, 59)), # Nose + (True, (60, 61, 62, 63, 64, 65, 66, 67)), # RightEye + (True, (68, 69, 70, 71, 72, 73, 74, 75)), # LeftEye + (True, (76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87)), # OuterLip + (True, (88, 89, 90, 91, 92, 93, 94, 95)), # InnerLip + ) + if self.norm_type in ['ocular', 'default']: + self.nme_left_index = 60 # ocular + self.nme_right_index = 72 # ocular + elif self.norm_type == 'pupil': + self.nme_left_index = 96 # pupils + self.nme_right_index = 97 # pupils + else: + raise NotImplementedError + self.classes_num = [98, 9, 98] + self.crop_op = True + self.flip_mapping = ( + [0, 32], [1, 31], [2, 30], [3, 29], [4, 28], [5, 27], [6, 26], [7, 25], [8, 24], [9, 23], [10, 22], + [11, 21], [12, 20], [13, 19], [14, 18], [15, 17], # cheek + [33, 46], [34, 45], [35, 44], [36, 43], [37, 42], [38, 50], [39, 49], [40, 48], [41, 47], # elbrow + [60, 72], [61, 71], [62, 70], [63, 69], [64, 68], [65, 75], [66, 74], [67, 73], + [55, 59], [56, 58], + [76, 82], [77, 81], [78, 80], [87, 83], [86, 84], + [88, 92], [89, 91], [95, 93], [96, 97] + ) + self.image_dir = osp.join(self.image_dir, 'WFLW', 'WFLW_images') + + self.label_num = self.nstack * 3 if self.use_AAM else self.nstack + self.loss_weights, self.criterions, self.metrics = [], [], [] + for i in range(self.nstack): + factor = (2 ** i) / (2 ** (self.nstack - 1)) + if self.use_AAM: + self.loss_weights += [factor * weight for weight in [1.0, 10.0, 10.0]] + self.criterions += [self.loss_func, "AWingLoss", "AWingLoss"] + self.metrics += ["NME", None, None] + else: + self.loss_weights += [factor * weight for weight in [1.0]] + self.criterions += [self.loss_func, ] + self.metrics += ["NME", ] + + self.key_metric_index = (self.nstack - 1) * 3 if self.use_AAM else (self.nstack - 1) + + # data + self.folder = self.get_foldername() + self.work_dir = osp.join(self.ckpt_dir, self.data_definition, self.folder) + self.model_dir = osp.join(self.work_dir, 'model') + self.log_dir = osp.join(self.work_dir, 'log') + + self.train_tsv_file = osp.join(self.annot_dir, self.data_definition, "train.tsv") + self.train_pic_dir = self.image_dir + + self.val_tsv_file = osp.join(self.annot_dir, self.data_definition, self.valset) + self.val_pic_dir = self.image_dir + + self.test_tsv_file = osp.join(self.annot_dir, self.data_definition, self.test_file) + self.test_pic_dir = self.image_dir + + # self.train_tsv_file = osp.join(self.annot_dir, '300VW', "train.tsv") + # self.train_pic_dir = self.image_dir + + # self.val_tsv_file = osp.join(self.annot_dir, '300VW', self.valset) + # self.val_pic_dir = self.image_dir + + # self.test_tsv_file = osp.join(self.annot_dir, '300VW', self.test_file) + # self.test_pic_dir = self.image_dir + + + def get_foldername(self): + str = '' + str += '{}_{}x{}_{}_ep{}_lr{}_bs{}'.format(self.data_definition, self.height, self.width, + self.optimizer, self.max_epoch, self.learn_rate, self.batch_size) + str += '_{}'.format(self.loss_func) + str += '_{}_{}'.format(self.star_dist, self.star_w) if self.loss_func == 'STARLoss' else '' + str += '_AAM' if self.use_AAM else '' + str += '_{}'.format(self.valset[:-4]) if self.valset != 'test.tsv' else '' + str += '_{}'.format(self.id) + return str diff --git a/modelscope/models/cv/facial_68ldk_detection/conf/base.py b/modelscope/models/cv/facial_68ldk_detection/conf/base.py new file mode 100644 index 00000000..55aded09 --- /dev/null +++ b/modelscope/models/cv/facial_68ldk_detection/conf/base.py @@ -0,0 +1,94 @@ +import uuid +import logging +import os.path as osp +from argparse import Namespace +# from tensorboardX import SummaryWriter + +class Base: + """ + Base configure file, which contains the basic training parameters and should be inherited by other attribute configure file. + """ + + def __init__(self, config_name, ckpt_dir='./', image_dir='./', annot_dir='./'): + self.type = config_name + self.id = str(uuid.uuid4()) + self.note = "" + + self.ckpt_dir = ckpt_dir + self.image_dir = image_dir + self.annot_dir = annot_dir + + self.loader_type = "alignment" + self.loss_func = "STARLoss" + + # train + self.batch_size = 128 + self.val_batch_size = 1 + self.test_batch_size = 32 + self.channels = 3 + self.width = 256 + self.height = 256 + + # mean values in r, g, b channel. + self.means = (127, 127, 127) + self.scale = 0.0078125 + + self.display_iteration = 100 + self.milestones = [50, 80] + self.max_epoch = 100 + + self.net = "stackedHGnet_v1" + self.nstack = 4 + + # ["adam", "sgd"] + self.optimizer = "adam" + self.learn_rate = 0.1 + self.momentum = 0.01 # caffe: 0.99 + self.weight_decay = 0.0 + self.nesterov = False + self.scheduler = "MultiStepLR" + self.gamma = 0.1 + + self.loss_weights = [1.0] + self.criterions = ["SoftmaxWithLoss"] + self.metrics = ["Accuracy"] + self.key_metric_index = 0 + self.classes_num = [1000] + self.label_num = len(self.classes_num) + + # model + self.ema = False + self.use_AAM = True + + # visualization + self.writer = None + + # log file + self.logger = None + + def init_instance(self): + # self.writer = SummaryWriter(logdir=self.log_dir, comment=self.type) + log_formatter = logging.Formatter("%(asctime)s %(levelname)-8s: %(message)s") + root_logger = logging.getLogger() + file_handler = logging.FileHandler(osp.join(self.log_dir, "log.txt")) + file_handler.setFormatter(log_formatter) + file_handler.setLevel(logging.NOTSET) + root_logger.addHandler(file_handler) + console_handler = logging.StreamHandler() + console_handler.setFormatter(log_formatter) + console_handler.setLevel(logging.NOTSET) + root_logger.addHandler(console_handler) + root_logger.setLevel(logging.NOTSET) + self.logger = root_logger + + def __del__(self): + # tensorboard --logdir self.log_dir + if self.writer is not None: + # self.writer.export_scalars_to_json(self.log_dir + "visual.json") + self.writer.close() + + def init_from_args(self, args: Namespace): + args_vars = vars(args) + for key, value in args_vars.items(): + if hasattr(self, key) and value is not None: + setattr(self, key, value) diff --git a/modelscope/models/cv/facial_68ldk_detection/infer.py b/modelscope/models/cv/facial_68ldk_detection/infer.py new file mode 100644 index 00000000..597120f4 --- /dev/null +++ b/modelscope/models/cv/facial_68ldk_detection/infer.py @@ -0,0 +1,182 @@ +import cv2 +import math +import copy +import numpy as np +import argparse +import torch + +# private package +from .lib import utility + +class GetCropMatrix(): + """ + from_shape -> transform_matrix + """ + + def __init__(self, image_size, target_face_scale, align_corners=False): + self.image_size = image_size + self.target_face_scale = target_face_scale + self.align_corners = align_corners + + def _compose_rotate_and_scale(self, angle, scale, shift_xy, from_center, to_center): + cosv = math.cos(angle) + sinv = math.sin(angle) + + fx, fy = from_center + tx, ty = to_center + + acos = scale * cosv + asin = scale * sinv + + a0 = acos + a1 = -asin + a2 = tx - acos * fx + asin * fy + shift_xy[0] + + b0 = asin + b1 = acos + b2 = ty - asin * fx - acos * fy + shift_xy[1] + + rot_scale_m = np.array([ + [a0, a1, a2], + [b0, b1, b2], + [0.0, 0.0, 1.0] + ], np.float32) + return rot_scale_m + + def process(self, scale, center_w, center_h): + if self.align_corners: + to_w, to_h = self.image_size - 1, self.image_size - 1 + else: + to_w, to_h = self.image_size, self.image_size + + rot_mu = 0 + scale_mu = self.image_size / (scale * self.target_face_scale * 200.0) + shift_xy_mu = (0, 0) + matrix = self._compose_rotate_and_scale( + rot_mu, scale_mu, shift_xy_mu, + from_center=[center_w, center_h], + to_center=[to_w / 2.0, to_h / 2.0]) + return matrix + + +class TransformPerspective(): + """ + image, matrix3x3 -> transformed_image + """ + + def __init__(self, image_size): + self.image_size = image_size + + def process(self, image, matrix): + return cv2.warpPerspective( + image, matrix, dsize=(self.image_size, self.image_size), + flags=cv2.INTER_LINEAR, borderValue=0) + + +class TransformPoints2D(): + """ + points (nx2), matrix (3x3) -> points (nx2) + """ + + def process(self, srcPoints, matrix): + # nx3 + desPoints = np.concatenate([srcPoints, np.ones_like(srcPoints[:, [0]])], axis=1) + desPoints = desPoints @ np.transpose(matrix) # nx3 + desPoints = desPoints[:, :2] / desPoints[:, [2, 2]] + return desPoints.astype(srcPoints.dtype) + +class Alignment: + def __init__(self, args, model_path, dl_framework, device_ids): + self.input_size = 256 + self.target_face_scale = 1.0 + self.dl_framework = dl_framework + + # model + if self.dl_framework == "pytorch": + # conf + self.config = utility.get_config(args) + self.config.device_id = device_ids[0] + + # set environment + utility.set_environment(self.config) + + net = utility.get_net(self.config) + if device_ids == [-1]: + checkpoint = torch.load(model_path, map_location="cpu") + else: + checkpoint = torch.load(model_path) + net.load_state_dict(checkpoint["net"]) + + if self.config.device_id == -1: + net = net.cpu() + else: + net = net.to(self.config.device_id) + + net.eval() + self.alignment = net + else: + assert False + + self.getCropMatrix = GetCropMatrix(image_size=self.input_size, target_face_scale=self.target_face_scale, + align_corners=True) + self.transformPerspective = TransformPerspective(image_size=self.input_size) + self.transformPoints2D = TransformPoints2D() + + def norm_points(self, points, align_corners=False): + if align_corners: + # [0, SIZE-1] -> [-1, +1] + return points / torch.tensor([self.input_size - 1, self.input_size - 1]).to(points).view(1, 1, 2) * 2 - 1 + else: + # [-0.5, SIZE-0.5] -> [-1, +1] + return (points * 2 + 1) / torch.tensor([self.input_size, self.input_size]).to(points).view(1, 1, 2) - 1 + + def denorm_points(self, points, align_corners=False): + if align_corners: + # [-1, +1] -> [0, SIZE-1] + return (points + 1) / 2 * torch.tensor([self.input_size - 1, self.input_size - 1]).to(points).view(1, 1, 2) + else: + # [-1, +1] -> [-0.5, SIZE-0.5] + return ((points + 1) * torch.tensor([self.input_size, self.input_size]).to(points).view(1, 1, 2) - 1) / 2 + + def preprocess(self, image, scale, center_w, center_h): + matrix = self.getCropMatrix.process(scale, center_w, center_h) + input_tensor = self.transformPerspective.process(image, matrix) + input_tensor = input_tensor[np.newaxis, :] + + input_tensor = torch.from_numpy(input_tensor) + input_tensor = input_tensor.float().permute(0, 3, 1, 2) + input_tensor = input_tensor / 255.0 * 2.0 - 1.0 + + if self.config.device_id == -1: + input_tensor = input_tensor.cpu() + else: + input_tensor = input_tensor.to(self.config.device_id) + + return input_tensor, matrix + + def postprocess(self, srcPoints, coeff): + # dstPoints = self.transformPoints2D.process(srcPoints, coeff) + # matrix^(-1) * src = dst + # src = matrix * dst + dstPoints = np.zeros(srcPoints.shape, dtype=np.float32) + for i in range(srcPoints.shape[0]): + dstPoints[i][0] = coeff[0][0] * srcPoints[i][0] + coeff[0][1] * srcPoints[i][1] + coeff[0][2] + dstPoints[i][1] = coeff[1][0] * srcPoints[i][0] + coeff[1][1] * srcPoints[i][1] + coeff[1][2] + return dstPoints + + def analyze(self, image, scale, center_w, center_h): + input_tensor, matrix = self.preprocess(image, scale, center_w, center_h) + + if self.dl_framework == "pytorch": + with torch.no_grad(): + output = self.alignment(input_tensor) + landmarks = output[-1][0] + else: + assert False + + landmarks = self.denorm_points(landmarks) + landmarks = landmarks.data.cpu().numpy()[0] + landmarks = self.postprocess(landmarks, np.linalg.inv(matrix)) + + return landmarks + diff --git a/modelscope/models/cv/facial_68ldk_detection/lib/__init__.py b/modelscope/models/cv/facial_68ldk_detection/lib/__init__.py new file mode 100644 index 00000000..0f808518 --- /dev/null +++ b/modelscope/models/cv/facial_68ldk_detection/lib/__init__.py @@ -0,0 +1,2 @@ +from .backbone import StackedHGNetV1 +from .utility import get_config, get_net diff --git a/modelscope/models/cv/facial_68ldk_detection/lib/backbone/__init__.py b/modelscope/models/cv/facial_68ldk_detection/lib/backbone/__init__.py new file mode 100644 index 00000000..cb1578aa --- /dev/null +++ b/modelscope/models/cv/facial_68ldk_detection/lib/backbone/__init__.py @@ -0,0 +1,5 @@ +from .stackedHGNetV1 import StackedHGNetV1 + +__all__ = [ + "StackedHGNetV1", +] \ No newline at end of file diff --git a/modelscope/models/cv/facial_68ldk_detection/lib/backbone/__pycache__/__init__.cpython-312.pyc b/modelscope/models/cv/facial_68ldk_detection/lib/backbone/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..91ae9bf0d6efaf57cc61f1801c77ffcede87d02f GIT binary patch literal 246 zcmX@j%ge<81ZvXL(t?5XV-N=hn4pZ$VnD`ph7^Vr#vF!R#wbQch7_iB#weyrW=)ot zj6g|E##?;BC5g$|sVN@reyJs4hDFRkVLwggTYSZs;qck@$FEKMcS-&K;xI{lEGf6)QXh~9jUaEe4d}dx| zNqoFsLFF$Fo80`A(wtPgB2J)bAO{tT0ErLGjEszT8MHpIF|dk$U}oZGYGf~B2TA|{ DcOO3L literal 0 HcmV?d00001 diff --git a/modelscope/models/cv/facial_68ldk_detection/lib/backbone/__pycache__/__init__.cpython-37.pyc b/modelscope/models/cv/facial_68ldk_detection/lib/backbone/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8ec2c83956e9efbc743976b84fda3320fd385477 GIT binary patch literal 235 zcmZWjI|{-;5Zz4#Mby&9UP$9&FCsQ-V-v7QGi;nuqnm6%fnC<^Q~D0%&6Z9-?UQ-k07hb+9R^{Y@LXs=TmA+PYF9UC7v68J%IO pixVI@7808&lf)|Kud&TY0VG-C07m((YE4p$XG7E4Tv=P`_#ZLgJcj@P literal 0 HcmV?d00001 diff --git a/modelscope/models/cv/facial_68ldk_detection/lib/backbone/__pycache__/__init__.cpython-39.pyc b/modelscope/models/cv/facial_68ldk_detection/lib/backbone/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a5cbbaba9c15d1a7580fdb0d3d75811ecb81adec GIT binary patch literal 230 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 QlP@J+`T{f!EluM80?@hehX4Qo literal 0 HcmV?d00001 diff --git a/modelscope/models/cv/facial_68ldk_detection/lib/backbone/__pycache__/stackedHGNetV1.cpython-37.pyc b/modelscope/models/cv/facial_68ldk_detection/lib/backbone/__pycache__/stackedHGNetV1.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6737dfa6d2f0d6f29dfe5e126def8b3af017a30c GIT binary patch literal 9196 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 literal 0 HcmV?d00001 diff --git a/modelscope/models/cv/facial_68ldk_detection/lib/backbone/__pycache__/stackedHGNetV1.cpython-39.pyc b/modelscope/models/cv/facial_68ldk_detection/lib/backbone/__pycache__/stackedHGNetV1.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f69878f57e9cd81be2332cd8d172146c38fb66df GIT binary patch literal 9067 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 L;~NU9>bCz2XWn-* literal 0 HcmV?d00001 diff --git a/modelscope/models/cv/facial_68ldk_detection/lib/backbone/core/__pycache__/coord_conv.cpython-37.pyc b/modelscope/models/cv/facial_68ldk_detection/lib/backbone/core/__pycache__/coord_conv.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..35ecca224b7b4c7b74ccb85167f0d32d6a120a9a GIT binary patch literal 4379 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.05, + xx_channel, zero_tensor) + yy_boundary_channel = torch.where(boundary_channel>0.05, + yy_channel, zero_tensor) + ret = torch.cat([input_tensor, xx_channel, yy_channel], dim=1) + + + if self.with_r: + rr = torch.sqrt(torch.pow(xx_channel, 2) + torch.pow(yy_channel, 2)) + rr = rr / torch.max(rr) + ret = torch.cat([ret, rr], dim=1) + + if self.with_boundary and type(heatmap) != type(None): + ret = torch.cat([ret, xx_boundary_channel, + yy_boundary_channel], dim=1) + return ret + + +class CoordConvTh(nn.Module): + """CoordConv layer as in the paper.""" + def __init__(self, x_dim, y_dim, with_r, with_boundary, + in_channels, out_channels, first_one=False, relu=False, bn=False, *args, **kwargs): + super(CoordConvTh, self).__init__() + self.addcoords = AddCoordsTh(x_dim=x_dim, y_dim=y_dim, with_r=with_r, + with_boundary=with_boundary) + in_channels += 2 + if with_r: + in_channels += 1 + if with_boundary and not first_one: + in_channels += 2 + self.conv = nn.Conv2d(in_channels=in_channels, out_channels=out_channels, *args, **kwargs) + self.relu = nn.ReLU() if relu else None + self.bn = nn.BatchNorm2d(out_channels) if bn else None + + self.with_boundary = with_boundary + self.first_one = first_one + + + def forward(self, input_tensor, heatmap=None): + assert (self.with_boundary and not self.first_one) == (heatmap is not None) + ret = self.addcoords(input_tensor, heatmap) + ret = self.conv(ret) + if self.bn is not None: + ret = self.bn(ret) + if self.relu is not None: + ret = self.relu(ret) + + return ret + + +''' +An alternative implementation for PyTorch with auto-infering the x-y dimensions. +''' +class AddCoords(nn.Module): + + def __init__(self, with_r=False): + super().__init__() + self.with_r = with_r + + def forward(self, input_tensor): + """ + Args: + input_tensor: shape(batch, channel, x_dim, y_dim) + """ + batch_size, _, x_dim, y_dim = input_tensor.size() + + xx_channel = torch.arange(x_dim).repeat(1, y_dim, 1).to(input_tensor) + yy_channel = torch.arange(y_dim).repeat(1, x_dim, 1).transpose(1, 2).to(input_tensor) + + xx_channel = xx_channel / (x_dim - 1) + yy_channel = yy_channel / (y_dim - 1) + + xx_channel = xx_channel * 2 - 1 + yy_channel = yy_channel * 2 - 1 + + xx_channel = xx_channel.repeat(batch_size, 1, 1, 1).transpose(2, 3) + yy_channel = yy_channel.repeat(batch_size, 1, 1, 1).transpose(2, 3) + + ret = torch.cat([ + input_tensor, + xx_channel.type_as(input_tensor), + yy_channel.type_as(input_tensor)], dim=1) + + if self.with_r: + rr = torch.sqrt(torch.pow(xx_channel - 0.5, 2) + torch.pow(yy_channel - 0.5, 2)) + ret = torch.cat([ret, rr], dim=1) + + return ret + + +class CoordConv(nn.Module): + + def __init__(self, in_channels, out_channels, with_r=False, **kwargs): + super().__init__() + self.addcoords = AddCoords(with_r=with_r) + in_channels += 2 + if with_r: + in_channels += 1 + self.conv = nn.Conv2d(in_channels, out_channels, **kwargs) + + def forward(self, x): + ret = self.addcoords(x) + ret = self.conv(ret) + return ret diff --git a/modelscope/models/cv/facial_68ldk_detection/lib/backbone/stackedHGNetV1.py b/modelscope/models/cv/facial_68ldk_detection/lib/backbone/stackedHGNetV1.py new file mode 100644 index 00000000..c81c30f8 --- /dev/null +++ b/modelscope/models/cv/facial_68ldk_detection/lib/backbone/stackedHGNetV1.py @@ -0,0 +1,307 @@ +import numpy as np + +import torch +import torch.nn as nn +import torch.nn.functional as F + +from .core.coord_conv import CoordConvTh +from ..dataset import get_decoder + + + +class Activation(nn.Module): + def __init__(self, kind: str = 'relu', channel=None): + super().__init__() + self.kind = kind + + if '+' in kind: + norm_str, act_str = kind.split('+') + else: + norm_str, act_str = 'none', kind + + self.norm_fn = { + 'in': F.instance_norm, + 'bn': nn.BatchNorm2d(channel), + 'bn_noaffine': nn.BatchNorm2d(channel, affine=False, track_running_stats=True), + 'none': None + }[norm_str] + + self.act_fn = { + 'relu': F.relu, + 'softplus': nn.Softplus(), + 'exp': torch.exp, + 'sigmoid': torch.sigmoid, + 'tanh': torch.tanh, + 'none': None + }[act_str] + + self.channel = channel + + def forward(self, x): + if self.norm_fn is not None: + x = self.norm_fn(x) + if self.act_fn is not None: + x = self.act_fn(x) + return x + + def extra_repr(self): + return f'kind={self.kind}, channel={self.channel}' + + +class ConvBlock(nn.Module): + def __init__(self, inp_dim, out_dim, kernel_size=3, stride=1, bn=False, relu=True, groups=1): + super(ConvBlock, self).__init__() + self.inp_dim = inp_dim + self.conv = nn.Conv2d(inp_dim, out_dim, kernel_size, + stride, padding=(kernel_size - 1) // 2, groups=groups, bias=True) + self.relu = None + self.bn = None + if relu: + self.relu = nn.ReLU() + if bn: + self.bn = nn.BatchNorm2d(out_dim) + + def forward(self, x): + x = self.conv(x) + if self.bn is not None: + x = self.bn(x) + if self.relu is not None: + x = self.relu(x) + return x + + +class ResBlock(nn.Module): + def __init__(self, inp_dim, out_dim, mid_dim=None): + super(ResBlock, self).__init__() + if mid_dim is None: + mid_dim = out_dim // 2 + self.relu = nn.ReLU() + self.bn1 = nn.BatchNorm2d(inp_dim) + self.conv1 = ConvBlock(inp_dim, mid_dim, 1, relu=False) + self.bn2 = nn.BatchNorm2d(mid_dim) + self.conv2 = ConvBlock(mid_dim, mid_dim, 3, relu=False) + self.bn3 = nn.BatchNorm2d(mid_dim) + self.conv3 = ConvBlock(mid_dim, out_dim, 1, relu=False) + self.skip_layer = ConvBlock(inp_dim, out_dim, 1, relu=False) + if inp_dim == out_dim: + self.need_skip = False + else: + self.need_skip = True + + def forward(self, x): + if self.need_skip: + residual = self.skip_layer(x) + else: + residual = x + out = self.bn1(x) + out = self.relu(out) + out = self.conv1(out) + out = self.bn2(out) + out = self.relu(out) + out = self.conv2(out) + out = self.bn3(out) + out = self.relu(out) + out = self.conv3(out) + out += residual + return out + + +class Hourglass(nn.Module): + def __init__(self, n, f, increase=0, up_mode='nearest', + add_coord=False, first_one=False, x_dim=64, y_dim=64): + super(Hourglass, self).__init__() + nf = f + increase + + Block = ResBlock + + if add_coord: + self.coordconv = CoordConvTh(x_dim=x_dim, y_dim=y_dim, + with_r=True, with_boundary=True, + relu=False, bn=False, + in_channels=f, out_channels=f, + first_one=first_one, + kernel_size=1, + stride=1, padding=0) + else: + self.coordconv = None + self.up1 = Block(f, f) + + # Lower branch + self.pool1 = nn.MaxPool2d(kernel_size=2, stride=2) + + self.low1 = Block(f, nf) + self.n = n + # Recursive hourglass + if self.n > 1: + self.low2 = Hourglass(n=n - 1, f=nf, increase=increase, up_mode=up_mode, add_coord=False) + else: + self.low2 = Block(nf, nf) + self.low3 = Block(nf, f) + self.up2 = nn.Upsample(scale_factor=2, mode=up_mode) + + def forward(self, x, heatmap=None): + if self.coordconv is not None: + x = self.coordconv(x, heatmap) + up1 = self.up1(x) + pool1 = self.pool1(x) + low1 = self.low1(pool1) + low2 = self.low2(low1) + low3 = self.low3(low2) + up2 = self.up2(low3) + return up1 + up2 + + +class E2HTransform(nn.Module): + def __init__(self, edge_info, num_points, num_edges): + super().__init__() + + e2h_matrix = np.zeros([num_points, num_edges]) + for edge_id, isclosed_indices in enumerate(edge_info): + is_closed, indices = isclosed_indices + for point_id in indices: + e2h_matrix[point_id, edge_id] = 1 + e2h_matrix = torch.from_numpy(e2h_matrix).float() + + # pn x en x 1 x 1. + self.register_buffer('weight', e2h_matrix.view( + e2h_matrix.size(0), e2h_matrix.size(1), 1, 1)) + + # some keypoints are not coverred by any edges, + # in these cases, we must add a constant bias to their heatmap weights. + bias = ((e2h_matrix @ torch.ones(e2h_matrix.size(1)).to( + e2h_matrix)) < 0.5).to(e2h_matrix) + # pn x 1. + self.register_buffer('bias', bias) + + def forward(self, edgemaps): + # input: batch_size x en x hw x hh. + # output: batch_size x pn x hw x hh. + return F.conv2d(edgemaps, weight=self.weight, bias=self.bias) + + +class StackedHGNetV1(nn.Module): + def __init__(self, config, classes_num, edge_info, + nstack=4, nlevels=4, in_channel=256, increase=0, + add_coord=True, decoder_type='default'): + super(StackedHGNetV1, self).__init__() + + self.cfg = config + self.coder_type = decoder_type + self.decoder = get_decoder(decoder_type=decoder_type) + self.nstack = nstack + self.add_coord = add_coord + + self.num_heats = classes_num[0] + + if self.add_coord: + convBlock = CoordConvTh(x_dim=self.cfg.width, y_dim=self.cfg.height, + with_r=True, with_boundary=False, + relu=True, bn=True, + in_channels=3, out_channels=64, + kernel_size=7, + stride=2, padding=3) + else: + convBlock = ConvBlock(3, 64, 7, 2, bn=True, relu=True) + + pool = nn.MaxPool2d(kernel_size=2, stride=2) + + Block = ResBlock + + self.pre = nn.Sequential( + convBlock, + Block(64, 128), + pool, + Block(128, 128), + Block(128, in_channel) + ) + + self.hgs = nn.ModuleList( + [Hourglass(n=nlevels, f=in_channel, increase=increase, add_coord=self.add_coord, first_one=(_ == 0), + x_dim=int(self.cfg.width / self.nstack), y_dim=int(self.cfg.height / self.nstack)) + for _ in range(nstack)]) + + self.features = nn.ModuleList([ + nn.Sequential( + Block(in_channel, in_channel), + ConvBlock(in_channel, in_channel, 1, bn=True, relu=True) + ) for _ in range(nstack)]) + + self.out_heatmaps = nn.ModuleList( + [ConvBlock(in_channel, self.num_heats, 1, relu=False, bn=False) + for _ in range(nstack)]) + + if self.cfg.use_AAM: + self.num_edges = classes_num[1] + self.num_points = classes_num[2] + + self.e2h_transform = E2HTransform(edge_info, self.num_points, self.num_edges) + self.out_edgemaps = nn.ModuleList( + [ConvBlock(in_channel, self.num_edges, 1, relu=False, bn=False) + for _ in range(nstack)]) + self.out_pointmaps = nn.ModuleList( + [ConvBlock(in_channel, self.num_points, 1, relu=False, bn=False) + for _ in range(nstack)]) + self.merge_edgemaps = nn.ModuleList( + [ConvBlock(self.num_edges, in_channel, 1, relu=False, bn=False) + for _ in range(nstack - 1)]) + self.merge_pointmaps = nn.ModuleList( + [ConvBlock(self.num_points, in_channel, 1, relu=False, bn=False) + for _ in range(nstack - 1)]) + self.edgemap_act = Activation("sigmoid", self.num_edges) + self.pointmap_act = Activation("sigmoid", self.num_points) + + self.merge_features = nn.ModuleList( + [ConvBlock(in_channel, in_channel, 1, relu=False, bn=False) + for _ in range(nstack - 1)]) + self.merge_heatmaps = nn.ModuleList( + [ConvBlock(self.num_heats, in_channel, 1, relu=False, bn=False) + for _ in range(nstack - 1)]) + + self.nstack = nstack + + self.heatmap_act = Activation("in+relu", self.num_heats) + + self.inference = False + + def set_inference(self, inference): + self.inference = inference + + def forward(self, x): + x = self.pre(x) + + y, fusionmaps = [], [] + heatmaps = None + for i in range(self.nstack): + hg = self.hgs[i](x, heatmap=heatmaps) + feature = self.features[i](hg) + + heatmaps0 = self.out_heatmaps[i](feature) + heatmaps = self.heatmap_act(heatmaps0) + + if self.cfg.use_AAM: + pointmaps0 = self.out_pointmaps[i](feature) + pointmaps = self.pointmap_act(pointmaps0) + edgemaps0 = self.out_edgemaps[i](feature) + edgemaps = self.edgemap_act(edgemaps0) + mask = self.e2h_transform(edgemaps) * pointmaps + fusion_heatmaps = mask * heatmaps + else: + fusion_heatmaps = heatmaps + + landmarks = self.decoder.get_coords_from_heatmap(fusion_heatmaps) + + if i < self.nstack - 1: + x = x + self.merge_features[i](feature) + \ + self.merge_heatmaps[i](heatmaps) + if self.cfg.use_AAM: + x += self.merge_pointmaps[i](pointmaps) + x += self.merge_edgemaps[i](edgemaps) + + y.append(landmarks) + if self.cfg.use_AAM: + y.append(pointmaps) + y.append(edgemaps) + + fusionmaps.append(fusion_heatmaps) + + return y, fusionmaps, landmarks diff --git a/modelscope/models/cv/facial_68ldk_detection/lib/dataset/__init__.py b/modelscope/models/cv/facial_68ldk_detection/lib/dataset/__init__.py new file mode 100644 index 00000000..7ff68531 --- /dev/null +++ b/modelscope/models/cv/facial_68ldk_detection/lib/dataset/__init__.py @@ -0,0 +1,10 @@ +from .encoder import get_encoder +from .decoder import get_decoder +from .alignmentDataset import AlignmentDataset + +__all__ = [ + "Augmentation", + "AlignmentDataset", + "get_encoder", + "get_decoder" +] diff --git a/modelscope/models/cv/facial_68ldk_detection/lib/dataset/__pycache__/__init__.cpython-312.pyc b/modelscope/models/cv/facial_68ldk_detection/lib/dataset/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8e792a840b4b149f5b0298697db82c7048a3373e GIT binary patch literal 360 zcmZ9Hu};G<5Qgm}ZV+uz7k1VxH4jiBRbu7=vRI}*TqE1597iG&3s1quz{a!i21ZOw zY=~~1>V#zBWc~jCJKZPyeLg=$u^!3G-ABB?x-eEUnEhom&qyGFH8QxwxbullOj@SB zPjzNUNidQ~WUsiKw4|7Pu8D+5%vT*Cw1x#}J^ zzNXv8aLbk4P!F}ITHR9d_bkeovdS~I+_i_3m8nFd;mVywSohERJjzdsG5$ms{aOBI LWSTtXZWbp;YM5ew literal 0 HcmV?d00001 diff --git a/modelscope/models/cv/facial_68ldk_detection/lib/dataset/__pycache__/__init__.cpython-37.pyc b/modelscope/models/cv/facial_68ldk_detection/lib/dataset/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..95c1b1299e237cd7cd898cd49bbdfb250071dfca GIT binary patch literal 348 zcmZ9HzfQw25XSBNX#%)XUn2`%I#!4xW(L^2SSEM4u571D9ErXRJFk?LiC1944$Z<@ z{^|RCx=-ha_4=B`dM-cSN=nFAGD{Uv+{Zg?BY*(4#8E+M(wWU%F7jFDws570<4`~e zE2wlKR#3l?=IT3Ul7>z<8iPdNc7Xk20T;X3Tcf>0A0Aau0|vqNqfTB0)A>Fv(q{>I z#8XpE)g^0wovKUJ+!h=4FKwQmDk+tmfhrq3Qq`WH&5(pP?hc$>q5^H2I!#MavCnja^41B6H zle0YfOwSBq1fvGY{0*~0&Niqd-@r#Do{k&kxw3U9mD@+D_Hj{-jZxMM-*y(pt4goi^U#Z0(Z|sUTisk=(%yAXs`hlVt?sC9@2UJ-lXBkL)^mQ^zfQ&4baK?{ NJbb}WfGlu4$uHhrVpsqG literal 0 HcmV?d00001 diff --git a/modelscope/models/cv/facial_68ldk_detection/lib/dataset/__pycache__/alignmentDataset.cpython-312.pyc b/modelscope/models/cv/facial_68ldk_detection/lib/dataset/__pycache__/alignmentDataset.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1a5425ff7fab627e11167755dbac9a10cf046402 GIT binary patch literal 18430 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

S`G5mb(i4_cle$8@0T#Hnu)h-@@0oM4Lg3 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 literal 0 HcmV?d00001 diff --git a/modelscope/models/cv/facial_68ldk_detection/lib/dataset/__pycache__/augmentation.cpython-39.pyc b/modelscope/models/cv/facial_68ldk_detection/lib/dataset/__pycache__/augmentation.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b69daa7fd35327c558edf680825c1ef4b31db81a GIT binary patch literal 10248 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 CRKVf@ literal 0 HcmV?d00001 diff --git a/modelscope/models/cv/facial_68ldk_detection/lib/dataset/alignmentDataset.py b/modelscope/models/cv/facial_68ldk_detection/lib/dataset/alignmentDataset.py new file mode 100644 index 00000000..8a58af2d --- /dev/null +++ b/modelscope/models/cv/facial_68ldk_detection/lib/dataset/alignmentDataset.py @@ -0,0 +1,314 @@ +import os +import sys +import cv2 +import math +import copy +import hashlib +import imageio +import numpy as np +import pandas as pd +from scipy import interpolate +from PIL import Image, ImageEnhance, ImageFile + +import torch +import torch.nn.functional as F +from torch.utils.data import Dataset + +ImageFile.LOAD_TRUNCATED_IMAGES = True + +from .encoder import get_encoder + + +class AlignmentDataset(Dataset): + + def __init__(self, tsv_flie, image_dir="", transform=None, + width=256, height=256, channels=3, + means=(127.5, 127.5, 127.5), scale=1 / 127.5, + classes_num=None, crop_op=True, aug_prob=0.0, edge_info=None, flip_mapping=None, is_train=True, + encoder_type='default', + ): + super(AlignmentDataset, self).__init__() + self.use_AAM = True + self.encoder_type = encoder_type + self.encoder = get_encoder(height, width, encoder_type=encoder_type) + self.items = pd.read_csv(tsv_flie, sep="\t") + self.image_dir = image_dir + self.landmark_num = classes_num[0] + self.transform = transform + + self.image_width = width + self.image_height = height + self.channels = channels + assert self.image_width == self.image_height + + self.means = means + self.scale = scale + + self.aug_prob = aug_prob + self.edge_info = edge_info + self.is_train = is_train + std_lmk_5pts = np.array([ + 196.0, 226.0, + 316.0, 226.0, + 256.0, 286.0, + 220.0, 360.4, + 292.0, 360.4], np.float32) / 256.0 - 1.0 + std_lmk_5pts = np.reshape(std_lmk_5pts, (5, 2)) # [-1 1] + target_face_scale = 1.0 if crop_op else 1.25 + + self.augmentation = Augmentation( + is_train=self.is_train, + aug_prob=self.aug_prob, + image_size=self.image_width, + crop_op=crop_op, + std_lmk_5pts=std_lmk_5pts, + target_face_scale=target_face_scale, + flip_rate=0.5, + flip_mapping=flip_mapping, + random_shift_sigma=0.05, + random_rot_sigma=math.pi / 180 * 18, + random_scale_sigma=0.1, + random_gray_rate=0.2, + random_occ_rate=0.4, + random_blur_rate=0.3, + random_gamma_rate=0.2, + random_nose_fusion_rate=0.2) + + def _circle(self, img, pt, sigma=1.0, label_type='Gaussian'): + # Check that any part of the gaussian is in-bounds + tmp_size = sigma * 3 + ul = [int(pt[0] - tmp_size), int(pt[1] - tmp_size)] + br = [int(pt[0] + tmp_size + 1), int(pt[1] + tmp_size + 1)] + if (ul[0] > img.shape[1] - 1 or ul[1] > img.shape[0] - 1 or + br[0] - 1 < 0 or br[1] - 1 < 0): + # If not, just return the image as is + return img + + # Generate gaussian + size = 2 * tmp_size + 1 + x = np.arange(0, size, 1, np.float32) + y = x[:, np.newaxis] + x0 = y0 = size // 2 + # The gaussian is not normalized, we want the center value to equal 1 + if label_type == 'Gaussian': + g = np.exp(- ((x - x0) ** 2 + (y - y0) ** 2) / (2 * sigma ** 2)) + else: + g = sigma / (((x - x0) ** 2 + (y - y0) ** 2 + sigma ** 2) ** 1.5) + + # Usable gaussian range + g_x = max(0, -ul[0]), min(br[0], img.shape[1]) - ul[0] + g_y = max(0, -ul[1]), min(br[1], img.shape[0]) - ul[1] + # Image range + img_x = max(0, ul[0]), min(br[0], img.shape[1]) + img_y = max(0, ul[1]), min(br[1], img.shape[0]) + + img[img_y[0]:img_y[1], img_x[0]:img_x[1]] = 255 * g[g_y[0]:g_y[1], g_x[0]:g_x[1]] + return img + + def _polylines(self, img, lmks, is_closed, color=255, thickness=1, draw_mode=cv2.LINE_AA, + interpolate_mode=cv2.INTER_AREA, scale=4): + h, w = img.shape + img_scale = cv2.resize(img, (w * scale, h * scale), interpolation=interpolate_mode) + lmks_scale = (lmks * scale + 0.5).astype(np.int32) + cv2.polylines(img_scale, [lmks_scale], is_closed, color, thickness * scale, draw_mode) + img = cv2.resize(img_scale, (w, h), interpolation=interpolate_mode) + return img + + def _generate_edgemap(self, points, scale=0.25, thickness=1): + h, w = self.image_height, self.image_width + edgemaps = [] + for is_closed, indices in self.edge_info: + edgemap = np.zeros([h, w], dtype=np.float32) + # align_corners: False. + part = copy.deepcopy(points[np.array(indices)]) + + part = self._fit_curve(part, is_closed) + part[:, 0] = np.clip(part[:, 0], 0, w - 1) + part[:, 1] = np.clip(part[:, 1], 0, h - 1) + edgemap = self._polylines(edgemap, part, is_closed, 255, thickness) + + edgemaps.append(edgemap) + edgemaps = np.stack(edgemaps, axis=0) / 255.0 + edgemaps = torch.from_numpy(edgemaps).float().unsqueeze(0) + edgemaps = F.interpolate(edgemaps, size=(int(w * scale), int(h * scale)), mode='bilinear', + align_corners=False).squeeze() + return edgemaps + + def _fit_curve(self, lmks, is_closed=False, density=5): + try: + x = lmks[:, 0].copy() + y = lmks[:, 1].copy() + if is_closed: + x = np.append(x, x[0]) + y = np.append(y, y[0]) + tck, u = interpolate.splprep([x, y], s=0, per=is_closed, k=3) + # bins = (x.shape[0] - 1) * density + 1 + # lmk_x, lmk_y = interpolate.splev(np.linspace(0, 1, bins), f) + intervals = np.array([]) + for i in range(len(u) - 1): + intervals = np.concatenate((intervals, np.linspace(u[i], u[i + 1], density, endpoint=False))) + if not is_closed: + intervals = np.concatenate((intervals, [u[-1]])) + lmk_x, lmk_y = interpolate.splev(intervals, tck, der=0) + # der_x, der_y = interpolate.splev(intervals, tck, der=1) + curve_lmks = np.stack([lmk_x, lmk_y], axis=-1) + # curve_ders = np.stack([der_x, der_y], axis=-1) + # origin_indices = np.arange(0, curve_lmks.shape[0], density) + + return curve_lmks + except: + return lmks + + def _image_id(self, image_path): + if not os.path.exists(image_path): + image_path = os.path.join(self.image_dir, image_path) + return hashlib.md5(open(image_path, "rb").read()).hexdigest() + + def _load_image(self, image_path): + if not os.path.exists(image_path): + image_path = os.path.join(self.image_dir, image_path) + + try: + # img = cv2.imdecode(np.fromfile(image_path, dtype=np.uint8), cv2.IMREAD_COLOR)#HWC, BGR, [0-255] + img = cv2.imread(image_path, cv2.IMREAD_COLOR) # HWC, BGR, [0-255] + assert img is not None and len(img.shape) == 3 and img.shape[2] == 3 + except: + try: + img = imageio.imread(image_path) # HWC, RGB, [0-255] + img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR) # HWC, BGR, [0-255] + assert img is not None and len(img.shape) == 3 and img.shape[2] == 3 + except: + try: + gifImg = imageio.mimread(image_path) # BHWC, RGB, [0-255] + img = gifImg[0] # HWC, RGB, [0-255] + img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR) # HWC, BGR, [0-255] + assert img is not None and len(img.shape) == 3 and img.shape[2] == 3 + except: + img = None + return img + + def _compose_rotate_and_scale(self, angle, scale, shift_xy, from_center, to_center): + cosv = math.cos(angle) + sinv = math.sin(angle) + + fx, fy = from_center + tx, ty = to_center + + acos = scale * cosv + asin = scale * sinv + + a0 = acos + a1 = -asin + a2 = tx - acos * fx + asin * fy + shift_xy[0] + + b0 = asin + b1 = acos + b2 = ty - asin * fx - acos * fy + shift_xy[1] + + rot_scale_m = np.array([ + [a0, a1, a2], + [b0, b1, b2], + [0.0, 0.0, 1.0] + ], np.float32) + return rot_scale_m + + def _transformPoints2D(self, points, matrix): + """ + points (nx2), matrix (3x3) -> points (nx2) + """ + dtype = points.dtype + + # nx3 + points = np.concatenate([points, np.ones_like(points[:, [0]])], axis=1) + points = points @ np.transpose(matrix) # nx3 + points = points[:, :2] / points[:, [2, 2]] + return points.astype(dtype) + + def _transformPerspective(self, image, matrix, target_shape): + """ + image, matrix3x3 -> transformed_image + """ + return cv2.warpPerspective( + image, matrix, + dsize=(target_shape[1], target_shape[0]), + flags=cv2.INTER_LINEAR, borderValue=0) + + def _norm_points(self, points, h, w, align_corners=False): + if align_corners: + # [0, SIZE-1] -> [-1, +1] + des_points = points / torch.tensor([w - 1, h - 1]).to(points).view(1, 2) * 2 - 1 + else: + # [-0.5, SIZE-0.5] -> [-1, +1] + des_points = (points * 2 + 1) / torch.tensor([w, h]).to(points).view(1, 2) - 1 + des_points = torch.clamp(des_points, -1, 1) + return des_points + + def _denorm_points(self, points, h, w, align_corners=False): + if align_corners: + # [-1, +1] -> [0, SIZE-1] + des_points = (points + 1) / 2 * torch.tensor([w - 1, h - 1]).to(points).view(1, 1, 2) + else: + # [-1, +1] -> [-0.5, SIZE-0.5] + des_points = ((points + 1) * torch.tensor([w, h]).to(points).view(1, 1, 2) - 1) / 2 + return des_points + + def __len__(self): + return len(self.items) + + def __getitem__(self, index): + sample = dict() + + image_path = self.items.iloc[index, 0] + landmarks_5pts = self.items.iloc[index, 1] + landmarks_5pts = np.array(list(map(float, landmarks_5pts.split(","))), dtype=np.float32).reshape(5, 2) + landmarks_target = self.items.iloc[index, 2] + landmarks_target = np.array(list(map(float, landmarks_target.split(","))), dtype=np.float32).reshape( + self.landmark_num, 2) + scale = float(self.items.iloc[index, 3]) + center_w, center_h = float(self.items.iloc[index, 4]), float(self.items.iloc[index, 5]) + if len(self.items.iloc[index]) > 6: + tags = np.array(list(map(lambda x: int(float(x)), self.items.iloc[index, 6].split(",")))) + else: + tags = np.array([]) + + # image & keypoints alignment + image_path = image_path.replace('\\', '/') + # wflw testset + image_path = image_path.replace( + '//msr-facestore/Workspace/MSRA_EP_Allergan/users/yanghuan/training_data/wflw/rawImages/', '') + # trainset + image_path = image_path.replace('./rawImages/', '') + image_path = os.path.join(self.image_dir, image_path) + + # image path + sample["image_path"] = image_path + + img = self._load_image(image_path) # HWC, BGR, [0, 255] + assert img is not None + + # augmentation + # landmarks_target = [-0.5, edge-0.5] + img, landmarks_target, matrix = \ + self.augmentation.process(img, landmarks_target, landmarks_5pts, scale, center_w, center_h) + + landmarks = self._norm_points(torch.from_numpy(landmarks_target), self.image_height, self.image_width) + + sample["label"] = [landmarks, ] + + if self.use_AAM: + pointmap = self.encoder.generate_heatmap(landmarks_target) + edgemap = self._generate_edgemap(landmarks_target) + sample["label"] += [pointmap, edgemap] + + sample['matrix'] = matrix + + # image normalization + img = img.transpose(2, 0, 1).astype(np.float32) # CHW, BGR, [0, 255] + img[0, :, :] = (img[0, :, :] - self.means[0]) * self.scale + img[1, :, :] = (img[1, :, :] - self.means[1]) * self.scale + img[2, :, :] = (img[2, :, :] - self.means[2]) * self.scale + sample["data"] = torch.from_numpy(img) # CHW, BGR, [-1, 1] + + sample["tags"] = tags + + return sample diff --git a/modelscope/models/cv/facial_68ldk_detection/lib/dataset/decoder/__init__.py b/modelscope/models/cv/facial_68ldk_detection/lib/dataset/decoder/__init__.py new file mode 100644 index 00000000..c5d450d1 --- /dev/null +++ b/modelscope/models/cv/facial_68ldk_detection/lib/dataset/decoder/__init__.py @@ -0,0 +1,8 @@ +from .decoder_default import decoder_default + +def get_decoder(decoder_type='default'): + if decoder_type == 'default': + decoder = decoder_default() + else: + raise NotImplementedError + return decoder \ No newline at end of file diff --git a/modelscope/models/cv/facial_68ldk_detection/lib/dataset/decoder/__pycache__/__init__.cpython-312.pyc b/modelscope/models/cv/facial_68ldk_detection/lib/dataset/decoder/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..52acc89983c9871239b40ea8975da4b957ebdd84 GIT binary patch literal 447 zcmX|-KTE?v6u{q0T2pOHp;-i%RzVDi=LZlc9bB@wbqO(dZKFvOE>|#6p@@T{ll=_h zM{yBdBrmc|t)Gwn#6g>k?_HWG}UavpI@%Nk`9B8{1Pl(&>9Sf{f(A;TzS zWRSW6yCyM@E}171G8~8Q$n^&v5iAiT@Gl5;g_|%z3IK5&f8-0tIf&D&K43x)nUlF% zpK2)SN;QQK!+c2JjLv7f``+HUH|A^5FsJrXht~FMt-Fv#U|Yzm(iWrSh$rB6nd0kG ft!hVMM8^R;=1m!@1trRv>xlRT`^!od&Aj{%h*xS) literal 0 HcmV?d00001 diff --git a/modelscope/models/cv/facial_68ldk_detection/lib/dataset/decoder/__pycache__/__init__.cpython-37.pyc b/modelscope/models/cv/facial_68ldk_detection/lib/dataset/decoder/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3aa95757c4003fbf2f92012e8001553764e61fca GIT binary patch literal 399 zcmYjN!A`?442`q0RqE(q>Oy^tS32!S|osgSt!QkB{pWoc8T8KTm-0N=nr@Jl_y ziC^G^Q*F{L`Pqq|{hVA)r@Mmf^yG8)&GE+{Ha6nqlD$113nmx`w>mp#LT8n4A9Y)T60L&AVLFi)yTSqQbQb z>6x@?l+J6ca=YMl9T!SdD_uS)%w67+W7;rGWm#F5F3ZlEuHT!JWBO3=>$MSsfCwTP hfc1wYhV8|NyJ4Fx2$|PM=as>wrVIZ!t$*Z1{sXIVUo8Lt literal 0 HcmV?d00001 diff --git a/modelscope/models/cv/facial_68ldk_detection/lib/dataset/decoder/__pycache__/__init__.cpython-39.pyc b/modelscope/models/cv/facial_68ldk_detection/lib/dataset/decoder/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cb6ba801d573e927416504181397e66e3ebc0ca6 GIT binary patch literal 396 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 literal 0 HcmV?d00001 diff --git a/modelscope/models/cv/facial_68ldk_detection/lib/dataset/decoder/decoder_default.py b/modelscope/models/cv/facial_68ldk_detection/lib/dataset/decoder/decoder_default.py new file mode 100644 index 00000000..7b0b4edd --- /dev/null +++ b/modelscope/models/cv/facial_68ldk_detection/lib/dataset/decoder/decoder_default.py @@ -0,0 +1,38 @@ +import torch + + +class decoder_default: + def __init__(self, weight=1, use_weight_map=False): + self.weight = weight + self.use_weight_map = use_weight_map + + def _make_grid(self, h, w): + yy, xx = torch.meshgrid( + torch.arange(h).float() / (h - 1) * 2 - 1, + torch.arange(w).float() / (w - 1) * 2 - 1) + return yy, xx + + def get_coords_from_heatmap(self, heatmap): + """ + inputs: + - heatmap: batch x npoints x h x w + + outputs: + - coords: batch x npoints x 2 (x,y), [-1, +1] + - radius_sq: batch x npoints + """ + batch, npoints, h, w = heatmap.shape + if self.use_weight_map: + heatmap = heatmap * self.weight + + yy, xx = self._make_grid(h, w) + yy = yy.view(1, 1, h, w).to(heatmap) + xx = xx.view(1, 1, h, w).to(heatmap) + + heatmap_sum = torch.clamp(heatmap.sum([2, 3]), min=1e-6) + + yy_coord = (yy * heatmap).sum([2, 3]) / heatmap_sum # batch x npoints + xx_coord = (xx * heatmap).sum([2, 3]) / heatmap_sum # batch x npoints + coords = torch.stack([xx_coord, yy_coord], dim=-1) + + return coords diff --git a/modelscope/models/cv/facial_68ldk_detection/lib/dataset/encoder/__init__.py b/modelscope/models/cv/facial_68ldk_detection/lib/dataset/encoder/__init__.py new file mode 100644 index 00000000..42d0b6f9 --- /dev/null +++ b/modelscope/models/cv/facial_68ldk_detection/lib/dataset/encoder/__init__.py @@ -0,0 +1,8 @@ +from .encoder_default import encoder_default + +def get_encoder(image_height, image_width, scale=0.25, sigma=1.5, encoder_type='default'): + if encoder_type == 'default': + encoder = encoder_default(image_height, image_width, scale, sigma) + else: + raise NotImplementedError + return encoder diff --git a/modelscope/models/cv/facial_68ldk_detection/lib/dataset/encoder/__pycache__/__init__.cpython-312.pyc b/modelscope/models/cv/facial_68ldk_detection/lib/dataset/encoder/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e5935921dba552e1aa682f52fbf0ee163e3a5307 GIT binary patch literal 526 zcmXv~JxIeq6n>X9O|h+2y9h4oAO^%+9sF5z(4mXCxP+LyCefrRmn#~GAmZTYWLH;l zaddQd5nbfa$;qwI4${fHntt$pzPtB6KHf{UIsp<(bGOY61n{lM7+T)+XJyj`0tAH+ z!66_Z1)^P{LzL>4@gw)ZLZU`nZcHe%32i!^kh{iMNYX!f=-qJ*c4aW zBV>@FOw06#!aqMZGGib3*aci7OKS)-SGP2#^hCW8^WCT&(ulS=B|D78%qogX5IG*T zeHwT^7v+C;8W8RaBXOOO$`W{yBPwIpJZ)29<}6Wu=SLWBV?T~4_ENcZhTAMYrY=vg z--(=-6L>D>G~qZ5jxce!lTeOx5p3H*E8w=h+D=8;qukCv*rZff?h{L<3-~bWH|d)> z|2ea8xAItiI(XiBpV_-Mdqt?!FB$_KYKyO>g}xkyhNXL|0=#bJ&F>adr_L`j62Avl klTWNF)3CH2#iSF`O*Sp5x_6@9dpbhs3swdN1Jy_4e?mfpbN~PV literal 0 HcmV?d00001 diff --git a/modelscope/models/cv/facial_68ldk_detection/lib/dataset/encoder/__pycache__/__init__.cpython-37.pyc b/modelscope/models/cv/facial_68ldk_detection/lib/dataset/encoder/__pycache__/__init__.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..285c6954fd48e3afba15b7f0a61684b9a8ede3e3 GIT binary patch literal 476 zcmYjOu};G<5Vg~!4Kx)!8#)RXSrJ3pU&KA(?9n*{A}|806g3Hh|izx9xuq1Sr|f(V+Ef<%N8;R{dn zUui_e;D&@7-&jdP+HOIaC;>VaFy-^yeBm3mygkO`Amp?V!uviME6Jy=IvzfTatpcx07UcaWHx3Al$` zRV?SFD7c>Ciwz1=l`NOHOmM?%FswU_#jz}8z)?kR6TK~9EVxGgP{fXMnC2;-#0{wOp literal 0 HcmV?d00001 diff --git a/modelscope/models/cv/facial_68ldk_detection/lib/dataset/encoder/__pycache__/__init__.cpython-39.pyc b/modelscope/models/cv/facial_68ldk_detection/lib/dataset/encoder/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..47c30144bcb688907b158672c0955e33fbc7698c GIT binary patch literal 473 zcmYjOu};G<5Vg~!4YUYy9uBu950e*%bVPas; z%7FL-#KgG`Qct>f_xybJ`ON$MLxT49K3H5*LOu=Iw-%CX^zsZr5J6KSiBBjIu5d*A zh5A%<=EOVr#%kix`UtWx7oY+G3%*MA7cQfH44dRv&jq6PTb*EvkM418oPMFLzTjy$77CZzNuO!b#)0;6X zRQ>>=X7jtzElZPoCb;G$Xx5y-f*{Ef9R%martU_dgGMl;EnNgcU3zTURP`{Qc`aoW fWgFOg;8xu>vj<(=RJ#{47poMm%omhq7(MF`Z)b6d literal 0 HcmV?d00001 diff --git a/modelscope/models/cv/facial_68ldk_detection/lib/dataset/encoder/__pycache__/encoder_default.cpython-312.pyc b/modelscope/models/cv/facial_68ldk_detection/lib/dataset/encoder/__pycache__/encoder_default.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3fc06e7f4fe9e7eb41a5d338f8fdb03aac3e3fdd GIT binary patch literal 4343 zcmbVPTWk~Q6`rdvi5*{JlM9zzAOTarxj?c|7VvTlU5E&jEu^iiiD%;2*kflr7D+m; z_JNg#?N+tBtHwzCV5*gBi>L&(Qo~cTZ&|eu9!!;JHqu7gl`7s4Ahp_;_WU!RI7y*w zJCgr%`Oi83`ETd@{TI8v4uh|I`)|f^;J!wJ@ljRg#XG>vVl2kuF>F+)_$Z;t_|DAkShPHj1+t#HLyN zHV&~N$|%K}SP~?9n(~=d2gipJEGGn6Zk$QS#1Oq99tuao@5ON~oPT+%0H2gGdvRshx{U!68*8r zn4e`tCdG;V>Rb(K%=u7qTD1g&5k4XYgEP%rR^*V;qYd8iva?1)fUnO?JOo?QDm~^1MNniYHxve)@Y1%g`bkQTw9Wi8Lgg!q$;tLPU$IeNmgi)#w~y;;bJfIW5zy6CP00lGrBr-E#c!!rO^P!~P()OVA*r-(g|4ht{h$%*k-Ia@!Ng$* zsH=VY%PO)*Ow?j&{Y-Uf8qT*{5{&$-OeZ;@Ku!S6$maN#zGV z{#nJf`#EN@?v(?pO)axixv7Gy5Ga`D#vVjV(I-tu<)Lpp&9j$smkQlQ*F9gwb3i`3 z+SHow{WMhQC@}ZBir(U6skySNuhP^npUrmM8G1waO4IgPDJK<%irm8CKOcK^EGt!- z&dEb-Ht(`+hhp22zy3E{_cIqH_0o-bn`Vb{L-`xUktZJie3#-GgycOf%bq=oXHVfq z#p7T098o++DxSe*PeAbm7CS1QGswoPW$pW8|NNvr&cmNq`p^B9Tndyg|8V*8sB(Gq zi{Z-9kIQ{ODTm@KJx5-WxOecY!4nT}{bBkUiCNuij^?tZS+K)`ZURmOTw1+91@{5! zJ;~zeZb4nH0VbhWL5W5+asAe9?APkt=Ke4N)p(dSq&2kg0>n)C^=h zg=gwBHmL0MO{lDbe?vyEKu*aj)uTNHU&uwOlWa8!?NB|MA*uJGc_M@`b}eJ)cS3c3 zLxgp2hz1A)qi85&ui-STN_AK3F$0T4m$4$oj!3WGL2X|QFCz|`!#I&?*fNG@`mq1jf)aBLZ4(`(`Xn+0U<+!A%uEH_2{&Ur&r7i*U6lB0Tq9Qv95fRGxhng&Co zpDDE8@LqCNdtFAaB=b3aW6=C?l>-+l8 zlTZHzoX;x2A;kc#CK!NL^yC2q)1XjjMS_{;#pt3mTtW$0ITl5358{ z)UmHF#*A^XAVO)?BF2+J4SI=mOeMwy0lo87d`iWqRbr|~C8m2+Jgk!8AmC^?2)GEb zfY-=$$_>^Ac-5!|V*+{~%`|OAt||<7LT4%olLo+QY|i)Qj>?wR23NK-JCf_l?^E2J zm4@A)T`jtcfs%K=S@9jMbR8?(zb_M;tqLQGySvh`cdoH`WgahGo4>9ce0vdB4hAZ| zcgptDGO=Q7kSFh)&7PjUkh_p)au*A|fFh4=dx}J{w?xmAf3iNbE_6J!ElessrylP+ zwc>PVdvkOi&sp<>o0pxMy2)t#TYd4m9p<`Hq~gY}qao@|CrEZ@%?$ z{q9w#d)AaQ<$LqO-GKsg_h7NND3k`~nbJX}b+Fv@)H)R)G1XKem6GD)hli;Ye}!17FEEA1EED zv<;S>gEGDP-OSbw4=!{poLnwD$JYF1Ubhh}x(JCah7yJmhn_B44&Pdi>v^9Lu7VD|F;b{3JR@-&{}QYJ5_5lz V*}lTs%2?Y!OoMpia|{~I|KF5~!4Cic literal 0 HcmV?d00001 diff --git a/modelscope/models/cv/facial_68ldk_detection/lib/dataset/encoder/__pycache__/encoder_default.cpython-37.pyc b/modelscope/models/cv/facial_68ldk_detection/lib/dataset/encoder/__pycache__/encoder_default.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c8708528ea2072622da5a8a3be0b29537f7802bd GIT binary patch literal 2296 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 literal 0 HcmV?d00001 diff --git a/modelscope/models/cv/facial_68ldk_detection/lib/dataset/encoder/encoder_default.py b/modelscope/models/cv/facial_68ldk_detection/lib/dataset/encoder/encoder_default.py new file mode 100644 index 00000000..92c22b13 --- /dev/null +++ b/modelscope/models/cv/facial_68ldk_detection/lib/dataset/encoder/encoder_default.py @@ -0,0 +1,63 @@ +import copy +import numpy as np + +import torch +import torch.nn.functional as F + + +class encoder_default: + def __init__(self, image_height, image_width, scale=0.25, sigma=1.5): + self.image_height = image_height + self.image_width = image_width + self.scale = scale + self.sigma = sigma + + def generate_heatmap(self, points): + # points = (num_pts, 2) + h, w = self.image_height, self.image_width + pointmaps = [] + for i in range(len(points)): + pointmap = np.zeros([h, w], dtype=np.float32) + # align_corners: False. + point = copy.deepcopy(points[i]) + point[0] = max(0, min(w - 1, point[0])) + point[1] = max(0, min(h - 1, point[1])) + pointmap = self._circle(pointmap, point, sigma=self.sigma) + + pointmaps.append(pointmap) + pointmaps = np.stack(pointmaps, axis=0) / 255.0 + pointmaps = torch.from_numpy(pointmaps).float().unsqueeze(0) + pointmaps = F.interpolate(pointmaps, size=(int(w * self.scale), int(h * self.scale)), mode='bilinear', + align_corners=False).squeeze() + return pointmaps + + def _circle(self, img, pt, sigma=1.0, label_type='Gaussian'): + # Check that any part of the gaussian is in-bounds + tmp_size = sigma * 3 + ul = [int(pt[0] - tmp_size), int(pt[1] - tmp_size)] + br = [int(pt[0] + tmp_size + 1), int(pt[1] + tmp_size + 1)] + if (ul[0] > img.shape[1] - 1 or ul[1] > img.shape[0] - 1 or + br[0] - 1 < 0 or br[1] - 1 < 0): + # If not, just return the image as is + return img + + # Generate gaussian + size = 2 * tmp_size + 1 + x = np.arange(0, size, 1, np.float32) + y = x[:, np.newaxis] + x0 = y0 = size // 2 + # The gaussian is not normalized, we want the center value to equal 1 + if label_type == 'Gaussian': + g = np.exp(- ((x - x0) ** 2 + (y - y0) ** 2) / (2 * sigma ** 2)) + else: + g = sigma / (((x - x0) ** 2 + (y - y0) ** 2 + sigma ** 2) ** 1.5) + + # Usable gaussian range + g_x = max(0, -ul[0]), min(br[0], img.shape[1]) - ul[0] + g_y = max(0, -ul[1]), min(br[1], img.shape[0]) - ul[1] + # Image range + img_x = max(0, ul[0]), min(br[0], img.shape[1]) + img_y = max(0, ul[1]), min(br[1], img.shape[0]) + + img[img_y[0]:img_y[1], img_x[0]:img_x[1]] = 255 * g[g_y[0]:g_y[1], g_x[0]:g_x[1]] + return img diff --git a/modelscope/models/cv/facial_68ldk_detection/lib/utility.py b/modelscope/models/cv/facial_68ldk_detection/lib/utility.py new file mode 100644 index 00000000..825f2ebc --- /dev/null +++ b/modelscope/models/cv/facial_68ldk_detection/lib/utility.py @@ -0,0 +1,52 @@ +import json +import os.path as osp +import time +import torch +import numpy as np + +# private package +from ..conf import * +from .backbone import StackedHGNetV1 + + +def get_config(args): + config = None + config_name = args.config_name + if config_name == "alignment": + config = Alignment(args) + else: + assert NotImplementedError + + return config + + +def get_net(config): + net = None + if config.net == "stackedHGnet_v1": + net = StackedHGNetV1(config=config, + classes_num=config.classes_num, + edge_info=config.edge_info, + nstack=config.nstack, + add_coord=config.add_coord, + decoder_type=config.decoder_type) + else: + assert False + return net + + +def set_environment(config): + if config.device_id >= 0: + assert torch.cuda.is_available() and torch.cuda.device_count() > config.device_id + torch.cuda.empty_cache() + config.device = torch.device("cuda", config.device_id) + config.use_gpu = True + else: + config.device = torch.device("cpu") + config.use_gpu = False + + torch.set_default_dtype(torch.float32) + torch.set_default_tensor_type(torch.FloatTensor) + torch.set_flush_denormal(True) # ignore extremely small value + torch.backends.cudnn.benchmark = True # This flag allows you to enable the inbuilt cudnn auto-tuner to find the best algorithm to use for your hardware. + torch.autograd.set_detect_anomaly(True) + diff --git a/modelscope/models/cv/facial_68ldk_detection/star_model.py b/modelscope/models/cv/facial_68ldk_detection/star_model.py new file mode 100644 index 00000000..25996708 --- /dev/null +++ b/modelscope/models/cv/facial_68ldk_detection/star_model.py @@ -0,0 +1,34 @@ +# Copyright (c) Alibaba, Inc. and its affiliates. +import os + +import numpy as np +import torch +import cv2 +import matplotlib.pyplot as plt + +from modelscope.metainfo import Models +from modelscope.models.base.base_torch_model import TorchModel +from modelscope.models.builder import MODELS +from modelscope.preprocessors import LoadImage +from modelscope.models.cv.facial_68ldk_detection import infer +from modelscope.outputs import OutputKeys +from modelscope.utils.constant import ModelFile, Tasks +from modelscope.utils.logger import get_logger + +logger = get_logger() + +@MODELS.register_module( + Tasks.facial_68ldk_detection, module_name=Models.star_68ldk_detection) +class FaceLandmarkDetection(TorchModel): + + def __init__(self, model_dir, *args, **kwargs): + super().__init__(model_dir, *args, **kwargs) + + def forward(self, Inputs): + return Inputs + + def postprocess(self, Inputs): + return Inputs + + def inference(self, data): + return data \ No newline at end of file diff --git a/modelscope/pipelines/cv/facial_68ldk_detection_pipeline.py b/modelscope/pipelines/cv/facial_68ldk_detection_pipeline.py new file mode 100644 index 00000000..60d0866b --- /dev/null +++ b/modelscope/pipelines/cv/facial_68ldk_detection_pipeline.py @@ -0,0 +1,87 @@ +# Copyright (c) Alibaba, Inc. and its affiliates. +from typing import Any, Dict, Union + + +import numpy as np +import torch +import cv2 +import argparse +import os + +from modelscope.metainfo import Pipelines +from modelscope.outputs import OutputKeys +from modelscope.pipelines.base import Input, Model, Pipeline +from modelscope.pipelines.builder import PIPELINES +from modelscope.preprocessors import LoadImage +from modelscope.models.cv.facial_68ldk_detection import infer +from modelscope.outputs import OutputKeys +from modelscope.utils.constant import ModelFile, Tasks +from modelscope.utils.logger import get_logger + +logger = get_logger() + +@PIPELINES.register_module( + Tasks.facial_68ldk_detection, module_name=Pipelines.facial_68ldk_detection) +class FaceLandmarkDetectionPipeline(Pipeline): + + def __init__(self, model: str, **kwargs): + """ + use `model` to create a image depth prediction pipeline for prediction + Args: + model: model id on modelscope hub. + """ + super().__init__(model=model, **kwargs) + + parser = argparse.ArgumentParser(description="Evaluation script") + args = parser.parse_args() + args.config_name = 'alignment' + + device_ids = list() + if torch.cuda.is_available(): + device_ids = [0] + else: + device_ids = [-1] + + model_path = os.path.join(model, 'pytorch_model.pkl') + + self.fld = infer.Alignment(args, model_path, dl_framework="pytorch", device_ids=device_ids) + + logger.info('Face 2d landmark detection model, pipeline init') + + def preprocess(self, input: Input) -> Dict[str, Any]: + print('start preprocess') + + image = LoadImage.convert_to_ndarray(input) + image = cv2.resize(image, (256, 256)) + + data = {'image': image} + + print('finish preprocess') + + return data + + def forward(self, input: Dict[str, Any]) -> Dict[str, Any]: + print('start infer') + + image = input['image'] + + if torch.cuda.is_available(): + image_np = image.cpu().numpy() + else: + image_np = image.numpy() + + x1, y1, x2, y2 = 0, 0, 256, 256 + scale = max(x2 - x1, y2 - y1) / 180 + center_w = (x1 + x2) / 2 + center_h = (y1 + y2) / 2 + scale, center_w, center_h = float(scale), float(center_w), float(center_h) + + results = self.fld.analyze(image_np, scale, center_w, center_h) + + print('finish infer') + + return results + + def postprocess(self, inputs: Dict[str, Any]) -> Dict[str, Any]: + outputs = {'landmarks': inputs} + return outputs diff --git a/modelscope/utils/constant.py b/modelscope/utils/constant.py index 9fcaf71c..ae2f647c 100644 --- a/modelscope/utils/constant.py +++ b/modelscope/utils/constant.py @@ -36,6 +36,7 @@ class CVTasks(object): face_processing_base = 'face-processing-base' face_attribute_recognition = 'face-attribute-recognition' face_2d_keypoints = 'face-2d-keypoints' + facial_68ldk_detection = 'facial-68ldk-detection' human_detection = 'human-detection' human_object_interaction = 'human-object-interaction' face_image_generation = 'face-image-generation'