【飛槳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)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章