应用体验:证件照一键生成

本项目主要是为了方便大家照不那么严格的证件照,纯自助,只要拿手机一拍,在“应用体验”页面上传,项目自动抠图和排版,再下载下来的就是符合背景色要求的证件照了。本项目只为方便大家,一些要求非常严格的证件照,还是建议在专业招照相馆或者自助机上进行。

整个项目使用步骤很简单:

  • 在“应用体验”页面拍照上传,要求露双肩。并根据证件照其它要求提前做好构图取景等。因为可以抠图换背景,所以不需要专业照相馆里的背景布
  • 选择合适的背景色,有红色、蓝色和白色三种颜色可选。然后点“提交图片”,系统就自动进行抠图换背景。
  • 选择合适的照片下载。处理后的照片显示出来,根据需求,点击合适的照片下载即可。

一、应用体验项目的问题分解

为了较快实现功能,选择了FastDeploy。就AIStudio的应用中心实现来推测,不太合适使用飞桨Serving,因此选型就剩下了FastDeploy、Hub以及Inference。其中前两个都封装的较好,属于开箱能用的。

1、实现基本功能,在notebook下跑通

  1. 拍照上传,使用AIStudio的上传功能
  2. 抠像,系统后台使用飞桨AI框架进行自动扣图。本项目最内核的部分就是这里了
  3. 后处理,主要是填背景色和证件照排版输出
    生成的图片,可以在AIStudio notebook下右键下载。

2、在本地应用中心调试跑通

BML CodeLab提供用户创建应用、调试应用和部署应用等功能。相关功能以Streamlit作为底层技术,为用户提供快速搭建交互式图形化界面的能力,只需要几行代码即可搭建一个炫酷的图形化界面。
文档参考:https://ai.baidu.com/ai-doc/AISTUDIO/Gktuwqf1x#应用

  • 按照应用中心例子,写应用代码。主要是页面展示
  • 将前面测试好的抠图和后处理代码,嵌入。
  • 本地“运行”调试,调试成功后部署即可。

在本项目中,为了更好的展示,也为了加快调试,使用了“默认图片”的设置,“运行”后直接点击“提交照片”即可测试。
会自动输出1寸照片和5寸6寸混排照片,选中合适的照片下载即可。

3、在服务端应用部署调试成功

可以使用“在浏览器打开”进行调试,但最终在部署后还需要调试,以免有任何遗漏,影响应用的体验。

二、在notebook下跑通

在学习FastDeploy、PaddleDet等多种套件模型后,选择FastDeploy里面的PP-Matting模型。具体文档见:https://gitee.com/paddlepaddle/FastDeploy/tree/develop/examples/vision/matting/ppmatting/python

1、安装FastDeploy

因最终“应用体验”使用的是cpu版本,所以这里最终安装cpu版本。

测试中发现cpu版本安装的时候较慢,尽管gpu版本文件1.68G,有时候反而安装速度要快于cpu版本。所以在调试的时候,大部分时候都是选择AIStudio高端版GPU版,FastDeploy也是安装的GPU版。因为飞桨面向用户的代码是不需要区分GPU和cpu,所以不管使用GPU还是cpu,除了处理速度不同外,开发者不会有任何不同的感受。

# !pip install fastdeploy-gpu-python -f https://www.paddlepaddle.org.cn/whl/fastdeploy.html
!pip install fastdeploy-python -f https://www.paddlepaddle.org.cn/whl/fastdeploy.html

2、准备PP-Matting模型

FastDeploy需要手动下载模型文件,从上面的文档中,可以看到下载语句。文档中是512 * 512大小模型,我这里选了1024* 1024图片的小的模型。

# 下面这句大约是PaddleSeg库里的抠图模型
# !cd ~/work/ && wget https://paddleseg.bj.bcebos.com/matting/models/deploy/pp-matting-hrnet_w18-human_1024.zip && unzip pp-matting-hrnet_w18-human_1024.zip
# fastdeploy库的模型
# !wget https://bj.bcebos.com/paddlehub/fastdeploy/PP-Matting-512.tgz && tar -xvf PP-Matting-512.tgz
!wget https://bj.bcebos.com/paddlehub/fastdeploy/PP-Matting-1024.tgz && tar -xvf PP-Matting-1024.tgz

3、抠图核心代码实现

PP-Matting API https://www.paddlepaddle.org.cn/fastdeploy-api-doc/python/html/matting.html

fastdeploy.vision.matting.PPMatting
class fastdeploy.vision.matting.PPMatting(model_file, params_file, config_file, runtime_option=None, model_format=<ModelFormat.PADDLE: 1>)[source]
Load a PPMatting model exported by PaddleSeg.

以下为手册中的例子,先跑通。然后学习和拆分核心代码,以移植到notebook下,并为最终“应用体验”部署做准备。

跑通PP-Matting例子

