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 2 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.preprocessors import LoadImage
from modelscope.utils.constant import ModelFile, Tasks
from modelscope.utils.logger import get_logger
from .base import EasyCVPipeline

logger = get_logger()


@PIPELINES.register_module(
Tasks.face_2d_keypoints, module_name=Pipelines.face_2d_keypoints)
@@ -110,67 +113,29 @@ class Face2DKeypointsPipeline(EasyCVPipeline):
for (x, y) in 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):
image_size = 256
enlarge_ratio = 1.1

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

x1 = pts[5][0]
x2 = pts[5][0]
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
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

x1 = np.min(pts[:, 0])
@@ -181,94 +146,87 @@ class Face2DKeypointsPipeline(EasyCVPipeline):
h = y2 - y1 + 1
x1 = int(x1 - (enlarge_ratio - 1.0) / 2.0 * w)
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_y2 = new_y1 + new_h

new_xy = new_x1, new_y1
pts = pts - new_xy

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]
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)
h, w, c = img.shape
img_rgb = copy.deepcopy(img)
img_rgb = img_rgb[:, :, ::-1]
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)

output_boxes = []
output_keypoints = []
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])
y1 = int(box[3])
x0 = int(box[0])
x1 = int(box[2])
sub_img = img[y0:y1, x0:x1]

keypoint = keypoints[idx]
keypoint = keypoints[index]
pts = [[keypoint[0], keypoint[1]], [keypoint[2], keypoint[3]],
[keypoint[4], keypoint[5]], [keypoint[6], keypoint[7]],
[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
angle = math.atan2((pts[1][1] - pts[0][1]),
(pts[1][0] - pts[0][0]))
# angle
theta = angle * (180 / np.pi)

center = [image_size // 2, image_size // 2]
center = [w // 2, h // 2]
cx, cy = center
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']

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]
tmp_keypoints = outputs['point']
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),
tmp_keypoints)


Loading…
Cancel
Save