Browse Source

Merge branch dev_face2d_fixbug into master

Title: [to #42322933]fix no face bug and adaptive for 360 degree of head 
        Link: https://code.alibaba-inc.com/Ali-MaaS/MaaS-lib/codereview/10599588
master
yingda.chen 3 years ago
parent
commit
e863fce7e8
1 changed files with 53 additions and 95 deletions
  1. +53
    -95
      modelscope/pipelines/cv/easycv_pipelines/face_2d_keypoints_pipeline.py

+ 53
- 95
modelscope/pipelines/cv/easycv_pipelines/face_2d_keypoints_pipeline.py View File

@@ -12,8 +12,11 @@ from modelscope.pipelines import pipeline
from modelscope.pipelines.builder import PIPELINES from modelscope.pipelines.builder import PIPELINES
from modelscope.preprocessors import LoadImage from modelscope.preprocessors import LoadImage
from modelscope.utils.constant import ModelFile, Tasks from modelscope.utils.constant import ModelFile, Tasks
from modelscope.utils.logger import get_logger
from .base import EasyCVPipeline from .base import EasyCVPipeline


logger = get_logger()



@PIPELINES.register_module( @PIPELINES.register_module(
Tasks.face_2d_keypoints, module_name=Pipelines.face_2d_keypoints) Tasks.face_2d_keypoints, module_name=Pipelines.face_2d_keypoints)
@@ -110,67 +113,29 @@ class Face2DKeypointsPipeline(EasyCVPipeline):
for (x, y) in landmark]) for (x, y) in landmark])
return M, landmark_ return M, landmark_


def random_normal(self):
"""
3-sigma rule
return: (-1, +1)
"""
mu, sigma = 0, 1
while True:
s = np.random.normal(mu, sigma)
if s < mu - 3 * sigma or s > mu + 3 * sigma:
continue
return s / 3 * sigma

def rotate_crop_img(self, img, pts, M): def rotate_crop_img(self, img, pts, M):
image_size = 256
enlarge_ratio = 1.1

imgT = cv2.warpAffine(img, M, (int(img.shape[1]), int(img.shape[0]))) imgT = cv2.warpAffine(img, M, (int(img.shape[1]), int(img.shape[0])))


x1 = pts[5][0] x1 = pts[5][0]
x2 = pts[5][0]
y1 = pts[5][1] y1 = pts[5][1]
x2 = pts[6][0]
y2 = pts[6][1]
w = x2 - x1 + 1
h = y2 - y1 + 1
x1 = int(x1 - (enlarge_ratio - 1.0) / 2.0 * w)
y1 = int(y1 - (enlarge_ratio - 1.0) / 2.0 * h)

new_w = int(enlarge_ratio * (1 + self.random_normal() * 0.1) * w)
new_h = int(enlarge_ratio * (1 + self.random_normal() * 0.1) * h)
new_x1 = x1 + int(self.random_normal() * image_size * 0.05)
new_y1 = y1 + int(self.random_normal() * image_size * 0.05)
new_x2 = new_x1 + new_w
new_y2 = new_y1 + new_h
y2 = pts[5][1]
for i in range(0, 9):
x1 = min(x1, pts[i][0])
x2 = max(x2, pts[i][0])
y1 = min(y1, pts[i][1])
y2 = max(y2, pts[i][1])


height, width, _ = imgT.shape height, width, _ = imgT.shape
dx = max(0, -new_x1)
dy = max(0, -new_y1)
new_x1 = max(0, new_x1)
new_y1 = max(0, new_y1)
x1 = min(max(0, int(x1)), width)
y1 = min(max(0, int(y1)), height)
x2 = min(max(0, int(x2)), width)
y2 = min(max(0, int(y2)), height)
sub_imgT = imgT[y1:y2, x1:x2]


edx = max(0, new_x2 - width)
edy = max(0, new_y2 - height)
new_x2 = min(width, new_x2)
new_y2 = min(height, new_y2)
return sub_imgT, imgT, [x1, y1, x2, y2]


