【飞桨PaddlePaddle学习心得】paddle学习创意赛-人脸抠图

目标

paddlehub项目链接:https://aistudio.baidu.com/aistudio/projectdetail/437104

PaddleHub DeepLabv3+模型(deeplabv3p_xception65_humanseg)实现一键抠图

实现功能

1.实现单张小姐姐图片的抠图(背景替换)
2.实现对视频的抠图(背景替换)将红昭愿的视频更换为宇宙背景

实现思路

功能1:

单张图片抠图采用paddlehub真的是一键抠图呀。

#安装1.6的paddlehub
pip install paddlehub==1.6.0 -i https://pypi.tuna.tsinghua.edu.cn/simple -t /home/aistudio/external-libraries
import paddlehub as hub
# 待预测图片
test_img_path = ["./data/yu.jpg"]
import matplotlib.pyplot as plt 
import matplotlib.image as mpimg 
img = mpimg.imread(test_img_path[0]) 
# 展示待预测图片
plt.figure(figsize=(10,10))
plt.imshow(img) 
plt.axis('off') 
plt.show()

待抠图的图片:
在这里插入图片描述

#加载paddlehua提供的人脸分割的模型
module = hub.Module(name="deeplabv3p_xception65_humanseg")

#paddlehub的所有输入必须要是一个字典格式的data,并且字典里面的内容要是一个list
input_dict = {"image": test_img_path}#传入也必须是个字典,字典的value必须是个list

# execute predict and print the result使用模型得到结果
results = module.segmentation(data=input_dict)
for result in results:
    print(result)#打印结果

# 预测结果展示
test_img_path = "./humanseg_output/yu.png"
img = mpimg.imread(test_img_path)
plt.figure(figsize=(10,10))
plt.imshow(img) 
plt.axis('off') 
plt.show()

抠图结果:
在这里插入图片描述

可以发现,前面的街道背景已经没有了。对于各种情况下的真人扣取都试试了一下,发现效果都挺好的。下面是模型的实现结果

模型结果对比
在这里插入图片描述
背景替换函数:

#图像合成函数
from PIL import Image
import numpy as np
#blend 混合
def blend_images(fore_image, base_image,savepath):
    """
    将抠出的人物图像换背景
    fore_image: 前景图片,抠出的人物图片 为png格式 会多一个通道
    base_image: 背景图片
    savepath:图片要保存的路径,图片保存的文件名和前景图片的名字一样
    """
    # 读入图片
    fore_image_dir = fore_image
    base_image = Image.open(base_image).convert('RGB')#如果是png可能多了一个A通道
    fore_image = Image.open(fore_image).resize(base_image.size) #将前图缩放背后景图一样大小
    # 图片加权合成
    scope_map = np.array(fore_image)[:,:,-1] / 255
    scope_map = scope_map[:,:,np.newaxis] #np.newaxis 为 numpy.ndarray(多维数组)增加一个轴
    scope_map = np.repeat(scope_map, repeats=3, axis=2)
    res_image = np.multiply(scope_map, np.array(fore_image)[:,:,:3]) + np.multiply((1-scope_map), np.array(base_image))
    #保存图片
    res_image = Image.fromarray(np.uint8(res_image))
    save_path = os.path.join(savepath, os.path.basename(fore_image_dir))
    res_image.save(save_path)

在这里插入图片描述

功能2:视频换背景
实现的思路:
因为paddlehub的模型的喂数据的问题,所有不能直接喂视频,需要传入一个字典,字典里面需要是一个list的数据。
1.先读取视频,使用opencv按帧读取转为为图片

# video 2 images
###step1
def extract_images(src_video, dst_dir):
    '''
    src_video:为目标的视频文件地址
    dst_dir:为视频图片的保存路径
    '''
    video = cv2.VideoCapture(src_video)
    count = 0
    while True:
        flag, frame = video.read()
        if not flag:
            break
        cv2.imwrite(os.path.join(dst_dir, str(count) + '.png'), frame)
        count = count + 1
    print('extracted {} frames in total.'.format(count))

2.对1中最后得到的的所有图片进行人物抠图