# #下载部署示例代码
!git clone https://github.com/PaddlePaddle/FastDeploy.git
%cd ~/FastDeploy/examples/vision/matting/ppmatting/python# # 下载PP-Matting模型文件和测试图片
!wget https://bj.bcebos.com/paddlehub/fastdeploy/PP-Matting-512.tgz
!tar -xvf PP-Matting-512.tgz
!wget https://bj.bcebos.com/paddlehub/fastdeploy/matting_input.jpg
!wget https://bj.bcebos.com/paddlehub/fastdeploy/matting_bgr.jpg
# # CPU推理
!python infer.py --model PP-Matting-512 --image matting_input.jpg --bg matting_bgr.jpg --device cpu
# # GPU推理
# !python infer.py --model PP-Matting-512 --image matting_input.jpg --bg matting_bgr.jpg --device gpu
# # GPU上使用TensorRT推理 (注意:TensorRT推理第一次运行,有序列化模型的操作,有一定耗时,需要耐心等待)
# !python infer.py --model PP-Matting-512 --image matting_input.jpg --bg matting_bgr.jpg --device gpu --use_trt True
%cd ~/

将PP-Matting例子代码移植到notebook下

使用PP-Matting-1024模型进行抠图
https://gitee.com/paddlepaddle/FastDeploy/tree/develop/examples/vision/matting/ppmatting/python

# 下载1024模型
!wget https://bj.bcebos.com/paddlehub/fastdeploy/PP-Matting-1024.tgz
!tar -xvf PP-Matting-1024.tgz
# 将infer.py代码移植到notebook下执行
import fastdeploy as fd
import cv2
import os# 配置runtime,加载模型
# runtime_option = build_option(args)
runtime_option = None
argsmodel = "/home/aistudio/PP-Matting-1024/"
model_file = os.path.join(argsmodel, "model.pdmodel")
params_file = os.path.join(argsmodel, "model.pdiparams")
config_file = os.path.join(argsmodel, "deploy.yaml")
# model = fd.vision.matting.PPMatting(
#     model_file, params_file, config_file, runtime_option=runtime_option)
model = fd.vision.matting.PPMatting(model_file, params_file, config_file)

抠图结束后,将其存为visualized_result_fg文件。

为了换背景色,先代码生成红、蓝和白三色图片。

# 写三张颜色背景图
import numpy as np
x = np.ndarray([800, 600, 3])
x[:, :, :] = 0
x[:, :, 0] = 255
cv2.imwrite("blue.jpg", x)
x[:, :, :] = 0
x[:, :, 1] = 255
cv2.imwrite("green.jpg", x)
x[:, :, :] = 0
x[:, :, 2] = 255
cv2.imwrite("red.jpg", x)
x[:, :, :] = 255
cv2.imwrite("white.jpg", x)
# 预测图片抠图结果
%cd ~/argsimage = "work/beautysmall.jpg"
argsbg = "beautysmall.jpg"
im = cv2.imread(argsimage)
# bg = cv2.imread(argsbg)
bgrgb = "red"
if bgrgb == "red":bgrgb = cv2.imread("red.jpg")
elif bgrgb == "blue":bgrgb = cv2.imread("blue.jpg")
else :bgrgb = cv2.imread("white.jpg")
bg = bgrgb
result = model.predict(im.copy())
# print(result)
# 可视化结果
vis_im = fd.vision.vis_matting(im, result)
vis_im_with_bg = fd.vision.swap_background_matting(im, bg, result)
# vis_im_with_red = fd.vision.swap_background_matting(im, bgrgb, result)
cv2.imwrite("visualized_result_fg.png", vis_im)
cv2.imwrite("visualized_result_replaced_bg.jpg", vis_im_with_bg)
print("Visualized result save in ./visualized_result_replaced_bg.jpg and ./visualized_result_fg.jpg"
)
# vis_im_with_red.show()

可以点击生成的图片:visualized_result_replaced_bg.jpg,观察是否达到了预计的目标。

4、后处理

证件照的大小要求:

1、一寸照片尺寸大小为:2.5*3.5cm(厘米)。一寸照片用的太普遍了,我们常见的有学生证、健康证、工作证、中小学生教师资格证、驾驶证等。2、二寸照片尺寸大小为:3.5*4.5cm(厘米)。二寸主要用在部分公务员和部分国家的签证。中国护照、港澳通行证、台湾通行证、韩国以及澳大利亚签证、雅思考试、全国计算机等级考试、英语四六级考试等。作者:兰花草
链接:https://www.zhihu.com/question/330460193/answer/723674520

zhege gengxiangxi
这个更详细
https://zhuanlan.zhihu.com/p/549253320

1寸 295px × 413px 25* 35
2寸 413px × 579px
5寸生活照片 89mm × 127mm 1050px × 1500px

针对1寸照片需求,我们需要把大小调整为295*413 。使用F.resize函数即可。

import numpy as np
from PIL import Image
from paddle.vision.transforms import functional as Ffake_img = (np.random.rand(256, 300, 3) * 255.).astype('uint8')fake_img = Image.fromarray(fake_img)converted_img = F.resize(fake_img, 224)
testim = F.tran
testimg = F.resize(vis_im, (295, 413, 3))
print(converted_img.size)
print(testimg.size)

加白框

