def process_image_yyy(image, face_data, engine_model, func_name, func_params=None, worker=None): """ 对上传图片进行处理(截取人脸部分做替换处理) Returns: image_output: 处理后的图片数据 """ # 处理和替换图片中的人脸部分 if 'face_image' in face_data: _img_np = face_data['face_image'] x = face_data['x'] y = face_data['y'] w = face_data['w'] h = face_data['h'] img_hash = face_data['img_hash'] face_image_orig = image_ndarray_to_pil(_img_np) # 如果 face_image 尺寸大于模型标准尺寸,则缩放为标准尺寸再处理 _img_w, _img_h = w, h _h = engine_model['model_size'] _img = image_ndarray_to_pil(_img_np) if _img_h != _h: _img = image_resize_default(_img, _h) _img_np = image_pil_to_ndarray(_img) # 处理图片(返回的已经是 PIL Image) _img_out_pil = engine_process_image(engine_model, _img_np, func_name) # 将返回图片缩放为原尺寸 if _img_h != _h: if _img_h > _h and ENABLE_ESRGAN: #_img_out_pil = esrgan_adapter.process_image( # _img_out_pil, engine_model['esrgan'], _img_w, _img_h) # 调用管理进程共享对象接口处理 ret = exec_esrgan(_img_out_pil, _img_w, _img_h, worker) if ret: _img_out_pil = ret else: _img_out_pil = image_resize_default(_img_out_pil, _img_h) else: _img_out_pil = image_resize_default(_img_out_pil, _img_h) # 检查是否为主demo,若是则将人脸处理结果保存为图标 if 'img_hash' in face_data: img_hash = face_data['img_hash'] if img_hash in app_config.IMG_HASH_ICON_DEMO: # 为生成界面图标用的指定图片 check_if_save_demo_icon(_img_out_pil, SAVE_ICON_DIR, func_name) # 将新旧人脸混合后贴回原图 x = x + int((image.size[0] - app_config.OUTPUT_SIZE_EDITOR[0]) / 2) y = y + int((image.size[1] - app_config.OUTPUT_SIZE_EDITOR[1]) / 2) edit_area = func_params[1] image_output = face_image_blend(image, _img_out_pil, face_image_orig, x, y, w, h, edit_area, worker) return image_output
def process_image_xxx(image, face_data, engine_model, func_name, func_params=None, worker=None): """ 对上传图片进行处理(直接处理整张图片) Returns: image_output: 处理后的图片数据 """ # 处理和替换图片中的人脸部分 # !!直接使用 pil 原图而不是 face_data 中的人脸图做处理 # 如果 image 尺寸不等于模型标准尺寸,则缩放为标准尺寸再处理 _img_w, _img_h = image.size[0:2] _h = engine_model['model_size'] if _img_h != _h: _img_pil = image_resize_default(image, _h) else: _img_pil = image _img_np = image_pil_to_ndarray(_img_pil) # 处理图片(返回的已经是 PIL Image) _img_out_pil = engine_process_image(engine_model, _img_np, func_name) # 将返回图片缩放为原尺寸 if _img_h != _h: if _img_h > _h and ENABLE_ESRGAN: #_img_out_pil = esrgan_adapter.process_image( # _img_out_pil, engine_model['esrgan'], _img_w, _img_h) # 调用管理进程共享对象接口处理 ret = exec_esrgan(_img_out_pil, _img_w, _img_h, worker) if ret: _img_out_pil = ret else: _img_out_pil = image_resize_default(_img_out_pil, _img_h) else: _img_out_pil = image_resize_default(_img_out_pil, _img_h) # 检查是否为主demo,若是则将人脸处理结果保存为图标 if 'img_hash' in face_data: img_hash = face_data['img_hash'] if img_hash in app_config.IMG_HASH_ICON_DEMO: # 为生成界面图标用的指定图片 check_if_save_demo_icon(_img_out_pil, SAVE_ICON_DIR, func_name) # 将新旧人脸混合后贴回原图 x, y = 0, 0 w, h = image.size[0], image.size[1] edit_area = func_params[1] _img_out_pil = face_image_blend(_img_out_pil, _img_out_pil, image, x, y, w, h, edit_area, worker) return _img_out_pil
def process_image(image, face_data, engine_model, func_name, func_params=None, worker=None): """ 对上传图片进行处理 Returns: image_output: 处理后的图片数据 """ # !!直接使用 pil 原图而不是 face_data 中的人脸图做处理 # 如果 image 尺寸不等于模型标准尺寸,则缩放为标准尺寸再处理 _img_w, _img_h = image.size[0:2] _h = engine_model['model_size'] if _img_h != _h: _img = image_resize_default(image, _h) else: _img = image # 处理图片 style_name = func_params[0] _img_out_pil = engine_process_image(engine_model, _img, style_name) # 将返回图片缩放为原尺寸 if _img_h != _h: if _img_h > _h and ENABLE_ESRGAN: #_img_out_pil = esrgan_adapter.process_image( # _img_out_pil, engine_model['esrgan'], _img_w, _img_h) # 调用管理进程共享对象接口处理 ret = exec_esrgan(_img_out_pil, _img_w, _img_h, worker) if ret: _img_out_pil = ret else: _img_out_pil = image_resize_default(_img_out_pil, _img_h) else: _img_out_pil = image_resize_default(_img_out_pil, _img_h) # 检查是否为主demo,若是则将人脸处理结果保存为图标 if 'img_hash' in face_data: img_hash = face_data['img_hash'] if img_hash in app_config.IMG_HASH_ICON_DEMO: # 为生成界面图标用的指定图片 check_if_save_demo_icon(_img_out_pil, SAVE_ICON_DIR, style_name) return _img_out_pil
def process_image(image, face_data, engine_model, func_name, func_params=None, worker=None): """ 对上传图片进行处理 Returns: image_output: 处理后的图片数据 """ # !!与其他引擎处理方式稍有不同:这里直接使用 pil 原图而不是 face_data 中的人脸图做处理 # 如果 image 尺寸不等于模型标准尺寸,则缩放为标准尺寸再处理 _img_w, _img_h = image.size[0:2] _h = engine_model['model_size'] if _img_h != _h: _img = image_resize_default(image, _h) else: _img = image # 处理图片 _img_out_pil = engine_process_image(engine_model, _img, func_name) # 将返回图片缩放为原尺寸 if _img_h != _h: if _img_h > _h and ENABLE_ESRGAN: #_img_out_pil = esrgan_adapter.process_image( # _img_out_pil, engine_model['esrgan'], _img_w, _img_h) # 调用管理进程共享对象接口处理 ret = exec_esrgan(_img_out_pil, _img_w, _img_h, worker) if ret: _img_out_pil = ret else: _img_out_pil = image_resize_default(_img_out_pil, _img_h) else: _img_out_pil = image_resize_default(_img_out_pil, _img_h) return _img_out_pil
def face_image_blend(image_output, face_image_new, face_image_orig, x, y, w, h, edit_area=None, worker=None): """替换输出图片中的人脸部分 将新的人脸图与原人脸图按比例融合,然后平滑替换到输出图中指定位置""" logger.info('call face_image_blend. x, y, w, h: {}, {}, {}, {}'.format( x, y, w, h)) #print('--> image_output.size: {}, face_image_new.size: {}, face_image_orig.size: {}' # .format(image_output.size, face_image_new.size, face_image_orig.size)) #print('--> type(image_output): {}, type(face_image_new): {}' # .format(type(image_output), type(face_image_new))) # 将处理后的人脸缩放为检测时的尺寸,然后按照相应坐标替换到原图中 face_image_new = image_resize_default(face_image_new, h) # 将处理后的人脸与原人脸做 alpha 混合,以平滑图像(会降低效果,暂无必要) #face_image_new = image_blend(face_image_orig, face_image_new, 0.7) # 设置掩模图片 # 为减少不必要的修改、提高图片质量,可在task参数中设置要编辑的人脸区域 logger.info('get face mask with area: {}'.format(edit_area)) mask = None if edit_area != None: if len(edit_area) == 0: # 如未指定人脸部分,则使用人像全部 edit_area = [ 'face', 'l_brow', 'r_brow', 'l_eye', 'r_eye', 'eye_g', 'l_ear', 'r_ear', 'ear_r', 'nose', 'u_lip', 'l_lip', 'neck', 'neck_l', 'mouth', 'cloth', 'hat', 'hair' ] # 解析获取人脸掩模图片 mask = mm_get_face_mask(face_image_new, edit_area, worker) if not mask: logger.info('call get_geometric_mask() to make mask') mask = get_geometric_mask(face_image_new) # 默认为椭圆型掩模图片 # 参考掩模将处理后的人脸替换到图中 #image_output.save('/app/app/dbg_image_output_1.png') image_output.paste(face_image_new, (x, y), mask) #image_output.save('/app/app/dbg_image_output_2.png') # 含义:使用变量mask对应的模板图像来填充所对应的区域。可以使用模式为“1”、“L”或者“RGBA”的图像作为模板图像。模板图像的尺寸必须与变量image对应的图像尺寸一致。如果变量mask对应图像的值为255,则模板图像的值直接被拷贝过来;如果变量mask对应图像的值为0,则保持当前图像的原始值。变量mask对应图像的其他值,将对两张图像的值进行透明融合。 return image_output
def process_image(image, engine_model, output_w, output_h): # 如果输入尺寸大于等于输出尺寸,则不必做超解析 in_w, in_h = image.size if in_h >= output_h: return image t1 = time.time() image = np.array(image).astype(np.uint8) # pil to numpy.array image = image * 1.0 / 255 image = torch.from_numpy(np.transpose(image[:, :, [2, 1, 0]], (2, 0, 1))).float() img_LR = image.unsqueeze(0) model = engine_model['model'] if torch.__version__ >= '0.4': img_LR = img_LR.to(torch.device('cuda')) with torch.no_grad(): output = model(img_LR).data.squeeze().float().cpu().clamp_( 0, 1).numpy() else: from torch.autograd import Variable img_LR = Variable(img_LR, volatile=True) img_LR = img_LR.cuda() output = model(img_LR).data.squeeze().float().cpu().clamp_(0, 1).numpy() output = np.transpose(output[[2, 1, 0], :, :], (1, 2, 0)) output = (output * 255.0).round().astype(np.uint8) output = transforms.ToPILImage()(output) # numpy.array to pil output = image_resize_default(output, output_h) t2 = time.time() print('--> esrgan: {}s used'.format(t2 - t1)) #print('--> type(output): {}'.format(type(output))) logger.info( 'esrgan process image, input size: {} w, {} h, output size: {} w, {} h' .format(in_w, in_h, output.size[0], output.size[1])) return output
def check_if_save_demo_icon(img_pil, icon_dir, icon_name): """将 icon demo 图片的人脸处理结果保存为图标""" if app_config.DEMO_ICON_ENABLE: os.makedirs(icon_dir, exist_ok=True) icon_file = os.path.join(icon_dir, '{}.jpg'.format(icon_name)) image_out = img_pil.copy() # 对于非人脸检测图,由于会扩展为正方形,处理后图片需要居中截取,否则会有边框,做图标不好看 img_w, img_h = img_pil.size #print('--> img_w: %s, img_h: %s' % (img_w, img_h)) if img_w >= 380: _sz = 380 x0 = int((img_w - _sz) / 2) y0 = int((img_h - _sz) / 2) x1 = x0 + _sz y1 = y0 + _sz image_out = image_out.crop((x0, y0, x1, y1)) icon_img_pil = image_resize_default(image_out, 200) # 缩放为前端所需图标大小 icon_img_pil.save(icon_file) logger.info('icon demo image saved to icon {:s} done!'.format(icon_file))
def process_image(image, face_data, engine_model, func_name, func_params=None, worker=None): """ 对上传图片进行处理 Returns: image_output: 处理后的图片数据 """ if 'img_hash' not in face_data: # 本引擎只能处理人脸图片 return None # !!直接使用 pil 原图而不是 face_data 中的人脸图做处理 # 如果 image 尺寸不等于模型标准尺寸,则缩放为标准尺寸再处理 _img_w, _img_h = image.size[0:2] _h = engine_model['model_size'] if _img_h > _h: _img_pil = image_resize_default(image, _h) else: _img_pil = image _img_cv2 = image_pil_to_cv2(_img_pil) # 开始处理人脸上妆 # 根据输入参数获取要修改的人脸区域及处理方式 func_name, func_arg = func_name, func_params[0] edit_area = [] for i in func_params[1]: if i == 'skin': # 肤色 edit_area.extend(['face', 'l_ear', 'r_ear', 'nose', 'l_brow', 'r_brow', 'u_lip', 'l_lip', 'neck']) elif i == 'lips': # 嘴唇 edit_area.extend(['u_lip', 'l_lip']) else: edit_area.append(i) logger.info('func_name: {}, func_arg: {}, func_params: {}, edit_area: {}' .format(func_name, func_arg, func_params, edit_area)) # 人脸解析器 - 内置 face-parsing.PyTorch:总共 18 个人脸部分(当前使用) # 正脸效果较好,侧脸或者小脸不佳 # 1 'face', 2 'l_brow', 3 'r_brow', 4 'l_eye', 5 'r_eye', # 6 'eye_g', 7 'l_ear', 8 'r_ear', 9 'ear_r', 10 'nose', # 11 'mouth', 12 'u_lip', 13 'l_lip', 14 'neck', 15 'neck_l', # 16 'cloth', 17 'hair', 18 'hat' face_area_map = { # 取值从数字 1 开始依次增加;0 为背景部分 'face': 1, 'l_brow': 2, 'r_brow': 3, 'l_eye': 4, 'r_eye': 5, 'eye_g': 6, 'l_ear': 7, 'r_ear': 8, 'ear_r': 9, 'nose': 10, 'teeth': 11, 'u_lip': 12, 'l_lip': 13, 'neck': 14, 'neck_l': 15, 'cloth': 16, 'hair': 17, 'hat': 18 } # 首先得到人脸解析图 face_areas = list(face_area_map.keys()) parsing, mask_pil = evaluate(_img_pil, engine_model, face_areas, edit_area) parsing = cv2.resize( parsing, _img_cv2.shape[0:2], interpolation=cv2.INTER_NEAREST) if ENABLE_MASK and mask_pil: mask_pil = image_resize_default(mask_pil, _img_cv2.shape[0]) _img_out = _img_cv2 if func_name == 'chg_color': # 着色处理 parts = [] # 需处理的人脸部分列表 colors = [] # 各人脸部分相应颜色列表 # colors 取值数量应与 parts 一致。 # 设定着色参数 def __set_color(part, color): if type(part) is list: for i in part: parts.append(face_area_map[i]) colors.append(color) else: parts.append(face_area_map[part]) colors.append(color) # 颜色示例 b,g,r: # [230, 50, 20] # 蓝 # [10, 250, 10] # 绿 # [10, 50, 250] # 红 # [20, 70, 180] # 唇红 #print('--> func_params:', func_params) for p in edit_area: __set_color(p, func_params[2]) if func_arg in ('avatar', 'hawk', 'red'): # 肤色系列 1 __set_color(['u_lip', 'l_lip'], [20, 70, 180]) c1, c2 = 0, 1 # 只修改蓝夜色 elif func_arg in ('jade', 'golden'): # 肤色系列 2 __set_color(['u_lip', 'l_lip'], [20, 70, 180]) c1, c2 = 0, 2 # 修改蓝绿夜色 else: # 部分着色,如发色 c1, c2 = 0, 1 # 默认只修改蓝夜色 # 置换指定区域颜色 for part, color in zip(parts, colors): print('--> change color to {} for {}'.format(color, part)) _img_out = change_color(_img_out, parsing, part, color, c1, c2) # 转换输出图从 cv2 到 PIL.Image _img_out_pil = image_cv2_to_pil(_img_out) if ENABLE_MASK: # 使用边缘模糊后的掩模图进行修正 _img_out_pil.paste(_img_out_pil, (0, 0), mask_pil) # 将返回图片缩放为原尺寸 if _img_h > _h: if _img_h > _h and ENABLE_ESRGAN: #_img_out_pil = esrgan_adapter.process_image( # _img_out_pil, engine_model['esrgan'], _img_w, _img_h) # 调用管理进程共享对象接口处理 ret = exec_esrgan(_img_out_pil, _img_w, _img_h, worker) if ret: _img_out_pil = ret else: _img_out_pil = image_resize_default(_img_out_pil, _img_h) else: _img_out_pil = image_resize_default(_img_out_pil, _img_h) # 检查是否为主demo,若是则将人脸处理结果保存为图标 if 'img_hash' in face_data: img_hash = face_data['img_hash'] if img_hash in app_config.IMG_HASH_ICON_DEMO: # 为生成界面图标用的指定图片 check_if_save_demo_icon(_img_out_pil, SAVE_ICON_DIR, func_arg) return _img_out_pil
def image_process_wrap(image, face_data=None, entry_process_image=None, engine_model=None, func_class='fc_editor', func_group=None, func_name=None, func_params=None, output_size_w=400, output_size_h=500, worker=None): """ 本函数包括两个功能: 1、face_data 为空时做图片预处理,主要是缩放为标准大小; 2、face_data 非空时做图片编辑处理,回调函数进行处理。 输出尺寸比例(output_size_w : output_size_h)应为 4:5,如 400x500 或 720x900。 """ if not image: raise Exception('image_process_wrap(): input image cannot be None!') # 1. 将 png 等图片统一转为 jpg 格式 image = image_convert_rgb(image) # 2. 根据图片尺寸判断是否归一化,并做相应的缩放裁剪 output_size_w, output_size_h = app_config.OUTPUT_SIZE_EDITOR # 归一化后的标准尺寸 img_w, img_h = image.size print('func_class: {}; img_w: {}, img_h: {}; output size w: {}, h: {}'. format(func_class, img_w, img_h, output_size_w, output_size_h)) needNormalize = False # 是否需要进行进行归一化 if img_w != output_size_w or img_h != output_size_h: needNormalize = True if needNormalize: # 图片裁剪为最大 output_size_w,output_size_h:大图片缩放裁剪、保留短边;小图片保持原尺寸 if img_w > output_size_w: # 过宽的,等比缩小为输出宽度 output_size_w newWidth = output_size_w newHeight = int(float(output_size_w) / img_w * img_h) image = image.resize((newWidth, newHeight), Image.ANTIALIAS) #image = image.thumbnail((newWidth, newHeight), Image.ANTIALIAS) img_w, img_h = image.size if img_h > output_size_h: # 过高的,居中裁剪为输出高度 output_size_h x0 = 0 y0 = int((img_h - output_size_h) / 2) x1 = output_size_w y1 = y0 + output_size_h image = image.crop((x0, y0, x1, y1)) img_w, img_h = image.size # 3. 居中扩展为正方形,宽高都为 output_size_h # image_norm = Image.new('RGBA', (output_size_h, output_size_h)) # 带透明信息 image_norm = Image.new('RGB', (output_size_h, output_size_h), (255, 255, 255)) # 不带透明信息 x = int((output_size_h - img_w) / 2) y = int((output_size_h - img_h) / 2) image_norm.paste(image, (x, y)) image_out = image_norm # 4. 将上述正方形图片交给引擎处理 if entry_process_image and hasattr(entry_process_image, '__call__'): #for v in func_params: # print('--> Optional argument (*args): ', v) ## 如果输入参数中有 **func_kwargs,则可以如下读取: #for k, v in func_kwargs.items(): # print('--> Optional argument %s (*kwargs): %s' % (k, v)) # 调用引擎回调函数对图片进行处理 #logger.info('call {}, func_name: {}, func_params: {}'.format(entry_process_image, func_name, func_params)) image_out = entry_process_image(image_norm, face_data, engine_model, func_name, func_params, worker=worker) if not image_out: image_norm.close() return None # 4. 处理后的图片再去扩展,恢复为步骤 1 后的尺寸(最大output_size_w,output_size_h),保存后返回给客户端 img_w, img_h = output_size_w, output_size_h # 使用指定输出尺寸,替代步骤 1 后的尺寸 x0 = int((output_size_h - img_w) / 2) y0 = int((output_size_h - img_h) / 2) x1 = x0 + img_w y1 = y0 + img_h image_out = image_out.crop((x0, y0, x1, y1)) image_norm.close() #logger.info('image wrap process done!') # 根据任务类型返回不同大小的输出图片 if func_class == 'fc_fun': _img_w, _img_h = app_config.OUTPUT_SIZE_FUN image_out = image_resize_default(image_out, _img_h) return image_out
def process_image(image, face_data, engine_model, func_name, func_params=None, worker=None): """ 对上传图片进行处理 Returns: image_output: 处理后的图片数据 """ # 处理和替换图片中的人脸部分 if 'face_image' in face_data: _img_np = face_data['face_image'] x = face_data['x'] y = face_data['y'] w = face_data['w'] h = face_data['h'] face_image_orig = image_ndarray_to_pil(_img_np) # 如果 face_image 尺寸大于模型标准尺寸,则缩放为标准尺寸再处理 _img_w, _img_h = w, h _h = engine_model['model_size'] if _img_h != _h: _img = image_resize_default(image_ndarray_to_pil(_img_np), _h) _img_np = image_pil_to_ndarray(_img) # 使用 face_image 构造测试数据集,包括内容、特征和大小 logger.info('face_image attr: {}, h {}. model size: {}.'.format( face_data['attr'], h, _h)) _test_dataset = MyTestData(_img_np, face_data['attr'], _h) # 处理图片 # test_atts 为目的特征列表;test_ints 为相应特征处理强度,取值 0~1 test_atts, test_ints = func_name, func_params[0] logger.info('func_params: {}, test_atts: {}, test_ints: {}'.format( func_params, test_atts, test_ints)) _img_out_pil = attgan_multi_process(engine_model, _test_dataset, test_atts, test_ints) # 如果为调试模式,则保存生成的人脸图片做分析用,产品化部署不需要 #if app_config.DEBUG: # out_file = os.path.join(script_dir, 'new_face.jpg') # _img_out_pil.save(out_file) # print('new image saved to {:s} done!'.format(out_file)) # 将返回图片缩放为原尺寸 if _img_h != _h: if _img_h > _h and ENABLE_ESRGAN: #_img_out_pil = esrgan_adapter.process_image( # _img_out_pil, engine_model['esrgan'], w, h) # 调用管理进程共享对象接口处理 ret = exec_esrgan(_img_out_pil, _img_w, _img_h, worker) if ret: _img_out_pil = ret else: _img_out_pil = image_resize_default(_img_out_pil, _img_h) else: _img_out_pil = image_resize_default(_img_out_pil, _img_h) # 将新旧人脸混合后贴回原图 x = x + int((image.size[0] - app_config.OUTPUT_SIZE_EDITOR[0]) / 2) y = y + int((image.size[1] - app_config.OUTPUT_SIZE_EDITOR[1]) / 2) edit_area = func_params[1] image_output = face_image_blend(image, _img_out_pil, face_image_orig, x, y, w, h, edit_area, worker) return image_output
def process_image(image, face_data, engine_model, func_name, func_params=None, worker=None): """ 对上传图片进行处理 Returns: image_output: 处理后的图片数据 注意:对于 facelet_pt 来说,由于引擎是根据 effect 分别在子进程中加载的,所以这里 func_name 没用到 """ logger.info( 'call process_image. func_name: "{}", func_params: "{}"'.format( func_name, func_params)) # 处理和替换图片中的人脸部分 if 'face_image' in face_data: _img_np = face_data['face_image'] x = face_data['x'] y = face_data['y'] w = face_data['w'] h = face_data['h'] face_image_orig = image_ndarray_to_pil(_img_np) # 由于真实处理过程使用CPU执行太慢,笔记本上运行会导致任务超时,故暂时用 sleep 模拟之 run_fake = False # 笔记本上运行设为 True,开发和生产服务器上为 False if run_fake: time.sleep(3) _img_out_pil = image_ndarray_to_pil(_img_np) else: # 如果 face_image 尺寸大于模型标准尺寸,则缩放为标准尺寸再处理 _img_w, _img_h = w, h _h = engine_model['model_size'] if _img_h != _h: _img = image_resize_default(image_ndarray_to_pil(_img_np), _h) _img_np = image_pil_to_ndarray(_img) _img_out = engine_process_image(engine_model, _img_np, func_name, func_params) # ndarray/Tensor 转成PIL.Image _img_out_pil = image_ndarray_to_pil(_img_out) # 如果为调试模式,则保存生成的人脸图片做分析用,产品化部署不需要 if app_config.DEBUG: out_file = os.path.join(script_dir, 'new_face.jpg') _img_out_pil.save(out_file) print('new image saved to {:s} done!'.format(out_file)) # 将返回图片缩放为原尺寸 if _img_h != _h: if _img_h > _h and ENABLE_ESRGAN: #_img_out_pil = esrgan_adapter.process_image( # _img_out_pil, engine_model['esrgan'], w, h) # 调用管理进程共享对象接口处理 ret = exec_esrgan(_img_out_pil, _img_w, _img_h, worker) if ret: _img_out_pil = ret else: _img_out_pil = image_resize_default( _img_out_pil, _img_h) else: _img_out_pil = image_resize_default(_img_out_pil, _img_h) # 将新旧人脸混合后贴回原图 x = x + int((image.size[0] - app_config.OUTPUT_SIZE_EDITOR[0]) / 2) y = y + int((image.size[1] - app_config.OUTPUT_SIZE_EDITOR[1]) / 2) edit_area = [] image_output = face_image_blend(image, _img_out_pil, face_image_orig, x, y, w, h, edit_area, worker) return image_output