sub_imgT = imgT[new_y1:new_y2, new_x1:new_x2]
if dx > 0 or dy > 0 or edx > 0 or edy > 0:
sub_imgT = cv2.copyMakeBorder(
sub_imgT,
dy,
edy,
dx,
edx,
cv2.BORDER_CONSTANT,
value=(103.94, 116.78, 123.68))

return sub_imgT, imgT, [new_x1, new_y1, new_x2,
new_y2], [dx, dy, edx, edy]

def crop_img(self, imgT, pts, angle):
image_size = 256
def crop_img(self, imgT, pts):
enlarge_ratio = 1.1 enlarge_ratio = 1.1


x1 = np.min(pts[:, 0]) x1 = np.min(pts[:, 0])
@@ -181,94 +146,87 @@ class Face2DKeypointsPipeline(EasyCVPipeline):
h = y2 - y1 + 1 h = y2 - y1 + 1
x1 = int(x1 - (enlarge_ratio - 1.0) / 2.0 * w) x1 = int(x1 - (enlarge_ratio - 1.0) / 2.0 * w)
y1 = int(y1 - (enlarge_ratio - 1.0) / 2.0 * h) y1 = int(y1 - (enlarge_ratio - 1.0) / 2.0 * h)
x1 = max(0, x1)
y1 = max(0, y1)


new_w = int(enlarge_ratio * (1 + self.random_normal() * 0.1) * w)
new_h = int(enlarge_ratio * (1 + self.random_normal() * 0.1) * h)
new_x1 = x1 + int(self.random_normal() * image_size * 0.05)
new_y1 = y1 + int(self.random_normal() * image_size * 0.05)
new_w = int(enlarge_ratio * w)
new_h = int(enlarge_ratio * h)
new_x1 = x1
new_y1 = y1
new_x2 = new_x1 + new_w new_x2 = new_x1 + new_w
new_y2 = new_y1 + new_h new_y2 = new_y1 + new_h


new_xy = new_x1, new_y1
pts = pts - new_xy

height, width, _ = imgT.shape height, width, _ = imgT.shape
dx = max(0, -new_x1)
dy = max(0, -new_y1)
new_x1 = max(0, new_x1)
new_y1 = max(0, new_y1)


edx = max(0, new_x2 - width)
edy = max(0, new_y2 - height)
new_x2 = min(width, new_x2)
new_y2 = min(height, new_y2)
new_x1 = min(max(0, new_x1), width)
new_y1 = min(max(0, new_y1), height)
new_x2 = max(min(width, new_x2), 0)
new_y2 = max(min(height, new_y2), 0)


sub_imgT = imgT[new_y1:new_y2, new_x1:new_x2] sub_imgT = imgT[new_y1:new_y2, new_x1:new_x2]
if dx > 0 or dy > 0 or edx > 0 or edy > 0:
sub_imgT = cv2.copyMakeBorder(
sub_imgT,
dy,
edy,
dx,
edx,
cv2.BORDER_CONSTANT,
value=(103.94, 116.78, 123.68))

return sub_imgT, [new_x1, new_y1, new_x2, new_y2], [dx, dy, edx, edy]


def __call__(self, inputs) -> Any:
image_size = 256
return sub_imgT, [new_x1, new_y1, new_x2, new_y2]


def __call__(self, inputs) -> Any:
img = LoadImage.convert_to_ndarray(inputs) img = LoadImage.convert_to_ndarray(inputs)
h, w, c = img.shape h, w, c = img.shape
img_rgb = copy.deepcopy(img) img_rgb = copy.deepcopy(img)
img_rgb = img_rgb[:, :, ::-1] img_rgb = img_rgb[:, :, ::-1]
det_result = self.face_detection(img_rgb) det_result = self.face_detection(img_rgb)

bboxes = np.array(det_result[OutputKeys.BOXES])
if bboxes.shape[0] == 0:
logger.warn('No face detected!')
results = {
OutputKeys.KEYPOINTS: [],
OutputKeys.POSES: [],
OutputKeys.BOXES: []
}
return results