思路,可以把图片调整为290 * 408 ,然后再叠加到295 * 413
也可以采用在295 * 413照片上画白线来解决。倾向于第二个方法。
弄明白了,单照片不用放边框。

平铺以便打印

5寸 8.9* 12.7 0.7
6寸 10.2* 15.2 0.67
大6寸 114* 15.2 0.75

这样5寸可以打9张 ,3列3排
295* 3 = 885 2.5* 3 = 7.5
413* 3 = 1239 3.5* 3=10.5

这样可以有足够的位置放白框。纵横间隔为40像素,这样打印照片的大小为:
295* 3+40* 4= 1045
413* 3 +40* 4 =1399 约等于1400 ,这样打印的时候有一定的盈余。

5、后处理实践

因为比较复杂,所以单独列一项出来。

几个技术,经过比较,后来决定使用csnd上现成的代码。
以下是中间走过的弯路

Pad增加边界

class paddle.vision.transforms.Pad(padding, fill=0, padding_mode=‘constant’, keys=None)

img (PIL.Image|np.ndarray|Paddle.Tensor) - 输入的图像数据,数据格式为’HWC’。

output (PIL.Image|np.ndarray|Paddle.Tensor) - 返回填充后的图像数据。

padding (int|list|tuple) - 在图像边界上进行填充的范围。如果提供的是单个 int 值,则该值用于填充图像所有边;如果提供的是长度为 2 的元组/列表,则分别为图像左/右和顶部/底部进行填充;如果提供的是长度为 4 的元组/列表,则按照左,上,右和下的顺序为图像填充。

fill (int|list|tuple,可选) - 用于填充的像素值。仅当 padding_mode 为 constant 时参数值有效。 默认值:0。 如果参数值是一个长度为 3 的元组,则会分别用于填充 R,G,B 通道。

Resize调整大小

class paddle.vision.transforms.Resize(size, interpolation=‘bilinear’, keys=None)[源代码]
将输入数据调整为指定大小。

需要调整称2.5:3.5 也就是5:7的比例,这样原图cai bu bi

CenterCrop

class paddle.vision.transforms.CenterCrop(size, keys=None)[源代码]
对输入图像进行裁剪,保持图片中心点不变。

主要是调整成5:7的比例

csdn学到的代码

这段代码不错。 拿来用了,来源于csdn论坛:http://t.csdn.cn/8UhHo