###step2
def manSeg(img_path,out_dir):
    # test images
    test_image_list = [os.path.join(img_path, img_name) for img_name in os.listdir(img_path)]
    # segment images!
    input_dict = {"image": test_image_list}
    module.segmentation(data=input_dict,output_dir = out_dir)

3.对2中最后得到的所有图片与背景图片进行合成

# blend images
def blend_vides(input_dir,base_image,save_dir):
    index = 0
    for img in os.listdir(input_dir):
        print('总共{}张,处理到了{}张图片'.format(len(os.listdir(input_dir)),index+1))
        fore_image = os.path.join(input_dir,img)
        blend_images(fore_image, base_image, save_dir)

4.将3中合成的所有图片合成为视频

# image2video
#将扣图和背景组合的图片从新合成为视频(
def img2video(dst_video_path,pic_path,size,frame):
    '''
    dst_video_path:合成视频的路径
    pic_path:合成的所有图片的路径
    size:图片的大小,即是视频的大小
    frame:帧率

    VideoWriter_fourcc为视频编解码器
    fourcc意为四字符代码(Four-Character Codes),顾名思义,该编码由四个字符组成,下面是VideoWriter_fourcc对象一些常用的参数,注意:字符顺序不能弄混
    cv2.VideoWriter_fourcc('I', '4', '2', '0'),该参数是YUV编码类型,文件名后缀为.avi
    cv2.VideoWriter_fourcc('P', 'I', 'M', 'I'),该参数是MPEG-1编码类型,文件名后缀为.avi
    cv2.VideoWriter_fourcc('X', 'V', 'I', 'D'),该参数是MPEG-4编码类型,文件名后缀为.avi
    cv2.VideoWriter_fourcc('T', 'H', 'E', 'O'),该参数是Ogg Vorbis,文件名后缀为.ogv
    cv2.VideoWriter_fourcc('F', 'L', 'V', '1'),该参数是Flash视频,文件名后缀为.flv
    cv2.VideoWriter_fourcc('m', 'p', '4', 'v')    文件名后缀为.mp4
    '''

    dst_video = cv2.VideoWriter(dst_video_path, cv2.VideoWriter_fourcc(*'mp4v'), frame, size, True)
    for index in range(len(os.listdir(pic_path))):
        frame = cv2.imread(os.path.join(pic_path,'{}.png'.format(index)))
        dst_video.write(frame)
    dst_video.release()

5.给4中得到的视频添加bgm

def add_audio(s_video_path,d_video_path):
    video_s = VideoFileClip(s_video_path)
    video_d = VideoFileClip(d_video_path)
    audio_o = video_s.audio
    video_dd = video_d.set_audio(audio_o)

    video_dd.write_videofile(d_video_path[0:d_video_path.rfind('/')+1]+'hong_audio.mp4')

主函数:

def change_video_bk():
    ##1.将视频按帧提取出图片image_list
    src_video = './work/video/hong-withaudio.mov'
    dst_dir = './work/video-imgs'
    checkdir(dst_dir)#如果不存在就创建,存在就清除里面内容 check1
    #function1
    extract_images(src_video, dst_dir)

    ##2.对image_list所有的图片进行抠图,然后更换背景保存图片得到processed_image_list
    out_dir = './work/video-seg_out'
    checkdir(out_dir)     #check2
    #function2.1
    manSeg(dst_dir,out_dir)

    base_image = './work/img/sea.jpg'
    save_dir = './work/video-imgs'
    checkdir(save_dir)    #check3
    #function2.2
    blend_vides(out_dir,base_image,save_dir)

    #3.将processed_image_list中的所有图片组成为video
    save_dir = './work/video-imgs'
    base_image = './work/img/sea.jpg'
    result_video_dir = './work/video-result/'
    checkdir(result_video_dir) #check4
    result_video_name = os.path.join(result_video_dir,'hong.mp4')  #最终输出的视频的名字
    size = Image.open(base_image).size
    frame_size = 25
    #function3 图片合成为视频
    img2video(result_video_name,save_dir,size,frame_size)
    #function4 给视频加上bgm
    add_audio(src_video,result_video_name)
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值