天天看點

【paddlepaddle】PaddleHub創意項目

文章目錄

    • 寫在前面
    • 思路
    • 技術棧
    • 模型介紹
    • 模型效果展示
    • 核心代碼

寫在前面

當《空山新雨後》的小姐姐遇上了《你的名字》,這将會是一場怎樣的盛宴呢!

最近被《空山新雨後》瘋狂洗腦,在B站看到小姐姐的歌伴舞後就有了給小姐姐換個背景的相法,
于是找來了你的名字的照片,讓小姐姐在星空下配合着悅耳的歌翩翩起舞
           

項目AIstudio位址:https://aistudio.baidu.com/aistudio/projectdetail/765734

視訊B站位址:https://www.bilibili.com/video/BV1QV41127gd/

思路

  1. 将原視訊提取為1幀1幀的圖檔
  2. 對每一張圖檔做人物分割和背景合成兩部分工作
  3. 将第二步得到的圖檔按照順序合并成一個新的視訊(注意這裡的視訊是沒有聲音的)
  4. 将原視訊的bgm添加到新合成的視訊上面

技術棧

  • paddlehub
  • deeplabv3p_xception65_humanseg(paddlehub提供的人物分割的模型)
  • opencv

模型介紹

DeepLabv3+ 是Google DeepLab語義分割系列網絡的最新作,其前作有 DeepLabv1, DeepLabv2, DeepLabv3。在最新作中,作者通過encoder-decoder進行多尺度資訊的融合,同時保留了原來的空洞卷積和ASSP層, 其骨幹網絡使用了Xception模型,提高了語義分割的健壯性和運作速率,在 PASCAL VOC 2012 dataset取得新的state-of-art performance。該PaddleHub Module使用百度自建資料集進行訓練,可用于人像分割,支援任意大小的圖檔輸入。點選檢視詳情

模型效果展示

【paddlepaddle】PaddleHub創意項目

核心代碼

step1: 從視訊中提取幀

#從視訊中提取幀
def extract_images(src_video, dst_dir):
    '''
    src_video:為目标的視訊檔案位址
    dst_dir:為視訊圖檔的儲存路徑
    '''
    video = cv2.VideoCapture(src_video)
    
    count = 0
    with tqdm(total=video.get(cv2.CAP_PROP_FRAME_COUNT)) as pbar:
        while True:
            flag, frame = video.read()
            if not flag:
                break
            cv2.imwrite(os.path.join(dst_dir, str(count) + '.png'), frame)
            count = count + 1
            pbar.update(1)
    print('extracted {} frames in total.'.format(count))
           

step2: 分割圖像

#分割圖像
def seg():
    dst_img_dir = './work/images'
    img_list = os.listdir(dst_img_dir)
    img_list = [os.path.join(dst_img_dir,str(i)+'.png') for i in range(5085)]
    print(len(img_list))
    module = hub.Module(name="deeplabv3p_xception65_humanseg")
    from tqdm import trange
    try:
        with trange(len(img_list)) as pbar:
            for i in pbar:
                tmp_list = []
                tmp_list.append(img_list[i])
                module.segmentation(data={'image':tmp_list},use_gpu=True,visualization =True,output_dir='output')
                pbar.set_description("Processing %s" % img_list[i].split('/')[-1])
    except KeyboardInterrupt:
        pbar.close()
        raise
    pbar.close()
           

step3: 圖檔轉換為視訊

#圖檔轉換為視訊
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)
    try:
        with trange(len(os.listdir(pic_path))) as pbar:
            for index in pbar:
                frame = cv2.imread(os.path.join(pic_path,'{}.png'.format(index)))
                dst_video.write(frame)
                pbar.set_description("Processing %s.png" % index)
    except KeyboardInterrupt:
        pbar.close()
        raise
    pbar.close()
    dst_video.release()
           

step4: 添加bgm

#給視訊加聲音
def add_audio(s_video_path,d_video_path,name):
    '''
    給視訊加聲音
    :param s_video_path: 原視訊位址-含有聲音的
    :param d_video_path: 目的視訊位址-需要加聲音的
    :return:
    '''
    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]+name)