diff --git a/applications/wyw2s_local_app.py b/applications/wyw2s_local_app.py new file mode 100644 index 0000000000000000000000000000000000000000..38d2b0f859dc04f36f11e1d3b8baa96a27c4330a --- /dev/null +++ b/applications/wyw2s_local_app.py @@ -0,0 +1,196 @@ +#-*-coding:utf-8-*- +''' +DpCas-Light +|||| ||||| |||| || ||||||| +|| || || || || || |||| || || +|| || || || || || || || || +|| || || || || ||====|| |||||| +|| || ||||| || || ||======|| || +|| || || || || || || || || +|||| || |||| || || ||||||| + +/--------------------- Who You Want To See ---------------------/ +''' +# date:2021-04-18 +# Author: Eric.Lee +# function: who you want to see "你想看谁" + +import os +import cv2 +import time + +from multiprocessing import Process +from multiprocessing import Manager + +import cv2 +import numpy as np +import random +import time + +# 加载模型组件库 +from face_detect.yolo_v3_face import yolo_v3_face_model +from insight_face.face_verify import insight_face_model +from face_multi_task.face_multi_task_component import FaceMuitiTask_Model +from face_euler_angle.face_euler_angle_component import FaceAngle_Model +# 加载工具库 +import sys +sys.path.append("./lib/wyw2s_lib/") +from cores.wyw2s_fuction import get_faces_batch_attribute +from utils.utils import parse_data_cfg +from utils.show_videos_thread import run_show +from moviepy.editor import * + + +def main_wyw2s(cfg_file,video_path = None): + + config = parse_data_cfg(cfg_file) + + face_detect_model = yolo_v3_face_model(conf_thres = 0.43) + face_verify_model = insight_face_model(threshold = 1.2) + face_multitask_model = FaceMuitiTask_Model() + face_euler_model = FaceAngle_Model() + + + print("\n/------------------------------------------------------------------------/\n") + YouWantToSee = config["YouWantToSee"] + YouWantToSee_=[name_ for name_ in YouWantToSee.split(",")] + print(" YouWantToSee : {}".format(YouWantToSee_)) + print("\n/------------------------------------------------------------------------/\n") + + p_colors = [] + for i in range(len(face_verify_model.face_names)): + if i == 0 : + p_colors.append((100,155,100)) + if i == 1 : + p_colors.append((0,255,0)) + elif i == 2: + p_colors.append((255,0,0)) + elif i == 3: + p_colors.append((0,255,255)) + elif i == 4: + p_colors.append((0,185,255)) + elif i == 5: + p_colors.append((255,185,55)) + else: + p_colors.append((random.randint(60,255),random.randint(70,255),random.randint(130,255))) + + + cap = cv2.VideoCapture(video_path) + + frame_count = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) + # 时间轴 + time_map = np.zeros([200,frame_count,3]).astype(np.uint8) + time_map[:,:,0].fill(105) + time_map[:,:,1].fill(105) + time_map[:,:,2].fill(105) + + pts_last = None + frame_idx = 0 + Flag_Last,Flag_Now = False,False + start_time = 0. + end_time = 0. + YouWantToSee_time_list = [] + + while cap.isOpened(): + ret,img = cap.read() + if ret: + frame_idx += 1 + video_time = cap.get(cv2.CAP_PROP_POS_MSEC) + + algo_image = img.copy() + + faces_bbox =face_detect_model.predict(img,vis = True) # 检测手,获取手的边界框 + if len(faces_bbox) > 0: + faces_identify,faces_identify_bboxes,bboxes,face_map = get_faces_batch_attribute(face_multitask_model,face_euler_model,faces_bbox,algo_image,use_cuda = True,vis = True) + YouHaveSeen_list = [] + if len(faces_identify) > 0: + results, face_dst = face_verify_model.predict(faces_identify) + face_dst = list(face_dst.cpu().detach().numpy()) + # print("face_dst : ",face_dst) + + for idx,bbox_ in enumerate(faces_identify_bboxes): + + cv2.putText(algo_image, "{}: {:.2f}".format(face_verify_model.face_names[results[idx] + 1],face_dst[idx]), (bbox_[0],bbox_[1]+23),cv2.FONT_HERSHEY_DUPLEX, 0.7, (255, 95,220), 5) + cv2.putText(algo_image, "{}: {:.2f}".format(face_verify_model.face_names[results[idx] + 1],face_dst[idx]), (bbox_[0],bbox_[1]+23),cv2.FONT_HERSHEY_DUPLEX, 0.7, p_colors[results[idx] + 1], 2) + if face_verify_model.face_names[results[idx] + 1] in YouWantToSee_: + YouHaveSeen_list.append(face_verify_model.face_names[results[idx] + 1]) + # 绘制时间轴 + if len(YouHaveSeen_list)>0: + cv2.rectangle(time_map, (frame_idx-1,0), (frame_idx,100), (0,255,0), -1) # 绘制时间轴 + print(" YouHaveSeen : {}".format(YouHaveSeen_list)) + Flag_Now = True + else: + cv2.rectangle(time_map, (frame_idx-1,100), (frame_idx,200), (255,0,0), -1) # 绘制时间轴 + print(" ------ ") + Flag_Now = False + + + else: + face_map = np.zeros([112*3,112*3,3]).astype(np.uint8) + face_map[:,:,0].fill(205) + face_map[:,:,1].fill(205) + face_map[:,:,2].fill(205) + print(" ------ ") + Flag_Now = False + + cv2.rectangle(time_map, (frame_idx-1,100), (frame_idx,200), (255,0,0), -1) # 绘制时间轴 + cv2.line(time_map, (frame_idx,100),(frame_idx,100), (0,80,255), 8) # 绘制时间轴 中轴线 + + #------------- + if Flag_Now == True and Flag_Last == False: + start_time = video_time + elif Flag_Now == False and Flag_Last == True: + YouWantToSee_time_list.append((start_time/1000.,video_time/1000.)) + + Flag_Last = Flag_Now + # + cv2.putText(algo_image, "WhoYouWant 2 See", (algo_image.shape[1]-420,45),cv2.FONT_HERSHEY_DUPLEX, 1.2, (205, 95,250), 7) + cv2.putText(algo_image, "WhoYouWant 2 See", (algo_image.shape[1]-420,45),cv2.FONT_HERSHEY_DUPLEX, 1.2, (12, 255,12), 2) + + cv2.putText(algo_image, "DpCas -", (algo_image.shape[1]-620,45),cv2.FONT_HERSHEY_DUPLEX, 1.2, (255, 95,210), 7) + cv2.putText(algo_image, "DpCas -", (algo_image.shape[1]-620,45),cv2.FONT_HERSHEY_DUPLEX, 1.2, (12, 255,12), 2) + + cv2.rectangle(algo_image, (algo_image.shape[1]-640,5), (algo_image.shape[1]-30,65), (0,185,255), 6) + cv2.rectangle(algo_image, (algo_image.shape[1]-640,5), (algo_image.shape[1]-30,65), (255,100,100), 2) + + cv2.putText(algo_image, "[{}/{}]".format(frame_idx,frame_count), (5,30),cv2.FONT_HERSHEY_DUPLEX, 1.0, (255, 95,220), 5) + cv2.putText(algo_image, "[{}/{}]".format(frame_idx,frame_count), (5,30),cv2.FONT_HERSHEY_DUPLEX, 1.0, (12, 255,12), 2) + + cv2.putText(algo_image, "[{:.2f} sec]".format(video_time/1000.), (5,70),cv2.FONT_HERSHEY_DUPLEX, 1.0, (15, 185,255), 7) + cv2.putText(algo_image, "[{:.2f} sec]".format(video_time/1000.), (5,70),cv2.FONT_HERSHEY_DUPLEX, 1.0, (255, 112,112), 2) + + # + cv2.putText(face_map, "YouWantToSee {}".format(YouWantToSee_), (5,face_map.shape[0]-3),cv2.FONT_HERSHEY_DUPLEX, 0.55, (255, 95,220), 5) + cv2.putText(face_map, "YouWantToSee {}".format(YouWantToSee_), (5,face_map.shape[0]-3),cv2.FONT_HERSHEY_DUPLEX, 0.55, (12, 215,12), 1) + + face_map = cv2.resize(face_map,(algo_image.shape[0],algo_image.shape[0])) + algo_image = np.hstack((algo_image,face_map)) # 合并显示 + time_map_r = cv2.resize(time_map,(algo_image.shape[1],200)) + algo_image = np.vstack((algo_image,time_map_r)) + + cv2.namedWindow('WhoYouWant2See', 0) + cv2.imshow('WhoYouWant2See', algo_image) + + key_id = cv2.waitKey(1) + if key_id == 27: + break + else: + break + #------------- + print("\n ----->>> YouWantToSee_Time_list : \n") + movie = VideoFileClip(video_path) + video_s = "./clip_wyw2s/" + if not os.path.exists(video_s): # 如果文件夹不存在 + os.mkdir(video_s) # 生成文件夹 + + seg_idx = 0 + for seg_ in YouWantToSee_time_list: + seg_idx += 1 + print(" Seg {} : {}".format(seg_idx,seg_)) + print(" 开始剪切目标人物视频 第 {} 段 \n".format(seg_idx)) + movie_clip = movie.subclip(seg_[0],seg_[1])# 将剪切的片段保存 + movie_clip.write_videofile("{}clip_{}.mp4".format(video_s,seg_idx)) + + run_show(path = video_s , vis = True) + + cv2.destroyAllWindows() diff --git a/components/face_detect/acc_model.py b/components/face_detect/acc_model.py new file mode 100644 index 0000000000000000000000000000000000000000..f2a865846edec40bd9a1dbf3a0c72ef202699ad6 --- /dev/null +++ b/components/face_detect/acc_model.py @@ -0,0 +1,243 @@ +import torch +import torch.nn as nn +import torchvision +import time +import numpy as np +import sys + +def get_model_op(model_,print_flag = False): + # print('/********************* modules *******************/') + op_dict = {} + idx = 0 + for m in model_.modules(): + idx += 1 + if isinstance(m, nn.Conv2d): + if 'Conv2d' not in op_dict.keys(): + op_dict['Conv2d'] = 1 + else: + op_dict['Conv2d'] += 1 + if print_flag: + print('{}) {}'.format(idx,m)) + pass + elif isinstance(m, nn.BatchNorm2d): + if 'BatchNorm2d' not in op_dict.keys(): + op_dict['BatchNorm2d'] = 1 + else: + op_dict['BatchNorm2d'] += 1 + if print_flag: + print('{}) {}'.format(idx,m)) + pass + elif isinstance(m, nn.Linear): + if 'Linear' not in op_dict.keys(): + op_dict['Linear'] = 1 + else: + op_dict['Linear'] += 1 + if print_flag: + print('{}) {}'.format(idx,m)) + pass + elif isinstance(m, nn.Sequential): + if print_flag: + print('*******************{}) {}'.format(idx,m)) + for n in m: + if print_flag: + print('{}) {}'.format(idx,n)) + if 'Conv2d' not in op_dict.keys(): + op_dict['Conv2d'] = 1 + else: + op_dict['Conv2d'] += 1 + if 'BatchNorm2d' not in op_dict.keys(): + op_dict['BatchNorm2d'] = 1 + else: + op_dict['BatchNorm2d'] += 1 + if 'Linear' not in op_dict.keys(): + op_dict['Linear'] = 1 + else: + op_dict['Linear'] += 1 + if 'ReLU6' not in op_dict.keys(): + op_dict['ReLU6'] = 1 + else: + op_dict['ReLU6'] += 1 + pass + elif isinstance(m, nn.ReLU6): + if print_flag: + print('{}) {}'.format(idx,m)) + if 'ReLU6' not in op_dict.keys(): + op_dict['ReLU6'] = 1 + else: + op_dict['ReLU6'] += 1 + pass + elif isinstance(m, nn.Module): + if print_flag: + print('{}) {}'.format(idx,m)) + for n in m.modules(): + if isinstance(n, nn.Conv2d): + if print_flag: + print('{}) {}'.format(idx,n)) + if 'Conv2d' not in op_dict.keys(): + op_dict['Conv2d'] = 1 + else: + op_dict['Conv2d'] += 1 + if 'BatchNorm2d' not in op_dict.keys(): + op_dict['BatchNorm2d'] = 1 + else: + op_dict['BatchNorm2d'] += 1 + if 'Linear' not in op_dict.keys(): + op_dict['Linear'] = 1 + else: + op_dict['Linear'] += 1 + if 'ReLU6' not in op_dict.keys(): + op_dict['ReLU6'] = 1 + else: + op_dict['ReLU6'] += 1 + pass + pass + + else: + if print_flag: + print('{}) {}'.format(idx,m)) + pass + + # print('\n/********************** {} ********************/\n'.format(ops.network)) + for key in op_dict.keys(): + if print_flag: + print(' operation - {} : {}'.format(key,op_dict[key])) + +class DummyModule(nn.Module): + def __init__(self): + super(DummyModule, self).__init__() + + def forward(self, x): + return x + +def fuse(conv, bn): + # https://tehnokv.com/posts/fusing-batchnorm-and-conv/ + with torch.no_grad(): + # init + if isinstance(conv, nn.Conv2d): + fusedconv = torch.nn.Conv2d(conv.in_channels, + conv.out_channels, + kernel_size=conv.kernel_size, + stride=conv.stride, + padding=conv.padding, + bias=True) + elif isinstance(conv, nn.ConvTranspose2d): # not supprot nn.ConvTranspose2d + fusedconv = nn.ConvTranspose2d( + conv.in_channels, + conv.out_channels, + kernel_size=conv.kernel_size, + stride=conv.stride, + padding=conv.padding, + output_padding=conv.output_padding, + bias=True) + else: + print("error") + exit() + + # prepare filters + w_conv = conv.weight.clone().view(conv.out_channels, -1) + w_bn = torch.diag(bn.weight.div(torch.sqrt(bn.eps + bn.running_var))) + fusedconv.weight.copy_(torch.mm(w_bn, w_conv).view(fusedconv.weight.size())) + + # prepare spatial bias + if conv.bias is not None: + b_conv = conv.bias + #b_conv = conv.bias.mul(bn.weight.div(torch.sqrt(bn.running_var + bn.eps))) # maybe, you should this one ? + else: + b_conv = torch.zeros(conv.weight.size(0)) + b_bn = bn.bias - bn.weight.mul(bn.running_mean).div(torch.sqrt(bn.running_var + bn.eps)) + fusedconv.bias.copy_(b_conv + b_bn) + + return fusedconv + +# idxx = 0 +def fuse_module(m): + # global idxx + children = list(m.named_children()) + c = None + cn = None + + for name, child in children: + # idxx += 1 + # print('-------------->>',idxx) + # if idxx%10==0: + # continue + # print("name {}, child {}".format(name, child)) + if isinstance(child, nn.BatchNorm2d) and c is not None: + bc = fuse(c, child) + m._modules[cn] = bc + # print('DummyModule() : ',DummyModule()) + m._modules[name] = DummyModule() + c = None + elif isinstance(child, nn.Conv2d): + c = child + cn = name + else: + fuse_module(child) + +def test_net(ops,m): + + use_cuda = torch.cuda.is_available() + use_cpu = False + if ops.force_cpu or use_cuda == False: + p = torch.randn([1, 3, 256, 256]) + device = torch.device("cpu") + use_cpu = True + else: + p = torch.randn([1, 3, 256, 256]).cuda() + device = torch.device("cuda:0") + + count = 50 + time_org = [] + m_o = m.to(device) + get_model_op(m_o) + # print(m) + for i in range(count): + s1 = time.time() + if use_cpu: + o_output = m_o(p) + else: + o_output = m_o(p).cpu() + s2 = time.time() + time_org.append(s2 - s1) + print("Original time: ", s2 - s1) + print('------------------------------------>>>>') + + fuse_module(m.to(torch.device("cpu"))) + + # print(m) + + m_f = m.to(device) + get_model_op(m_f) + + time_fuse = [] + for i in range(count): + s1 = time.time() + if use_cpu: + f_output = m_f(p) + else: + f_output = m_f(p).cpu() + s2 = time.time() + time_fuse.append(s2 - s1) + print("Fused time: ", s2 - s1) + + print("-" * 50) + print("org time:", np.mean(time_org)) + print("fuse time:", np.mean(time_fuse)) + for o in o_output: + print("org size:", o.size()) + for o in f_output: + print("fuse size:", o.size()) + for i in range(len(o_output)): + assert o_output[i].size()==f_output[i].size() + print("output[{}] max abs diff: {}".format(i, (o_output[i] - f_output[i]).abs().max().item())) + print("output[{}] MSE diff: {}".format(i, nn.MSELoss()(o_output[i], f_output[i]).item())) + + +def acc_model(ops,m): + # print('\n-------------------------------->>> before acc model') + get_model_op(m) + fuse_module(m) + # print('\n-------------------------------->>> after acc model') + get_model_op(m) + + return m diff --git a/components/face_detect/utils/__init__.py b/components/face_detect/utils/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/components/face_detect/utils/common_utils.py b/components/face_detect/utils/common_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..6e8f105c9850fc59d0bfebbd0bcef1b746887da9 --- /dev/null +++ b/components/face_detect/utils/common_utils.py @@ -0,0 +1,656 @@ +#-*-coding:utf-8-*- +# date:2020-04-11 +# Author: Eric.Lee + +import os +import shutil +import cv2 +import numpy as np +import json +import torch +from dp_models.faceboxes.config import cfg +from dp_models.faceboxes.layers.functions.prior_box import PriorBox +from dp_models.faceboxes.utils.box_utils import decode +from dp_models.faceboxes.headpose.pose import * +import torch.nn.functional as F + +def mkdir_(path, flag_rm=False): + if os.path.exists(path): + if flag_rm == True: + shutil.rmtree(path) + os.mkdir(path) + print('remove {} done ~ '.format(path)) + else: + os.mkdir(path) + +def plot_box(bbox, img, color=None, label=None, line_thickness=None): + tl = line_thickness or round(0.002 * max(img.shape[0:2])) + 1 + color = color or [random.randint(0, 255) for _ in range(3)] + c1, c2 = (int(bbox[0]), int(bbox[1])), (int(bbox[2]), int(bbox[3])) + cv2.rectangle(img, c1, c2, color, thickness=tl)# 目标的bbox + if label: + tf = max(tl - 2, 1) + t_size = cv2.getTextSize(label, 0, fontScale=tl / 4, thickness=tf)[0] # label size + c2 = c1[0] + t_size[0], c1[1] - t_size[1] - 3 # 字体的bbox + cv2.rectangle(img, c1, c2, color, -1) # label 矩形填充 + # 文本绘制 + cv2.putText(img, label, (c1[0], c1[1] - 2), 0, tl / 4, [225, 255, 255],thickness=tf, lineType=cv2.LINE_AA) + +class JSON_Encoder(json.JSONEncoder): + def default(self, obj): + if isinstance(obj, np.integer): + return int(obj) + elif isinstance(obj, np.floating): + return float(obj) + elif isinstance(obj, np.ndarray): + return obj.tolist() + else: + return super(JSON_Encoder, self).default(obj) + +def draw_landmarks(img,output,r_bboxes,draw_circle): + img_width = img.shape[1] + img_height = img.shape[0] + dict_landmarks = {} + global_dict_landmarks = {} # 全局坐标系坐标 + faceswap_list = [] + + face_pts = [] + + for i in range(int(output.shape[0]/2)): + x = output[i*2+0]*float(img_width) + y = output[i*2+1]*float(img_height) + + face_pts .append([x+r_bboxes[0],y+r_bboxes[1]]) + + if i ==33 or i == 46 or i == 96 or i == 97 or i == 54 or i == 76 or i == 82: + faceswap_list.append((x+r_bboxes[0],y+r_bboxes[1])) + # cv2.circle(img, (int(x),int(y)), 8, (0,255,255),-1) + # + if 41>= i >=33: + if 'left_eyebrow' not in dict_landmarks.keys(): + dict_landmarks['left_eyebrow'] = [] + global_dict_landmarks['left_eyebrow'] = [] + dict_landmarks['left_eyebrow'].append([int(x),int(y),(0,255,0)]) + global_dict_landmarks['left_eyebrow'].append([int(x+r_bboxes[0]),int(y+r_bboxes[1])]) + + + if draw_circle: + cv2.circle(img, (int(x),int(y)), 2, (0,255,0),-1) + elif 50>= i >=42: + if 'right_eyebrow' not in dict_landmarks.keys(): + dict_landmarks['right_eyebrow'] = [] + global_dict_landmarks['right_eyebrow'] = [] + dict_landmarks['right_eyebrow'].append([int(x),int(y),(0,255,0)]) + global_dict_landmarks['right_eyebrow'].append([int(x+r_bboxes[0]),int(y+r_bboxes[1])]) + if draw_circle: + cv2.circle(img, (int(x),int(y)), 2, (0,255,0),-1) + elif 67>= i >=60: + if 'left_eye' not in dict_landmarks.keys(): + dict_landmarks['left_eye'] = [] + global_dict_landmarks['left_eye'] = [] + dict_landmarks['left_eye'].append([int(x),int(y),(255,55,255)]) + global_dict_landmarks['left_eye'].append([int(x+r_bboxes[0]),int(y+r_bboxes[1])]) + if draw_circle: + cv2.circle(img, (int(x),int(y)), 2, (255,0,255),-1) + elif 75>= i >=68: + if 'right_eye' not in dict_landmarks.keys(): + dict_landmarks['right_eye'] = [] + global_dict_landmarks['right_eye'] = [] + dict_landmarks['right_eye'].append([int(x),int(y),(255,55,255)]) + global_dict_landmarks['right_eye'].append([int(x+r_bboxes[0]),int(y+r_bboxes[1])]) + if draw_circle: + cv2.circle(img, (int(x),int(y)), 2, (255,0,255),-1) + elif 97>= i >=96: + if 'eye_center' not in dict_landmarks.keys(): + global_dict_landmarks['eye_center'] = [] + global_dict_landmarks['eye_center'].append([int(x+r_bboxes[0]),int(y+r_bboxes[1])]) + + cv2.circle(img, (int(x),int(y)), 2, (0,0,255),-1) + elif 54>= i >=51: + if 'bridge_nose' not in dict_landmarks.keys(): + dict_landmarks['bridge_nose'] = [] + global_dict_landmarks['bridge_nose'] = [] + dict_landmarks['bridge_nose'].append([int(x),int(y),(0,170,255)]) + global_dict_landmarks['bridge_nose'].append([int(x+r_bboxes[0]),int(y+r_bboxes[1])]) + if draw_circle: + cv2.circle(img, (int(x),int(y)), 2, (0,170,255),-1) + elif 32>= i >=0: + if 'basin' not in dict_landmarks.keys(): + dict_landmarks['basin'] = [] + global_dict_landmarks['basin'] = [] + dict_landmarks['basin'].append([int(x),int(y),(255,30,30)]) + global_dict_landmarks['basin'].append([int(x+r_bboxes[0]),int(y+r_bboxes[1])]) + if draw_circle: + cv2.circle(img, (int(x),int(y)), 2, (255,30,30),-1) + elif 59>= i >=55: + if 'wing_nose' not in dict_landmarks.keys(): + dict_landmarks['wing_nose'] = [] + global_dict_landmarks['wing_nose'] = [] + dict_landmarks['wing_nose'].append([int(x),int(y),(0,255,255)]) + global_dict_landmarks['wing_nose'].append([int(x+r_bboxes[0]),int(y+r_bboxes[1])]) + if draw_circle: + cv2.circle(img, (int(x),int(y)), 2, (0,255,255),-1) + elif 87>= i >=76: + if 'out_lip' not in dict_landmarks.keys(): + dict_landmarks['out_lip'] = [] + global_dict_landmarks['out_lip'] = [] + dict_landmarks['out_lip'].append([int(x),int(y),(255,255,0)]) + global_dict_landmarks['out_lip'].append([int(x+r_bboxes[0]),int(y+r_bboxes[1])]) + if draw_circle: + cv2.circle(img, (int(x),int(y)), 2, (255,255,0),-1) + elif 95>= i >=88: + if 'in_lip' not in dict_landmarks.keys(): + dict_landmarks['in_lip'] = [] + global_dict_landmarks['in_lip'] = [] + dict_landmarks['in_lip'].append([int(x),int(y),(50,220,255)]) + global_dict_landmarks['in_lip'].append([int(x+r_bboxes[0]),int(y+r_bboxes[1])]) + if draw_circle: + cv2.circle(img, (int(x),int(y)), 2, (50,220,255),-1) + # else: + # if draw_circle: + # cv2.circle(img, (int(x),int(y)), 2, (255,0,255),-1) + + faceswap_list_e = [] + + for i in range(5): + faceswap_list_e.append(faceswap_list[i][0]) + for i in range(5): + faceswap_list_e.append(faceswap_list[i][1]) + + + return dict_landmarks,faceswap_list_e,global_dict_landmarks,face_pts + +def draw_contour(image,dict,r_bbox,face_pts): + x0 = r_bbox[0]# 全图偏置 + y0 = r_bbox[1] + + #------------------------------------------ + face_ola_pts = [] + face_ola_pts.append(face_pts[33]) + face_ola_pts.append(face_pts[38]) + face_ola_pts.append(face_pts[50]) + face_ola_pts.append(face_pts[46]) + + face_ola_pts.append(face_pts[60]) + face_ola_pts.append(face_pts[64]) + face_ola_pts.append(face_pts[68]) + face_ola_pts.append(face_pts[72]) + + face_ola_pts.append(face_pts[51]) + face_ola_pts.append(face_pts[55]) + face_ola_pts.append(face_pts[59]) + + face_ola_pts.append(face_pts[53]) + face_ola_pts.append(face_pts[57]) + + pts_num = len(face_ola_pts) + reprojectdst, euler_angle = get_head_pose(np.array(face_ola_pts).reshape((pts_num,2)),image,vis = False) + pitch, yaw, roll = euler_angle + + for key in dict.keys(): + # print(key) + _,_,color = dict[key][0] + + if 'left_eye' == key: + eye_x = np.mean([dict[key][i][0]+x0 for i in range(len(dict[key]))]) + eye_y = np.mean([dict[key][i][1]+y0 for i in range(len(dict[key]))]) + cv2.circle(image, (int(eye_x),int(eye_y)), 3, (255,255,55),-1) + if 'right_eye' == key: + eye_x = np.mean([dict[key][i][0]+x0 for i in range(len(dict[key]))]) + eye_y = np.mean([dict[key][i][1]+y0 for i in range(len(dict[key]))]) + cv2.circle(image, (int(eye_x),int(eye_y)), 3, (255,215,25),-1) + + if 'basin' == key or 'wing_nose' == key: + pts = np.array([[dict[key][i][0]+x0,dict[key][i][1]+y0] for i in range(len(dict[key]))],np.int32) + # print(pts) + cv2.polylines(image,[pts],False,color,thickness = 2) + + else: + points_array = np.zeros((1,len(dict[key]),2),dtype = np.int32) + for i in range(len(dict[key])): + x,y,_ = dict[key][i] + points_array[0,i,0] = x+x0 + points_array[0,i,1] = y+y0 + + # cv2.fillPoly(image, points_array, color) + cv2.drawContours(image,points_array,-1,color,thickness=2) + return (pitch, yaw, roll) + +import random +rgbs = [] +for j in range(100): + rgb = (random.randint(0,255),random.randint(0,255),random.randint(0,255)) + rgbs.append(rgb) + +def draw_global_contour(image,dict): + + + x0,y0 = 0,0 + idx = 0 + for key in dict.keys(): + idx += 1 + # print(key) + # _,_ = dict[key][0] + + if 'left_eye' == key: + eye_x = np.mean([dict[key][i][0]+x0 for i in range(len(dict[key]))]) + eye_y = np.mean([dict[key][i][1]+y0 for i in range(len(dict[key]))]) + cv2.circle(image, (int(eye_x),int(eye_y)), 3, (255,255,55),-1) + if 'right_eye' == key: + eye_x = np.mean([dict[key][i][0]+x0 for i in range(len(dict[key]))]) + eye_y = np.mean([dict[key][i][1]+y0 for i in range(len(dict[key]))]) + cv2.circle(image, (int(eye_x),int(eye_y)), 3, (255,215,25),-1) + + if 'basin' == key or 'wing_nose' == key: + pts = np.array([[dict[key][i][0]+x0,dict[key][i][1]+y0] for i in range(len(dict[key]))],np.int32) + # print(pts) + cv2.polylines(image,[pts],False,rgbs[idx],thickness = 2) + + else: + points_array = np.zeros((1,len(dict[key]),2),dtype = np.int32) + for i in range(len(dict[key])): + x,y = dict[key][i] + points_array[0,i,0] = x+x0 + points_array[0,i,1] = y+y0 + + # cv2.fillPoly(image, points_array, color) + cv2.drawContours(image,points_array,-1,rgbs[idx],thickness=2) + +def refine_face_bbox(bbox,img_shape): + height,width,_ = img_shape + + x1,y1,x2,y2 = bbox + + expand_w = (x2-x1) + expand_h = (y2-y1) + + x1 -= expand_w*0.06 + y1 += expand_h*0.15 + x2 += expand_w*0.06 + y2 += expand_h*0.03 + + x1,y1,x2,y2 = int(x1),int(y1),int(x2),int(y2) + + x1 = int(max(0,x1)) + y1 = int(max(0,y1)) + x2 = int(min(x2,width-1)) + y2 = int(min(y2,height-1)) + + return (x1,y1,x2,y2) +def py_cpu_nms(dets, thresh): + """Pure Python NMS baseline.""" + x1 = dets[:, 0] + y1 = dets[:, 1] + x2 = dets[:, 2] + y2 = dets[:, 3] + scores = dets[:, 4] + + areas = (x2 - x1 + 1) * (y2 - y1 + 1) + order = scores.argsort()[::-1] + + keep = [] + while order.size > 0: + i = order[0] + keep.append(i) + xx1 = np.maximum(x1[i], x1[order[1:]]) + yy1 = np.maximum(y1[i], y1[order[1:]]) + xx2 = np.minimum(x2[i], x2[order[1:]]) + yy2 = np.minimum(y2[i], y2[order[1:]]) + + w = np.maximum(0.0, xx2 - xx1 + 1) + h = np.maximum(0.0, yy2 - yy1 + 1) + inter = w * h + ovr = inter / (areas[i] + areas[order[1:]] - inter) + + inds = np.where(ovr <= thresh)[0] + order = order[inds + 1] + + return keep + +def check_keys(model, pretrained_state_dict): + ckpt_keys = set(pretrained_state_dict.keys()) + model_keys = set(model.state_dict().keys()) + used_pretrained_keys = model_keys & ckpt_keys + unused_pretrained_keys = ckpt_keys - model_keys + missing_keys = model_keys - ckpt_keys + # print('Missing keys:{}'.format(len(missing_keys))) + # print('Unused checkpoint keys:{}'.format(len(unused_pretrained_keys))) + # print('Used keys:{}'.format(len(used_pretrained_keys))) + assert len(used_pretrained_keys) > 0, 'load NONE from pretrained checkpoint' + return True + +def remove_prefix(state_dict, prefix): + ''' Old style model is stored with all names of parameters sharing common prefix 'module.' ''' + # print('remove prefix \'{}\''.format(prefix)) + f = lambda x: x.split(prefix, 1)[-1] if x.startswith(prefix) else x + return {f(key): value for key, value in state_dict.items()} + + +def load_model(model, pretrained_path, load_to_cpu): + # print('Loading pretrained model from {}'.format(pretrained_path)) + if load_to_cpu: + pretrained_dict = torch.load(pretrained_path, map_location=lambda storage, loc: storage) + else: + device = torch.cuda.current_device() + pretrained_dict = torch.load(pretrained_path, map_location=lambda storage, loc: storage.cuda(device)) + if "state_dict" in pretrained_dict.keys(): + pretrained_dict = remove_prefix(pretrained_dict['state_dict'], 'module.') + else: + pretrained_dict = remove_prefix(pretrained_dict, 'module.') + check_keys(model, pretrained_dict) + model.load_state_dict(pretrained_dict, strict=False) + return model + + +def detect_faces(ops,detect_model,img_raw,device): + resize = 1 + img = np.float32(img_raw) + if resize != 1: + img = cv2.resize(img, None, None, fx=resize, fy=resize, interpolation=cv2.INTER_LINEAR) + im_height, im_width, _ = img.shape + scale = torch.Tensor([img.shape[1], img.shape[0], img.shape[1], img.shape[0]]) + img -= (104, 117, 123) + img = img.transpose(2, 0, 1) + img = torch.from_numpy(img).unsqueeze(0) + img = img.to(device) + scale = scale.to(device) + + + loc, conf = detect_model(img) # forward pass + + priorbox = PriorBox(cfg, image_size=(im_height, im_width)) + priors = priorbox.forward() + priors = priors.to(device) + prior_data = priors.data + boxes = decode(loc.data.squeeze(0), prior_data, cfg['variance']) + boxes = boxes * scale / resize + boxes = boxes.cpu().numpy() + scores = conf.squeeze(0).data.cpu().numpy()[:, 1] + + # ignore low scores + inds = np.where(scores > ops.confidence_threshold)[0] + boxes = boxes[inds] + scores = scores[inds] + + # keep top-K before NMS + order = scores.argsort()[::-1][:ops.top_k] + boxes = boxes[order] + scores = scores[order] + + # do NMS + dets = np.hstack((boxes, scores[:, np.newaxis])).astype(np.float32, copy=False) + #keep = py_cpu_nms(dets, ops.nms_threshold) + # keep = nms(dets, ops.nms_threshold,force_cpu=True) + keep = py_cpu_nms(dets, ops.nms_threshold) + dets = dets[keep, :] + + # keep top-K faster NMS + dets = dets[:ops.keep_top_k, :] + + return dets + + + + +def get_faces_batch_landmarks(ops,landmarks_model,express_model,dets,img_raw,use_cuda,draw_bbox = True): + # 绘制图像 + image_batch = None + r_bboxes = [] + imgs_crop = [] + for b in dets: + + text = "{:.4f}".format(b[4]) + b = list(map(int, b)) + + r_bbox = refine_face_bbox((b[0],b[1],b[2],b[3]),img_raw.shape) + r_bboxes.append(r_bbox) + img_crop = img_raw[r_bbox[1]:r_bbox[3],r_bbox[0]:r_bbox[2]] + imgs_crop.append(img_crop) + img_ = cv2.resize(img_crop, (256,256), interpolation = cv2.INTER_LINEAR) # INTER_LINEAR INTER_CUBIC + + img_ = img_.astype(np.float32) + img_ = (img_-128.)/256. + + img_ = img_.transpose(2, 0, 1) + img_ = np.expand_dims(img_,0) + + if image_batch is None: + image_batch = img_ + else: + image_batch = np.concatenate((image_batch,img_),axis=0) + for b in dets: + + text = "{:.4f}".format(b[4]) + b = list(map(int, b)) + if draw_bbox: + cv2.rectangle(img_raw, (b[0], b[1]), (b[2], b[3]), (0, 0, 255), 2) + cx = b[0] + cy = b[1] - 3 + if draw_bbox: + cv2.putText(img_raw, text, (cx, cy),cv2.FONT_HERSHEY_DUPLEX, 0.6, (155, 155, 255),3) + cv2.putText(img_raw, text, (cx, cy),cv2.FONT_HERSHEY_DUPLEX, 0.6, (155, 10, 10),1) + + # 填充最大 关键点 批次数据 + # if len(dets) < 5: + # im_mask = np.zeros([1,3,ops.landmarks_img_size[0],ops.landmarks_img_size[1]], dtype = np.float32) + # for i in range(ops.max_batch_size-len(dets)): + # if image_batch is None: + # image_batch = im_mask + # else: + # image_batch = np.concatenate((image_batch,im_mask),axis=0) + + image_batch = torch.from_numpy(image_batch).float() + + if use_cuda: + image_batch = image_batch.cuda() # (bs, 3, h, w) + #----------------- express + pre_e = express_model(image_batch.float()) + + outputs_e = F.softmax(pre_e,dim = 1) + + # print("outputs_e size : ",outputs_e.size()) + + outputs_e = outputs_e.cpu().detach().numpy() + outputs_e = np.array(outputs_e) + # + max_index_e = np.argmax(outputs_e,axis = 1) + # print("max_index_e shape :",max_index_e.shape) + # print("max_index_e:",max_index_e) + # print("outputs_e .shape:",outputs_e.shape) + express_dict = { + 0:"001.anger", + 1:"002.disgust", + 2:"003.fear", + 3:"004.happy", + 4:"005.normal", + 5:"006.sad", + 6:"007.surprised", + } + express_list = [] + for kk in range(max_index_e.shape[0]): + max_index_ = max_index_e[kk] + score_ = outputs_e[kk][max_index_] + express_list.append((max_index_,express_dict[max_index_],score_)) + # print("max_index : {}, score : {:.3f}, express : {}".format(max_index_,score_,express_dict[max_index_])) + # score_e = outputs_e[max_index_e] + # print("score_e : ",score_e) + #----------------- landmarks + pre_ = landmarks_model(image_batch.float()) + + # print(pre_.size()) + output = pre_.cpu().detach().numpy() + # print('output shape : ',output.shape) + # n_array = np.zeros([ops.landmarks_img_size[0],ops.landmarks_img_size[1],3], dtype = np.float) + faceswap_landmarks = [] + output_dict_ = [] + for i in range(len(dets)): + + dict_landmarks,list_e,global_dict_landmarks,face_pts = draw_landmarks(imgs_crop[i],output[i],r_bboxes[i],draw_circle = False) + faceswap_landmarks.append(list_e) + pitch, yaw, roll = draw_contour(img_raw,dict_landmarks,r_bboxes[i],face_pts) + + output_dict_.append({ + "xyxy":(r_bboxes[i][0],r_bboxes[i][1],r_bboxes[i][2],r_bboxes[i][3]), + "score":str(dets[i][4]), + "landmarks":global_dict_landmarks, + "euler_angle":(int(pitch[0]), int(yaw[0]), int(roll[0])), + "express":(float(express_list[i][0]),float(express_list[i][2])), + }) + + + # print('dets :',dets) + #----------------------------------------------------------------------------------- + for i in range(len(dets)): + bbox = dets[i] + min_x = int(bbox[0]) + min_y = int(bbox[1]) + max_x = int(bbox[2]) + max_y = int(bbox[3]) + cv2.rectangle(img_raw, (min_x, min_y), (max_x, max_y), (255, 0, 255), thickness=4) + for k in range(5): + x = int(faceswap_landmarks[i][k+0]) + y = int(faceswap_landmarks[i][k+5]) + # cv2.circle(img_raw,(x,y),5+k*2,(0,0,255),-1) + if draw_bbox: + cv2.circle(img_raw,(x,y),2,(0,0,255),-1) + if draw_bbox: + + cv2.putText(img_raw, "express:{},{:.2f}".format(express_list[i][1],express_list[i][2]), (min_x, min_y-20),cv2.FONT_HERSHEY_DUPLEX, 0.6, (155, 155, 255),3) + cv2.putText(img_raw, "express:{},{:.2f}".format(express_list[i][1],express_list[i][2]), (min_x, min_y-20),cv2.FONT_HERSHEY_DUPLEX, 0.6, (155, 10, 10),1) + if draw_bbox: + cv2.putText(img_raw, 'face:'+str(len(dets)), (3,35),cv2.FONT_HERSHEY_DUPLEX, 1.45, (55, 255, 255),5) + cv2.putText(img_raw, 'face:'+str(len(dets)), (3,35),cv2.FONT_HERSHEY_DUPLEX, 1.45, (135, 135, 5),2) + + return output_dict_ +def get_faces_batch_landmarks_plfd(ops,landmarks_model,express_model,dets,img_raw,use_cuda,draw_bbox = True): + # 绘制图像 + image_batch = None + r_bboxes = [] + imgs_crop = [] + for b in dets: + + text = "{:.4f}".format(b[4]) + b = list(map(int, b)) + + r_bbox = refine_face_bbox((b[0],b[1],b[2],b[3]),img_raw.shape) + r_bboxes.append(r_bbox) + img_crop = img_raw[r_bbox[1]:r_bbox[3],r_bbox[0]:r_bbox[2]] + imgs_crop.append(img_crop) + img_ = cv2.resize(img_crop, (112,112), interpolation = cv2.INTER_LINEAR) # INTER_LINEAR INTER_CUBIC + + img_ = img_.astype(np.float32) + img_ = img_/256. + + img_ = img_.transpose(2, 0, 1) + img_ = np.expand_dims(img_,0) + + if image_batch is None: + image_batch = img_ + else: + image_batch = np.concatenate((image_batch,img_),axis=0) + for b in dets: + + text = "{:.4f}".format(b[4]) + b = list(map(int, b)) + if draw_bbox: + cv2.rectangle(img_raw, (b[0], b[1]), (b[2], b[3]), (0, 0, 255), 2) + cx = b[0] + cy = b[1] - 3 + if draw_bbox: + cv2.putText(img_raw, text, (cx, cy),cv2.FONT_HERSHEY_DUPLEX, 0.6, (155, 155, 255),3) + cv2.putText(img_raw, text, (cx, cy),cv2.FONT_HERSHEY_DUPLEX, 0.6, (155, 10, 10),1) + + # 填充最大 关键点 批次数据 + # if len(dets) < 5: + # im_mask = np.zeros([1,3,ops.landmarks_img_size[0],ops.landmarks_img_size[1]], dtype = np.float32) + # for i in range(ops.max_batch_size-len(dets)): + # if image_batch is None: + # image_batch = im_mask + # else: + # image_batch = np.concatenate((image_batch,im_mask),axis=0) + + image_batch = torch.from_numpy(image_batch).float() + + if use_cuda: + image_batch = image_batch.cuda() # (bs, 3, h, w) + + #----------------- express + pre_e = express_model(image_batch.float()) + + outputs_e = F.softmax(pre_e,dim = 1) + + # print("outputs_e size : ",outputs_e.size()) + + outputs_e = outputs_e.cpu().detach().numpy() + outputs_e = np.array(outputs_e) + # + max_index_e = np.argmax(outputs_e,axis = 1) + # print("max_index_e shape :",max_index_e.shape) + # print("max_index_e:",max_index_e) + # print("outputs_e .shape:",outputs_e.shape) + express_dict = { + 0:"001.anger", + 1:"002.disgust", + 2:"003.fear", + 3:"004.happy", + 4:"005.normal", + 5:"006.sad", + 6:"007.surprised", + } + express_list = [] + for kk in range(max_index_e.shape[0]): + max_index_ = max_index_e[kk] + score_ = outputs_e[kk][max_index_] + express_list.append((max_index_,express_dict[max_index_],score_)) + # print("max_index : {}, score : {:.3f}, express : {}".format(max_index_,score_,express_dict[max_index_])) + # score_e = outputs_e[max_index_e] + # print("score_e : ",score_e) + #----------------------------------------- + _,pre_ = landmarks_model(image_batch.float()) + # print("pre_ : ",pre_) + # print(pre_.size()) + output = pre_.cpu().detach().numpy() + # print('output shape : ',output.shape) + # n_array = np.zeros([ops.landmarks_img_size[0],ops.landmarks_img_size[1],3], dtype = np.float) + faceswap_landmarks = [] + output_dict_ = [] + for i in range(len(dets)): + + dict_landmarks,list_e,global_dict_landmarks,face_pts = draw_landmarks(imgs_crop[i],output[i],r_bboxes[i],draw_circle = False) + faceswap_landmarks.append(list_e) + pitch, yaw, roll = draw_contour(img_raw,dict_landmarks,r_bboxes[i],face_pts) + + output_dict_.append({ + "xyxy":(r_bboxes[i][0],r_bboxes[i][1],r_bboxes[i][2],r_bboxes[i][3]), + "score":str(dets[i][4]), + "landmarks":global_dict_landmarks, + "euler_angle":(int(pitch[0]), int(yaw[0]), int(roll[0])), + "express":(float(express_list[i][0]),float(express_list[i][2])), + }) + + + # print('dets :',dets) + #----------------------------------------------------------------------------------- + for i in range(len(dets)): + bbox = dets[i] + min_x = int(bbox[0]) + min_y = int(bbox[1]) + max_x = int(bbox[2]) + max_y = int(bbox[3]) + cv2.rectangle(img_raw, (min_x, min_y), (max_x, max_y), (255, 0, 255), thickness=2) + for k in range(5): + x = int(faceswap_landmarks[i][k+0]) + y = int(faceswap_landmarks[i][k+5]) + # cv2.circle(img_raw,(x,y),5+k*2,(0,0,255),-1) + if draw_bbox: + cv2.circle(img_raw,(x,y),2,(0,0,255),-1) + if draw_bbox: + + cv2.putText(img_raw, "express:{},{:.2f}".format(express_list[i][1],express_list[i][2]), (min_x, min_y-20),cv2.FONT_HERSHEY_DUPLEX, 0.6, (155, 155, 255),3) + cv2.putText(img_raw, "express:{},{:.2f}".format(express_list[i][1],express_list[i][2]), (min_x, min_y-20),cv2.FONT_HERSHEY_DUPLEX, 0.6, (155, 10, 10),1) + + if draw_bbox: + cv2.putText(img_raw, 'face:'+str(len(dets)), (3,35),cv2.FONT_HERSHEY_DUPLEX, 1.45, (55, 255, 255),5) + cv2.putText(img_raw, 'face:'+str(len(dets)), (3,35),cv2.FONT_HERSHEY_DUPLEX, 1.45, (135, 135, 5),2) + + return output_dict_ diff --git a/components/face_detect/utils/datasets.py b/components/face_detect/utils/datasets.py new file mode 100644 index 0000000000000000000000000000000000000000..02ebd47c2cb05043fe27f0912c2fc61e1282ea83 --- /dev/null +++ b/components/face_detect/utils/datasets.py @@ -0,0 +1,395 @@ +import glob +import math +import os +import random +import shutil +from pathlib import Path +from PIL import Image +from tqdm import tqdm +import cv2 +import numpy as np +import torch +from torch.utils.data import Dataset +from torch.utils.data import DataLoader + +def xyxy2xywh(x): + # Convert bounding box format from [x1, y1, x2, y2] to [x, y, w, h] + y = torch.zeros_like(x) if isinstance(x, torch.Tensor) else np.zeros_like(x) + y[:, 0] = (x[:, 0] + x[:, 2]) / 2 + y[:, 1] = (x[:, 1] + x[:, 3]) / 2 + y[:, 2] = x[:, 2] - x[:, 0] + y[:, 3] = x[:, 3] - x[:, 1] + return y + + +def xywh2xyxy(x): + # Convert bounding box format from [x, y, w, h] to [x1, y1, x2, y2] + y = torch.zeros_like(x) if isinstance(x, torch.Tensor) else np.zeros_like(x) + y[:, 0] = x[:, 0] - x[:, 2] / 2 + y[:, 1] = x[:, 1] - x[:, 3] / 2 + y[:, 2] = x[:, 0] + x[:, 2] / 2 + y[:, 3] = x[:, 1] + x[:, 3] / 2 + return y + + +class LoadImages: # for inference + def __init__(self, path, img_size=416): + self.height = img_size + img_formats = ['.jpg', '.jpeg', '.png', '.tif'] + vid_formats = ['.mov', '.avi', '.mp4'] + + files = [] + if os.path.isdir(path): + files = sorted(glob.glob('%s/*.*' % path)) + elif os.path.isfile(path): + files = [path] + + images = [x for x in files if os.path.splitext(x)[-1].lower() in img_formats] + videos = [x for x in files if os.path.splitext(x)[-1].lower() in vid_formats] + nI, nV = len(images), len(videos) + + self.files = images + videos + self.nF = nI + nV # number of files + self.video_flag = [False] * nI + [True] * nV + self.mode = 'images' + if any(videos): + self.new_video(videos[0]) # new video + else: + self.cap = None + assert self.nF > 0, 'No images or videos found in ' + path + + def __iter__(self): + self.count = 0 + return self + + def __next__(self): + if self.count == self.nF: + raise StopIteration + path = self.files[self.count] + + if self.video_flag[self.count]: + # Read video + self.mode = 'video' + ret_val, img0 = self.cap.read() + if not ret_val: + self.count += 1 + self.cap.release() + if self.count == self.nF: # last video + raise StopIteration + else: + path = self.files[self.count] + self.new_video(path) + ret_val, img0 = self.cap.read() + + self.frame += 1 + print('video %g/%g (%g/%g) %s: ' % (self.count + 1, self.nF, self.frame, self.nframes, path), end='') + + else: + # Read image + self.count += 1 + img0 = cv2.imread(path) # BGR + assert img0 is not None, 'File Not Found ' + path + print('image %g/%g %s: ' % (self.count, self.nF, path), end='') + + # Padded resize + img, _, _, _ = letterbox(img0, height=self.height) + + # Normalize RGB + img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB + img = np.ascontiguousarray(img, dtype=np.float32) # uint8 to float32 + img /= 255.0 # 0 - 255 to 0.0 - 1.0 + + # cv2.imwrite(path + '.letterbox.jpg', 255 * img.transpose((1, 2, 0))[:, :, ::-1]) # save letterbox image + return path, img, img0, self.cap + + def new_video(self, path): + self.frame = 0 + self.cap = cv2.VideoCapture(path) + self.nframes = int(self.cap.get(cv2.CAP_PROP_FRAME_COUNT)) + + def __len__(self): + return self.nF # number of files + + +class LoadWebcam: # for inference + def __init__(self, img_size=416): + self.cam = cv2.VideoCapture(0) + self.height = img_size + + def __iter__(self): + self.count = -1 + return self + + def __next__(self): + self.count += 1 + if cv2.waitKey(1) == 27: # esc to quit + cv2.destroyAllWindows() + raise StopIteration + + # Read image + ret_val, img0 = self.cam.read() + assert ret_val, 'Webcam Error' + img_path = 'webcam_%g.jpg' % self.count + img0 = cv2.flip(img0, 1) # flip left-right + + # Padded resize + img, _, _, _ = letterbox(img0, height=self.height) + + # Normalize RGB + img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB + img = np.ascontiguousarray(img, dtype=np.float32) # uint8 to float32 + img /= 255.0 # 0 - 255 to 0.0 - 1.0 + + return img_path, img, img0, self.cam + + def __len__(self): + return 0 + + +class LoadImagesAndLabels(Dataset): # for training/testing + def __init__(self, path, batch_size, img_size=416, augment=True, multi_scale=False): + print('LoadImagesAndLabels init : ',path) + with open(path, 'r') as file: + img_files = file.read().splitlines() + img_files = list(filter(lambda x: len(x) > 0, img_files)) + np.random.shuffle(img_files) # shuffle img_list + print("shuffle image...") + self.img_files = img_files + assert len(self.img_files) > 0, 'No images found in %s' % path + self.img_size = img_size + self.batch_size = batch_size + self.multi_scale = multi_scale + self.augment = augment + self.scale_index = 0 + if self.multi_scale: + self.img_size = img_size # initiate with maximum multi_scale size, in case of out of memory + print("Multi scale images training, init img_size", self.img_size) + else: + print("Fixed scale images, img_size", self.img_size) + self.label_files = [ + x.replace('images', 'labels').replace("JPEGImages", 'labels').replace('.bmp', '.txt').replace('.jpg', '.txt').replace('.png', '.txt') + for x in self.img_files] + + # print('self.img_files : ',self.img_files[1]) + # print('self.label_files : ',self.label_files[1]) + + def __len__(self): + return len(self.img_files) + + def __getitem__(self, index): + + # if self.multi_scale and (index % self.batch_size == 0) and index != 0: + if self.multi_scale and (self.scale_index % self.batch_size == 0)and self.scale_index != 0: + self.img_size = random.choice(range(11, 18)) * 32 + # print("++++++ change img_size, index:", self.img_size, index) + if self.multi_scale: + self.scale_index += 1 + if self.scale_index >= (100*self.batch_size): + self.scale_index = 0 + + + img_path = self.img_files[index] + label_path = self.label_files[index] + + img = cv2.imread(img_path) # BGR + assert img is not None, 'File Not Found ' + img_path + + augment_hsv = random.random() < 0.5 # hsv_aug prob = 0.5 + if self.augment and augment_hsv: + # SV augmentation by 50% + fraction = 0.50 # must be < 1.0 + img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) + S = img_hsv[:, :, 1].astype(np.float32) + V = img_hsv[:, :, 2].astype(np.float32) + + a = (random.random() * 2 - 1) * fraction + 1 # a in [-0,5, 1.5] + S *= a + if a > 1: + np.clip(S, None, 255, out=S) + + a = (random.random() * 2 - 1) * fraction + 1 + V *= a + if a > 1: + np.clip(V, None, 255, out=V) + + img_hsv[:, :, 1] = S # .astype(np.uint8) + img_hsv[:, :, 2] = V # .astype(np.uint8) + cv2.cvtColor(img_hsv, cv2.COLOR_HSV2BGR, dst=img) + + h, w, _ = img.shape + img, ratio, padw, padh = letterbox(img, height=self.img_size, augment=self.augment) + + # Load labels + labels = [] + if os.path.isfile(label_path): + with open(label_path, 'r') as file: + lines = file.read().splitlines() + + x = np.array([x.split() for x in lines], dtype=np.float32) + if x.size > 0: + # Normalized xywh to pixel xyxy format + labels = x.copy() + labels[:, 1] = ratio * w * (x[:, 1] - x[:, 3] / 2) + padw + labels[:, 2] = ratio * h * (x[:, 2] - x[:, 4] / 2) + padh + labels[:, 3] = ratio * w * (x[:, 1] + x[:, 3] / 2) + padw + labels[:, 4] = ratio * h * (x[:, 2] + x[:, 4] / 2) + padh + + # Augment image and labels + if self.augment: + img, labels = random_affine(img, labels, degrees=(-10, 10), translate=(0.10, 0.10), scale=(0.9, 1.1)) + + nL = len(labels) # number of labels + if nL: + # convert xyxy to xywh + labels[:, 1:5] = xyxy2xywh(labels[:, 1:5]) / self.img_size # 转化 格式 ,且 归一化 + + if self.augment: + # random left-right flip + lr_flip = True + if lr_flip and random.random() > 0.5: + img = np.fliplr(img) + if nL: + labels[:, 1] = 1 - labels[:, 1] + + # random up-down flip + ud_flip = False + if ud_flip and random.random() > 0.5: + img = np.flipud(img) + if nL: + labels[:, 2] = 1 - labels[:, 2] + + labels_out = torch.zeros((nL, 6))# 加了 一个 batch size + if nL: + labels_out[:, 1:] = torch.from_numpy(labels) + + # Normalize + img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB, to 3x416x416 + img = np.ascontiguousarray(img, dtype=np.float32) # uint8 to float32 + img /= 255.0 # 0 - 255 to 0.0 - 1.0 + + return torch.from_numpy(img), labels_out, img_path, (h, w) + + @staticmethod + def collate_fn(batch): + img, label, path, hw = list(zip(*batch)) # transposed + for i, l in enumerate(label): + l[:, 0] = i # 获取 物体的 归属于 图片 的 index + return torch.stack(img, 0), torch.cat(label, 0), path, hw + + +def letterbox(img, height=416, augment=False, color=(127.5, 127.5, 127.5)): + # Resize a rectangular image to a padded square + shape = img.shape[:2] # shape = [height, width] + ratio = float(height) / max(shape) # ratio = old / new + new_shape = (round(shape[1] * ratio), round(shape[0] * ratio)) + dw = (height - new_shape[0]) / 2 # width padding + dh = (height - new_shape[1]) / 2 # height padding + top, bottom = round(dh - 0.1), round(dh + 0.1) + left, right = round(dw - 0.1), round(dw + 0.1) + # resize img + if augment: + interpolation = np.random.choice([None, cv2.INTER_NEAREST, cv2.INTER_LINEAR, + None, cv2.INTER_NEAREST, cv2.INTER_LINEAR, + cv2.INTER_AREA, cv2.INTER_CUBIC, cv2.INTER_LANCZOS4]) + if interpolation is None: + img = cv2.resize(img, new_shape) + else: + img = cv2.resize(img, new_shape, interpolation=interpolation) + else: + img = cv2.resize(img, new_shape, interpolation=cv2.INTER_NEAREST) + # print("resize time:",time.time()-s1) + + img = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color) # padded square + return img, ratio, dw, dh + + +def random_affine(img, targets=(), degrees=(-10, 10), translate=(.1, .1), scale=(.9, 1.1), shear=(-2, 2), + borderValue=(127.5, 127.5, 127.5)): + # torchvision.transforms.RandomAffine(degrees=(-10, 10), translate=(.1, .1), scale=(.9, 1.1), shear=(-10, 10)) + # https://medium.com/uruvideo/dataset-augmentation-with-random-homographies-a8f4b44830d4 + + if targets is None: + targets = [] + border = 0 # width of added border (optional) + height = max(img.shape[0], img.shape[1]) + border * 2 + + # Rotation and Scale + R = np.eye(3) + a = random.random() * (degrees[1] - degrees[0]) + degrees[0] + # a += random.choice([-180, -90, 0, 90]) # 90deg rotations added to small rotations + s = random.random() * (scale[1] - scale[0]) + scale[0] + R[:2] = cv2.getRotationMatrix2D(angle=a, center=(img.shape[1] / 2, img.shape[0] / 2), scale=s) + + # Translation + T = np.eye(3) + T[0, 2] = (random.random() * 2 - 1) * translate[0] * img.shape[0] + border # x translation (pixels) + T[1, 2] = (random.random() * 2 - 1) * translate[1] * img.shape[1] + border # y translation (pixels) + + # Shear + S = np.eye(3) + S[0, 1] = math.tan((random.random() * (shear[1] - shear[0]) + shear[0]) * math.pi / 180) # x shear (deg) + S[1, 0] = math.tan((random.random() * (shear[1] - shear[0]) + shear[0]) * math.pi / 180) # y shear (deg) + + M = S @ T @ R # Combined rotation matrix. ORDER IS IMPORTANT HERE!! + imw = cv2.warpPerspective(img, M, dsize=(height, height), flags=cv2.INTER_LINEAR, + borderValue=borderValue) # BGR order borderValue + + # Return warped points also + if len(targets) > 0: + n = targets.shape[0] + points = targets[:, 1:5].copy() + area0 = (points[:, 2] - points[:, 0]) * (points[:, 3] - points[:, 1]) + + # warp points + xy = np.ones((n * 4, 3)) + xy[:, :2] = points[:, [0, 1, 2, 3, 0, 3, 2, 1]].reshape(n * 4, 2) # x1y1, x2y2, x1y2, x2y1 + xy = (xy @ M.T)[:, :2].reshape(n, 8) + + # create new boxes + x = xy[:, [0, 2, 4, 6]] + y = xy[:, [1, 3, 5, 7]] + xy = np.concatenate((x.min(1), y.min(1), x.max(1), y.max(1))).reshape(4, n).T + + # apply angle-based reduction of bounding boxes + radians = a * math.pi / 180 + reduction = max(abs(math.sin(radians)), abs(math.cos(radians))) ** 0.5 + x = (xy[:, 2] + xy[:, 0]) / 2 + y = (xy[:, 3] + xy[:, 1]) / 2 + w = (xy[:, 2] - xy[:, 0]) * reduction + h = (xy[:, 3] - xy[:, 1]) * reduction + xy = np.concatenate((x - w / 2, y - h / 2, x + w / 2, y + h / 2)).reshape(4, n).T + + # reject warped points outside of image + np.clip(xy, 0, height, out=xy) + w = xy[:, 2] - xy[:, 0] + h = xy[:, 3] - xy[:, 1] + area = w * h + ar = np.maximum(w / (h + 1e-16), h / (w + 1e-16)) + i = (w > 4) & (h > 4) & (area / (area0 + 1e-16) > 0.1) & (ar < 10) + + targets = targets[i] + targets[:, 1:5] = xy[i] + + return imw, targets + + +def convert_images2bmp(): + # cv2.imread() jpg at 230 img/s, *.bmp at 400 img/s + for path in ['../coco/images/val2014/', '../coco/images/train2014/']: + folder = os.sep + Path(path).name + output = path.replace(folder, folder + 'bmp') + if os.path.exists(output): + shutil.rmtree(output) # delete output folder + os.makedirs(output) # make new output folder + + for f in tqdm(glob.glob('%s*.jpg' % path)): + save_name = f.replace('.jpg', '.bmp').replace(folder, folder + 'bmp') + cv2.imwrite(save_name, cv2.imread(f)) + + for label_path in ['../coco/trainvalno5k.txt', '../coco/5k.txt']: + with open(label_path, 'r') as file: + lines = file.read() + lines = lines.replace('2014/', '2014bmp/').replace('.jpg', '.bmp').replace( + '/Users/glennjocher/PycharmProjects/', '../') + with open(label_path.replace('5k', '5k_bmp'), 'w') as file: + file.write(lines) diff --git a/components/face_detect/utils/torch_utils.py b/components/face_detect/utils/torch_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..2c7352ebe21d8d2563a3a8cccf36e2a87aaf9352 --- /dev/null +++ b/components/face_detect/utils/torch_utils.py @@ -0,0 +1,24 @@ +import torch + +def init_seeds(seed=0): + torch.manual_seed(seed) + torch.cuda.manual_seed(seed) + torch.cuda.manual_seed_all(seed) + +def select_device(force_cpu=False): + if force_cpu: + cuda = False + device = torch.device('cpu') + else: + cuda = torch.cuda.is_available() + device = torch.device('cuda:0' if cuda else 'cpu') + + if torch.cuda.device_count() > 1: + device = torch.device('cuda' if cuda else 'cpu') + # print('Found %g GPUs' % torch.cuda.device_count()) + # print('Multi-GPU Issue: https://github.com/ultralytics/yolov3/issues/21') + # torch.cuda.set_device(0) # OPTIONAL: Set your GPU if multiple available + # print('Using ', torch.cuda.device_count(), ' GPUs') + + # print('Using %s %s\n' % (device.type, torch.cuda.get_device_properties(0) if cuda else '')) + return device diff --git a/components/face_detect/utils/utils.py b/components/face_detect/utils/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..fd529c54a7e3205b2fa42cee288bc7b295af17de --- /dev/null +++ b/components/face_detect/utils/utils.py @@ -0,0 +1,438 @@ +import glob +import random +import time +from collections import defaultdict + +import cv2 +import numpy as np +import torch +import torch.nn as nn +from dp_models.light_pose.modules.keypoints import BODY_PARTS_KPT_IDS, BODY_PARTS_PAF_IDS + +# Set printoptions +torch.set_printoptions(linewidth=1320, precision=5, profile='long') +np.set_printoptions(linewidth=320, formatter={'float_kind': '{:11.5g}'.format}) # format short g, %precision=5 + +# Prevent OpenCV from multithreading (to use PyTorch DataLoader) +cv2.setNumThreads(0) + +def float3(x): # format floats to 3 decimals + return float(format(x, '.3f')) + +def init_seeds(seed=0): + random.seed(seed) + np.random.seed(seed) + torch.manual_seed(seed) + + if torch.cuda.is_available(): + torch.cuda.manual_seed(seed) + torch.cuda.manual_seed_all(seed) + else: + torch.manual_seed(seed) + torch.manual_seed_all(seed) + + +def load_classes(path): + # Loads class labels at 'path' + fp = open(path, 'r') + names = fp.read().split('\n') + return list(filter(None, names)) # filter removes empty strings (such as last line) + + +def model_info(model): + # Plots a line-by-line description of a PyTorch model + n_p = sum(x.numel() for x in model.parameters()) # number parameters + n_g = sum(x.numel() for x in model.parameters() if x.requires_grad) # number gradients + print('\n%5s %60s %9s %12s %20s %10s %10s' % ('layer', 'name', 'gradient', 'parameters', 'shape', 'mu', 'sigma')) + for i, (name, p) in enumerate(model.named_parameters()): + # name = name.replace('module_list.', '') + print('%5g %60s %9s %12g %20s %10.3g %10.3g' % ( + i, name, p.requires_grad, p.numel(), list(p.shape), p.mean(), p.std())) + print('Model Summary: %g layers, %g parameters, %g gradients' % (i + 1, n_p, n_g)) + + + + + +def weights_init_normal(m): + classname = m.__class__.__name__ + if classname.find('Conv') != -1: + torch.nn.init.normal_(m.weight.data, 0.0, 0.03) + elif classname.find('BatchNorm2d') != -1: + torch.nn.init.normal_(m.weight.data, 1.0, 0.03) + torch.nn.init.constant_(m.bias.data, 0.0) + + +def xyxy2xywh(x): + # Convert bounding box format from [x1, y1, x2, y2] to [x, y, w, h] + y = torch.zeros_like(x) if isinstance(x, torch.Tensor) else np.zeros_like(x) + y[:, 0] = (x[:, 0] + x[:, 2]) / 2 + y[:, 1] = (x[:, 1] + x[:, 3]) / 2 + y[:, 2] = x[:, 2] - x[:, 0] + y[:, 3] = x[:, 3] - x[:, 1] + return y + + +def xywh2xyxy(x): + # Convert bounding box format from [x, y, w, h] to [x1, y1, x2, y2] + y = torch.zeros_like(x) if isinstance(x, torch.Tensor) else np.zeros_like(x) + y[:, 0] = x[:, 0] - x[:, 2] / 2 + y[:, 1] = x[:, 1] - x[:, 3] / 2 + y[:, 2] = x[:, 0] + x[:, 2] / 2 + y[:, 3] = x[:, 1] + x[:, 3] / 2 + return y + +def scale_coords(img_size, coords, img0_shape):# image size 转为 原图尺寸 + # Rescale x1, y1, x2, y2 from 416 to image size + # print('coords : ',coords) + # print('img0_shape : ',img0_shape) + gain = float(img_size) / max(img0_shape) # gain = old / new + # print('gain : ',gain) + pad_x = (img_size - img0_shape[1] * gain) / 2 # width padding + pad_y = (img_size - img0_shape[0] * gain) / 2 # height padding + # print('pad_xpad_y : ',pad_x,pad_y) + coords[:, [0, 2]] -= pad_x + coords[:, [1, 3]] -= pad_y + coords[:, :4] /= gain + coords[:, :4] = torch.clamp(coords[:, :4], min=0)# 夹紧区间最小值不为负数 + return coords + + +def ap_per_class(tp, conf, pred_cls, target_cls): + """ Compute the average precision, given the recall and precision curves. + Source: https://github.com/rafaelpadilla/Object-Detection-Metrics. + # Arguments + tp: True positives (list). + conf: Objectness value from 0-1 (list). + pred_cls: Predicted object classes (list). + target_cls: True object classes (list). + # Returns + The average precision as computed in py-faster-rcnn. + """ + + # Sort by objectness + i = np.argsort(-conf) + tp, conf, pred_cls = tp[i], conf[i], pred_cls[i] + + # Find unique classes + unique_classes = np.unique(target_cls) + + # Create Precision-Recall curve and compute AP for each class + ap, p, r = [], [], [] + for c in unique_classes: + i = pred_cls == c + n_gt = (target_cls == c).sum() # Number of ground truth objects + n_p = i.sum() # Number of predicted objects + + if n_p == 0 and n_gt == 0: + continue + elif n_p == 0 or n_gt == 0: + ap.append(0) + r.append(0) + p.append(0) + else: + # Accumulate FPs and TPs + fpc = (1 - tp[i]).cumsum() + tpc = (tp[i]).cumsum() + + # Recall + recall_curve = tpc / (n_gt + 1e-16) + r.append(recall_curve[-1]) + + # Precision + precision_curve = tpc / (tpc + fpc) + p.append(precision_curve[-1]) + + # AP from recall-precision curve + ap.append(compute_ap(recall_curve, precision_curve)) + + # Plot + # plt.plot(recall_curve, precision_curve) + + # Compute F1 score (harmonic mean of precision and recall) + p, r, ap = np.array(p), np.array(r), np.array(ap) + f1 = 2 * p * r / (p + r + 1e-16) + + return p, r, ap, f1, unique_classes.astype('int32') + + +def compute_ap(recall, precision): + """ Compute the average precision, given the recall and precision curves. + Source: https://github.com/rbgirshick/py-faster-rcnn. + # Arguments + recall: The recall curve (list). + precision: The precision curve (list). + # Returns + The average precision as computed in py-faster-rcnn. + """ + # correct AP calculation + # first append sentinel values at the end + + mrec = np.concatenate(([0.], recall, [1.])) + mpre = np.concatenate(([0.], precision, [0.])) + + # compute the precision envelope + for i in range(mpre.size - 1, 0, -1): + mpre[i - 1] = np.maximum(mpre[i - 1], mpre[i]) + + # to calculate area under PR curve, look for points + # where X axis (recall) changes value + i = np.where(mrec[1:] != mrec[:-1])[0] + + # and sum (\Delta recall) * prec + ap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1]) + return ap + + +def bbox_iou(box1, box2, x1y1x2y2=True): + # Returns the IoU of box1 to box2. box1 is 4, box2 is nx4 + box2 = box2.t() + + # Get the coordinates of bounding boxes + if x1y1x2y2: + # x1, y1, x2, y2 = box1 + b1_x1, b1_y1, b1_x2, b1_y2 = box1[0], box1[1], box1[2], box1[3] + b2_x1, b2_y1, b2_x2, b2_y2 = box2[0], box2[1], box2[2], box2[3] + else: + # x, y, w, h = box1 + b1_x1, b1_x2 = box1[0] - box1[2] / 2, box1[0] + box1[2] / 2 + b1_y1, b1_y2 = box1[1] - box1[3] / 2, box1[1] + box1[3] / 2 + b2_x1, b2_x2 = box2[0] - box2[2] / 2, box2[0] + box2[2] / 2 + b2_y1, b2_y2 = box2[1] - box2[3] / 2, box2[1] + box2[3] / 2 + + # Intersection area + inter_area = (torch.min(b1_x2, b2_x2) - torch.max(b1_x1, b2_x1)).clamp(0) * \ + (torch.min(b1_y2, b2_y2) - torch.max(b1_y1, b2_y1)).clamp(0) + + # Union Area + union_area = ((b1_x2 - b1_x1) * (b1_y2 - b1_y1) + 1e-16) + \ + (b2_x2 - b2_x1) * (b2_y2 - b2_y1) - inter_area + + return inter_area / union_area # iou + + +def wh_iou(box1, box2): + + box2 = box2.t() + + # w, h = box1 + w1, h1 = box1[0], box1[1] + w2, h2 = box2[0], box2[1] + + # Intersection area + inter_area = torch.min(w1, w2) * torch.min(h1, h2) + + # Union Area + union_area = (w1 * h1 + 1e-16) + w2 * h2 - inter_area + + return inter_area / union_area # iou + + +def compute_loss(p, targets): # predictions, targets + FT = torch.cuda.FloatTensor if p[0].is_cuda else torch.FloatTensor + lxy, lwh, lcls, lconf = FT([0]), FT([0]), FT([0]), FT([0]) # losses 初始化 为 0 + txy, twh, tcls, indices = targets + MSE = nn.MSELoss() + CE = nn.CrossEntropyLoss() + BCE = nn.BCEWithLogitsLoss()# 多标签分类时 使用 如 [1,1,0], + + # Compute losses + for i, pi0 in enumerate(p): # layer i predictions, i + b, a, gj, gi = indices[i] # image_idx, anchor_idx, gridx, gridy + + # print(i,') b, a, gj, gi : ') + # print('b', b) + # print('a', a) + # print('gj', gj) + # print('gi', gi) + + tconf = torch.zeros_like(pi0[..., 0]) # conf + + # print('tconf: ',tconf.size()) + # Compute losses + k = 1 # nT / bs + if len(b) > 0: + pi = pi0[b, a, gj, gi] # predictions closest to anchors + tconf[b, a, gj, gi] = 1 # conf + + lxy += (k * 8) * MSE(torch.sigmoid(pi[..., 0:2]), txy[i]) # xy loss + lwh += (k * 4) * MSE(pi[..., 2:4], twh[i]) # wh loss + lcls += (k * 1) * CE(pi[..., 5:], tcls[i]) # class_conf loss + + lconf += (k * 64) * BCE(pi0[..., 4], tconf) # obj_conf loss + loss = lxy + lwh + lconf + lcls + + # Add to dictionary + d = defaultdict(float) + losses = [loss.item(), lxy.item(), lwh.item(), lconf.item(), lcls.item()] + for name, x in zip(['total', 'xy', 'wh', 'conf', 'cls'], losses): + d[name] = x + + return loss, d + + +def build_targets(model, targets): + # targets = [image, class, x, y, w, h] + if isinstance(model, nn.parallel.DistributedDataParallel): + model = model.module + + txy, twh, tcls, indices = [], [], [], [] + for i, layer in enumerate(get_yolo_layers(model)):# 遍历 3 个 yolo layer + # print(i,'layer ',model.module_list[layer]) + layer = model.module_list[layer][0] + + # iou of targets-anchors + gwh = targets[:, 4:6] * layer.nG # 以 grid 为单位的 wh + iou = [wh_iou(x, gwh) for x in layer.anchor_vec] + iou, a = torch.stack(iou, 0).max(0) # best iou and anchor + + # reject below threshold ious (OPTIONAL, increases P, lowers R) + reject = True + if reject: + j = iou > 0.10 + t, a, gwh = targets[j], a[j], gwh[j] + else: + t = targets + + # Indices + b, c = t[:, :2].long().t() # target image, class + gxy = t[:, 2:4] * layer.nG + gi, gj = gxy.long().t() # grid_i, grid_j + indices.append((b, a, gj, gi)) # img_index , anchor_index , grid_x , grid_y + + # print('b, a, gj, gi : ') + # print('b', b) + # print('a', a) + # print('gj', gj) + # print('gi', gi) + # print('class c',c) + + # XY coordinates + txy.append(gxy - gxy.floor())#转化为grid相对坐标 + + # Width and height + twh.append(torch.log(gwh / layer.anchor_vec[a])) # yolo method 对数 + # twh.append(torch.sqrt(gwh / layer.anchor_vec[a]) / 2) # power method + + # Class + tcls.append(c) + # try: + # print('c.max,layer.nC: ',c.max().item() ,layer.nC) + # except: + # pass + if c.shape[0]: + assert c.max().item() <= layer.nC, 'Target classes exceed model classes' + + return txy, twh, tcls, indices + + +# @profile +def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.4): + """ + Removes detections with lower object confidence score than 'conf_thres' + Non-Maximum Suppression to further filter detections. + Returns detections with shape: + (x1, y1, x2, y2, object_conf, class_conf, class) + """ + + min_wh = 2 # (pixels) minimum box width and height + + output = [None] * len(prediction) + for image_i, pred in enumerate(prediction): + # Experiment: Prior class size rejection + # x, y, w, h = pred[:, 0], pred[:, 1], pred[:, 2], pred[:, 3] + # a = w * h # area + # ar = w / (h + 1e-16) # aspect ratio + # n = len(w) + # log_w, log_h, log_a, log_ar = torch.log(w), torch.log(h), torch.log(a), torch.log(ar) + # shape_likelihood = np.zeros((n, 60), dtype=np.float32) + # x = np.concatenate((log_w.reshape(-1, 1), log_h.reshape(-1, 1)), 1) + # from scipy.stats import multivariate_normal + # for c in range(60): + # shape_likelihood[:, c] = + # multivariate_normal.pdf(x, mean=mat['class_mu'][c, :2], cov=mat['class_cov'][c, :2, :2]) + + # Filter out confidence scores below threshold + class_conf, class_pred = pred[:, 5:].max(1) # max class_conf, index + pred[:, 4] *= class_conf # finall conf = obj_conf * class_conf + + i = (pred[:, 4] > conf_thres) & (pred[:, 2] > min_wh) & (pred[:, 3] > min_wh) + # s2=time.time() + pred2 = pred[i] + # print("++++++pred2 = pred[i]",time.time()-s2, pred2) + + # If none are remaining => process next image + if len(pred2) == 0: + continue + + # Select predicted classes + class_conf = class_conf[i] + class_pred = class_pred[i].unsqueeze(1).float() + + # Box (center x, center y, width, height) to (x1, y1, x2, y2) + pred2[:, :4] = xywh2xyxy(pred2[:, :4]) + # pred[:, 4] *= class_conf # improves mAP from 0.549 to 0.551 + + # Detections ordered as (x1y1x2y2, obj_conf, class_conf, class_pred) + pred2 = torch.cat((pred2[:, :5], class_conf.unsqueeze(1), class_pred), 1) + + # Get detections sorted by decreasing confidence scores + pred2 = pred2[(-pred2[:, 4]).argsort()] + + det_max = [] + nms_style = 'MERGE' # 'OR' (default), 'AND', 'MERGE' (experimental) + for c in pred2[:, -1].unique(): + dc = pred2[pred2[:, -1] == c] # select class c + dc = dc[:min(len(dc), 100)] # limit to first 100 boxes + + # Non-maximum suppression + if nms_style == 'OR': # default + # METHOD1 + # ind = list(range(len(dc))) + # while len(ind): + # j = ind[0] + # det_max.append(dc[j:j + 1]) # save highest conf detection + # reject = (bbox_iou(dc[j], dc[ind]) > nms_thres).nonzero() + # [ind.pop(i) for i in reversed(reject)] + + # METHOD2 + while dc.shape[0]: + det_max.append(dc[:1]) # save highest conf detection + if len(dc) == 1: # Stop if we're at the last detection + break + iou = bbox_iou(dc[0], dc[1:]) # iou with other boxes + dc = dc[1:][iou < nms_thres] # remove ious > threshold + + elif nms_style == 'AND': # requires overlap, single boxes erased + while len(dc) > 1: + iou = bbox_iou(dc[0], dc[1:]) # iou with other boxes + if iou.max() > 0.5: + det_max.append(dc[:1]) + dc = dc[1:][iou < nms_thres] # remove ious > threshold + + elif nms_style == 'MERGE': # weighted mixture box + while len(dc): + i = bbox_iou(dc[0], dc) > nms_thres # iou with other boxes + weights = dc[i, 4:5] + dc[0, :4] = (weights * dc[i, :4]).sum(0) / weights.sum() + det_max.append(dc[:1]) + dc = dc[i == 0] + + if len(det_max): + det_max = torch.cat(det_max) # concatenate + output[image_i] = det_max[(-det_max[:, 4]).argsort()] # sort + return output + + +def get_yolo_layers(model): + yolo_layer_index = [] + for index, l in enumerate(model.module_list): + try: + a = l[0].img_size and l[0].nG # only yolo layer need img_size and nG + # print("---"*50) + # print(l, index) + yolo_layer_index.append(index) + except: + pass + assert len(yolo_layer_index) > 0, "can not find yolo layer" + return yolo_layer_index diff --git a/components/face_detect/yolo_v3_face.py b/components/face_detect/yolo_v3_face.py new file mode 100644 index 0000000000000000000000000000000000000000..c79eb3fc808a9d93bf51151db532bf6c3dd39805 --- /dev/null +++ b/components/face_detect/yolo_v3_face.py @@ -0,0 +1,311 @@ +#-*-coding:utf-8-*- +# date:2021-04-16 +# Author: Eric.Lee +# function: yolo v3 face detect + +import os +import cv2 +import numpy as np +import time + +import torch + +from hand_detect.yolov3 import Yolov3, Yolov3Tiny +from hand_detect.utils.torch_utils import select_device +from hand_detect.acc_model import acc_model + +import torch.backends.cudnn as cudnn +import torch.nn.functional as F + + +import random + +def show_model_param(model): + params = list(model.parameters()) + k = 0 + for i in params: + l = 1 + for j in i.size(): + l *= j + print("该层的结构: {}, 参数和: {}".format(str(list(i.size())), str(l))) + k = k + l + print("----------------------") + print("总参数数量和: " + str(k)) + +def process_data(img, img_size=416):# 图像预处理 + img, _, _, _ = letterbox(img, height=img_size) + # Normalize RG25 + img = img[:, :, ::-1].transpose(2, 0, 1) # BGR to RGB + img = np.ascontiguousarray(img, dtype=np.float32) # uint8 to float32 + img /= 255.0 # 0 - 255 to 0.0 - 1.0 + return img + +def plot_one_box(x, img, color=None, label=None, line_thickness=None): + # Plots one bounding box on image img + tl = line_thickness or round(0.002 * max(img.shape[0:2])) + 1 # line thickness + color = color or [random.randint(0, 255) for _ in range(3)] + c1, c2 = (int(x[0]), int(x[1])), (int(x[2]), int(x[3])) + cv2.rectangle(img, c1, c2, color, thickness=tl) + if label: + tf = max(tl - 1, 1) # font thickness + t_size = cv2.getTextSize(label, 0, fontScale=tl / 3, thickness=tf)[0] + c2 = c1[0] + t_size[0], c1[1] - t_size[1] - 3 + cv2.rectangle(img, c1, c2, color, -1) # filled + cv2.putText(img, label, (c1[0], c1[1] - 2), 0, tl / 3, [255, 55,90], thickness=tf, lineType=cv2.LINE_AA) + +def bbox_iou(box1, box2, x1y1x2y2=True): + # Returns the IoU of box1 to box2. box1 is 4, box2 is nx4 + box2 = box2.t() + + # Get the coordinates of bounding boxes + if x1y1x2y2: + # x1, y1, x2, y2 = box1 + b1_x1, b1_y1, b1_x2, b1_y2 = box1[0], box1[1], box1[2], box1[3] + b2_x1, b2_y1, b2_x2, b2_y2 = box2[0], box2[1], box2[2], box2[3] + else: + # x, y, w, h = box1 + b1_x1, b1_x2 = box1[0] - box1[2] / 2, box1[0] + box1[2] / 2 + b1_y1, b1_y2 = box1[1] - box1[3] / 2, box1[1] + box1[3] / 2 + b2_x1, b2_x2 = box2[0] - box2[2] / 2, box2[0] + box2[2] / 2 + b2_y1, b2_y2 = box2[1] - box2[3] / 2, box2[1] + box2[3] / 2 + + # Intersection area + inter_area = (torch.min(b1_x2, b2_x2) - torch.max(b1_x1, b2_x1)).clamp(0) * \ + (torch.min(b1_y2, b2_y2) - torch.max(b1_y1, b2_y1)).clamp(0) + + # Union Area + union_area = ((b1_x2 - b1_x1) * (b1_y2 - b1_y1) + 1e-16) + \ + (b2_x2 - b2_x1) * (b2_y2 - b2_y1) - inter_area + + return inter_area / union_area # iou + +def xywh2xyxy(x): + # Convert bounding box format from [x, y, w, h] to [x1, y1, x2, y2] + y = torch.zeros_like(x) if isinstance(x, torch.Tensor) else np.zeros_like(x) + y[:, 0] = x[:, 0] - x[:, 2] / 2 + y[:, 1] = x[:, 1] - x[:, 3] / 2 + y[:, 2] = x[:, 0] + x[:, 2] / 2 + y[:, 3] = x[:, 1] + x[:, 3] / 2 + return y + + +def scale_coords(img_size, coords, img0_shape):# image size 转为 原图尺寸 + # Rescale x1, y1, x2, y2 from 416 to image size + # print('coords : ',coords) + # print('img0_shape : ',img0_shape) + gain = float(img_size) / max(img0_shape) # gain = old / new + # print('gain : ',gain) + pad_x = (img_size - img0_shape[1] * gain) / 2 # width padding + pad_y = (img_size - img0_shape[0] * gain) / 2 # height padding + # print('pad_xpad_y : ',pad_x,pad_y) + coords[:, [0, 2]] -= pad_x + coords[:, [1, 3]] -= pad_y + coords[:, :4] /= gain + coords[:, :4] = torch.clamp(coords[:, :4], min=0)# 夹紧区间最小值不为负数 + return coords + +def non_max_suppression(prediction, conf_thres=0.5, nms_thres=0.4): + """ + Removes detections with lower object confidence score than 'conf_thres' + Non-Maximum Suppression to further filter detections. + Returns detections with shape: + (x1, y1, x2, y2, object_conf, class_conf, class) + """ + + min_wh = 2 # (pixels) minimum box width and height + + output = [None] * len(prediction) + for image_i, pred in enumerate(prediction): + # Experiment: Prior class size rejection + # x, y, w, h = pred[:, 0], pred[:, 1], pred[:, 2], pred[:, 3] + # a = w * h # area + # ar = w / (h + 1e-16) # aspect ratio + # n = len(w) + # log_w, log_h, log_a, log_ar = torch.log(w), torch.log(h), torch.log(a), torch.log(ar) + # shape_likelihood = np.zeros((n, 60), dtype=np.float32) + # x = np.concatenate((log_w.reshape(-1, 1), log_h.reshape(-1, 1)), 1) + # from scipy.stats import multivariate_normal + # for c in range(60): + # shape_likelihood[:, c] = + # multivariate_normal.pdf(x, mean=mat['class_mu'][c, :2], cov=mat['class_cov'][c, :2, :2]) + + # Filter out confidence scores below threshold + class_conf, class_pred = pred[:, 5:].max(1) # max class_conf, index + pred[:, 4] *= class_conf # finall conf = obj_conf * class_conf + + i = (pred[:, 4] > conf_thres) & (pred[:, 2] > min_wh) & (pred[:, 3] > min_wh) + # s2=time.time() + pred2 = pred[i] + # print("++++++pred2 = pred[i]",time.time()-s2, pred2) + + # If none are remaining => process next image + if len(pred2) == 0: + continue + + # Select predicted classes + class_conf = class_conf[i] + class_pred = class_pred[i].unsqueeze(1).float() + + # Box (center x, center y, width, height) to (x1, y1, x2, y2) + pred2[:, :4] = xywh2xyxy(pred2[:, :4]) + # pred[:, 4] *= class_conf # improves mAP from 0.549 to 0.551 + + # Detections ordered as (x1y1x2y2, obj_conf, class_conf, class_pred) + pred2 = torch.cat((pred2[:, :5], class_conf.unsqueeze(1), class_pred), 1) + + # Get detections sorted by decreasing confidence scores + pred2 = pred2[(-pred2[:, 4]).argsort()] + + det_max = [] + nms_style = 'MERGE' # 'OR' (default), 'AND', 'MERGE' (experimental) + for c in pred2[:, -1].unique(): + dc = pred2[pred2[:, -1] == c] # select class c + dc = dc[:min(len(dc), 100)] # limit to first 100 boxes + + # Non-maximum suppression + if nms_style == 'OR': # default + # METHOD1 + # ind = list(range(len(dc))) + # while len(ind): + # j = ind[0] + # det_max.append(dc[j:j + 1]) # save highest conf detection + # reject = (bbox_iou(dc[j], dc[ind]) > nms_thres).nonzero() + # [ind.pop(i) for i in reversed(reject)] + + # METHOD2 + while dc.shape[0]: + det_max.append(dc[:1]) # save highest conf detection + if len(dc) == 1: # Stop if we're at the last detection + break + iou = bbox_iou(dc[0], dc[1:]) # iou with other boxes + dc = dc[1:][iou < nms_thres] # remove ious > threshold + + elif nms_style == 'AND': # requires overlap, single boxes erased + while len(dc) > 1: + iou = bbox_iou(dc[0], dc[1:]) # iou with other boxes + if iou.max() > 0.5: + det_max.append(dc[:1]) + dc = dc[1:][iou < nms_thres] # remove ious > threshold + + elif nms_style == 'MERGE': # weighted mixture box + while len(dc): + i = bbox_iou(dc[0], dc) > nms_thres # iou with other boxes + weights = dc[i, 4:5] + dc[0, :4] = (weights * dc[i, :4]).sum(0) / weights.sum() + det_max.append(dc[:1]) + dc = dc[i == 0] + + if len(det_max): + det_max = torch.cat(det_max) # concatenate + output[image_i] = det_max[(-det_max[:, 4]).argsort()] # sort + return output + +def letterbox(img, height=416, augment=False, color=(127.5, 127.5, 127.5)): + # Resize a rectangular image to a padded square + shape = img.shape[:2] # shape = [height, width] + ratio = float(height) / max(shape) # ratio = old / new + new_shape = (round(shape[1] * ratio), round(shape[0] * ratio)) + dw = (height - new_shape[0]) / 2 # width padding + dh = (height - new_shape[1]) / 2 # height padding + top, bottom = round(dh - 0.1), round(dh + 0.1) + left, right = round(dw - 0.1), round(dw + 0.1) + # resize img + if augment: + interpolation = np.random.choice([None, cv2.INTER_NEAREST, cv2.INTER_LINEAR, + None, cv2.INTER_NEAREST, cv2.INTER_LINEAR, + cv2.INTER_AREA, cv2.INTER_CUBIC, cv2.INTER_LANCZOS4]) + if interpolation is None: + img = cv2.resize(img, new_shape) + else: + img = cv2.resize(img, new_shape, interpolation=interpolation) + else: + img = cv2.resize(img, new_shape, interpolation=cv2.INTER_NEAREST) + # print("resize time:",time.time()-s1) + + img = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color) # padded square + return img, ratio, dw, dh +#--------------------------------------------------------- +# model_path = './coco_model/yolov3_coco.pt' # 检测模型路径 +# model_arch = 'yolov3' # 模型类型 +# img_size = 416 # 图像尺寸 +# conf_thres = 0.35# 检测置信度 +# nms_thres = 0.5 # nms 阈值 +class yolo_v3_face_model(object): + def __init__(self, + model_path = './components/face_detect/weights/face_yolo_416-20210418.pt', + model_arch = 'yolov3', + yolo_anchor_scale = 1., + img_size=416, + conf_thres=0.4, + nms_thres=0.4,): + print("yolo v3 face_model loading : {}".format(model_path)) + self.use_cuda = torch.cuda.is_available() + self.device = torch.device("cuda:0" if self.use_cuda else "cpu") + self.img_size = img_size + self.classes = ["Face"] + self.num_classes = len(self.classes) + self.conf_thres = conf_thres + self.nms_thres = nms_thres + #----------------------------------------------------------------------- + weights = model_path + if "tiny" in model_arch: + a_scalse = 416./img_size*yolo_anchor_scale + anchors=[(10, 14), (23, 27), (37, 58), (81, 82), (135, 169), (344, 319)] + anchors_new = [ (int(anchors[j][0]/a_scalse),int(anchors[j][1]/a_scalse)) for j in range(len(anchors)) ] + + model = Yolov3Tiny(self.num_classes,anchors = anchors_new) + else: + a_scalse = 416./img_size + anchors=[(10,13), (16,30), (33,23), (30,61), (62,45), (59,119), (116,90), (156,198), (373,326)] + anchors_new = [ (int(anchors[j][0]/a_scalse),int(anchors[j][1]/a_scalse)) for j in range(len(anchors)) ] + model = Yolov3(self.num_classes,anchors = anchors_new) + #----------------------------------------------------------------------- + + self.model = model + # show_model_param(self.model)# 显示模型参数 + + # print('num_classes : ',self.num_classes) + + self.device = select_device() # 运行硬件选择 + self.use_cuda = torch.cuda.is_available() + # Load weights + if os.access(weights,os.F_OK):# 判断模型文件是否存在 + self.model.load_state_dict(torch.load(weights, map_location=lambda storage, loc: storage)['model']) + else: + print('------- >>> error : model not exists') + return False + # + self.model.eval()#模型设置为 eval + acc_model('',self.model) + self.model = self.model.to(self.device) + + def predict(self, img_,vis): + with torch.no_grad(): + t = time.time() + img = process_data(img_, self.img_size) + t1 = time.time() + img = torch.from_numpy(img).unsqueeze(0).to(self.device) + + pred, _ = self.model(img)#图片检测 + + t2 = time.time() + detections = non_max_suppression(pred, self.conf_thres, self.nms_thres)[0] # nms + t3 = time.time() + # print("t3 time:", t3) + + if (detections is None) or len(detections) == 0: + return [] + # Rescale boxes from 416 to true image size + detections[:, :4] = scale_coords(self.img_size, detections[:, :4], img_.shape).round() + # 绘制检测结果 :detect reslut + dets_for_landmarks = [] + colors = [(v // 32 * 64 + 64, (v // 8) % 4 * 64, v % 8 * 32) for v in range(1, 10 + 1)][::-1] + + output_dict_ = [] + for *xyxy, conf, cls_conf, cls in detections: + label = '%s %.2f' % (self.classes[0], conf) + x1,y1,x2,y2 = xyxy + output_dict_.append((float(x1),float(y1),float(x2),float(y2),float(conf.item()))) + if vis: + plot_one_box(xyxy, img_, label=label, color=(0,175,255), line_thickness = 2) + return output_dict_ diff --git a/components/face_detect/yolov3.py b/components/face_detect/yolov3.py new file mode 100644 index 0000000000000000000000000000000000000000..519ae7e290976a6fa2a75508312fb2fb1baa5928 --- /dev/null +++ b/components/face_detect/yolov3.py @@ -0,0 +1,505 @@ +import os +import numpy as np +from collections import OrderedDict + +import torch +import torch.nn.functional as F +import torch.nn as nn + + +# reference: +# https://github.com/ultralytics/yolov3/blob/master/models.py +# https://github.com/TencentYoutuResearch/ObjectDetection-OneStageDet/blob/master/yolo/vedanet/network/backbone/brick/darknet53.py +# network structure https://blog.csdn.net/u010397980/article/details/85058630 + +flag_yolo_structure = False # True 查看 相关的网络 log + +class Conv2dBatchLeaky(nn.Module): + def __init__(self, in_channels, out_channels, kernel_size, stride, leaky_slope=0.1): + super(Conv2dBatchLeaky, self).__init__() + + self.in_channels = in_channels + self.out_channels = out_channels + self.kernel_size = kernel_size + self.stride = stride + if isinstance(kernel_size, (list, tuple)): + self.padding = [int(ii/2) for ii in kernel_size] + if flag_yolo_structure: + print('------------------->>>> Conv2dBatchLeaky isinstance') + else: + self.padding = int(kernel_size/2) + + self.leaky_slope = leaky_slope + # Layer + # LeakyReLU : y = max(0, x) + leaky_slope*min(0,x) + self.layers = nn.Sequential( + nn.Conv2d(self.in_channels, self.out_channels, self.kernel_size, self.stride, self.padding, bias=False), + nn.BatchNorm2d(self.out_channels), + nn.LeakyReLU(self.leaky_slope, inplace=True) + ) + + def forward(self, x): + x = self.layers(x) + return x + +class ResBlockSum(nn.Module): + def __init__(self, nchannels): + super().__init__() + self.block = nn.Sequential( + Conv2dBatchLeaky(nchannels, int(nchannels/2), 1, 1), + Conv2dBatchLeaky(int(nchannels/2), nchannels, 3, 1) + ) + + def forward(self, x): + return x + self.block(x) + +class HeadBody(nn.Module): + def __init__(self, in_channels, out_channels): + super(HeadBody, self).__init__() + + self.layer = nn.Sequential( + Conv2dBatchLeaky(in_channels, out_channels, 1, 1), + Conv2dBatchLeaky(out_channels, out_channels*2, 3, 1), + Conv2dBatchLeaky(out_channels*2, out_channels, 1, 1), + Conv2dBatchLeaky(out_channels, out_channels*2, 3, 1), + Conv2dBatchLeaky(out_channels*2, out_channels, 1, 1) + ) + + def forward(self, x): + x = self.layer(x) + return x + +class Upsample(nn.Module): + # Custom Upsample layer (nn.Upsample gives deprecated warning message) + + def __init__(self, scale_factor=1, mode='nearest'): + super(Upsample, self).__init__() + self.scale_factor = scale_factor + self.mode = mode + + def forward(self, x): + return F.interpolate(x, scale_factor=self.scale_factor, mode=self.mode) + +# default anchors=[(10,13), (16,30), (33,23), (30,61), (62,45), (59,119), (116,90), (156,198), (373,326)] +class YOLOLayer(nn.Module): + def __init__(self, anchors, nC): + super(YOLOLayer, self).__init__() + + self.anchors = torch.FloatTensor(anchors) + self.nA = len(anchors) # number of anchors (3) + self.nC = nC # number of classes + self.img_size = 0 + if flag_yolo_structure: + print('init YOLOLayer ------ >>> ') + print('anchors : ',self.anchors) + print('nA : ',self.nA) + print('nC : ',self.nC) + print('img_size : ',self.img_size) + + def forward(self, p, img_size, var=None):# p : feature map + bs, nG = p.shape[0], p.shape[-1] # batch_size , grid + if flag_yolo_structure: + print('bs, nG --->>> ',bs, nG) + if self.img_size != img_size: + create_grids(self, img_size, nG, p.device) + + # p.view(bs, 255, 13, 13) -- > (bs, 3, 13, 13, 85) # (bs, anchors, grid, grid, xywh + confidence + classes) + p = p.view(bs, self.nA, self.nC + 5, nG, nG).permute(0, 1, 3, 4, 2).contiguous() # prediction + + if self.training: + return p + else: # inference + io = p.clone() # inference output + io[..., 0:2] = torch.sigmoid(io[..., 0:2]) + self.grid_xy # xy + io[..., 2:4] = torch.exp(io[..., 2:4]) * self.anchor_wh # wh yolo method + io[..., 4:] = torch.sigmoid(io[..., 4:]) # p_conf, p_cls + io[..., :4] *= self.stride + if self.nC == 1: + io[..., 5] = 1 # single-class model + # flatten prediction, reshape from [bs, nA, nG, nG, nC] to [bs, nA * nG * nG, nC] + return io.view(bs, -1, 5 + self.nC), p + +def create_grids(self, img_size, nG, device='cpu'): + # self.nA : len(anchors) # number of anchors (3) + # self.nC : nC # number of classes + # nG : feature map grid 13*13 26*26 52*52 + self.img_size = img_size + self.stride = img_size / nG + if flag_yolo_structure: + print('create_grids stride : ',self.stride) + + # build xy offsets + grid_x = torch.arange(nG).repeat((nG, 1)).view((1, 1, nG, nG)).float() + grid_y = grid_x.permute(0, 1, 3, 2) + self.grid_xy = torch.stack((grid_x, grid_y), 4).to(device) + if flag_yolo_structure: + print('grid_x : ',grid_x.size(),grid_x) + print('grid_y : ',grid_y.size(),grid_y) + print('grid_xy : ',self.grid_xy.size(),self.grid_xy) + + # build wh gains + self.anchor_vec = self.anchors.to(device) / self.stride # 基于 stride 的归一化 + # print('self.anchor_vecself.anchor_vecself.anchor_vec:',self.anchor_vec) + self.anchor_wh = self.anchor_vec.view(1, self.nA, 1, 1, 2).to(device) + self.nG = torch.FloatTensor([nG]).to(device) + + +def get_yolo_layer_index(module_list): + yolo_layer_index = [] + for index, l in enumerate(module_list): + try: + a = l[0].img_size and l[0].nG # only yolo layer need img_size and nG + yolo_layer_index.append(index) + except: + pass + assert len(yolo_layer_index) > 0, "can not find yolo layer" + return yolo_layer_index + + +# ----------------------yolov3------------------------ + +class Yolov3(nn.Module): + def __init__(self, num_classes=80, anchors=[(10,13), (16,30), (33,23), (30,61), (62,45), (59,119), (116,90), (156,198), (373,326)]): + super().__init__() + anchor_mask1 = [i for i in range(2 * len(anchors) // 3, len(anchors), 1)] # [6, 7, 8] + anchor_mask2 = [i for i in range(len(anchors) // 3, 2 * len(anchors) // 3, 1)] # [3, 4, 5] + anchor_mask3 = [i for i in range(0, len(anchors) // 3, 1)] # [0, 1, 2] + if flag_yolo_structure: + print('anchor_mask1 : ',anchor_mask1) # 大物体 anchor + print('anchor_mask2 : ',anchor_mask2) # 中物体 anchor + print('anchor_mask3 : ',anchor_mask3) # 小物体 anchor + + # Network + # OrderedDict 是 dict 的子类,其最大特征是,它可以“维护”添加 key-value 对的顺序 + layer_list = [] + + ''' + ****** Conv2dBatchLeaky ***** + op : Conv2d,BatchNorm2d,LeakyReLU + inputs : in_channels, out_channels, kernel_size, stride, leaky_slope + ''' + + ''' + ****** ResBlockSum ****** + op : Conv2dBatchLeaky * 2 + x + inputs : nchannels + ''' + # list 0 + layer_list.append(OrderedDict([ + ('0_stage1_conv', Conv2dBatchLeaky(3, 32, 3, 1, 1)), # 416 x 416 x 32 # Convolutional + + ("0_stage2_conv", Conv2dBatchLeaky(32, 64, 3, 2)), # 208 x 208 x 64 # Convolutional + ("0_stage2_ressum1", ResBlockSum(64)), # Convolutional*2 + Resiudal + + ("0_stage3_conv", Conv2dBatchLeaky(64, 128, 3, 2)), # 104 x 104 128 # Convolutional + ("0_stage3_ressum1", ResBlockSum(128)), + ("0_stage3_ressum2", ResBlockSum(128)), # (Convolutional*2 + Resiudal)**2 + + ("0_stage4_conv", Conv2dBatchLeaky(128, 256, 3, 2)), # 52 x 52 x 256 # Convolutional + ("0_stage4_ressum1", ResBlockSum(256)), + ("0_stage4_ressum2", ResBlockSum(256)), + ("0_stage4_ressum3", ResBlockSum(256)), + ("0_stage4_ressum4", ResBlockSum(256)), + ("0_stage4_ressum5", ResBlockSum(256)), + ("0_stage4_ressum6", ResBlockSum(256)), + ("0_stage4_ressum7", ResBlockSum(256)), + ("0_stage4_ressum8", ResBlockSum(256)), # 52 x 52 x 256 output_feature_0 (Convolutional*2 + Resiudal)**8 + ])) + # list 1 + layer_list.append(OrderedDict([ + ("1_stage5_conv", Conv2dBatchLeaky(256, 512, 3, 2)), # 26 x 26 x 512 # Convolutional + ("1_stage5_ressum1", ResBlockSum(512)), + ("1_stage5_ressum2", ResBlockSum(512)), + ("1_stage5_ressum3", ResBlockSum(512)), + ("1_stage5_ressum4", ResBlockSum(512)), + ("1_stage5_ressum5", ResBlockSum(512)), + ("1_stage5_ressum6", ResBlockSum(512)), + ("1_stage5_ressum7", ResBlockSum(512)), + ("1_stage5_ressum8", ResBlockSum(512)), # 26 x 26 x 512 output_feature_1 # (Convolutional*2 + Resiudal)**8 + ])) + + ''' + ****** HeadBody ****** + op : Conv2dBatchLeaky * 5 + inputs : in_channels, out_channels + ''' + # list 2 + layer_list.append(OrderedDict([ + ("2_stage6_conv", Conv2dBatchLeaky(512, 1024, 3, 2)), # 13 x 13 x 1024 # Convolutional + ("2_stage6_ressum1", ResBlockSum(1024)), + ("2_stage6_ressum2", ResBlockSum(1024)), + ("2_stage6_ressum3", ResBlockSum(1024)), + ("2_stage6_ressum4", ResBlockSum(1024)), # 13 x 13 x 1024 output_feature_2 # (Convolutional*2 + Resiudal)**4 + ("2_headbody1", HeadBody(in_channels=1024, out_channels=512)), # 13 x 13 x 512 # Convalutional Set = Conv2dBatchLeaky * 5 + ])) + # list 3 + layer_list.append(OrderedDict([ + ("3_conv_1", Conv2dBatchLeaky(in_channels=512, out_channels=1024, kernel_size=3, stride=1)), + ("3_conv_2", nn.Conv2d(in_channels=1024, out_channels=len(anchor_mask1) * (num_classes + 5), kernel_size=1, stride=1, padding=0, bias=True)), + ])) # predict one + # list 4 + layer_list.append(OrderedDict([ + ("4_yolo", YOLOLayer([anchors[i] for i in anchor_mask1], num_classes)) + ])) # 3*((x, y, w, h, confidence) + classes ) + + # list 5 + layer_list.append(OrderedDict([ + ("5_conv", Conv2dBatchLeaky(512, 256, 1, 1)), + ("5_upsample", Upsample(scale_factor=2)), + ])) + # list 6 + layer_list.append(OrderedDict([ + ("6_head_body2", HeadBody(in_channels=768, out_channels=256)) # Convalutional Set = Conv2dBatchLeaky * 5 + ])) + # list 7 + layer_list.append(OrderedDict([ + ("7_conv_1", Conv2dBatchLeaky(in_channels=256, out_channels=512, kernel_size=3, stride=1)), + ("7_conv_2", nn.Conv2d(in_channels=512, out_channels=len(anchor_mask2) * (num_classes + 5), kernel_size=1, stride=1, padding=0, bias=True)), + ])) # predict two + # list 8 + layer_list.append(OrderedDict([ + ("8_yolo", YOLOLayer([anchors[i] for i in anchor_mask2], num_classes)) + ])) # 3*((x, y, w, h, confidence) + classes ) + # list 9 + layer_list.append(OrderedDict([ + ("9_conv", Conv2dBatchLeaky(256, 128, 1, 1)), + ("9_upsample", Upsample(scale_factor=2)), + ])) + # list 10 + layer_list.append(OrderedDict([ + ("10_head_body3", HeadBody(in_channels=384, out_channels=128)) # Convalutional Set = Conv2dBatchLeaky * 5 + ])) + # list 11 + layer_list.append(OrderedDict([ + ("11_conv_1", Conv2dBatchLeaky(in_channels=128, out_channels=256, kernel_size=3, stride=1)), + ("11_conv_2", nn.Conv2d(in_channels=256, out_channels=len(anchor_mask3) * (num_classes + 5), kernel_size=1, stride=1, padding=0, bias=True)), + ])) # predict three + # list 12 + layer_list.append(OrderedDict([ + ("12_yolo", YOLOLayer([anchors[i] for i in anchor_mask3], num_classes)) + ])) # 3*((x, y, w, h, confidence) + classes ) + # nn.ModuleList类似于pytho中的list类型,只是将一系列层装入列表,并没有实现forward()方法,因此也不会有网络模型产生的副作用 + self.module_list = nn.ModuleList([nn.Sequential(i) for i in layer_list]) + self.yolo_layer_index = get_yolo_layer_index(self.module_list) + if flag_yolo_structure: + print('yolo_layer : ',len(layer_list),'\n') + print(self.module_list[4]) + print(self.module_list[8]) + print(self.module_list[12]) + + # print('self.module_list -------->>> ',self.module_list) + # print('self.yolo_layer_index -------->>> ',self.yolo_layer_index) + + def forward(self, x): + img_size = x.shape[-1] + if flag_yolo_structure: + print('forward img_size : ',img_size,x.shape) + output = [] + + x = self.module_list[0](x) + x_route1 = x + x = self.module_list[1](x) + x_route2 = x + x = self.module_list[2](x) + + yolo_head = self.module_list[3](x) + if flag_yolo_structure: + print('mask1 yolo_head : ',yolo_head.size()) + yolo_head_out_13x13 = self.module_list[4][0](yolo_head, img_size) + output.append(yolo_head_out_13x13) + + x = self.module_list[5](x) + x = torch.cat([x, x_route2], 1) + x = self.module_list[6](x) + + yolo_head = self.module_list[7](x) + if flag_yolo_structure: + print('mask2 yolo_head : ',yolo_head.size()) + yolo_head_out_26x26 = self.module_list[8][0](yolo_head, img_size) + output.append(yolo_head_out_26x26) + + x = self.module_list[9](x) + x = torch.cat([x, x_route1], 1) + x = self.module_list[10](x) + + yolo_head = self.module_list[11](x) + if flag_yolo_structure: + print('mask3 yolo_head : ',yolo_head.size()) + yolo_head_out_52x52 = self.module_list[12][0](yolo_head, img_size) + output.append(yolo_head_out_52x52) + + if self.training: + return output + else: + io, p = list(zip(*output)) # inference output, training output + return torch.cat(io, 1), p + + +# ----------------------yolov3 tiny------------------------ + +class EmptyLayer(nn.Module): + """Placeholder for 'route' and 'shortcut' layers""" + def __init__(self): + super(EmptyLayer, self).__init__() + + def forward(self, x): + return x + + +class Yolov3Tiny(nn.Module): + def __init__(self, num_classes=80, anchors=[(10, 14), (23, 27), (37, 58), (81, 82), (135, 169), (344, 319)]): + super(Yolov3Tiny, self).__init__() + + anchor_mask1 = [i for i in range(len(anchors) // 2, len(anchors), 1)] # [3, 4, 5] + anchor_mask2 = [i for i in range(0, len(anchors) // 2, 1)] # [0, 1, 2] + + layer_list = [] + layer_list.append(OrderedDict([ + # layer 0 + ("conv_0", nn.Conv2d(in_channels=3, out_channels=16, kernel_size=3, stride=1, padding=1, bias=False)), + ("batch_norm_0", nn.BatchNorm2d(16)), + ("leaky_0", nn.LeakyReLU(0.1)), + # layer 1 + ("maxpool_1", nn.MaxPool2d(kernel_size=2, stride=2, padding=0)), + # layer 2 + ("conv_2", nn.Conv2d(in_channels=16, out_channels=32, kernel_size=3, stride=1, padding=1, bias=False)), + ("batch_norm_2", nn.BatchNorm2d(32)), + ("leaky_2", nn.LeakyReLU(0.1)), + # layer 3 + ("maxpool_3", nn.MaxPool2d(kernel_size=2, stride=2, padding=0)), + # layer 4 + ("conv_4", nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3, stride=1, padding=1, bias=False)), + ("batch_norm_4", nn.BatchNorm2d(64)), + ("leaky_4", nn.LeakyReLU(0.1)), + # layer 5 + ("maxpool_5", nn.MaxPool2d(kernel_size=2, stride=2, padding=0)), + # layer 6 + ("conv_6", nn.Conv2d(in_channels=64, out_channels=128, kernel_size=3, stride=1, padding=1, bias=False)), + ("batch_norm_6", nn.BatchNorm2d(128)), + ("leaky_6", nn.LeakyReLU(0.1)), + # layer 7 + ("maxpool_7", nn.MaxPool2d(kernel_size=2, stride=2, padding=0)), + # layer 8 + ("conv_8", nn.Conv2d(in_channels=128, out_channels=256, kernel_size=3, stride=1, padding=1, bias=False)), + ("batch_norm_8", nn.BatchNorm2d(256)), + ("leaky_8", nn.LeakyReLU(0.1)), + ])) + + layer_list.append(OrderedDict([ + # layer 9 + ("maxpool_9", nn.MaxPool2d(kernel_size=2, stride=2, padding=0)), + # layer 10 + ("conv_10", nn.Conv2d(in_channels=256, out_channels=512, kernel_size=3, stride=1, padding=1, bias=False)), + ("batch_norm_10", nn.BatchNorm2d(512)), + ("leaky_10", nn.LeakyReLU(0.1)), + # layer 11 + ('_debug_padding_11', nn.ZeroPad2d((0, 1, 0, 1))), + ("maxpool_11", nn.MaxPool2d(kernel_size=2, stride=1, padding=0)), + # layer 12 + ("conv_12", nn.Conv2d(in_channels=512, out_channels=1024, kernel_size=3, stride=1, padding=1, bias=False)), + ("batch_norm_12", nn.BatchNorm2d(1024)), + ("leaky_12", nn.LeakyReLU(0.1)), + # layer 13 + ("conv_13", nn.Conv2d(in_channels=1024, out_channels=256, kernel_size=1, stride=1, padding=0, bias=False)), + ("batch_norm_13", nn.BatchNorm2d(256)), + ("leaky_13", nn.LeakyReLU(0.1)), + ])) + + layer_list.append(OrderedDict([ + # layer 14 + ("conv_14", nn.Conv2d(in_channels=256, out_channels=512, kernel_size=3, stride=1, padding=1, bias=False)), + ("batch_norm_14", nn.BatchNorm2d(512)), + ("leaky_14", nn.LeakyReLU(0.1)), + # layer 15 + ("conv_15", + nn.Conv2d(in_channels=512, out_channels=len(anchor_mask1) * (num_classes + 5), kernel_size=1, stride=1, padding=0, bias=True)), + ])) + + # layer 16 + anchor_tmp1 = [anchors[i] for i in anchor_mask1] + layer_list.append(OrderedDict([("yolo_16", YOLOLayer(anchor_tmp1, num_classes))])) + + # layer 17 + layer_list.append(OrderedDict([("route_17", EmptyLayer())])) + + layer_list.append(OrderedDict([ + # layer 18 + ("conv_18", nn.Conv2d(in_channels=256, out_channels=128, kernel_size=1, stride=1, padding=0, bias=False)), + ("batch_norm_18", nn.BatchNorm2d(128)), + ("leaky_18", nn.LeakyReLU(0.1)), + # layer 19 + ("upsample_19", Upsample(scale_factor=2)), + ])) + + # layer 20 + layer_list.append(OrderedDict([('route_20', EmptyLayer())])) + + layer_list.append(OrderedDict([ + # layer 21 + ("conv_21", nn.Conv2d(in_channels=384, out_channels=256, kernel_size=3, stride=1, padding=1, bias=False)), + ("batch_norm_21", nn.BatchNorm2d(256)), + ("leaky_21", nn.LeakyReLU(0.1)), + # layer 22 + ("conv_22", + nn.Conv2d(in_channels=256, out_channels=len(anchor_mask2) * (num_classes + 5), kernel_size=1, stride=1, padding=0, bias=True)), + ])) + + # layer 23 + anchor_tmp2 = [anchors[i] for i in anchor_mask2] + layer_list.append(OrderedDict([("yolo_23", YOLOLayer(anchor_tmp2, num_classes))])) + + self.module_list = nn.ModuleList([nn.Sequential(layer) for layer in layer_list]) + self.yolo_layer_index = get_yolo_layer_index(self.module_list) + + def forward(self, x): + img_size = x.shape[-1] + output = [] + + x = self.module_list[0](x) # layer0 to layer8 + x_route8 = x + x = self.module_list[1](x) # layer9 to layer13 + x_route13 = x + x = self.module_list[2](x) # layer14, layer15 + x = self.module_list[3][0](x, img_size) # yolo_16 + output.append(x) + x = self.module_list[5](x_route13) # layer18, layer19 + x = torch.cat([x, x_route8], 1) # route + x = self.module_list[7](x) # layer21, layer22 + x = self.module_list[8][0](x, img_size) # yolo_23 + output.append(x) + + if self.training: + return output + else: + io, p = list(zip(*output)) # inference output, training output + return torch.cat(io, 1), p + + +if __name__ == "__main__": + dummy_input = torch.Tensor(5, 3, 416, 416) + model = Yolov3(num_classes=80) + params = list(model.parameters()) + k = 0 + for i in params: + l = 1 + for j in i.size(): + l *= j + # print("该层的结构: {}, 参数和: {}".format(str(list(i.size())), str(l))) + k = k + l + print("----------------------") + print("总参数数量和: " + str(k)) + print("-----------yolo layer") + for index in model.yolo_layer_index: + print(model.module_list[index]) + + print("-----------train") + model.train() + for res in model(dummy_input): + print("res:", np.shape(res)) + + print("-----------eval") + model.eval() + inference_out, train_out = model(dummy_input) + print("inference_out:", np.shape(inference_out)) + for o in train_out: + print("train_out:", np.shape(o)) diff --git a/components/face_euler_angle/face_euler_angle_component.py b/components/face_euler_angle/face_euler_angle_component.py new file mode 100644 index 0000000000000000000000000000000000000000..e489f8d43012dedb01e987fb35cbc007cce5cd7d --- /dev/null +++ b/components/face_euler_angle/face_euler_angle_component.py @@ -0,0 +1,50 @@ +#-*-coding:utf-8-*- +# date:2020-04-11 +# author: Eric.Lee +# function : face_euler_angle - yaw,pitch,roll + +import os +import torch +import cv2 +import torch.nn.functional as F + +from face_euler_angle.network.resnet import resnet18 +from face_euler_angle.utils.common_utils import * + +import numpy as np +class FaceAngle_Model(object): + def __init__(self, + model_path = './components/face_euler_angle/weights_euler_angle/resnet_18_imgsize_256-epoch-225.pth', + img_size=256, + num_classes = 3,# yaw,pitch,roll + ): + + use_cuda = torch.cuda.is_available() + self.use_cuda = use_cuda + self.device = torch.device("cuda:0" if use_cuda else "cpu") # 可选的设备类型及序号 + self.img_size = img_size + #----------------------------------------------------------------------- + model_ = resnet18(num_classes=num_classes, img_size=img_size) + chkpt = torch.load(model_path, map_location=lambda storage, loc: storage) + model_.load_state_dict(chkpt) + model_.eval() + + print("load face euler angle model : {}".format(model_path)) + + self.model_ = model_.to(self.device) + + def predict(self, img,vis = False):# img is align img + with torch.no_grad(): + img_ = torch.from_numpy(img) + # img_ = img_.unsqueeze_(0) + if self.use_cuda: + img_ = img_.cuda() # (bs, 3, h, w) + + output_ = self.model_(img_.float()) + # print(pre_.size()) + output_ = output_.cpu().detach().numpy() + + + output_ = output_*90. + + return output_ diff --git a/components/face_euler_angle/network/resnet.py b/components/face_euler_angle/network/resnet.py new file mode 100644 index 0000000000000000000000000000000000000000..433b22f51f92dfe5e3e0f4d503c1d64c54c3dadd --- /dev/null +++ b/components/face_euler_angle/network/resnet.py @@ -0,0 +1,262 @@ +import torch +import torch.nn as nn +import math +import torch.utils.model_zoo as model_zoo + +__all__ = ['ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101', + 'resnet152'] + + +model_urls = { + 'resnet18': 'https://download.pytorch.org/models/resnet18-5c106cde.pth', + 'resnet34': 'https://download.pytorch.org/models/resnet34-333f7ec4.pth', + 'resnet50': 'https://download.pytorch.org/models/resnet50-19c8e357.pth', + 'resnet101': 'https://download.pytorch.org/models/resnet101-5d3b4d8f.pth', + 'resnet152': 'https://download.pytorch.org/models/resnet152-b121ed2d.pth', +} + + +def conv3x3(in_planes, out_planes, stride=1): + """3x3 convolution with padding""" + return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride, + padding=1, bias=False) + + +class BasicBlock(nn.Module): + expansion = 1 + + def __init__(self, inplanes, planes, stride=1, downsample=None): + super(BasicBlock, self).__init__() + self.conv1 = conv3x3(inplanes, planes, stride) + self.bn1 = nn.BatchNorm2d(planes) + self.relu = nn.ReLU(inplace=True) + self.conv2 = conv3x3(planes, planes) + self.bn2 = nn.BatchNorm2d(planes) + self.downsample = downsample + self.stride = stride + + def forward(self, x): + residual = x + + out = self.conv1(x) + out = self.bn1(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.bn2(out) + + if self.downsample is not None: + residual = self.downsample(x) + + out += residual + out = self.relu(out) + + return out + +class Bottleneck(nn.Module): + expansion = 4 + + def __init__(self, inplanes, planes, stride=1, downsample=None): + super(Bottleneck, self).__init__() + self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False) + self.bn1 = nn.BatchNorm2d(planes) + self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, + padding=1, bias=False) + self.bn2 = nn.BatchNorm2d(planes) + self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False) + self.bn3 = nn.BatchNorm2d(planes * 4) + self.relu = nn.ReLU(inplace=True) + self.downsample = downsample + self.stride = stride + + def forward(self, x): + residual = x + + out = self.conv1(x) + out = self.bn1(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.bn2(out) + out = self.relu(out) + + out = self.conv3(out) + out = self.bn3(out) + + if self.downsample is not None: + residual = self.downsample(x) + + out += residual + out = self.relu(out) + + return out + + +class ResNet(nn.Module): + + def __init__(self, block, layers, num_classes=1000, img_size=224,dropout_factor = 1.): + self.inplanes = 64 + self.dropout_factor = dropout_factor + super(ResNet, self).__init__() + + self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, + bias=False) + self.bn1 = nn.BatchNorm2d(64) + self.relu = nn.ReLU(inplace=True) + # see this issue: https://github.com/xxradon/PytorchToCaffe/issues/16 + # self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) + self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, ceil_mode=True) + self.layer1 = self._make_layer(block, 64, layers[0]) + self.layer2 = self._make_layer(block, 128, layers[1], stride=2) + self.layer3 = self._make_layer(block, 256, layers[2], stride=2) + self.layer4 = self._make_layer(block, 512, layers[3], stride=2) + + assert img_size % 32 == 0 + pool_kernel = int(img_size / 32) + self.avgpool = nn.AvgPool2d(pool_kernel, stride=1, ceil_mode=True) + + self.dropout = nn.Dropout(self.dropout_factor) + + self.fc = nn.Linear(512 * block.expansion, num_classes) + + for m in self.modules(): + if isinstance(m, nn.Conv2d): + n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels + m.weight.data.normal_(0, math.sqrt(2. / n)) + elif isinstance(m, nn.BatchNorm2d): + m.weight.data.fill_(1) + m.bias.data.zero_() + + def _make_layer(self, block, planes, blocks, stride=1): + downsample = None + if stride != 1 or self.inplanes != planes * block.expansion: + downsample = nn.Sequential( + nn.Conv2d(self.inplanes, planes * block.expansion, + kernel_size=1, stride=stride, bias=False), + nn.BatchNorm2d(planes * block.expansion), + ) + + layers = [] + layers.append(block(self.inplanes, planes, stride, downsample)) + self.inplanes = planes * block.expansion + for i in range(1, blocks): + layers.append(block(self.inplanes, planes)) + + return nn.Sequential(*layers) + + def forward(self, x): + x = self.conv1(x) + x = self.bn1(x) + x = self.relu(x) + x = self.maxpool(x) + + x = self.layer1(x) + x = self.layer2(x) + x = self.layer3(x) + x = self.layer4(x) + + x = self.avgpool(x) + x = x.view(x.size(0), -1) + + x = self.dropout(x) + + x = self.fc(x) + + return x + + +def load_model(model, pretrained_state_dict): + model_dict = model.state_dict() + pretrained_dict = {k: v for k, v in pretrained_state_dict.items() if + k in model_dict and model_dict[k].size() == pretrained_state_dict[k].size()} + model.load_state_dict(pretrained_dict, strict=False) + if len(pretrained_dict) == 0: + print("[INFO] No params were loaded ...") + else: + for k, v in pretrained_state_dict.items(): + if k in pretrained_dict: + print("==>> Load {} {}".format(k, v.size())) + else: + print("[INFO] Skip {} {}".format(k, v.size())) + return model + + +def resnet18(pretrained=False, **kwargs): + """Constructs a ResNet-18 model. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(BasicBlock, [2, 2, 2, 2], **kwargs) + if pretrained: + # model.load_state_dict(model_zoo.load_url(model_urls['resnet18'])) + print("Load pretrained model from {}".format(model_urls['resnet18'])) + pretrained_state_dict = model_zoo.load_url(model_urls['resnet18']) + model = load_model(model, pretrained_state_dict) + return model + + +def resnet34(pretrained=False, **kwargs): + """Constructs a ResNet-34 model. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(BasicBlock, [3, 4, 6, 3], **kwargs) + if pretrained: + # model.load_state_dict(model_zoo.load_url(model_urls['resnet34'])) + print("Load pretrained model from {}".format(model_urls['resnet34'])) + pretrained_state_dict = model_zoo.load_url(model_urls['resnet34']) + model = load_model(model, pretrained_state_dict) + return model + + +def resnet50(pretrained=False, **kwargs): + """Constructs a ResNet-50 model. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(Bottleneck, [3, 4, 6, 3], **kwargs) + if pretrained: + # model.load_state_dict(model_zoo.load_url(model_urls['resnet50'])) + print("Load pretrained model from {}".format(model_urls['resnet50'])) + pretrained_state_dict = model_zoo.load_url(model_urls['resnet50']) + model = load_model(model, pretrained_state_dict) + return model + + +def resnet101(pretrained=False, **kwargs): + """Constructs a ResNet-101 model. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(Bottleneck, [3, 4, 23, 3], **kwargs) + if pretrained: + # model.load_state_dict(model_zoo.load_url(model_urls['resnet101'])) + print("Load pretrained model from {}".format(model_urls['resnet101'])) + pretrained_state_dict = model_zoo.load_url(model_urls['resnet101']) + model = load_model(model, pretrained_state_dict) + return model + + +def resnet152(pretrained=False, **kwargs): + """Constructs a ResNet-152 model. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(Bottleneck, [3, 8, 36, 3], **kwargs) + if pretrained: + # model.load_state_dict(model_zoo.load_url(model_urls['resnet152'])) + print("Load pretrained model from {}".format(model_urls['resnet152'])) + pretrained_state_dict = model_zoo.load_url(model_urls['resnet152']) + model = load_model(model, pretrained_state_dict) + return model + +if __name__ == "__main__": + input = torch.randn([32, 3, 256,256]) + model = resnet34(False, num_classes=2, img_size=256) + output = model(input) + print(output.size()) diff --git a/components/face_euler_angle/utils/common_utils.py b/components/face_euler_angle/utils/common_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..1e5b172d5efb740952deacaa38d34aa2e3abe980 --- /dev/null +++ b/components/face_euler_angle/utils/common_utils.py @@ -0,0 +1,132 @@ +#-*-coding:utf-8-*- +# date:2020-04-11 +# Author: Eric.Lee +# function: common utils + +import os +import shutil +import cv2 +import numpy as np +import json + +def mkdir_(path, flag_rm=False): + if os.path.exists(path): + if flag_rm == True: + shutil.rmtree(path) + os.mkdir(path) + print('remove {} done ~ '.format(path)) + else: + os.mkdir(path) + +def plot_box(bbox, img, color=None, label=None, line_thickness=None): + tl = line_thickness or round(0.002 * max(img.shape[0:2])) + 1 + color = color or [random.randint(0, 255) for _ in range(3)] + c1, c2 = (int(bbox[0]), int(bbox[1])), (int(bbox[2]), int(bbox[3])) + cv2.rectangle(img, c1, c2, color, thickness=tl)# 目标的bbox + if label: + tf = max(tl - 2, 1) + t_size = cv2.getTextSize(label, 0, fontScale=tl / 3, thickness=tf)[0] # label size + c2 = c1[0] + t_size[0], c1[1] - t_size[1] - 3 # 字体的bbox + cv2.rectangle(img, c1, c2, color, -1) # label 矩形填充 + # 文本绘制 + cv2.putText(img, label, (c1[0], c1[1] - 2), 0, tl / 4, [225, 255, 255],thickness=tf, lineType=cv2.LINE_AA) + +class JSON_Encoder(json.JSONEncoder): + def default(self, obj): + if isinstance(obj, np.integer): + return int(obj) + elif isinstance(obj, np.floating): + return float(obj) + elif isinstance(obj, np.ndarray): + return obj.tolist() + else: + return super(JSON_Encoder, self).default(obj) + +def draw_landmarks(img,output,draw_circle): + img_width = img.shape[1] + img_height = img.shape[0] + dict_landmarks = {} + for i in range(int(output.shape[0]/2)): + x = output[i*2+0]*float(img_width) + y = output[i*2+1]*float(img_height) + if 41>= i >=33: + if 'left_eyebrow' not in dict_landmarks.keys(): + dict_landmarks['left_eyebrow'] = [] + dict_landmarks['left_eyebrow'].append([int(x),int(y),(0,255,0)]) + if draw_circle: + cv2.circle(img, (int(x),int(y)), 2, (0,255,0),-1) + elif 50>= i >=42: + if 'right_eyebrow' not in dict_landmarks.keys(): + dict_landmarks['right_eyebrow'] = [] + dict_landmarks['right_eyebrow'].append([int(x),int(y),(0,255,0)]) + if draw_circle: + cv2.circle(img, (int(x),int(y)), 2, (0,255,0),-1) + elif 67>= i >=60: + if 'left_eye' not in dict_landmarks.keys(): + dict_landmarks['left_eye'] = [] + dict_landmarks['left_eye'].append([int(x),int(y),(255,0,255)]) + if draw_circle: + cv2.circle(img, (int(x),int(y)), 2, (255,0,255),-1) + elif 75>= i >=68: + if 'right_eye' not in dict_landmarks.keys(): + dict_landmarks['right_eye'] = [] + dict_landmarks['right_eye'].append([int(x),int(y),(255,0,255)]) + if draw_circle: + cv2.circle(img, (int(x),int(y)), 2, (255,0,255),-1) + elif 97>= i >=96: + cv2.circle(img, (int(x),int(y)), 2, (0,0,255),-1) + elif 54>= i >=51: + if 'bridge_nose' not in dict_landmarks.keys(): + dict_landmarks['bridge_nose'] = [] + dict_landmarks['bridge_nose'].append([int(x),int(y),(0,170,255)]) + if draw_circle: + cv2.circle(img, (int(x),int(y)), 2, (0,170,255),-1) + elif 32>= i >=0: + if 'basin' not in dict_landmarks.keys(): + dict_landmarks['basin'] = [] + dict_landmarks['basin'].append([int(x),int(y),(255,30,30)]) + if draw_circle: + cv2.circle(img, (int(x),int(y)), 2, (255,30,30),-1) + elif 59>= i >=55: + if 'wing_nose' not in dict_landmarks.keys(): + dict_landmarks['wing_nose'] = [] + dict_landmarks['wing_nose'].append([int(x),int(y),(0,255,255)]) + if draw_circle: + cv2.circle(img, (int(x),int(y)), 2, (0,255,255),-1) + elif 87>= i >=76: + if 'out_lip' not in dict_landmarks.keys(): + dict_landmarks['out_lip'] = [] + dict_landmarks['out_lip'].append([int(x),int(y),(255,255,0)]) + if draw_circle: + cv2.circle(img, (int(x),int(y)), 2, (255,255,0),-1) + elif 95>= i >=88: + if 'in_lip' not in dict_landmarks.keys(): + dict_landmarks['in_lip'] = [] + dict_landmarks['in_lip'].append([int(x),int(y),(50,220,255)]) + if draw_circle: + cv2.circle(img, (int(x),int(y)), 2, (50,220,255),-1) + else: + if draw_circle: + cv2.circle(img, (int(x),int(y)), 2, (255,0,255),-1) + + return dict_landmarks + +def draw_contour(image,dict): + for key in dict.keys(): + # print(key) + _,_,color = dict[key][0] + + if 'basin' == key or 'wing_nose' == key: + pts = np.array([[dict[key][i][0],dict[key][i][1]] for i in range(len(dict[key]))],np.int32) + # print(pts) + cv2.polylines(image,[pts],False,color) + + else: + points_array = np.zeros((1,len(dict[key]),2),dtype = np.int32) + for i in range(len(dict[key])): + x,y,_ = dict[key][i] + points_array[0,i,0] = x + points_array[0,i,1] = y + + # cv2.fillPoly(image, points_array, color) + cv2.drawContours(image,points_array,-1,color,thickness=1) diff --git a/components/face_euler_angle/utils/model_utils.py b/components/face_euler_angle/utils/model_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..48cc3d33db8dafe7ed54f344825f6905e1adac26 --- /dev/null +++ b/components/face_euler_angle/utils/model_utils.py @@ -0,0 +1,61 @@ +#-*-coding:utf-8-*- +# date:2020-04-11 +# Author: Eric.Lee +# function: model utils + +import os +import numpy as np +import torch +import torch.backends.cudnn as cudnn +import random + +def get_acc(output, label): + total = output.shape[0] + _, pred_label = output.max(1) + num_correct = (pred_label == label).sum().item() + return num_correct / float(total) + +def set_learning_rate(optimizer, lr): + for param_group in optimizer.param_groups: + param_group['lr'] = lr + +def set_seed(seed = 666): + np.random.seed(seed) + random.seed(seed) + torch.manual_seed(seed) + if torch.cuda.is_available(): + torch.cuda.manual_seed(seed) + torch.cuda.manual_seed_all(seed) + cudnn.deterministic = True + +def split_trainval_datasets(ops): + print(' --------------->>> split_trainval_datasets ') + train_split_datasets = [] + train_split_datasets_label = [] + + val_split_datasets = [] + val_split_datasets_label = [] + for idx,doc in enumerate(sorted(os.listdir(ops.train_path), key=lambda x:int(x.split('.')[0]), reverse=False)): + # print(' %s label is %s \n'%(doc,idx)) + + data_list = os.listdir(ops.train_path+doc) + random.shuffle(data_list) + + cal_split_num = int(len(data_list)*ops.val_factor) + + for i,file in enumerate(data_list): + if '.jpg' in file: + if i < cal_split_num: + val_split_datasets.append(ops.train_path+doc + '/' + file) + val_split_datasets_label.append(idx) + else: + train_split_datasets.append(ops.train_path+doc + '/' + file) + train_split_datasets_label.append(idx) + + print(ops.train_path+doc + '/' + file,idx) + + print('\n') + print('train_split_datasets len {}'.format(len(train_split_datasets))) + print('val_split_datasets len {}'.format(len(val_split_datasets))) + + return train_split_datasets,train_split_datasets_label,val_split_datasets,val_split_datasets_label diff --git a/components/face_multi_task/face_multi_task_component.py b/components/face_multi_task/face_multi_task_component.py new file mode 100644 index 0000000000000000000000000000000000000000..0d2b655d389128f41a9537b8fd4e024468ae60cd --- /dev/null +++ b/components/face_multi_task/face_multi_task_component.py @@ -0,0 +1,87 @@ +#-*-coding:utf-8-*- +# date:2020-04-11 +# author: Eric.Lee +# function : face_multi_task - landmarks & age & gender + +import os +import torch +import cv2 +import torch.nn.functional as F + +from face_multi_task.network.resnet import resnet50 +from face_multi_task.utils.common_utils import * + +import numpy as np +class FaceMuitiTask_Model(object): + def __init__(self, + model_path = './components/face_multi_task/weights_multask/resnet_50_imgsize-256-20210411.pth', + img_size=256, + num_classes = 196,# 人脸关键点,年龄,性别 + ): + + use_cuda = torch.cuda.is_available() + self.use_cuda = use_cuda + self.device = torch.device("cuda:0" if use_cuda else "cpu") # 可选的设备类型及序号 + self.img_size = img_size + #----------------------------------------------------------------------- + face_multi_model = resnet50(landmarks_num=num_classes, img_size=img_size) + chkpt = torch.load(model_path, map_location=lambda storage, loc: storage) + face_multi_model.load_state_dict(chkpt) + face_multi_model.eval() + + print("load face multi task model : {}".format(model_path)) + + self.face_multi_model = face_multi_model.to(self.device) + + def predict(self, img,vis = False):# img is align img + with torch.no_grad(): + # img = cv2.resize(img, (self.img_size,self.img_size), interpolation = cv2.INTER_LINEAR) + # #-------------------- inferece face + # + # img_ = img.astype(np.float32) + # img_ = (img_-128.)/256. + # + # img_ = img_.transpose(2, 0, 1) + img_ = torch.from_numpy(img) + # img_ = img_.unsqueeze_(0) + # + if self.use_cuda: + img_ = img_.cuda() # (bs, 3, h, w) + + output_landmarks,output_gender,output_age = self.face_multi_model(img_.float()) + # print(pre_.size()) + output_landmarks = output_landmarks.cpu().detach().numpy() + + output_gender = output_gender + output_gender = output_gender.cpu().detach().numpy() + output_gender = np.array(output_gender) + + output_age = output_age.cpu().detach().numpy() + output_age = (output_age*100.+50.) + + return output_landmarks,output_gender,output_age +if __name__ == '__main__': + au_model = FaceMuitiTask_Component() + path = "./samples/" + for img_name in os.listdir(path): + img_path = path + img_name + img = cv2.imread(img_path) + dict_landmarks,output_gender,output_age = au_model.predict(img,vis = False) + draw_contour(img,dict_landmarks) + + + cv2.putText(img, 'gender:{}'.format(output_gender), (2,20), + cv2.FONT_HERSHEY_COMPLEX, 0.8, (0, 255, 0),2) + cv2.putText(img, 'gender:{}'.format(output_gender), (2,20), + cv2.FONT_HERSHEY_COMPLEX, 0.8, (255,20,0),1) + + cv2.putText(img, 'age:{:.2f}'.format(output_age), (2,50), + cv2.FONT_HERSHEY_COMPLEX, 0.8, (0, 255, 0),2) + cv2.putText(img, 'age:{:.2f}'.format(output_age), (2,50), + cv2.FONT_HERSHEY_COMPLEX, 0.8, (255,20, 0),1) + + cv2.namedWindow('image',0) + cv2.imshow('image',img) + cv2.waitKey(500) + + cv2.destroyAllWindows() diff --git a/components/face_multi_task/network/resnet.py b/components/face_multi_task/network/resnet.py new file mode 100644 index 0000000000000000000000000000000000000000..effa5bd28368ef154bd24357777ff280afba5dd4 --- /dev/null +++ b/components/face_multi_task/network/resnet.py @@ -0,0 +1,285 @@ +import torch +import torch.nn as nn +import math +import torch.utils.model_zoo as model_zoo + +__all__ = ['ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101', + 'resnet152'] + + +model_urls = { + 'resnet18': 'https://download.pytorch.org/models/resnet18-5c106cde.pth', + 'resnet34': 'https://download.pytorch.org/models/resnet34-333f7ec4.pth', + 'resnet50': 'https://download.pytorch.org/models/resnet50-19c8e357.pth', + 'resnet101': 'https://download.pytorch.org/models/resnet101-5d3b4d8f.pth', + 'resnet152': 'https://download.pytorch.org/models/resnet152-b121ed2d.pth', +} + + +def conv3x3(in_planes, out_planes, stride=1): + """3x3 convolution with padding""" + return nn.Conv2d(in_planes, out_planes, kernel_size=3, stride=stride, + padding=1, bias=False) + + +class BasicBlock(nn.Module): + expansion = 1 + + def __init__(self, inplanes, planes, stride=1, downsample=None): + super(BasicBlock, self).__init__() + self.conv1 = conv3x3(inplanes, planes, stride) + self.bn1 = nn.BatchNorm2d(planes) + self.relu = nn.ReLU(inplace=True) + self.conv2 = conv3x3(planes, planes) + self.bn2 = nn.BatchNorm2d(planes) + self.downsample = downsample + self.stride = stride + + def forward(self, x): + residual = x + + out = self.conv1(x) + out = self.bn1(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.bn2(out) + + if self.downsample is not None: + residual = self.downsample(x) + + out += residual + out = self.relu(out) + + return out + +class Bottleneck(nn.Module): + expansion = 4 + + def __init__(self, inplanes, planes, stride=1, downsample=None): + super(Bottleneck, self).__init__() + self.conv1 = nn.Conv2d(inplanes, planes, kernel_size=1, bias=False) + self.bn1 = nn.BatchNorm2d(planes) + self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, stride=stride, + padding=1, bias=False) + self.bn2 = nn.BatchNorm2d(planes) + self.conv3 = nn.Conv2d(planes, planes * 4, kernel_size=1, bias=False) + self.bn3 = nn.BatchNorm2d(planes * 4) + self.relu = nn.ReLU(inplace=True) + self.downsample = downsample + self.stride = stride + + def forward(self, x): + residual = x + + out = self.conv1(x) + out = self.bn1(out) + out = self.relu(out) + + out = self.conv2(out) + out = self.bn2(out) + out = self.relu(out) + + out = self.conv3(out) + out = self.bn3(out) + + if self.downsample is not None: + residual = self.downsample(x) + + out += residual + out = self.relu(out) + + return out + + +class ResNet(nn.Module): + + def __init__(self, block, layers, landmarks_num=1000, img_size=224,dropout_factor = 1.): + self.inplanes = 64 + self.dropout_factor = dropout_factor + super(ResNet, self).__init__() + # 26 + # 586 train_sequence + self.conv1 = nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=3, + bias=False) + self.bn1 = nn.BatchNorm2d(64) + self.relu = nn.ReLU(inplace=True) + # see this issue: https://github.com/xxradon/PytorchToCaffe/issues/16 + # self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1) + self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, ceil_mode=True) + self.layer1 = self._make_layer(block, 64, layers[0]) + self.layer2 = self._make_layer(block, 128, layers[1], stride=2) + self.layer3 = self._make_layer(block, 256, layers[2], stride=2) + self.layer4 = self._make_layer(block, 512, layers[3], stride=2) + + assert img_size % 32 == 0 + pool_kernel = int(img_size / 32) + self.avgpool = nn.AvgPool2d(pool_kernel, stride=1, ceil_mode=True) + + self.dropout1 = nn.Dropout(self.dropout_factor) + self.dropout2 = nn.Dropout(0.8) + self.dropout3 = nn.Dropout(0.8) + + self.dropout = nn.Dropout(self.dropout_factor) + + self.fc_landmarks_1 = nn.Linear(512 * block.expansion, 1024) + self.fc_landmarks_2 = nn.Linear(1024, landmarks_num) + + self.fc_gender_1 = nn.Linear(512 * block.expansion, 64) + self.fc_gender_2 = nn.Linear(64, 2) + + self.fc_age_1 = nn.Linear(512 * block.expansion, 64) + self.fc_age_2 = nn.Linear(64, 1) + + for m in self.modules(): + if isinstance(m, nn.Conv2d): + n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels + m.weight.data.normal_(0, math.sqrt(2. / n)) + elif isinstance(m, nn.BatchNorm2d): + m.weight.data.fill_(1) + m.bias.data.zero_() + + def _make_layer(self, block, planes, blocks, stride=1): + downsample = None + if stride != 1 or self.inplanes != planes * block.expansion: + downsample = nn.Sequential( + nn.Conv2d(self.inplanes, planes * block.expansion, + kernel_size=1, stride=stride, bias=False), + nn.BatchNorm2d(planes * block.expansion), + ) + + layers = [] + layers.append(block(self.inplanes, planes, stride, downsample)) + self.inplanes = planes * block.expansion + for i in range(1, blocks): + layers.append(block(self.inplanes, planes)) + + return nn.Sequential(*layers) + + def forward(self, x): + x = self.conv1(x) + x = self.bn1(x) + x = self.relu(x) + x = self.maxpool(x) + + x = self.layer1(x) + x = self.layer2(x) + x = self.layer3(x) + x = self.layer4(x) + + x = self.avgpool(x) + x = x.view(x.size(0), -1) + +# x = self.dropout(x) + + landmarks = self.fc_landmarks_1(x) + landmarks = self.dropout1(landmarks) + landmarks = self.fc_landmarks_2(landmarks) + + gender = self.fc_gender_1(x) + gender = self.dropout2(gender) + gender = self.fc_gender_2(gender) + + age = self.fc_age_1(x) + age = self.dropout3(age) + age = self.fc_age_2(age) + + + return landmarks,gender,age + + +def load_model(model, pretrained_state_dict): + model_dict = model.state_dict() + pretrained_dict = {k: v for k, v in pretrained_state_dict.items() if + k in model_dict and model_dict[k].size() == pretrained_state_dict[k].size()} + model.load_state_dict(pretrained_dict, strict=False) + if len(pretrained_dict) == 0: + print("[INFO] No params were loaded ...") + else: + for k, v in pretrained_state_dict.items(): + if k in pretrained_dict: + print("==>> Load {} {}".format(k, v.size())) + else: + print("[INFO] Skip {} {}".format(k, v.size())) + return model + + +def resnet18(pretrained=False, **kwargs): + """Constructs a ResNet-18 model. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(BasicBlock, [2, 2, 2, 2], **kwargs) + if pretrained: + # model.load_state_dict(model_zoo.load_url(model_urls['resnet18'])) + print("Load pretrained model from {}".format(model_urls['resnet18'])) + pretrained_state_dict = model_zoo.load_url(model_urls['resnet18']) + model = load_model(model, pretrained_state_dict) + return model + + +def resnet34(pretrained=False, **kwargs): + """Constructs a ResNet-34 model. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(BasicBlock, [3, 4, 6, 3], **kwargs) + if pretrained: + # model.load_state_dict(model_zoo.load_url(model_urls['resnet34'])) + print("Load pretrained model from {}".format(model_urls['resnet34'])) + pretrained_state_dict = model_zoo.load_url(model_urls['resnet34']) + model = load_model(model, pretrained_state_dict) + return model + + +def resnet50(pretrained=False, **kwargs): + """Constructs a ResNet-50 model. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(Bottleneck, [3, 4, 6, 3], **kwargs) + if pretrained: + # model.load_state_dict(model_zoo.load_url(model_urls['resnet50'])) + print("Load pretrained model from {}".format(model_urls['resnet50'])) + pretrained_state_dict = model_zoo.load_url(model_urls['resnet50']) + model = load_model(model, pretrained_state_dict) + return model + + +def resnet101(pretrained=False, **kwargs): + """Constructs a ResNet-101 model. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(Bottleneck, [3, 4, 23, 3], **kwargs) + if pretrained: + # model.load_state_dict(model_zoo.load_url(model_urls['resnet101'])) + print("Load pretrained model from {}".format(model_urls['resnet101'])) + pretrained_state_dict = model_zoo.load_url(model_urls['resnet101']) + model = load_model(model, pretrained_state_dict) + return model + + +def resnet152(pretrained=False, **kwargs): + """Constructs a ResNet-152 model. + + Args: + pretrained (bool): If True, returns a model pre-trained on ImageNet + """ + model = ResNet(Bottleneck, [3, 8, 36, 3], **kwargs) + if pretrained: + # model.load_state_dict(model_zoo.load_url(model_urls['resnet152'])) + print("Load pretrained model from {}".format(model_urls['resnet152'])) + pretrained_state_dict = model_zoo.load_url(model_urls['resnet152']) + model = load_model(model, pretrained_state_dict) + return model + +if __name__ == "__main__": + input = torch.randn([32, 3, 256,256]) + model = resnet50(pretrained=False, landmarks_num=196, img_size=256) + landmarks,gender,age = model(input) + print(landmarks.size(),gender.size(),age.size()) diff --git a/components/face_multi_task/utils/common_utils.py b/components/face_multi_task/utils/common_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..1e5b172d5efb740952deacaa38d34aa2e3abe980 --- /dev/null +++ b/components/face_multi_task/utils/common_utils.py @@ -0,0 +1,132 @@ +#-*-coding:utf-8-*- +# date:2020-04-11 +# Author: Eric.Lee +# function: common utils + +import os +import shutil +import cv2 +import numpy as np +import json + +def mkdir_(path, flag_rm=False): + if os.path.exists(path): + if flag_rm == True: + shutil.rmtree(path) + os.mkdir(path) + print('remove {} done ~ '.format(path)) + else: + os.mkdir(path) + +def plot_box(bbox, img, color=None, label=None, line_thickness=None): + tl = line_thickness or round(0.002 * max(img.shape[0:2])) + 1 + color = color or [random.randint(0, 255) for _ in range(3)] + c1, c2 = (int(bbox[0]), int(bbox[1])), (int(bbox[2]), int(bbox[3])) + cv2.rectangle(img, c1, c2, color, thickness=tl)# 目标的bbox + if label: + tf = max(tl - 2, 1) + t_size = cv2.getTextSize(label, 0, fontScale=tl / 3, thickness=tf)[0] # label size + c2 = c1[0] + t_size[0], c1[1] - t_size[1] - 3 # 字体的bbox + cv2.rectangle(img, c1, c2, color, -1) # label 矩形填充 + # 文本绘制 + cv2.putText(img, label, (c1[0], c1[1] - 2), 0, tl / 4, [225, 255, 255],thickness=tf, lineType=cv2.LINE_AA) + +class JSON_Encoder(json.JSONEncoder): + def default(self, obj): + if isinstance(obj, np.integer): + return int(obj) + elif isinstance(obj, np.floating): + return float(obj) + elif isinstance(obj, np.ndarray): + return obj.tolist() + else: + return super(JSON_Encoder, self).default(obj) + +def draw_landmarks(img,output,draw_circle): + img_width = img.shape[1] + img_height = img.shape[0] + dict_landmarks = {} + for i in range(int(output.shape[0]/2)): + x = output[i*2+0]*float(img_width) + y = output[i*2+1]*float(img_height) + if 41>= i >=33: + if 'left_eyebrow' not in dict_landmarks.keys(): + dict_landmarks['left_eyebrow'] = [] + dict_landmarks['left_eyebrow'].append([int(x),int(y),(0,255,0)]) + if draw_circle: + cv2.circle(img, (int(x),int(y)), 2, (0,255,0),-1) + elif 50>= i >=42: + if 'right_eyebrow' not in dict_landmarks.keys(): + dict_landmarks['right_eyebrow'] = [] + dict_landmarks['right_eyebrow'].append([int(x),int(y),(0,255,0)]) + if draw_circle: + cv2.circle(img, (int(x),int(y)), 2, (0,255,0),-1) + elif 67>= i >=60: + if 'left_eye' not in dict_landmarks.keys(): + dict_landmarks['left_eye'] = [] + dict_landmarks['left_eye'].append([int(x),int(y),(255,0,255)]) + if draw_circle: + cv2.circle(img, (int(x),int(y)), 2, (255,0,255),-1) + elif 75>= i >=68: + if 'right_eye' not in dict_landmarks.keys(): + dict_landmarks['right_eye'] = [] + dict_landmarks['right_eye'].append([int(x),int(y),(255,0,255)]) + if draw_circle: + cv2.circle(img, (int(x),int(y)), 2, (255,0,255),-1) + elif 97>= i >=96: + cv2.circle(img, (int(x),int(y)), 2, (0,0,255),-1) + elif 54>= i >=51: + if 'bridge_nose' not in dict_landmarks.keys(): + dict_landmarks['bridge_nose'] = [] + dict_landmarks['bridge_nose'].append([int(x),int(y),(0,170,255)]) + if draw_circle: + cv2.circle(img, (int(x),int(y)), 2, (0,170,255),-1) + elif 32>= i >=0: + if 'basin' not in dict_landmarks.keys(): + dict_landmarks['basin'] = [] + dict_landmarks['basin'].append([int(x),int(y),(255,30,30)]) + if draw_circle: + cv2.circle(img, (int(x),int(y)), 2, (255,30,30),-1) + elif 59>= i >=55: + if 'wing_nose' not in dict_landmarks.keys(): + dict_landmarks['wing_nose'] = [] + dict_landmarks['wing_nose'].append([int(x),int(y),(0,255,255)]) + if draw_circle: + cv2.circle(img, (int(x),int(y)), 2, (0,255,255),-1) + elif 87>= i >=76: + if 'out_lip' not in dict_landmarks.keys(): + dict_landmarks['out_lip'] = [] + dict_landmarks['out_lip'].append([int(x),int(y),(255,255,0)]) + if draw_circle: + cv2.circle(img, (int(x),int(y)), 2, (255,255,0),-1) + elif 95>= i >=88: + if 'in_lip' not in dict_landmarks.keys(): + dict_landmarks['in_lip'] = [] + dict_landmarks['in_lip'].append([int(x),int(y),(50,220,255)]) + if draw_circle: + cv2.circle(img, (int(x),int(y)), 2, (50,220,255),-1) + else: + if draw_circle: + cv2.circle(img, (int(x),int(y)), 2, (255,0,255),-1) + + return dict_landmarks + +def draw_contour(image,dict): + for key in dict.keys(): + # print(key) + _,_,color = dict[key][0] + + if 'basin' == key or 'wing_nose' == key: + pts = np.array([[dict[key][i][0],dict[key][i][1]] for i in range(len(dict[key]))],np.int32) + # print(pts) + cv2.polylines(image,[pts],False,color) + + else: + points_array = np.zeros((1,len(dict[key]),2),dtype = np.int32) + for i in range(len(dict[key])): + x,y,_ = dict[key][i] + points_array[0,i,0] = x + points_array[0,i,1] = y + + # cv2.fillPoly(image, points_array, color) + cv2.drawContours(image,points_array,-1,color,thickness=1) diff --git a/components/face_multi_task/utils/model_utils.py b/components/face_multi_task/utils/model_utils.py new file mode 100644 index 0000000000000000000000000000000000000000..48cc3d33db8dafe7ed54f344825f6905e1adac26 --- /dev/null +++ b/components/face_multi_task/utils/model_utils.py @@ -0,0 +1,61 @@ +#-*-coding:utf-8-*- +# date:2020-04-11 +# Author: Eric.Lee +# function: model utils + +import os +import numpy as np +import torch +import torch.backends.cudnn as cudnn +import random + +def get_acc(output, label): + total = output.shape[0] + _, pred_label = output.max(1) + num_correct = (pred_label == label).sum().item() + return num_correct / float(total) + +def set_learning_rate(optimizer, lr): + for param_group in optimizer.param_groups: + param_group['lr'] = lr + +def set_seed(seed = 666): + np.random.seed(seed) + random.seed(seed) + torch.manual_seed(seed) + if torch.cuda.is_available(): + torch.cuda.manual_seed(seed) + torch.cuda.manual_seed_all(seed) + cudnn.deterministic = True + +def split_trainval_datasets(ops): + print(' --------------->>> split_trainval_datasets ') + train_split_datasets = [] + train_split_datasets_label = [] + + val_split_datasets = [] + val_split_datasets_label = [] + for idx,doc in enumerate(sorted(os.listdir(ops.train_path), key=lambda x:int(x.split('.')[0]), reverse=False)): + # print(' %s label is %s \n'%(doc,idx)) + + data_list = os.listdir(ops.train_path+doc) + random.shuffle(data_list) + + cal_split_num = int(len(data_list)*ops.val_factor) + + for i,file in enumerate(data_list): + if '.jpg' in file: + if i < cal_split_num: + val_split_datasets.append(ops.train_path+doc + '/' + file) + val_split_datasets_label.append(idx) + else: + train_split_datasets.append(ops.train_path+doc + '/' + file) + train_split_datasets_label.append(idx) + + print(ops.train_path+doc + '/' + file,idx) + + print('\n') + print('train_split_datasets len {}'.format(len(train_split_datasets))) + print('val_split_datasets len {}'.format(len(val_split_datasets))) + + return train_split_datasets,train_split_datasets_label,val_split_datasets,val_split_datasets_label diff --git a/lib/wyw2s_lib/cfg/wyw2s.cfg b/lib/wyw2s_lib/cfg/wyw2s.cfg new file mode 100644 index 0000000000000000000000000000000000000000..869466b16601275b58329db725fb4b4f22e652ee --- /dev/null +++ b/lib/wyw2s_lib/cfg/wyw2s.cfg @@ -0,0 +1 @@ +YouWantToSee=BradPitt diff --git a/lib/wyw2s_lib/cores/wyw2s_fuction.py b/lib/wyw2s_lib/cores/wyw2s_fuction.py new file mode 100644 index 0000000000000000000000000000000000000000..0f58ab591fb9293950b48bb3f37e90a5f0661b36 --- /dev/null +++ b/lib/wyw2s_lib/cores/wyw2s_fuction.py @@ -0,0 +1,372 @@ +#-*-coding:utf-8-*- +''' +DpCas-Light +|||| |||| |||| || |||| +|| || || || || || |||| || || +|| || || || || || || || || +|| || || || || ||====|| |||| +|| || |||| || || ||======|| || +|| || || || || || || || || +|||| || |||| || || |||| + +/------------------ Who You Want 2 See ------------------/ +''' +# date:2021-04-17 +# Author: Eric.Lee +# function: pipline + +import os +import numpy as np +import cv2 +import torch +from PIL import Image + +def compute_iou(rec1, rec2): + """ + computing IoU + :param rec1: (y0, x0, y1, x1), which reflects + (top, left, bottom, right) + :param rec2: (y0, x0, y1, x1) + :return: scala value of IoU + """ + # computing area of each rectangles + S_rec1 = (rec1[2] - rec1[0]) * (rec1[3] - rec1[1]) + S_rec2 = (rec2[2] - rec2[0]) * (rec2[3] - rec2[1]) + + # computing the sum_area + sum_area = S_rec1 + S_rec2 + + # find the each edge of intersect rectangle + left_line = max(rec1[1], rec2[1]) + right_line = min(rec1[3], rec2[3]) + top_line = max(rec1[0], rec2[0]) + bottom_line = min(rec1[2], rec2[2]) + + # judge if there is an intersect + if left_line >= right_line or top_line >= bottom_line: + return 0 + else: + intersect = (right_line - left_line) * (bottom_line - top_line) + #return (intersect / (sum_area - intersect))*1.0 + return (intersect / (S_rec1 + 1e-6))*1.0 + +def draw_landmarks(img,output,face_w,face_h,x0,y0,vis = False): + img_width = img.shape[1] + img_height = img.shape[0] + dict_landmarks = {} + eyes_center = [] + x_list = [] + y_list = [] + for i in range(int(output.shape[0]/2)): + x = output[i*2+0]*float(face_w) + x0 + y = output[i*2+1]*float(face_h) + y0 + + x_list.append(x) + y_list.append(y) + + if 41>= i >=33: + if 'left_eyebrow' not in dict_landmarks.keys(): + dict_landmarks['left_eyebrow'] = [] + dict_landmarks['left_eyebrow'].append([int(x),int(y),(0,255,0)]) + if vis: + cv2.circle(img, (int(x),int(y)), 2, (0,255,0),-1) + elif 50>= i >=42: + if 'right_eyebrow' not in dict_landmarks.keys(): + dict_landmarks['right_eyebrow'] = [] + dict_landmarks['right_eyebrow'].append([int(x),int(y),(0,255,0)]) + if vis: + cv2.circle(img, (int(x),int(y)), 2, (0,255,0),-1) + elif 67>= i >=60: + if 'left_eye' not in dict_landmarks.keys(): + dict_landmarks['left_eye'] = [] + dict_landmarks['left_eye'].append([int(x),int(y),(255,55,255)]) + if vis: + cv2.circle(img, (int(x),int(y)), 2, (255,0,255),-1) + elif 75>= i >=68: + if 'right_eye' not in dict_landmarks.keys(): + dict_landmarks['right_eye'] = [] + dict_landmarks['right_eye'].append([int(x),int(y),(255,55,255)]) + if vis: + cv2.circle(img, (int(x),int(y)), 2, (255,0,255),-1) + elif 97>= i >=96: + eyes_center.append((x,y)) + if vis: + cv2.circle(img, (int(x),int(y)), 2, (0,0,255),-1) + elif 54>= i >=51: + if 'bridge_nose' not in dict_landmarks.keys(): + dict_landmarks['bridge_nose'] = [] + dict_landmarks['bridge_nose'].append([int(x),int(y),(0,170,255)]) + if vis: + cv2.circle(img, (int(x),int(y)), 2, (0,170,255),-1) + elif 32>= i >=0: + if 'basin' not in dict_landmarks.keys(): + dict_landmarks['basin'] = [] + dict_landmarks['basin'].append([int(x),int(y),(255,30,30)]) + if vis: + cv2.circle(img, (int(x),int(y)), 2, (255,30,30),-1) + elif 59>= i >=55: + if 'wing_nose' not in dict_landmarks.keys(): + dict_landmarks['wing_nose'] = [] + dict_landmarks['wing_nose'].append([int(x),int(y),(0,255,255)]) + if vis: + cv2.circle(img, (int(x),int(y)), 2, (0,255,255),-1) + elif 87>= i >=76: + if 'out_lip' not in dict_landmarks.keys(): + dict_landmarks['out_lip'] = [] + dict_landmarks['out_lip'].append([int(x),int(y),(255,255,0)]) + if vis: + cv2.circle(img, (int(x),int(y)), 2, (255,255,0),-1) + elif 95>= i >=88: + if 'in_lip' not in dict_landmarks.keys(): + dict_landmarks['in_lip'] = [] + dict_landmarks['in_lip'].append([int(x),int(y),(50,220,255)]) + if vis: + cv2.circle(img, (int(x),int(y)), 2, (50,220,255),-1) + else: + if vis: + cv2.circle(img, (int(x),int(y)), 2, (255,0,255),-1) + face_area = (max(x_list) - min(x_list))*(max(y_list) - min(y_list)) + return dict_landmarks,eyes_center,face_area + +def draw_contour(image,dict,vis = False): + x0 = 0# 偏置 + y0 = 0 + + for key in dict.keys(): + # print(key) + _,_,color = dict[key][0] + + if 'left_eye' == key: + eye_x = np.mean([dict[key][i][0]+x0 for i in range(len(dict[key]))]) + eye_y = np.mean([dict[key][i][1]+y0 for i in range(len(dict[key]))]) + if vis: + cv2.circle(image, (int(eye_x),int(eye_y)), 3, (255,255,55),-1) + if 'right_eye' == key: + eye_x = np.mean([dict[key][i][0]+x0 for i in range(len(dict[key]))]) + eye_y = np.mean([dict[key][i][1]+y0 for i in range(len(dict[key]))]) + if vis: + cv2.circle(image, (int(eye_x),int(eye_y)), 3, (255,215,25),-1) + + if 'basin' == key or 'wing_nose' == key: + pts = np.array([[dict[key][i][0]+x0,dict[key][i][1]+y0] for i in range(len(dict[key]))],np.int32) + if vis: + cv2.polylines(image,[pts],False,color,thickness = 2) + + else: + points_array = np.zeros((1,len(dict[key]),2),dtype = np.int32) + for i in range(len(dict[key])): + x,y,_ = dict[key][i] + points_array[0,i,0] = x+x0 + points_array[0,i,1] = y+y0 + + # cv2.fillPoly(image, points_array, color) + if vis: + cv2.drawContours(image,points_array,-1,color,thickness=2) + + +def plot_box(x, img, color=None, label=None, line_thickness=None): + # Plots one bounding box on image img + tl = line_thickness or round(0.002 * max(img.shape[0:2])) + 1 # line thickness + color = color or [random.randint(0, 255) for _ in range(3)] + c1, c2 = (int(x[0]), int(x[1])), (int(x[2]), int(x[3])) + cv2.rectangle(img, c1, c2, color, thickness=tl) + if label: + tf = max(tl - 1, 2) # font thickness + t_size = cv2.getTextSize(label, 0, fontScale=tl / 3, thickness=tf)[0] + c2 = c1[0] + t_size[0], c1[1] - t_size[1] - 3 + cv2.rectangle(img, c1, c2, color, -1) # filled + cv2.putText(img, label, (c1[0], c1[1] - 2), 0, tl / 3, [185, 195,190], thickness=tf, lineType=cv2.LINE_AA) +#------------------------------------------------------------------------------- + +def face_alignment(imgn,eye_left_n,eye_right_n,\ +desiredLeftEye=(0.34, 0.42),desiredFaceWidth=256, desiredFaceHeight=None): + + if desiredFaceHeight is None: + desiredFaceHeight = desiredFaceWidth + + leftEyeCenter = eye_left_n + rightEyeCenter = eye_right_n + # compute the angle between the eye centroids + dY = rightEyeCenter[1] - leftEyeCenter[1] + dX = rightEyeCenter[0] - leftEyeCenter[0] + angle = np.degrees(np.arctan2(dY, dX)) + + + # compute the desired right eye x-coordinate based on the + # desired x-coordinate of the left eye + desiredRightEyeX = 1.0 - desiredLeftEye[0] + # determine the scale of the new resulting image by taking + # the ratio of the distance between eyes in the *current* + # image to the ratio of distance between eyes in the + # *desired* image + dist = np.sqrt((dX ** 2) + (dY ** 2)) + desiredDist = (desiredRightEyeX - desiredLeftEye[0]) + desiredDist *= desiredFaceWidth + scale = desiredDist / dist + # compute center (x, y)-coordinates (i.e., the median point) + # between the two eyes in the input image + eyesCenter = ((leftEyeCenter[0] + rightEyeCenter[0]) / 2,(leftEyeCenter[1] + rightEyeCenter[1]) / 2) + # grab the rotation matrix for rotating and scaling the face + M = cv2.getRotationMatrix2D(eyesCenter, angle, scale) + # update the translation component of the matrix + tX = desiredFaceWidth * 0.5 + tY = desiredFaceHeight * desiredLeftEye[1] + M[0, 2] += (tX - eyesCenter[0]) + M[1, 2] += (tY - eyesCenter[1]) + + M_reg = np.zeros((3,3),dtype = np.float32) + M_reg[0,:] = M[0,:] + M_reg[1,:] = M[1,:] + M_reg[2,:] = (0,0,1.) + # print(M_reg) + M_I = np.linalg.inv(M_reg)#矩阵求逆,从而获得,目标图到原图的关系 + # print(M_I) + # apply the affine transformation + (w, h) = (desiredFaceWidth, desiredFaceHeight) + # cv_resize_model = [cv2.INTER_LINEAR,cv2.INTER_CUBIC,cv2.INTER_NEAREST,cv2.INTER_AREA] + + output = cv2.warpAffine(imgn, M, (w, h),flags=cv2.INTER_LINEAR,borderMode=cv2.BORDER_CONSTANT)# + + #--------------------------------------------------------------------------------------- + + # ptx1 = int(eye_left_gt_n[0]*M[0][0] + eye_left_gt_n[1]*M[0][1] + M[0][2]) + # pty1 = int(eye_left_gt_n[0]*M[1][0] + eye_left_gt_n[1]*M[1][1] + M[1][2]) + # + # ptx2 = int(eye_right_gt_n[0]*M[0][0] + eye_right_gt_n[1]*M[0][1] + M[0][2]) + # pty2 = int(eye_right_gt_n[0]*M[1][0] + eye_right_gt_n[1]*M[1][1] + M[1][2]) + + return output + +def refine_face_bbox(bbox,img_shape): + height,width,_ = img_shape + + x1,y1,x2,y2 = bbox + + expand_w = (x2-x1) + expand_h = (y2-y1) + + x1 -= expand_w*0.12 + y1 -= expand_h*0.12 + x2 += expand_w*0.12 + y2 += expand_h*0.08 + + x1,y1,x2,y2 = int(x1),int(y1),int(x2),int(y2) + + x1 = np.clip(x1,0,width-1) + y1 = np.clip(y1,0,height-1) + x2 = np.clip(x2,0,width-1) + y2 = np.clip(y2,0,height-1) + + return (x1,y1,x2,y2) + +def get_faces_batch_attribute(face_multitask_model,face_euler_model,dets,img_raw,use_cuda,face_size = 256,vis = False): + + face_map = np.zeros([112*3,112*3,3]).astype(np.uint8) + face_map[:,:,0].fill(205) + face_map[:,:,1].fill(205) + face_map[:,:,2].fill(205) + if len(dets) == 0: + return [],[],[],face_map + img_align = img_raw.copy() + # 绘制图像 + image_batch = None + r_bboxes = [] + imgs_crop = [] + for b in dets: + b = list(map(int, b)) + + r_bbox = refine_face_bbox((b[0],b[1],b[2],b[3]),img_raw.shape) + r_bboxes.append(r_bbox) + img_crop = img_raw[r_bbox[1]:r_bbox[3],r_bbox[0]:r_bbox[2]] + imgs_crop.append(img_crop) + img_ = cv2.resize(img_crop, (face_size,face_size), interpolation = cv2.INTER_LINEAR) # INTER_LINEAR INTER_CUBIC + + img_ = img_.astype(np.float32) + img_ = (img_-128.)/256. + + img_ = img_.transpose(2, 0, 1) + img_ = np.expand_dims(img_,0) + + if image_batch is None: + image_batch = img_ + else: + image_batch = np.concatenate((image_batch,img_),axis=0) + + # # 填充最大 关键点 批次数据 + # if len(dets) < ops.max_batch_size: + # im_mask = np.zeros([1,3,ops.landmarks_img_size[0],ops.landmarks_img_size[1]], dtype = np.float32) + # for i in range(ops.max_batch_size-len(dets)): + # if image_batch is None: + # image_batch = im_mask + # else: + # image_batch = np.concatenate((image_batch,im_mask),axis=0) + # + # print("image_batch shape:",image_batch.shape) + # image_batch = torch.from_numpy(image_batch).float() + # # + # if use_cuda: + # image_batch = image_batch.cuda() # (bs, 3, h, w) + + landmarks_pre,gender_pre,age_pre = face_multitask_model.predict(image_batch) + euler_angles = face_euler_model.predict(image_batch) + # print(" -------->>> euler_angles : ",euler_angles) + # print("landmarks_pre,gender_pre,age_pre :",landmarks_pre.shape,gender_pre.shape,age_pre.shape) + + faces_identify = [] # 符合要求,需要识别的人的图像 + faces_identify_bboxes = []# 符合要求,需要识别的人脸边界框 + faceid_idx = 0 # 符合要求,需要识别的人的索引计数器 + for i in range(len(dets)): + x0,y0 = r_bboxes[i][0],r_bboxes[i][1] + face_w = r_bboxes[i][2]-r_bboxes[i][0] + face_h = r_bboxes[i][3]-r_bboxes[i][1] + dict_landmarks,eyes_center,face_area = draw_landmarks(img_raw,landmarks_pre[i],face_w,face_h,x0,y0,vis = False) + + gray_ = cv2.cvtColor(img_align[r_bboxes[i][1]:r_bboxes[i][3],r_bboxes[i][0]:r_bboxes[i][2],:], cv2.COLOR_BGR2GRAY) + + blur_ = cv2.Laplacian(gray_, cv2.CV_64F).var() + + gender_max_index = np.argmax(gender_pre[i])#概率最大类别索引 + score_gender = gender_pre[i][gender_max_index]# 最大概率 + + yaw,pitch,roll = euler_angles[i] + + cv2.putText(img_raw, "yaw:{:.1f},pitch:{:.1f},roll:{:.1f}".format(yaw,pitch,roll),(int(r_bboxes[i][0]-20),int(r_bboxes[i][1]-30)),cv2.FONT_HERSHEY_DUPLEX, 0.65, (253,139,54), 5) + cv2.putText(img_raw, "yaw:{:.1f},pitch:{:.1f},roll:{:.1f}".format(yaw,pitch,roll),(int(r_bboxes[i][0]-20),int(r_bboxes[i][1]-30)),cv2.FONT_HERSHEY_DUPLEX, 0.65, (20,185,255), 1) + + cv2.putText(img_raw, "{}".format(int(face_area)),(int(r_bboxes[i][0]-1),int(r_bboxes[i][3]-3)),cv2.FONT_HERSHEY_DUPLEX, 0.65, (253,39,54), 5) # face_area + cv2.putText(img_raw, "{}".format(int(face_area)),(int(r_bboxes[i][0]-1),int(r_bboxes[i][3]-3)),cv2.FONT_HERSHEY_DUPLEX, 0.65, (20,185,255), 1) + if gender_max_index == 1.: + gender_str = "male" + else: + gender_str = "female" + + if abs(yaw)<45.: + face_align_output = face_alignment(img_align,eyes_center[0],eyes_center[1], + desiredLeftEye=(0.365, 0.38),desiredFaceWidth=112, desiredFaceHeight=None) + else: + face_align_output = face_alignment(img_align,eyes_center[0],eyes_center[1], + desiredLeftEye=(0.38, 0.40),desiredFaceWidth=112, desiredFaceHeight=None) + + + # plot_box(r_bboxes[i][0:4], img_raw,label="{}, age: {:.1f}, unblur:{}".format(gender_str,age_pre[i][0],int(blur_)), color=(255,90,90), line_thickness=2) + plot_box(r_bboxes[i][0:4], img_raw,label="{}, age: {:.1f}".format(gender_str,age_pre[i][0]), color=(255,90,90), line_thickness=2) + # print("face_area:",face_area) + # if (blur_>35) and abs(yaw)<36. and abs(pitch)<30. and (face_area>(60*60)): + if abs(yaw)<36. and abs(pitch)<36. and (face_area>(60*60)): + if vis : + draw_contour(img_raw,dict_landmarks,vis = True) + + faces_identify.append(Image.fromarray(face_align_output)) + faces_identify_bboxes.append(r_bboxes[i][0:4]) + + if faceid_idx<9: + y1_map,y2_map = int(faceid_idx/3)*112,(int(faceid_idx/3)+1)*112 + x1_map,x2_map = int(faceid_idx%3)*112,(int(faceid_idx%3)+1)*112 + face_map[y1_map:y2_map,x1_map:x2_map,:] = face_align_output + cv2.rectangle(face_map, (int(x1_map),int(y1_map)), (int(x2_map),int(y2_map)), (55,255,255), 2) + faceid_idx += 1 + else: + cv2.putText(img_raw, "bad for face reco",(int(r_bboxes[i][0]-1),int(r_bboxes[i][3]+20)),cv2.FONT_HERSHEY_DUPLEX, 0.65, (20,15,255), 4) + cv2.putText(img_raw, "bad for face reco",(int(r_bboxes[i][0]-1),int(r_bboxes[i][3]+20)),cv2.FONT_HERSHEY_DUPLEX, 0.65, (220,185,25), 1) + + return faces_identify,faces_identify_bboxes,r_bboxes,face_map diff --git a/lib/wyw2s_lib/make_facebank_tools/README.md b/lib/wyw2s_lib/make_facebank_tools/README.md new file mode 100644 index 0000000000000000000000000000000000000000..811b867b7e4336fd6fbd150acbfc38a7826b7673 --- /dev/null +++ b/lib/wyw2s_lib/make_facebank_tools/README.md @@ -0,0 +1,5 @@ + + +* make_facebank.py # 构建人脸底库 + +* 默认人脸需要alignment ,以及 resize 到分辨率 112*112 diff --git a/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-40-1.jpg b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-40-1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8f65f1142e11cf19a4a6cc7ab9b9c1172b939dfa Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-40-1.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-41-10.jpg b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-41-10.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ec95e32dde20691b1bbc1b4b30471207abc62dad Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-41-10.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-41-11.jpg b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-41-11.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a30c4193ccbaa1b7e901915fec8f6f7c01033c8f Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-41-11.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-41-12.jpg b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-41-12.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6da7a37adf7deff4974b1a7b8eb0b07330536329 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-41-12.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-41-13.jpg b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-41-13.jpg new file mode 100644 index 0000000000000000000000000000000000000000..67a7c0b7eea1f4bd59596fb7196060ee421856b6 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-41-13.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-41-14.jpg b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-41-14.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b1c74b4b69c0e1a2c4ef2b4bb9190eaa76740ead Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-41-14.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-41-2.jpg b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-41-2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c384a13743c5809ef193e263cc4becdfca33f35c Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-41-2.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-41-3.jpg b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-41-3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cca2426cf95211e03bb4a1adb6ba0864c2ddc4dd Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-41-3.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-41-4.jpg b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-41-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6382df21e051c3ed279e90f3c2e084d2c6b99a8a Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-41-4.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-41-5.jpg b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-41-5.jpg new file mode 100644 index 0000000000000000000000000000000000000000..44d1f5fc04ac281184da27d2c8a19d6e91a3e945 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-41-5.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-41-6.jpg b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-41-6.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7cc19bf348eaa595ee96f1c19b6bb9151a31ae1a Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-41-6.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-41-7.jpg b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-41-7.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bf955cf3b97a9db39c8feeb049d663b169552129 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-41-7.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-41-8.jpg b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-41-8.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a752c392ec8ba43efdef215aed25fedd482a1c34 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-41-8.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-41-9.jpg b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-41-9.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9df4f6090c0d0c53d1100f2c7f80fe55e4f32566 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-41-9.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-42-15.jpg b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-42-15.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c58ea37d1feb660978f5f2a30cc39c8a2a08056f Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-42-15.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-42-16.jpg b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-42-16.jpg new file mode 100644 index 0000000000000000000000000000000000000000..75c128f8814aef8acfd2f7d06672804882701b5f Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-42-16.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-42-17.jpg b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-42-17.jpg new file mode 100644 index 0000000000000000000000000000000000000000..41349ed44c5cf00ecda39ee4c0d0cb4345d69700 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-42-17.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-42-18.jpg b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-42-18.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fad30df05b0f14e2656222b34a6f30fd4646815c Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-42-18.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-42-19.jpg b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-42-19.jpg new file mode 100644 index 0000000000000000000000000000000000000000..02a464c25fd94fbd51e4585342680250e64c3bf5 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-42-19.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-42-20.jpg b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-42-20.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7726658b5623ab9fcf75f0d4363a1a421f03c189 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-42-20.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-42-21.jpg b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-42-21.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0534998c0d3ece07936d693f04d85df495fc95b0 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-42-21.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-42-22.jpg b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-42-22.jpg new file mode 100644 index 0000000000000000000000000000000000000000..090589e039d8d3ffb4444bf8522ea73dbd952ded Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-42-22.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-42-23.jpg b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-42-23.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a4edf877c4d4a05c448e723bc508b488cfa6a629 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-42-23.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-42-24.jpg b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-42-24.jpg new file mode 100644 index 0000000000000000000000000000000000000000..901e35ef5142f772afa54c5130371b20d0cfda40 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/AngelinaJolie/2021-04-20-02-52-42-24.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/AnneHathaway/2021-04-15-03-17-26-2.jpg b/lib/wyw2s_lib/make_facebank_tools/images/AnneHathaway/2021-04-15-03-17-26-2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..46cbe66ab5e056ef1bb1d7d70338ea132128200b Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/AnneHathaway/2021-04-15-03-17-26-2.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/AnneHathaway/2021-04-15-03-17-26-3.jpg b/lib/wyw2s_lib/make_facebank_tools/images/AnneHathaway/2021-04-15-03-17-26-3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0a9c6eae0917f12d3552ea8bd57c6f3b33e0aaec Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/AnneHathaway/2021-04-15-03-17-26-3.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/AnneHathaway/2021-04-15-03-17-26-4.jpg b/lib/wyw2s_lib/make_facebank_tools/images/AnneHathaway/2021-04-15-03-17-26-4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..48cc5fac5628b9bf035e24522b302ba58055b11d Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/AnneHathaway/2021-04-15-03-17-26-4.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/AnneHathaway/2021-04-15-03-17-26-5.jpg b/lib/wyw2s_lib/make_facebank_tools/images/AnneHathaway/2021-04-15-03-17-26-5.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5f92db9552aef04a14cfc75dc469ea5bce04c2a3 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/AnneHathaway/2021-04-15-03-17-26-5.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/AnneHathaway/2021-04-15-03-17-26-6.jpg b/lib/wyw2s_lib/make_facebank_tools/images/AnneHathaway/2021-04-15-03-17-26-6.jpg new file mode 100644 index 0000000000000000000000000000000000000000..58893901043a2f0025d9307d5a0512cd231b0551 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/AnneHathaway/2021-04-15-03-17-26-6.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/AnneHathaway/2021-04-15-03-17-26-7.jpg b/lib/wyw2s_lib/make_facebank_tools/images/AnneHathaway/2021-04-15-03-17-26-7.jpg new file mode 100644 index 0000000000000000000000000000000000000000..240e870ae270f97468e42b54593a4e33781afe92 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/AnneHathaway/2021-04-15-03-17-26-7.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/AnneHathaway/2021-04-15-03-17-27-10.jpg b/lib/wyw2s_lib/make_facebank_tools/images/AnneHathaway/2021-04-15-03-17-27-10.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d2933a7b8d97689569d83f6281906718349fb5d5 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/AnneHathaway/2021-04-15-03-17-27-10.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/AnneHathaway/2021-04-15-03-17-27-11.jpg b/lib/wyw2s_lib/make_facebank_tools/images/AnneHathaway/2021-04-15-03-17-27-11.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3e0e7fa4bd1f91d2256d1594ad5eafc558582440 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/AnneHathaway/2021-04-15-03-17-27-11.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/AnneHathaway/2021-04-15-03-17-27-8.jpg b/lib/wyw2s_lib/make_facebank_tools/images/AnneHathaway/2021-04-15-03-17-27-8.jpg new file mode 100644 index 0000000000000000000000000000000000000000..28a4029728c3913df109b1243e6c371d301076fc Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/AnneHathaway/2021-04-15-03-17-27-8.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/AnneHathaway/2021-04-15-03-17-27-9.jpg b/lib/wyw2s_lib/make_facebank_tools/images/AnneHathaway/2021-04-15-03-17-27-9.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ddbd690103c841f8fb006ce3351c11b5ba3b20ff Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/AnneHathaway/2021-04-15-03-17-27-9.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-44-35.jpg b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-44-35.jpg new file mode 100644 index 0000000000000000000000000000000000000000..da071e103eb07c0e5ea260f419eecadc21fe77f3 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-44-35.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-44-36.jpg b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-44-36.jpg new file mode 100644 index 0000000000000000000000000000000000000000..98ca24a7da7aab0a456f87df78e4659a776266dd Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-44-36.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-44-37.jpg b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-44-37.jpg new file mode 100644 index 0000000000000000000000000000000000000000..89f2890ef74319361c128fbb16ef836ce7fd4ba9 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-44-37.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-44-38.jpg b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-44-38.jpg new file mode 100644 index 0000000000000000000000000000000000000000..47e495a37ebc7f056b1558ee5a09382021ee3e25 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-44-38.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-44-39.jpg b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-44-39.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f5335dd229d1312eb8b487ad12c19532405118fa Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-44-39.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-44-40.jpg b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-44-40.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6c99d7bece7e5b00e55503645da10bcb4d1791f8 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-44-40.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-44-41.jpg b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-44-41.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5da3d151111569586aeab240e45b0fb2b39f2e93 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-44-41.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-44-42.jpg b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-44-42.jpg new file mode 100644 index 0000000000000000000000000000000000000000..44dba985e12a775b1862c906b486e5f344bc0df1 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-44-42.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-44-43.jpg b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-44-43.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5ea67d61eb731dd234b7371ab1755cadc1c599dd Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-44-43.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-44-44.jpg b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-44-44.jpg new file mode 100644 index 0000000000000000000000000000000000000000..179a72807335566c94af53d7c3e13a4c077c566c Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-44-44.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-45-45.jpg b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-45-45.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c27a268c382871cc28dd6c923326fccf19bee3bb Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-45-45.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-45-46.jpg b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-45-46.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8aae8d64a5a86aa7545125378f3b554b4c8290cd Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-45-46.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-45-47.jpg b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-45-47.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8a63d90a30d15330b29794d37a078ed3b5584204 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-45-47.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-45-48.jpg b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-45-48.jpg new file mode 100644 index 0000000000000000000000000000000000000000..930020f0f6ca5b8f0e8693de003c1b158e6cb789 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-45-48.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-45-49.jpg b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-45-49.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3fab9677e75ad3593dc7279acb9b4487bc896576 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-45-49.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-45-50.jpg b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-45-50.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9b0c349e57042e8c9bca63569e709b41cbe7a0de Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-45-50.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-45-51.jpg b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-45-51.jpg new file mode 100644 index 0000000000000000000000000000000000000000..24045230d1e068e8c41e4ab346d6f371b5bd2fbc Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-45-51.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-45-52.jpg b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-45-52.jpg new file mode 100644 index 0000000000000000000000000000000000000000..47b387c0c1f0a809dbf278f74ce9a3c3934daade Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-45-52.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-45-53.jpg b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-45-53.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a28215a5c71cd34d6f9a860700e3eb53bf1c1bcd Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-45-53.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-45-54.jpg b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-45-54.jpg new file mode 100644 index 0000000000000000000000000000000000000000..244b08726e79f133beb151b16043b52f2598a891 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-45-54.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-45-55.jpg b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-45-55.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6eeed79bf5dbdcd07b9ecf871359d2b5d3a6da95 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-45-55.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-45-56.jpg b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-45-56.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0ea922beef57397463868fc20ba5ab37f4e29511 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-45-56.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-45-57.jpg b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-45-57.jpg new file mode 100644 index 0000000000000000000000000000000000000000..003ab8b949adf896a3e91af43afb169696ba4794 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-45-57.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-46-58.jpg b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-46-58.jpg new file mode 100644 index 0000000000000000000000000000000000000000..353f707cae047f296804665e50b3d9a4c205bd8d Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/BradPitt/2021-04-20-02-52-46-58.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-36-37.jpg b/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-36-37.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a2b31bf4c7bf6d453d4bb1fbff1291ef4651a70c Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-36-37.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-36-38.jpg b/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-36-38.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9820df5960ba44ad474c2cc66709bd8835a31389 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-36-38.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-36-39.jpg b/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-36-39.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7aae1f4fee04e3677548f0c54efb129cbd248563 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-36-39.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-36-40.jpg b/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-36-40.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b430a132ca183a4e8ca14ece8b7f5613b922a8d0 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-36-40.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-37-41.jpg b/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-37-41.jpg new file mode 100644 index 0000000000000000000000000000000000000000..26dec2e69db0fb6dccb0320841af35d326190b3a Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-37-41.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-37-42.jpg b/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-37-42.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6f1f0f7876f5ebf58cc21a3eaf240e81409253d7 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-37-42.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-37-43.jpg b/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-37-43.jpg new file mode 100644 index 0000000000000000000000000000000000000000..43f4c7c28db8889fb4ce049062c767c5c8430ccc Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-37-43.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-37-44.jpg b/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-37-44.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b7fddc575b3d9ec36d07f5daefd5a5248daa8431 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-37-44.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-37-45.jpg b/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-37-45.jpg new file mode 100644 index 0000000000000000000000000000000000000000..768ce12d28e6c7c37182e59ef7b85ccf33457d1a Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-37-45.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-37-46.jpg b/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-37-46.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b73321c6ee396595e7f40d8c8529cfc55c8d9457 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-37-46.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-37-47.jpg b/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-37-47.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0b6d08b3864074310af20792695a82c263c51b81 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-37-47.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-37-48.jpg b/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-37-48.jpg new file mode 100644 index 0000000000000000000000000000000000000000..47e6eb09cfc46ec8b419d0478ced023569ddb476 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-37-48.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-37-49.jpg b/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-37-49.jpg new file mode 100644 index 0000000000000000000000000000000000000000..20b9980b1b4c5ce3d5e2814d449a2d69dc902536 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-37-49.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-37-50.jpg b/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-37-50.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8e3e6fd93c06014d40839198b81d5a0fe21c358a Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-37-50.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-37-51.jpg b/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-37-51.jpg new file mode 100644 index 0000000000000000000000000000000000000000..eafb13b233cd7e314d9dfb593214d7324f4214c1 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/JenniferAniston/2021-04-19-20-19-37-51.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/JohnnyDepp/2021-04-15-03-17-33-88.jpg b/lib/wyw2s_lib/make_facebank_tools/images/JohnnyDepp/2021-04-15-03-17-33-88.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c22890e076932d43d4c638adec3633418513c223 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/JohnnyDepp/2021-04-15-03-17-33-88.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/JohnnyDepp/2021-04-15-03-17-33-89.jpg b/lib/wyw2s_lib/make_facebank_tools/images/JohnnyDepp/2021-04-15-03-17-33-89.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4d64acf556b98d54d626ebbefdc4b406388e1404 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/JohnnyDepp/2021-04-15-03-17-33-89.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/JohnnyDepp/2021-04-15-03-17-33-90.jpg b/lib/wyw2s_lib/make_facebank_tools/images/JohnnyDepp/2021-04-15-03-17-33-90.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e01ae548900655aaa37a576163ecbddb8f9cadef Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/JohnnyDepp/2021-04-15-03-17-33-90.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/JohnnyDepp/2021-04-15-03-17-33-91.jpg b/lib/wyw2s_lib/make_facebank_tools/images/JohnnyDepp/2021-04-15-03-17-33-91.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cef2c915b832e3b5cc67b91dbf5c3e107b78aa51 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/JohnnyDepp/2021-04-15-03-17-33-91.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/JohnnyDepp/2021-04-15-03-17-33-92.jpg b/lib/wyw2s_lib/make_facebank_tools/images/JohnnyDepp/2021-04-15-03-17-33-92.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6f490fa80605a8c864759e5bd009f49595b307cd Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/JohnnyDepp/2021-04-15-03-17-33-92.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/JohnnyDepp/2021-04-15-03-17-33-93.jpg b/lib/wyw2s_lib/make_facebank_tools/images/JohnnyDepp/2021-04-15-03-17-33-93.jpg new file mode 100644 index 0000000000000000000000000000000000000000..89e1f0dafbc4db547871ea95a9110d73556f9bed Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/JohnnyDepp/2021-04-15-03-17-33-93.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/JohnnyDepp/2021-04-15-03-17-33-94.jpg b/lib/wyw2s_lib/make_facebank_tools/images/JohnnyDepp/2021-04-15-03-17-33-94.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d1f1b51de90dd673e631923b6ab847ced2821bf1 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/JohnnyDepp/2021-04-15-03-17-33-94.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/JohnnyDepp/2021-04-15-03-17-33-95.jpg b/lib/wyw2s_lib/make_facebank_tools/images/JohnnyDepp/2021-04-15-03-17-33-95.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f5aa42c5f48c5419be7becebca03b7add420a452 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/JohnnyDepp/2021-04-15-03-17-33-95.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/JudeLaw/2021-04-15-03-17-33-96.jpg b/lib/wyw2s_lib/make_facebank_tools/images/JudeLaw/2021-04-15-03-17-33-96.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ae78b7211fc7c57dd6e314fb473d49625916e1f2 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/JudeLaw/2021-04-15-03-17-33-96.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/JudeLaw/2021-04-15-03-17-33-97.jpg b/lib/wyw2s_lib/make_facebank_tools/images/JudeLaw/2021-04-15-03-17-33-97.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c14a9c79e36114c86925caf5b1fae8e7db1aa2dd Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/JudeLaw/2021-04-15-03-17-33-97.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/JudeLaw/2021-04-15-03-17-33-98.jpg b/lib/wyw2s_lib/make_facebank_tools/images/JudeLaw/2021-04-15-03-17-33-98.jpg new file mode 100644 index 0000000000000000000000000000000000000000..af26e5c914f084db12ecc6fa96594acf7f6bc318 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/JudeLaw/2021-04-15-03-17-33-98.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/JudeLaw/2021-04-15-03-17-33-99.jpg b/lib/wyw2s_lib/make_facebank_tools/images/JudeLaw/2021-04-15-03-17-33-99.jpg new file mode 100644 index 0000000000000000000000000000000000000000..36b2be668d470a55cbb49fc652b96bab2d063d46 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/JudeLaw/2021-04-15-03-17-33-99.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/JudeLaw/2021-04-15-03-17-34-100.jpg b/lib/wyw2s_lib/make_facebank_tools/images/JudeLaw/2021-04-15-03-17-34-100.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9b803e3c26cda14408b7b82d5132e7feafa4c8f9 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/JudeLaw/2021-04-15-03-17-34-100.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/JudeLaw/2021-04-15-03-17-34-101.jpg b/lib/wyw2s_lib/make_facebank_tools/images/JudeLaw/2021-04-15-03-17-34-101.jpg new file mode 100644 index 0000000000000000000000000000000000000000..451e6771aaaff66c6e289c5a6e9897fda243f239 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/JudeLaw/2021-04-15-03-17-34-101.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/JudeLaw/2021-04-15-03-17-34-102.jpg b/lib/wyw2s_lib/make_facebank_tools/images/JudeLaw/2021-04-15-03-17-34-102.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a0f106ae7946e0b69539b0748f894701c613e568 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/JudeLaw/2021-04-15-03-17-34-102.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/JudeLaw/2021-04-15-03-17-34-103.jpg b/lib/wyw2s_lib/make_facebank_tools/images/JudeLaw/2021-04-15-03-17-34-103.jpg new file mode 100644 index 0000000000000000000000000000000000000000..359c79369d3162038b937e66d8f5c6084f3cb509 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/JudeLaw/2021-04-15-03-17-34-103.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/JudeLaw/2021-04-15-03-17-34-104.jpg b/lib/wyw2s_lib/make_facebank_tools/images/JudeLaw/2021-04-15-03-17-34-104.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c63070f36fc0e2fe90bdbc00f31324edf8a91ca5 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/JudeLaw/2021-04-15-03-17-34-104.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-38-163.jpg b/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-38-163.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cc09d8ae44eaaf7d66f5fc0cd285147a76d860d2 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-38-163.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-38-164.jpg b/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-38-164.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7ab7fb19c29d0406a6474a8b615bfe32d3248279 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-38-164.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-165.jpg b/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-165.jpg new file mode 100644 index 0000000000000000000000000000000000000000..da32992492090c545f4266185766271f5e25af96 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-165.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-166.jpg b/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-166.jpg new file mode 100644 index 0000000000000000000000000000000000000000..625dc9813858be90f9feddd123e0637f25cef395 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-166.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-167.jpg b/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-167.jpg new file mode 100644 index 0000000000000000000000000000000000000000..880a391af9639cfc4552314f2e31286d2cbc295a Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-167.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-168.jpg b/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-168.jpg new file mode 100644 index 0000000000000000000000000000000000000000..48b2cac719cb94dc46fca1430cab9bc230c196d1 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-168.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-169.jpg b/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-169.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9d2e77a72efcbeb5b92d65a78c20185c6b0ea9d5 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-169.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-170.jpg b/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-170.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ab9cf0e3840b9aae744fc5bedfdb349119a6ff65 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-170.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-171.jpg b/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-171.jpg new file mode 100644 index 0000000000000000000000000000000000000000..acc4f72e4bbee92b5b3554a4439afa2d780511c8 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-171.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-172.jpg b/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-172.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0a79b8a6738d363f609744c5aa2437b2a8e7cc37 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-172.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-173.jpg b/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-173.jpg new file mode 100644 index 0000000000000000000000000000000000000000..156cc0d3cbf1aa71e272145e3d965fd15c098fb3 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-173.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-174.jpg b/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-174.jpg new file mode 100644 index 0000000000000000000000000000000000000000..01c325ec2c24e45d69b410d7eb25529d176a2edf Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-174.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-175.jpg b/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-175.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d73554b665529043bbb44535d7a17cf472123ce3 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-175.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-176.jpg b/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-176.jpg new file mode 100644 index 0000000000000000000000000000000000000000..58609f389c60b7605a04124bfd546cc87b8a8f86 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-176.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-177.jpg b/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-177.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3920c502fefa54d52145308ebb4b96f23c34cf58 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-177.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-178.jpg b/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-178.jpg new file mode 100644 index 0000000000000000000000000000000000000000..565ee9cb86c3072d7da1d7a2007dfe895c2aa9c9 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/NicoleKidman/2021-04-15-03-17-39-178.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/ScarlettJohansson/2021-04-15-03-17-40-179.jpg b/lib/wyw2s_lib/make_facebank_tools/images/ScarlettJohansson/2021-04-15-03-17-40-179.jpg new file mode 100644 index 0000000000000000000000000000000000000000..414fb3d87adae09b6ab88b2957cd53b2cebaf48b Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/ScarlettJohansson/2021-04-15-03-17-40-179.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/ScarlettJohansson/2021-04-15-03-17-40-180.jpg b/lib/wyw2s_lib/make_facebank_tools/images/ScarlettJohansson/2021-04-15-03-17-40-180.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1eb69dc063563fe89dd9b3a05dc8402349fe3c84 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/ScarlettJohansson/2021-04-15-03-17-40-180.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/ScarlettJohansson/2021-04-15-03-17-40-181.jpg b/lib/wyw2s_lib/make_facebank_tools/images/ScarlettJohansson/2021-04-15-03-17-40-181.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7672abf8c3e91df155f6fbd7915157d113f3f076 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/ScarlettJohansson/2021-04-15-03-17-40-181.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/ScarlettJohansson/2021-04-15-03-17-40-182.jpg b/lib/wyw2s_lib/make_facebank_tools/images/ScarlettJohansson/2021-04-15-03-17-40-182.jpg new file mode 100644 index 0000000000000000000000000000000000000000..630c2de86bcc12c66b36b79fdcb5ce719455c38c Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/ScarlettJohansson/2021-04-15-03-17-40-182.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/ScarlettJohansson/2021-04-15-03-17-40-183.jpg b/lib/wyw2s_lib/make_facebank_tools/images/ScarlettJohansson/2021-04-15-03-17-40-183.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a3599f3e2ac4e96f6b6541905b53952c599ac74f Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/ScarlettJohansson/2021-04-15-03-17-40-183.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/ScarlettJohansson/2021-04-15-03-17-40-184.jpg b/lib/wyw2s_lib/make_facebank_tools/images/ScarlettJohansson/2021-04-15-03-17-40-184.jpg new file mode 100644 index 0000000000000000000000000000000000000000..dbc6a899ba53f87c8057983051cb92575d8806a7 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/ScarlettJohansson/2021-04-15-03-17-40-184.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/ScarlettJohansson/2021-04-15-03-17-40-185.jpg b/lib/wyw2s_lib/make_facebank_tools/images/ScarlettJohansson/2021-04-15-03-17-40-185.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b4a6f619677d9ac0ba91a8200ed16e103c6cdd1b Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/ScarlettJohansson/2021-04-15-03-17-40-185.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/ScarlettJohansson/2021-04-15-03-17-40-186.jpg b/lib/wyw2s_lib/make_facebank_tools/images/ScarlettJohansson/2021-04-15-03-17-40-186.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b5f4431b3f2565b83e1a912829873cf0d54c4829 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/ScarlettJohansson/2021-04-15-03-17-40-186.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/ScarlettJohansson/2021-04-15-03-17-40-187.jpg b/lib/wyw2s_lib/make_facebank_tools/images/ScarlettJohansson/2021-04-15-03-17-40-187.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0997410b88f2e7d06589da50dd45d62aa3f0c86d Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/ScarlettJohansson/2021-04-15-03-17-40-187.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/ScarlettJohansson/2021-04-15-03-17-40-188.jpg b/lib/wyw2s_lib/make_facebank_tools/images/ScarlettJohansson/2021-04-15-03-17-40-188.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f88ca2d2767e31d12afa68d8353904a4b5f10fa9 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/ScarlettJohansson/2021-04-15-03-17-40-188.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/ScarlettJohansson/2021-04-15-03-17-40-189.jpg b/lib/wyw2s_lib/make_facebank_tools/images/ScarlettJohansson/2021-04-15-03-17-40-189.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8a69b600be1acbff9a15cd4fc42a779dd97f037a Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/ScarlettJohansson/2021-04-15-03-17-40-189.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/ScarlettJohansson/2021-04-15-03-17-41-190.jpg b/lib/wyw2s_lib/make_facebank_tools/images/ScarlettJohansson/2021-04-15-03-17-41-190.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bcb82321a5a6a812b639bc78d08c6ff16a8163ea Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/ScarlettJohansson/2021-04-15-03-17-41-190.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/ScarlettJohansson/2021-04-15-03-17-41-191.jpg b/lib/wyw2s_lib/make_facebank_tools/images/ScarlettJohansson/2021-04-15-03-17-41-191.jpg new file mode 100644 index 0000000000000000000000000000000000000000..99376e60fed725b65fdf24748fe9969a11582a68 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/ScarlettJohansson/2021-04-15-03-17-41-191.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/TomCruise/2021-04-15-03-17-41-192.jpg b/lib/wyw2s_lib/make_facebank_tools/images/TomCruise/2021-04-15-03-17-41-192.jpg new file mode 100644 index 0000000000000000000000000000000000000000..da8491f890ff8f340faba540419ddf47a85c10a5 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/TomCruise/2021-04-15-03-17-41-192.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/TomCruise/2021-04-15-03-17-41-193.jpg b/lib/wyw2s_lib/make_facebank_tools/images/TomCruise/2021-04-15-03-17-41-193.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b5069871f84f8bdce829131b60c029ee1e2707ba Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/TomCruise/2021-04-15-03-17-41-193.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/TomCruise/2021-04-15-03-17-41-194.jpg b/lib/wyw2s_lib/make_facebank_tools/images/TomCruise/2021-04-15-03-17-41-194.jpg new file mode 100644 index 0000000000000000000000000000000000000000..be479e003db7ddefeea2a94876418e6f70f09c78 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/TomCruise/2021-04-15-03-17-41-194.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/TomCruise/2021-04-15-03-17-41-195.jpg b/lib/wyw2s_lib/make_facebank_tools/images/TomCruise/2021-04-15-03-17-41-195.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e46fdb05243116c1de8643f2a19477cf5cf25ba3 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/TomCruise/2021-04-15-03-17-41-195.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/TomCruise/2021-04-15-03-17-41-196.jpg b/lib/wyw2s_lib/make_facebank_tools/images/TomCruise/2021-04-15-03-17-41-196.jpg new file mode 100644 index 0000000000000000000000000000000000000000..26a41e28c83da0c17fd96d73caacc8f742ffa91d Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/TomCruise/2021-04-15-03-17-41-196.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/TomCruise/2021-04-15-03-17-41-197.jpg b/lib/wyw2s_lib/make_facebank_tools/images/TomCruise/2021-04-15-03-17-41-197.jpg new file mode 100644 index 0000000000000000000000000000000000000000..028bffcbdcfdf07a40fcde1a206f526aeb7e25b5 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/TomCruise/2021-04-15-03-17-41-197.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/TomCruise/2021-04-15-03-17-41-198.jpg b/lib/wyw2s_lib/make_facebank_tools/images/TomCruise/2021-04-15-03-17-41-198.jpg new file mode 100644 index 0000000000000000000000000000000000000000..dee13c61ddcb13fec17a4c4c46e165f6f62dd69b Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/TomCruise/2021-04-15-03-17-41-198.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/TomCruise/2021-04-15-03-17-41-199.jpg b/lib/wyw2s_lib/make_facebank_tools/images/TomCruise/2021-04-15-03-17-41-199.jpg new file mode 100644 index 0000000000000000000000000000000000000000..89a30870ec353f328a2c551b3ac69a1f865baad1 Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/TomCruise/2021-04-15-03-17-41-199.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/images/TomCruise/2021-04-15-03-17-41-200.jpg b/lib/wyw2s_lib/make_facebank_tools/images/TomCruise/2021-04-15-03-17-41-200.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0f4440985aefd3afb8f383f7354f3f8e14999bdc Binary files /dev/null and b/lib/wyw2s_lib/make_facebank_tools/images/TomCruise/2021-04-15-03-17-41-200.jpg differ diff --git a/lib/wyw2s_lib/make_facebank_tools/make_facebank.py b/lib/wyw2s_lib/make_facebank_tools/make_facebank.py new file mode 100644 index 0000000000000000000000000000000000000000..f729c44ac1640031f9fa2ae3fc807ed6e7f45f6a --- /dev/null +++ b/lib/wyw2s_lib/make_facebank_tools/make_facebank.py @@ -0,0 +1,76 @@ +# make facebank +import warnings +warnings.filterwarnings("ignore") +import os +import torch +from model import Backbone +import argparse +from pathlib import Path +from torchvision import transforms as trans +from PIL import Image +import numpy as np +def prepare_facebank(path_images,facebank_path, model, mtcnn, device , tta = True): + # + test_transform_ = trans.Compose([ + trans.ToTensor(), + trans.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5]) + ]) + # + model.eval() + embeddings = [] + names = ['Unknown'] + idx = 0 + for path in path_images.iterdir(): + if path.is_file(): + continue + else: + idx += 1 + print("idx {} : {}".format(idx,path)) + embs = [] + for file in path.iterdir(): + # print(file) + if not file.is_file(): + continue + else: + + try: + # print("---------------------------") + img = Image.open(file) + print(" {}) {}".format(idx,file)) + except: + continue + + with torch.no_grad(): + if tta: + mirror = trans.functional.hflip(img) + emb = model(test_transform_(img).to(device).unsqueeze(0)) + emb_mirror = model(test_transform_(mirror).to(device).unsqueeze(0)) + embs.append(l2_norm(emb + emb_mirror)) + else: + embs.append(model(test_transform_(img).to(device).unsqueeze(0))) + if len(embs) == 0: + continue + embedding = torch.cat(embs).mean(0,keepdim=True) + embeddings.append(embedding) + names.append(path.name) + embeddings = torch.cat(embeddings) + names = np.array(names) + torch.save(embeddings, facebank_path+'/facebank.pth') + np.save(facebank_path + '/names', names) + return embeddings, names + +if __name__ == '__main__': + # 需要制作人脸库对应的 图片地址 + path_images = "./images/" + + + # 定义模型 + device_ = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") + model_ = Backbone(50, 1., "ir_se").to(device_) + # 加载模型 + if os.access("./model_ir_se50.pth",os.F_OK): + model_.load_state_dict(torch.load("./model_ir_se50.pth")) + + model_.eval() + facebank_path = "./facebank/" # 人脸库对应地址 + targets, names = prepare_facebank(Path(path_images), facebank_path,model_, "" ,device_, tta = False) # 构建 人脸 底库 diff --git a/lib/wyw2s_lib/make_facebank_tools/model.py b/lib/wyw2s_lib/make_facebank_tools/model.py new file mode 100644 index 0000000000000000000000000000000000000000..237751d6c1a37fa5f06eac35b53f7e769bbc845f --- /dev/null +++ b/lib/wyw2s_lib/make_facebank_tools/model.py @@ -0,0 +1,305 @@ +from torch.nn import Linear, Conv2d, BatchNorm1d, BatchNorm2d, PReLU, ReLU, Sigmoid, Dropout2d, Dropout, AvgPool2d, MaxPool2d, AdaptiveAvgPool2d, Sequential, Module, Parameter +import torch.nn.functional as F +import torch +from collections import namedtuple +import math +import pdb + +################################## Original Arcface Model ############################################################# + +class Flatten(Module): + def forward(self, input): + return input.view(input.size(0), -1) + +def l2_norm(input,axis=1): + norm = torch.norm(input,2,axis,True) + output = torch.div(input, norm) + return output + +class SEModule(Module): + def __init__(self, channels, reduction): + super(SEModule, self).__init__() + self.avg_pool = AdaptiveAvgPool2d(1) + self.fc1 = Conv2d( + channels, channels // reduction, kernel_size=1, padding=0 ,bias=False) + self.relu = ReLU(inplace=True) + self.fc2 = Conv2d( + channels // reduction, channels, kernel_size=1, padding=0 ,bias=False) + self.sigmoid = Sigmoid() + + def forward(self, x): + module_input = x + x = self.avg_pool(x) + x = self.fc1(x) + x = self.relu(x) + x = self.fc2(x) + x = self.sigmoid(x) + return module_input * x + +class bottleneck_IR(Module): + def __init__(self, in_channel, depth, stride): + super(bottleneck_IR, self).__init__() + if in_channel == depth: + self.shortcut_layer = MaxPool2d(1, stride) + else: + self.shortcut_layer = Sequential( + Conv2d(in_channel, depth, (1, 1), stride ,bias=False), BatchNorm2d(depth)) + self.res_layer = Sequential( + BatchNorm2d(in_channel), + Conv2d(in_channel, depth, (3, 3), (1, 1), 1 ,bias=False), PReLU(depth), + Conv2d(depth, depth, (3, 3), stride, 1 ,bias=False), BatchNorm2d(depth)) + + def forward(self, x): + shortcut = self.shortcut_layer(x) + res = self.res_layer(x) + return res + shortcut + +class bottleneck_IR_SE(Module): + def __init__(self, in_channel, depth, stride): + super(bottleneck_IR_SE, self).__init__() + if in_channel == depth: + self.shortcut_layer = MaxPool2d(1, stride) + else: + self.shortcut_layer = Sequential( + Conv2d(in_channel, depth, (1, 1), stride ,bias=False), + BatchNorm2d(depth)) + self.res_layer = Sequential( + BatchNorm2d(in_channel), + Conv2d(in_channel, depth, (3,3), (1,1),1 ,bias=False), + PReLU(depth), + Conv2d(depth, depth, (3,3), stride, 1 ,bias=False), + BatchNorm2d(depth), + SEModule(depth,16) + ) + def forward(self,x): + shortcut = self.shortcut_layer(x) + res = self.res_layer(x) + return res + shortcut + +class Bottleneck(namedtuple('Block', ['in_channel', 'depth', 'stride'])): + '''A named tuple describing a ResNet block.''' + +def get_block(in_channel, depth, num_units, stride = 2): + return [Bottleneck(in_channel, depth, stride)] + [Bottleneck(depth, depth, 1) for i in range(num_units-1)] + +def get_blocks(num_layers): + if num_layers == 50: + blocks = [ + get_block(in_channel=64, depth=64, num_units = 3), + get_block(in_channel=64, depth=128, num_units=4), + get_block(in_channel=128, depth=256, num_units=14), + get_block(in_channel=256, depth=512, num_units=3) + ] + elif num_layers == 100: + blocks = [ + get_block(in_channel=64, depth=64, num_units=3), + get_block(in_channel=64, depth=128, num_units=13), + get_block(in_channel=128, depth=256, num_units=30), + get_block(in_channel=256, depth=512, num_units=3) + ] + elif num_layers == 152: + blocks = [ + get_block(in_channel=64, depth=64, num_units=3), + get_block(in_channel=64, depth=128, num_units=8), + get_block(in_channel=128, depth=256, num_units=36), + get_block(in_channel=256, depth=512, num_units=3) + ] + return blocks + +class Backbone(Module): + def __init__(self, num_layers, drop_ratio, mode='ir'): + super(Backbone, self).__init__() + assert num_layers in [50, 100, 152], 'num_layers should be 50,100, or 152' + assert mode in ['ir', 'ir_se'], 'mode should be ir or ir_se' + blocks = get_blocks(num_layers) + if mode == 'ir': + unit_module = bottleneck_IR + elif mode == 'ir_se': + unit_module = bottleneck_IR_SE + self.input_layer = Sequential(Conv2d(3, 64, (3, 3), 1, 1 ,bias=False), + BatchNorm2d(64), + PReLU(64)) + self.output_layer = Sequential(BatchNorm2d(512), + Dropout(drop_ratio), + Flatten(), + Linear(512 * 7 * 7, 512), + BatchNorm1d(512)) + modules = [] + for block in blocks: + for bottleneck in block: + modules.append( + unit_module(bottleneck.in_channel, + bottleneck.depth, + bottleneck.stride)) + self.body = Sequential(*modules) + + def forward(self,x): + x = self.input_layer(x) + x = self.body(x) + x = self.output_layer(x) + return l2_norm(x) + +################################## MobileFaceNet ############################################################# + +class Conv_block(Module): + def __init__(self, in_c, out_c, kernel=(1, 1), stride=(1, 1), padding=(0, 0), groups=1): + super(Conv_block, self).__init__() + self.conv = Conv2d(in_c, out_channels=out_c, kernel_size=kernel, groups=groups, stride=stride, padding=padding, bias=False) + self.bn = BatchNorm2d(out_c) + self.prelu = PReLU(out_c) + def forward(self, x): + x = self.conv(x) + x = self.bn(x) + x = self.prelu(x) + return x + +class Linear_block(Module): + def __init__(self, in_c, out_c, kernel=(1, 1), stride=(1, 1), padding=(0, 0), groups=1): + super(Linear_block, self).__init__() + self.conv = Conv2d(in_c, out_channels=out_c, kernel_size=kernel, groups=groups, stride=stride, padding=padding, bias=False) + self.bn = BatchNorm2d(out_c) + def forward(self, x): + x = self.conv(x) + x = self.bn(x) + return x + +class Depth_Wise(Module): + def __init__(self, in_c, out_c, residual = False, kernel=(3, 3), stride=(2, 2), padding=(1, 1), groups=1): + super(Depth_Wise, self).__init__() + self.conv = Conv_block(in_c, out_c=groups, kernel=(1, 1), padding=(0, 0), stride=(1, 1)) + self.conv_dw = Conv_block(groups, groups, groups=groups, kernel=kernel, padding=padding, stride=stride) + self.project = Linear_block(groups, out_c, kernel=(1, 1), padding=(0, 0), stride=(1, 1)) + self.residual = residual + def forward(self, x): + if self.residual: + short_cut = x + x = self.conv(x) + x = self.conv_dw(x) + x = self.project(x) + if self.residual: + output = short_cut + x + else: + output = x + return output + +class Residual(Module): + def __init__(self, c, num_block, groups, kernel=(3, 3), stride=(1, 1), padding=(1, 1)): + super(Residual, self).__init__() + modules = [] + for _ in range(num_block): + modules.append(Depth_Wise(c, c, residual=True, kernel=kernel, padding=padding, stride=stride, groups=groups)) + self.model = Sequential(*modules) + def forward(self, x): + return self.model(x) + +class MobileFaceNet(Module): + def __init__(self, embedding_size): + super(MobileFaceNet, self).__init__() + self.conv1 = Conv_block(3, 64, kernel=(3, 3), stride=(2, 2), padding=(1, 1)) + self.conv2_dw = Conv_block(64, 64, kernel=(3, 3), stride=(1, 1), padding=(1, 1), groups=64) + self.conv_23 = Depth_Wise(64, 64, kernel=(3, 3), stride=(2, 2), padding=(1, 1), groups=128) + self.conv_3 = Residual(64, num_block=4, groups=128, kernel=(3, 3), stride=(1, 1), padding=(1, 1)) + self.conv_34 = Depth_Wise(64, 128, kernel=(3, 3), stride=(2, 2), padding=(1, 1), groups=256) + self.conv_4 = Residual(128, num_block=6, groups=256, kernel=(3, 3), stride=(1, 1), padding=(1, 1)) + self.conv_45 = Depth_Wise(128, 128, kernel=(3, 3), stride=(2, 2), padding=(1, 1), groups=512) + self.conv_5 = Residual(128, num_block=2, groups=256, kernel=(3, 3), stride=(1, 1), padding=(1, 1)) + self.conv_6_sep = Conv_block(128, 512, kernel=(1, 1), stride=(1, 1), padding=(0, 0)) + self.conv_6_dw = Linear_block(512, 512, groups=512, kernel=(7,7), stride=(1, 1), padding=(0, 0)) + self.conv_6_flatten = Flatten() + self.linear = Linear(512, embedding_size, bias=False) + self.bn = BatchNorm1d(embedding_size) + + def forward(self, x): + out = self.conv1(x) + + out = self.conv2_dw(out) + + out = self.conv_23(out) + + out = self.conv_3(out) + + out = self.conv_34(out) + + out = self.conv_4(out) + + out = self.conv_45(out) + + out = self.conv_5(out) + + out = self.conv_6_sep(out) + + out = self.conv_6_dw(out) + + out = self.conv_6_flatten(out) + + out = self.linear(out) + + out = self.bn(out) + return l2_norm(out) + +################################## Arcface head ############################################################# + +class Arcface(Module): + # implementation of additive margin softmax loss in https://arxiv.org/abs/1801.05599 + def __init__(self, embedding_size=512, classnum=51332, s=64., m=0.5): + super(Arcface, self).__init__() + self.classnum = classnum + self.kernel = Parameter(torch.Tensor(embedding_size,classnum)) + # initial kernel + self.kernel.data.uniform_(-1, 1).renorm_(2,1,1e-5).mul_(1e5) + self.m = m # the margin value, default is 0.5 + self.s = s # scalar value default is 64, see normface https://arxiv.org/abs/1704.06369 + self.cos_m = math.cos(m) + self.sin_m = math.sin(m) + self.mm = self.sin_m * m # issue 1 + self.threshold = math.cos(math.pi - m) + def forward(self, embbedings, label): + # weights norm + nB = len(embbedings) + kernel_norm = l2_norm(self.kernel,axis=0) + # cos(theta+m) + cos_theta = torch.mm(embbedings,kernel_norm) +# output = torch.mm(embbedings,kernel_norm) + cos_theta = cos_theta.clamp(-1,1) # for numerical stability + cos_theta_2 = torch.pow(cos_theta, 2) + sin_theta_2 = 1 - cos_theta_2 + sin_theta = torch.sqrt(sin_theta_2) + cos_theta_m = (cos_theta * self.cos_m - sin_theta * self.sin_m) + # this condition controls the theta+m should in range [0, pi] + # 0<=theta+m<=pi + # -m<=theta<=pi-m + cond_v = cos_theta - self.threshold + cond_mask = cond_v <= 0 + keep_val = (cos_theta - self.mm) # when theta not in [0,pi], use cosface instead + cos_theta_m[cond_mask] = keep_val[cond_mask] + output = cos_theta * 1.0 # a little bit hacky way to prevent in_place operation on cos_theta + idx_ = torch.arange(0, nB, dtype=torch.long) + output[idx_, label] = cos_theta_m[idx_, label] + output *= self.s # scale up in order to make softmax work, first introduced in normface + return output + +################################## Cosface head ############################################################# + +class Am_softmax(Module): + # implementation of additive margin softmax loss in https://arxiv.org/abs/1801.05599 + def __init__(self,embedding_size=512,classnum=51332): + super(Am_softmax, self).__init__() + self.classnum = classnum + self.kernel = Parameter(torch.Tensor(embedding_size,classnum)) + # initial kernel + self.kernel.data.uniform_(-1, 1).renorm_(2,1,1e-5).mul_(1e5) + self.m = 0.35 # additive margin recommended by the paper + self.s = 30. # see normface https://arxiv.org/abs/1704.06369 + def forward(self,embbedings,label): + kernel_norm = l2_norm(self.kernel,axis=0) + cos_theta = torch.mm(embbedings,kernel_norm) + cos_theta = cos_theta.clamp(-1,1) # for numerical stability + phi = cos_theta - self.m + label = label.view(-1,1) #size=(B,1) + index = cos_theta.data * 0.0 #size=(B,Classnum) + index.scatter_(1,label.data.view(-1,1),1) + index = index.byte() + output = cos_theta * 1.0 + output[index] = phi[index] #only change the correct predicted output + output *= self.s # scale up in order to make softmax work, first introduced in normface + return output diff --git a/lib/wyw2s_lib/utils/show_videos_thread.py b/lib/wyw2s_lib/utils/show_videos_thread.py new file mode 100644 index 0000000000000000000000000000000000000000..8f4180d5198dc38b47470fba1003cedaab06a114 --- /dev/null +++ b/lib/wyw2s_lib/utils/show_videos_thread.py @@ -0,0 +1,84 @@ +#-*-coding:utf-8-*- +''' +DpCas-Light +|||| |||| |||| || |||| +|| || || || || || |||| || || +|| || || || || || || || || +|| || || || || ||====|| |||| +|| || |||| || || ||======|| || +|| || || || || || || || || +|||| || |||| || || |||| + +/------------------ Who You Want 2 See ------------------/ +''' +# date:2020-12-12 +# Author: Eric.Lee +# function: show clip video +import os +import cv2 +import copy +import time + +import threading +from threading import current_thread, Lock + +import psutil +import numpy as np +import random + +lock = Lock() +def run_one_process(path,process_id,vis): + + lock.acquire() + video_ = cv2.VideoCapture(path) + lock.release() + while True: + ret, img_ = video_.read() + + if ret: + #------------------------------------------------ + if vis: + cv2.namedWindow('video_seg_{}'.format(process_id),0) + cv2.resizeWindow('video_seg_{}'.format(process_id), 300, 210); + cv2.moveWindow('video_seg_{}'.format(process_id), (process_id%6)*300+60,int(process_id/6)*230) + cv2.imshow('video_seg_{}'.format(process_id),img_) + if cv2.waitKey(300) == 27: + flag_break =True + break + else: + break + if vis: + cv2.waitKey(30000) + cv2.destroyWindow('video_seg_{}'.format(process_id)) + +def run_show(path,vis): + seg_num = len(os.listdir(path)) + + videos_path = os.listdir(path) + # #-------------------------------------- + st_ = time.time() + process_list = [] + for i in range(0,seg_num): + # print(video_list[i]) + t = threading.Thread(target=run_one_process, args=(path + videos_path[i],i,vis)) + process_list.append(t) + + + for i in range(0,seg_num): + process_list[i].start() + + print(' start run ~ ') + + for i in range(0,seg_num): + process_list[i].join()# 设置主线程等待子线程结束 + + del process_list + et_ = time.time() + + +if __name__ == "__main__": + path = './video/' + vis = True + + run_show_hights(path,vis) + #-------------------------------------- diff --git a/lib/wyw2s_lib/utils/utils.py b/lib/wyw2s_lib/utils/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..248c711a81dc66ef35dc9f220f82a7d31f294093 --- /dev/null +++ b/lib/wyw2s_lib/utils/utils.py @@ -0,0 +1,15 @@ +import os + +"""Parses the data configuration file""" +def parse_data_cfg(path): + print('data_cfg : ',path) + options = dict() + with open(path, 'r',encoding='UTF-8') as fp: + lines = fp.readlines() + for line in lines: + line = line.strip() + if line == '' or line.startswith('#'): + continue + key, value = line.split('=') + options[key.strip()] = value.strip() + return options diff --git a/main.py b/main.py index 2c4d3cb37f7a5a6d83b96264e2912a0c73d6c25f..c466e39e33427794cb9725c219540833aa9c4e3f 100644 --- a/main.py +++ b/main.py @@ -9,7 +9,7 @@ || || || || || || || || || |||| || |||| || || ||||||| -/-------------------- HandPose_X --------------------/ +/-------------------- APP_X --------------------/ ''' # date:2020-10-19.7.23.24 # Author: Eric.Lee @@ -22,12 +22,13 @@ import sys sys.path.append("./components/") # 添加模型组件路径 from applications.handpose_local_app import main_handpose_x #加载 handpose 应用 +from applications.wyw2s_local_app import main_wyw2s #加载 whoyouwant2see 应用 def demo_logo(): print("\n/*********************************/") print("/---------------------------------/\n") print(" WELCOME : DpCas-Light ") - print(" << HandPose_X >> ") + print(" << APP_X >> ") print(" Copyright 2021 Eric.Lee2021 ") print(" Apache License 2.0 ") print("\n/---------------------------------/") @@ -35,7 +36,15 @@ def demo_logo(): if __name__ == '__main__': demo_logo() - cfg_file = "./lib/hand_lib/cfg/handpose.cfg" - main_handpose_x(cfg_file)#加载 handpose 应用 + APP_P = "wyw2s" + + if APP_P == "handpose_x": # 手势识别 + cfg_file = "./lib/hand_lib/cfg/handpose.cfg" + main_handpose_x(cfg_file)#加载 handpose 应用 + + elif APP_P == "wyw2s": # 基于人脸识别的视频剪辑 + cfg_file = "./lib/wyw2s_lib/cfg/wyw2s.cfg" + + main_wyw2s(cfg_file,video_path = "./video/f1.mp4")#加载 handpose 应用 print(" well done ~")