# Author:ZM
# http://t.csdn.cn/8UhHo"""
照片尺寸,宽*高(单位:像素)
1寸照片:295*413
2寸照片:413*626
5寸照片(横版):1500*1050
6寸照片(横版):1800*1200
"""
from PIL import Image,ImageDrawWIDTH_1IN = 295
HEIGHT_1IN = 413WIDTH_2IN = 413
HEIGHT_2IN = 626WIDTH_5IN = 1500
HEIGHT_5IN = 1050# 非全景6寸照片
WIDTH_6IN = 1950
HEIGHT_6IN = 1300def cut_photo(photo,choice):"""将照片按照比例进行裁剪成1寸、2寸:param photo: 待处理的照片:param choice: <int> 1代表1寸,2代表2寸:return: 处理后的照片"""width = photo.size[0] # 宽height = photo.size[1] #高rate = height / widthif choice == 1:if rate < (HEIGHT_1IN/WIDTH_1IN):x = (width - int(height / HEIGHT_1IN * WIDTH_1IN)) / 2y = 0cutted_photo = photo.crop((x, y, x + (int(height / HEIGHT_1IN * WIDTH_1IN)), y + height))else:x = 0y = (height - int(width / WIDTH_1IN * HEIGHT_1IN)) / 2cutted_photo = photo.crop((x, y, x + width, y + (int(width / WIDTH_1IN * HEIGHT_1IN))))return cutted_photoif choice == 2:if rate < (HEIGHT_2IN/WIDTH_2IN):x = (width - int(height / HEIGHT_2IN * WIDTH_2IN)) / 2y = 0cutted_photo = im.crop((x, y, x + (int(height / HEIGHT_2IN * WIDTH_2IN)), y + height))else:x = 0y = (height - int(width / WIDTH_2IN * HEIGHT_2IN)) / 2cutted_photo = im.crop((x, y, x + width, y + (int(width / WIDTH_2IN * HEIGHT_2IN))))return cutted_photodef resize_photo(photo,choice):'''缩放照片:param photo: 待处理的照片:param choice: <int> 1代表1寸,2代表2寸:return: 处理后的照片'''if choice == 1:resized_photo = photo.resize((WIDTH_1IN,HEIGHT_1IN))return resized_photoif choice == 2:resized_photo = photo.resize((WIDTH_2IN, HEIGHT_2IN))return resized_photodef layout_photo_5_1(photo):"""在5寸照片上排版1寸照片:param photo: 待处理照片1寸:return: 处理后的照片"""bk = Image.new("RGB", [WIDTH_5IN,HEIGHT_5IN], (255,255,255))draw = ImageDraw.Draw(bk)# 创建画笔draw.line([(0,HEIGHT_5IN/2),(WIDTH_5IN,HEIGHT_5IN/2)],fill=128) # 横线draw.line([(WIDTH_5IN*0.25,0),(WIDTH_5IN*0.25,HEIGHT_5IN)],fill=128) # 第1条竖线draw.line([(WIDTH_5IN*0.5,0),(WIDTH_5IN*0.5,HEIGHT_5IN)],fill=128) # 第2条竖线draw.line([(WIDTH_5IN*0.75,0),(WIDTH_5IN*0.75,HEIGHT_5IN)],fill=128) # 第3条竖线focus_point = [0.125 * WIDTH_5IN,0.25 * HEIGHT_5IN]start_point = [focus_point[0] - 0.5 * WIDTH_1IN, focus_point[1] - 0.5 * HEIGHT_1IN]for i in range(0,2):for k in range(0,4):bk.paste(photo, (int(start_point[0] + (k * WIDTH_5IN / 4)), int(start_point[1] + 0.5 * i * HEIGHT_5IN)))return bkdef layout_photo_5_2(photo):"""在5寸照片上排版2寸照片:param photo: 待处理照片2寸:return: 处理后的照片"""bk = Image.new("RGB", [HEIGHT_5IN,WIDTH_5IN], (255,255,255)) # 竖版排版# 创建画笔draw = ImageDraw.Draw(bk)draw.line([(0,WIDTH_5IN/2),(WIDTH_5IN,WIDTH_5IN/2)],fill=128) # 横线draw.line([(HEIGHT_5IN*0.5,0),(HEIGHT_5IN*0.5,WIDTH_5IN)],fill=128) # 竖线focus_point = [0.25 * HEIGHT_5IN, 0.25 * WIDTH_5IN]start_point = [focus_point[0] - 0.5 * WIDTH_2IN, focus_point[1] - 0.5 * HEIGHT_2IN]#print(focus_point,start_point)for i in range(0,2):for k in range(0,2):bk.paste(photo, (int(start_point[0] + (k * HEIGHT_5IN / 2)), int(start_point[1] + 0.5* i * WIDTH_5IN)))return bkdef layout_photo_5_mix(photo1,photo2):"""在5寸照片上混合排版1寸、2寸照片:param photo1: 待处理照片1寸:param photo1: 待处理照片2寸:return: 处理后的照片"""bk = Image.new("RGB", [WIDTH_5IN,HEIGHT_5IN], (255,255,255))# 创建画笔draw = ImageDraw.Draw(bk)draw.line([(0,HEIGHT_5IN/2),(WIDTH_5IN,HEIGHT_5IN/2)],fill=128) # 横线draw.line([(WIDTH_5IN*0.25,0),(WIDTH_5IN*0.25,HEIGHT_5IN)],fill=128) # 第1条竖线draw.line([(WIDTH_5IN*0.5,0),(WIDTH_5IN*0.5,HEIGHT_5IN)],fill=128) # 第2条竖线focus_point = [0.125 * WIDTH_5IN,0.25 * HEIGHT_5IN]start_point = [focus_point[0] - 0.5 * WIDTH_1IN, focus_point[1] - 0.5 * HEIGHT_1IN]focus_point2 = [0.75 * WIDTH_5IN, 0.25 * HEIGHT_5IN]start_point2 = [focus_point2[0] - 0.5 * HEIGHT_2IN, focus_point2[1] - 0.5 * WIDTH_2IN]for i in range(0,2):for k in range(0,2):bk.paste(photo1, (int(start_point[0] + (k * WIDTH_5IN / 4)), int(start_point[1] + 0.5 * i * HEIGHT_5IN)))bk.paste(photo2,(int(start_point2[0]),int(start_point2[1])))bk.paste(photo2,(int(start_point2[0]),int(start_point2[1] + 0.5 * HEIGHT_5IN)))return bkdef layout_photo_6_1(photo):"""在6寸照片上排版2寸照片:param photo: 待处理照片1寸:return: 处理后的照片"""bk = Image.new("RGB", [HEIGHT_6IN,WIDTH_6IN], (255,255,255)) # 竖版排版# 创建画笔draw = ImageDraw.Draw(bk)draw.line([(0,WIDTH_6IN*0.25),(WIDTH_6IN,WIDTH_6IN*0.25)],fill=128) # 横线draw.line([(0,WIDTH_6IN*0.5),(WIDTH_6IN,WIDTH_6IN*0.5)],fill=128) # 横线draw.line([(0,WIDTH_6IN*0.75),(WIDTH_6IN,WIDTH_6IN*0.75)],fill=128) # 横线draw.line([(HEIGHT_6IN*0.25,0),(HEIGHT_6IN*0.25,WIDTH_6IN)],fill=128) # 竖线draw.line([(HEIGHT_6IN*0.5,0),(HEIGHT_6IN*0.5,WIDTH_6IN)],fill=128) # 竖线draw.line([(HEIGHT_6IN*0.75,0),(HEIGHT_6IN*0.75,WIDTH_6IN)],fill=128) # 竖线focus_point = [0.125 * HEIGHT_6IN, 0.125 * WIDTH_6IN]start_point = [focus_point[0] - 0.5 * WIDTH_1IN, focus_point[1] - 0.5 * HEIGHT_1IN]#print(focus_point,start_point)for i in range(0,4):for k in range(0,4):bk.paste(photo, (int(start_point[0] + (k * HEIGHT_6IN / 4)), int(start_point[1] + i * 0.25 * WIDTH_6IN )))return bkdef layout_photo_6_2(photo):"""在6寸照片上排版2寸照片:param photo: 待处理照片2寸:return: 处理后的照片"""bk = Image.new("RGB", [WIDTH_6IN,HEIGHT_6IN], (255,255,255))# 创建画笔draw = ImageDraw.Draw(bk)draw.line([(0,HEIGHT_6IN/2),(WIDTH_6IN,HEIGHT_6IN/2)],fill=128) # 横线draw.line([(WIDTH_6IN*0.25,0),(WIDTH_6IN*0.25,HEIGHT_6IN)],fill=128) # 第1条竖线draw.line([(WIDTH_6IN*0.5,0),(WIDTH_6IN*0.5,HEIGHT_6IN)],fill=128) # 第2条竖线draw.line([(WIDTH_6IN*0.75,0),(WIDTH_6IN*0.75,HEIGHT_6IN)],fill=128) # 第3条竖线focus_point = [0.125 * WIDTH_6IN,0.25 * HEIGHT_6IN]start_point = [focus_point[0] - 0.5 * WIDTH_2IN, focus_point[1] - 0.5 * HEIGHT_2IN]for i in range(0,2):for k in range(0,4):bk.paste(photo, (int(start_point[0] + (k * WIDTH_6IN / 4)), int(start_point[1] + 0.5 * i * HEIGHT_6IN)))return bkdef layout_photo_6_mix1(photo1,photo2):"""在6寸照片上混合排版1寸、2寸照片:param photo1: 待处理照片1寸:param photo1: 待处理照片2寸:return: 处理后的照片"""bk = Image.new("RGB", [WIDTH_6IN,HEIGHT_6IN], (255,255,255))# 创建画笔draw = ImageDraw.Draw(bk)draw.line([(0,HEIGHT_6IN*0.5),(WIDTH_6IN,HEIGHT_6IN/2)],fill=128) # 横线draw.line([(0,HEIGHT_6IN*0.25),(WIDTH_6IN*0.5,HEIGHT_6IN*0.25)],fill=128) # 短横线draw.line([(0,HEIGHT_6IN*0.75),(WIDTH_6IN*0.5,HEIGHT_6IN*0.75)],fill=128) # 短横线draw.line([(WIDTH_6IN*0.25,0),(WIDTH_6IN*0.25,HEIGHT_6IN)],fill=128) # 第1条竖线draw.line([(WIDTH_6IN*0.5,0),(WIDTH_6IN*0.5,HEIGHT_6IN)],fill=128) # 第2条竖线draw.line([(WIDTH_6IN*0.75,0),(WIDTH_6IN*0.75,HEIGHT_6IN)],fill=128) # 第3条竖线focus_point = [0.125 * WIDTH_6IN, 0.125 * HEIGHT_6IN]start_point = [focus_point[0] - 0.5 * HEIGHT_1IN, focus_point[1] - 0.5 * WIDTH_1IN]for i in range(0,4):for k in range(0,2):bk.paste(photo1, (int(start_point[0] + (0.25 * k * WIDTH_6IN )), int(start_point[1] + 0.25 * i * HEIGHT_6IN)))focus_point2 = [0.625 * WIDTH_6IN, 0.25 * HEIGHT_6IN]start_point2 = [focus_point2[0] - 0.5 * WIDTH_2IN, focus_point2[1] - 0.5 * HEIGHT_2IN]for i in range(0,2):for k in range(0,2):bk.paste(photo2,(int(start_point2[0] + (0.25 * k * WIDTH_6IN)), int(start_point2[1] + 0.5 * i * HEIGHT_6IN)))# 显示图片# bk.show()return bkdef layout_photo_6_mix2(photo1,photo2):"""在6寸照片上混合排版1寸、2寸照片:param photo1: 待处理照片1寸:param photo1: 待处理照片2寸:return: 处理后的照片"""bk = Image.new("RGB", [HEIGHT_6IN,WIDTH_6IN], (255,255,255)) # 竖版排版# 创建画笔draw = ImageDraw.Draw(bk)draw.line([(350,0),(350,WIDTH_6IN)],fill=128) # 竖线draw.line([(700,0),(700,WIDTH_6IN)],fill=128) # 竖线draw.line([(0,WIDTH_6IN*0.25),(700,WIDTH_6IN*0.25)],fill=128) # 横线1draw.line([(0,WIDTH_6IN*0.5),(700,WIDTH_6IN*0.5)],fill=128) # 横线2draw.line([(0,WIDTH_6IN*0.75),(700,WIDTH_6IN*0.75)],fill=128) # 横线3draw.line([(700,WIDTH_6IN/3),(HEIGHT_6IN,WIDTH_6IN/3)],fill=128) # 横线4draw.line([(700,WIDTH_6IN*2/3),(HEIGHT_6IN,WIDTH_6IN*2/3)],fill=128) # 横线5focus_point = [0.5 * 350, 0.125 * WIDTH_6IN]start_point = [focus_point[0] - 0.5 * WIDTH_1IN, focus_point[1] - 0.5 * HEIGHT_1IN]#print(focus_point,start_point)for i in range(0,4):for k in range(0,2):bk.paste(photo1, (int(start_point[0] + (k * 350)), int(start_point[1] + i * 0.25 * WIDTH_6IN )))focus_point2 = [0.5 * HEIGHT_6IN+350,  WIDTH_6IN/6]start_point2 = [focus_point2[0] - 0.5 * WIDTH_2IN, focus_point2[1] - 0.5 * HEIGHT_2IN]for i in range(0,3):bk.paste(photo2, (int(start_point2[0]), int(start_point2[1] + i  * WIDTH_6IN /3)))return bkim = Image.open('beautysmall.jpg')
width = im.size[0]
height = im.size[1]
rate = height / width
layout_photo_5_1(resize_photo(cut_photo(im,1),1)).save('5_1.jpg')
layout_photo_5_2(resize_photo(cut_photo(im,2),2)).save('5_2.jpg')
layout_photo_6_1(resize_photo(cut_photo(im,1),1)).save('6_1.jpg')
layout_photo_6_2(resize_photo(cut_photo(im,2),2)).save('6_2.jpg')
layout_photo_5_mix(resize_photo(cut_photo(im,1),1),resize_photo(cut_photo(im,2),2).rotate(90,expand=True)).save('5_1_mix.jpg')
layout_photo_6_mix1(resize_photo(cut_photo(im,1),1).rotate(90,expand=True),resize_photo(cut_photo(im,2),2)).save('6_mix1.jpg')
layout_photo_6_mix2(resize_photo(cut_photo(im,1),1),resize_photo(cut_photo(im,2),2)).save('6_mix2.jpg')

将该文件命名为printpic.py存盘到work目录,并调试调用。
发现每个函数需要单独import,否则报错。

from work.printpic import cut_photo
from work.printpic import resize_photo from work.printpic import layout_photo_5_1
from work.printpic import layout_photo_5_2
from work.printpic import layout_photo_6_1
from work.printpic import layout_photo_6_2
from work.printpic import layout_photo_5_mix
from work.printpic import layout_photo_6_mix1
from work.printpic import layout_photo_6_mix2from PIL import Image,ImageDraw
im = Image.open('visualized_result_replaced_bg.jpg')
layout_photo_5_1(resize_photo(cut_photo(im,1),1)).save('5_1.jpg')
layout_photo_5_2(resize_photo(cut_photo(im,2),2)).save('5_2.jpg')
layout_photo_6_1(resize_photo(cut_photo(im,1),1)).save('6_1.jpg')
layout_photo_6_2(resize_photo(cut_photo(im,2),2)).save('6_2.jpg')
layout_photo_5_mix(resize_photo(cut_photo(im,1),1),resize_photo(cut_photo(im,2),2).rotate(90,expand=True)).save('5_1_mix.jpg')
layout_photo_6_mix1(resize_photo(cut_photo(im,1),1).rotate(90,expand=True),resize_photo(cut_photo(im,2),2)).save('6_mix1.jpg')
layout_photo_6_mix2(resize_photo(cut_photo(im,1),1),resize_photo(cut_photo(im,2),2)).save('6_mix2.jpg')

6、使用PaddleSeg里面的pp-matting(尝试过,未入选)

# !git clone https://github.com/PaddlePaddle/PaddleSeg
# %%writefile pipinstall.sh
# cd PaddleSeg
# pip install -r requirements.txt
# pip install -e .
# cd Matting
# pip install -r requirements.txt
# !sh pipinstall.sh
# !cd ~/work/ && wget https://paddleseg.bj.bcebos.com/matting/models/deploy/pp-matting-hrnet_w18-human_1024.zip && unzip pp-matting-hrnet_w18-human_1024.zip

背景替换

export CUDA_VISIBLE_DEVICES=0
python bg_replace.py \--config configs/modnet/modnet-mobilenetv2.yml \--model_path output/best_model/model.pdparams \--image_path path/to/your/image \--background path/to/your/background/image \--save_dir ./output/results \--fg_estimate True

如模型需要trimap信息,需要通过--trimap_path传入trimap路径。

--background可以传入背景图片路劲,或选择(‘r’,‘g’,‘b’,‘w’)中的一种,代表红,绿,蓝,白背景, 若不提供则采用绿色作为背景。

--fg_estimate False 可关闭前景估计功能,可提升预测速度,但图像质量会有所降低

注意: --image_path必须是一张图片的具体路径。

你可以直接下载我们提供的模型进行背景替换。

# !cd PaddleSeg/Matting && python tools/bg_replace.py \
#     --config configs/modnet/modnet-mobilenetv2.yml \
#     --model_path ~/work/pp-matting-hrnet_w18-human_1024/model.pdiparams \
#     --image_path ~/work/beautysmall.jpg \
#     --background "b" \
#     --save_dir ~/work/ \
#     --fg_estimate True

三、应用创建工具

点击新建-应用创建工具,生成应用文件模版,我这里改名为:app.streamlit.py。刚开始看见满屏的代码,可能有点不知所措,可以参考这个项目大头贴拍照机:https://aistudio.baidu.com/aistudio/projectdetail/5045676

1、将前面跑通的notebook代码写入app.streamlit.py

主要是注意代码中涉及到目录文件的代码,因为最终部署的时候需要打包到一个文件夹中,所以没法像传统项目那样在根目录下放好几个目录。当然可以在打包目录里面放几个目录。这个项目中,我们把打包目录设定为~/work目录 。

2、本机运行测试

根据报错信息,哪里出错调哪里。

3、应用部署调试

因为使用了FastDeploy库,所以需要在打包目录写一个requirements.txt文件。
文件内容为:fastdeploy-python -f https://www.paddlepaddle.org.cn/whl/fastdeploy.html

调试

fastdeploy部署报错error: the following arguments are required: --recipe, --mode

usage: infer.py [-h] --recipe RECIPE --mode MODE [--queue_dir QUEUE_DIR][--base BASE] [--docker_args DOCKER_ARGS]
infer.py: error: the following arguments are required: --recipe, --mode

修改成这样报错:

pwdpath = !pwd
!cd ~/FastDeploy/examples/vision/matting/ppmatting/python && python infer.py  --recipe $pwdpath --mode MODE --model PP-Matting-512 --image matting_input.jpg --bg matting_bgr.jpg --device cpu

报错

usage: infer.py [-h] --recipe RECIPE --mode MODE [--queue_dir QUEUE_DIR][--base BASE] [--docker_args DOCKER_ARGS]
infer.py: error: unrecognized arguments: --model PP-Matting-512 --image matting_input.jpg --bg matting_bgr.jpg --device cpu

这样看全乱套了啊!

在按照手册安装好FastDeploy之后,终于正常了!
pip install fastdeploy-gpu-python -f https://www.paddlepaddle.org.cn/whl/fastdeploy.html

照片后处理程序报错

在notebook下正常,赚到命令行下就报错

aistudio@jupyter-209599-1243758:~/work$ python printpic.py
Traceback (most recent call last):File "printpic.py", line 267, in <module>main(inputfile="testli.jpg")File "printpic.py", line 259, in mainlayout_photo_5_2(resize_photo(cut_photo(im,2),2)).save('5_2.jpg')File "printpic.py", line 52, in cut_photocutted_photo = im.crop((x, y, x + (int(height / HEIGHT_2IN * WIDTH_2IN)), y + height))
NameError: name 'im' is not defined

刚开始以为是图片大小不合适导致的,后来发现是原代码有小bug,im确实没有在函数中定义,它使用了全局变量,在我将后处理程序放入main函数后,该变量就不是全局变量了,导致该bug暴露出来。
将第52行的im改成photo即可。 cutted_photo = photo.crop((x, y, x + (int(height / HEIGHT_2IN * WIDTH_2IN)), y + height))

期间在测试PP-Matting一运行就报错

用系统自带的代码测试一下,ok,参见手册:https://github.com/PaddlePaddle/FastDeploy/tree/develop/examples/vision/matting/ppmatting/python
于是查找前面的问题,发现是因为调用了错误的模型导致的的,应该是"/home/aistudio/work/PP-Matting-1024/",错误的用了work/pp-matting-hrnet_w18-human_1024

应用体验部署的时候报目录超过2G限制

只有一个100M大小的模型文件,其实没有超限,原来是应用体验部署只支持飞桨2.3.2版本,我的是2.4.0版本,所以会报错。
后来使用在python代码中下载模型的方式,绕过了这个问题。

No module named ‘keypoint’

Traceback (most recent call last):File "infer.py", line 8, in <module>from keypoint import FaceLandMark
ModuleNotFoundError: No module named 'keypoint'

经检查,发现是FastDeploy没有成功git clone下来,而根目录下正好有个infer.py文件,导致这种神奇的报错。

结束语

让我们荡起双桨,在AI的海洋乘风破浪!

飞桨官网:https://www.paddlepaddle.org.cn

因为水平有限,难免有不足之处,还请大家多多帮助。

作者:段春华, 网名skywalk 或 天马行空,济宁市极快软件科技有限公司的AI架构师,百度飞桨PPDE。

我在AI Studio上获得至尊等级,点亮10个徽章,来互关呀~ https://aistudio.baidu.com/aistudio/personalcenter/thirdview/141218

此文章为搬运
原项目链接

应用体验:证件照一键生成相关推荐

  1. 营业执照在线一键生成_如何在线制作证件照?证件照一键生成的方法

    如何在线制作证件照?每一年的毕业季也是就业季,几百多万的大学生都面临着找工作,而在工作之前必须准备好证件照,这样方便参加面试和入职.随着市场需求的逐步扩大,很多便捷的软件和网站都被设计出来了,比如小编 ...

  2. Deco 智能代码体验版正式上线啦,快来体验设计稿一键生成代码~

    Deco 是什么?- Deco 智能代码项目是我们团队在「前端智能化」方向上的探索,其聚焦设计稿一键生成多端代码这一切入点,实现将 Sketch/Photoshop 等设计稿进行解析并直接生成多端代码 ...

  3. 京东Deco 智能代码体验版正式上线啦,快来体验设计稿一键生成代码~

    点击上方 前端Q,关注公众号 回复加群,加入前端Q技术交流群 Deco 是什么? - Deco 智能代码项目是我们团队在「前端智能化」方向上的探索,其聚焦设计稿一键生成多端代码这一切入点,实现将 Sk ...

  4. 国产开源「文本-视频生成」模型!免费在线体验,一键实现视频生成自由

    原文链接:全球首发,国产开源「文本-视频生成」模型!免费在线体验,一键实现视频生成自由 去年4月,OpenAI发布的DALL-E 2用更高的分辨率.更真实的图像生成以及更准确地理解自然描述,横扫整个A ...

  5. 教你用支付宝一键生成证件照,简单又实用,效果比照相馆的好太多

    教你用支付宝一键生成证件照,简单又实用,效果比照相馆的好太多 在工作和生活中,我们有很多时候需要用到自己的证件照,去照相馆拍照有时候不方便还麻烦,拍摄的效果自己不满意,今天来跟大家分享一下如何用支付宝 ...

  6. 获取当前横竖屏_Chrome扩展程序一键生成网页骨架屏

    对于依赖接口渲染的页面,在拿到数据之前页面往往是空白的,为了提示用户当前正在加载中,往往会使用进度条.loading图标或骨架屏的方式.对于前两种方案而言,实现比较简单:本文主要研究骨架屏的应用及实现 ...

  7. python把一堆图片分成n份,用Python一键生成炫酷九宫格图片,火了朋友圈

    原标题:用Python一键生成炫酷九宫格图片,火了朋友圈 作为一个男同胞来说,为了给女朋友拍一张美美的照片,着实需要花费很大的时间和精力,不仅仅需要从众多的图片中精心挑选,而且还需要有着超强的图片精修 ...

  8. activex for chrome扩展程序 下载”_Chrome扩展程序一键生成网页骨架屏

    对于依赖接口渲染的页面,在拿到数据之前页面往往是空白的,为了提示用户当前正在加载中,往往会使用进度条.loading图标或骨架屏的方式.对于前两种方案而言,实现比较简单:本文主要研究骨架屏的应用及实现 ...

  9. CVPR 2020丨基于范例的精细可控图像翻译CoCosNet,一键生成你心目中的图像

    编者按:图像翻译是近年来的研究热点,类比于自然语言翻译,它将输入图像的表达转化为另一种表达,在图像创作.图像风格化.图像修复.域自适应学习等领域有着广泛应用.然而现有技术通常仅能产生合理的目标域图像, ...

最新文章

  1. Android隐藏状态栏和标题栏,相当于全屏效果
  2. 宏基因组实战7. bwa序列比对, samtools查看, bedtools丰度统计
  3. jQuery原理系列-css选择器实现
  4. java for 嵌套_Java中的for循环嵌套
  5. Java NIO示例:多人网络聊天室
  6. 关于vue外卖项目的一些总结
  7. C#条件编译,发布多平台和多种选择性的项目
  8. 没有什么不可能!郴州女孩江梦南,从双耳失聪到清华博士!
  9. SQL Server数据库查询速度慢的原因
  10. linux kernel source code analysis
  11. LinkedHashMap如何保证有序
  12. QCSPCChart SPC for JS
  13. spring配置c3p0连接池
  14. dubbo源码解析(二)springBoot+dubbo案例整合
  15. open ai gpt_GPT-3:第一个人工智能?
  16. LED软模组圆弧屏、弧形屏、柔性软屏、创意LED显示屏案例
  17. 如何用excel搭建数据模型,销售数据管理软件
  18. VBA打印机设置(列出所有打印机名字、选用合适的打印机并设计端口号)
  19. 重构业务系统,我是这样做的
  20. 解决锐捷客户端出现密码不匹配,请输入正确密码问题

热门文章

  1. cocos creator画线绕圈的实现方式,包括绕圈和回退
  2. Update:实时后端云服务野狗获 2400 万 Pre-A 融资
  3. 带上这份说明书,痛痛快快吃一顿日式烧肉!
  4. 电影优惠卡html页面,一款HTML5简约风的电影卡片模板(列表)
  5. 昨天、今天和明天,135天了
  6. 网络通信编程学习笔记(六):socket编程实战
  7. ext editorGridpanel 验证
  8. java计算机毕业设计科技专业师生沟通平台源程序+mysql+系统+lw文档+远程调试
  9. 在matlab表示特殊矩阵,MATLAB特殊矩阵以及矩阵转置
  10. Android Studio两种控件布局