boxes, keypoints = self._choose_face(det_result) boxes, keypoints = self._choose_face(det_result)


output_boxes = [] output_boxes = []
output_keypoints = [] output_keypoints = []
output_poses = [] output_poses = []
for idx, box_ori in enumerate(boxes):
box = self.expend_box(box_ori, w, h, scalex=0.15, scaley=0.15)
for index, box_ori in enumerate(boxes):
box = self.expend_box(box_ori, w, h, scalex=0.1, scaley=0.1)
y0 = int(box[1]) y0 = int(box[1])
y1 = int(box[3]) y1 = int(box[3])
x0 = int(box[0]) x0 = int(box[0])
x1 = int(box[2]) x1 = int(box[2])
sub_img = img[y0:y1, x0:x1] sub_img = img[y0:y1, x0:x1]


keypoint = keypoints[idx]
keypoint = keypoints[index]
pts = [[keypoint[0], keypoint[1]], [keypoint[2], keypoint[3]], pts = [[keypoint[0], keypoint[1]], [keypoint[2], keypoint[3]],
[keypoint[4], keypoint[5]], [keypoint[6], keypoint[7]], [keypoint[4], keypoint[5]], [keypoint[6], keypoint[7]],
[keypoint[8], keypoint[9]], [box[0], box[1]], [keypoint[8], keypoint[9]], [box[0], box[1]],
[box[2], box[3]]]
[box[2], box[1]], [box[0], box[3]], [box[2], box[3]]]
# radian # radian
angle = math.atan2((pts[1][1] - pts[0][1]), angle = math.atan2((pts[1][1] - pts[0][1]),
(pts[1][0] - pts[0][0])) (pts[1][0] - pts[0][0]))
# angle # angle
theta = angle * (180 / np.pi) theta = angle * (180 / np.pi)


center = [image_size // 2, image_size // 2]
center = [w // 2, h // 2]
cx, cy = center cx, cy = center
M, landmark_ = self.rotate_point(theta, (cx, cy), pts) M, landmark_ = self.rotate_point(theta, (cx, cy), pts)
sub_img, imgT, bbox, delta_border = self.rotate_crop_img(
img, pts, M)
sub_imgT, imgT, bbox = self.rotate_crop_img(img, landmark_, M)


outputs = self.predict_op([sub_img])[0]
outputs = self.predict_op([sub_imgT])[0]
tmp_keypoints = outputs['point'] tmp_keypoints = outputs['point']


for idx in range(0, len(tmp_keypoints)): for idx in range(0, len(tmp_keypoints)):
tmp_keypoints[idx][0] += (delta_border[0] + bbox[0])
tmp_keypoints[idx][1] += (delta_border[1] + bbox[1])
tmp_keypoints[idx][0] += bbox[0]
tmp_keypoints[idx][1] += bbox[1]


for idx in range(0, 3):
sub_img, bbox, delta_border = self.crop_img(
imgT, tmp_keypoints, 0)
for idx in range(0, 6):
sub_img, bbox = self.crop_img(imgT, tmp_keypoints)
outputs = self.predict_op([sub_img])[0] outputs = self.predict_op([sub_img])[0]
tmp_keypoints = outputs['point'] tmp_keypoints = outputs['point']
for idx in range(0, len(tmp_keypoints)): for idx in range(0, len(tmp_keypoints)):
tmp_keypoints[idx][0] += (delta_border[0] + bbox[0])
tmp_keypoints[idx][1] += (delta_border[1] + bbox[1])
tmp_keypoints[idx][0] += bbox[0]
tmp_keypoints[idx][1] += bbox[1]


M2, tmp_keypoints = self.rotate_point(-theta, (cx, cy), M2, tmp_keypoints = self.rotate_point(-theta, (cx, cy),
tmp_keypoints) tmp_keypoints)


Loading…
Cancel
Save