知識(shí)
不管是網(wǎng)站,軟件還是小程序,都要直接或間接能為您產(chǎn)生價(jià)值,我們?cè)谧非笃湟曈X(jué)表現(xiàn)的同時(shí),更側(cè)重于功能的便捷,營(yíng)銷(xiāo)的便利,運(yùn)營(yíng)的高效,讓網(wǎng)站成為營(yíng)銷(xiāo)工具,讓軟件能切實(shí)提升企業(yè)內(nèi)部管理水平和效率。優(yōu)秀的程序?yàn)楹笃谏?jí)提供便捷的支持!
10萬(wàn)+的短視頻被批量生產(chǎn)了,Python表示不服
發(fā)表時(shí)間:2019-9-14
發(fā)布人:葵宇科技
瀏覽次數(shù):39
作者丨星安果
來(lái)源丨AirPython
1
目 標(biāo) 場(chǎng) 景
前期有些自媒體大 V 靠搬運(yùn)一些搞笑、好玩的 GIF,然后利用剪輯軟件合成一段視頻,再添加一個(gè)節(jié)奏感強(qiáng)的 BGM 后,上傳各大自媒體平臺(tái)后,能帶來(lái)不錯(cuò)的閱讀量和收益。
本篇文章的目的是帶大家利用 Python 實(shí)現(xiàn)制作 GIF 動(dòng)畫(huà)視頻,批量制作短視頻這一騷操作。
2
準(zhǔn) 備 工 作
# moviepy 用于視頻剪輯和背景音樂(lè)的合成、剪輯
pip3 install moviepy
另外,項(xiàng)目中需要利用「PIL」庫(kù)來(lái)分析、獲取 GIF 動(dòng)畫(huà)中的所有幀圖片。
# 將GIF圖片轉(zhuǎn)為幀,需要對(duì)GIF進(jìn)行分析
pip3 install ffmpeg
另外再準(zhǔn)備一段 BGM 作為視頻的背景音樂(lè)。
3
編 寫(xiě) 腳 本
第一步,我們需要把每一個(gè) GIF 動(dòng)畫(huà)轉(zhuǎn)為一段視頻。
由于 GIF 動(dòng)畫(huà)已經(jīng)是一段包含很多幀的視頻了,沒(méi)法直接通過(guò) moviepy 庫(kù)轉(zhuǎn)為一段普通視頻。
所以,這里需要對(duì) GIF 動(dòng)畫(huà)進(jìn)行分析,將動(dòng)畫(huà)轉(zhuǎn)為「靜態(tài)幀圖片」。
def get_gif_frames(gif_path, temp_path):
"""
獲取一段GIf圖片下的所有靜態(tài)幀
get_gif_frames('./../gifs/3.gif', './../gif_temp/')
:return:
"""
# 分析gif圖片
mode = analyseImage(gif_path)['mode']
im = Image.open(gif_path)
i = 1
p = im.getpalette()
last_frame = im.convert('RGBA')
try:
while True:
# print("saving %s (%s) frame %d, %s %s" % (gif_path, mode, i, im.size, im.tile))
'''
If the GIF uses local colour tables, each frame will have its own palette.
If not, we need to apply the global palette to the new frame.
'''
if not im.getpalette():
im.putpalette(p)
new_frame = Image.new('RGBA', im.size)
'''
Is this file a "partial"-mode GIF where frames update a region of a different size to the entire image?
If so, we need to construct the new frame by pasting it>if mode == 'partial':
new_frame.paste(last_frame)
new_frame.paste(im, (0, 0), im.convert('RGBA'))
new_frame.save(temp_path + '/%s-%d.png' % (''.join(os.path.basename(gif_path).split('.')[:-1]), i), 'PNG')
i += 1
last_frame = new_frame
im.seek(im.tell() + 1)
except EOFError:
# print('產(chǎn)生EOFError!!!')
pass
另外,我們下載的 GIF 動(dòng)畫(huà)的靜態(tài)幀圖片分辨率大概率是不一致的,所以對(duì)圖片批量修改分辨率「修改分辨率」變的很有必要。
這里將所有圖片的分辨率統(tǒng)一修改為 720*1080,在轉(zhuǎn)換的過(guò)程中,如果存在空白部分,就使用黑色進(jìn)行填充。
def resize_image(target_image_path, target_size):
"""
調(diào)整圖片大小,缺失的部分用黑色填充
:param target_image_path: 圖片路徑
:param target_size: 分辨率大小
:return:
"""
image = Image.open(target_image_path)
iw, ih = image.size # 原始圖像的尺寸
w, h = target_size # 目標(biāo)圖像的尺寸
scale = min(w / iw, h / ih) # 轉(zhuǎn)換的最小比例
# 保證長(zhǎng)或?qū)?#xff0c;至少一個(gè)符合目標(biāo)圖像的尺寸
nw = int(iw * scale)
nh = int(ih * scale)
image = image.resize((nw, nh), Image.BICUBIC) # 縮小圖像
# image.show()
new_image = Image.new('RGB', target_size, (0, 0, 0, 0)) # 生成黑色圖像
# // 為整數(shù)除法,計(jì)算圖像的位置
new_image.paste(image, ((w - nw) // 2, (h - nh) // 2)) # 將圖像填充為中間圖像,兩側(cè)為灰色的樣式
# new_image.show()
# 覆蓋原圖片
new_image.save(target_image_path)
在轉(zhuǎn)換為視頻之前,我們需要提供一個(gè)「合理的轉(zhuǎn)換幀率」來(lái)保證視頻播放的流暢性。由于最后需要將多段視頻合成為一段視頻,這里默認(rèn)指定幀率為 10幀/s。
GIF 動(dòng)畫(huà)原始的幀率、播放時(shí)長(zhǎng)等動(dòng)畫(huà)文件屬性值可以利用「imgpy」獲取到。 def get_gif_info(gif_path):
"""
獲取gif文件的詳細(xì)信息
每一個(gè)gif的幀率不一樣,有的<10fps;有的>10fps
:param gif_path:
:return:
"""
with Img(fp=gif_path) as im:
# 1.有多少幀
frame_count = im.frame_count
# 2.圖片信息
# {'version': b'GIF89a', 'background': 31, 'duration': 70, 'extension': (b'NETSCAPE2.0', 795), 'loop': 0}
duration_pre = im.info.get('duration')
# 根據(jù)規(guī)律,除以7位實(shí)際的播放時(shí)長(zhǎng)
duration = duration_pre / 7
# 6.color palette
# print(im.mode_desc)
# print((frame_count, duration))
# 返回幀率和時(shí)長(zhǎng)
return (frame_count / duration), duration
def pics_to_video(pics_path, output_path, fps, duration):
"""
圖片轉(zhuǎn)為視頻
pics_to_video('./../gif_temp/', './../video_temp/temp1.mp4', 20)
:param pics_path:
:param output_path:
:return:
"""
image_paths = list(map(lambda x: pics_path + x, os.listdir(pics_path)))
# 注意:這里必須進(jìn)行一次排序,保證所有幀的順序是一致
image_paths = sort_strings_with_emb_numbers(image_paths)
# 過(guò)濾掉非圖片
image_paths = list(filter(lambda image_path: image_path.endswith('.png'), image_paths))
# 圖片剪輯類(lèi)
clip = ImageSequenceClip(image_paths,
fps=fps)
# 寫(xiě)成視頻之前,需要把gif都轉(zhuǎn)成同一個(gè)分辨率
clip.write_videofile(output_path)
第二步是將所有的視頻文件進(jìn)行剪輯,寫(xiě)入一個(gè)單獨(dú)的文件中。利用 moviepy 庫(kù)下面的 「 VideoFileClip 」可以非??旖莘奖愕赝瓿蛇@一操作。
def compound_a_video(self, videos_path):
"""
合成一個(gè)視頻
:param videos_output:視頻集合的完整目錄
:return:
"""
# 定義一個(gè)數(shù)組
L = []
for video_path in videos_path:
# 載入視頻
video = VideoFileClip(video_path)
# 添加到數(shù)組
L.append(video)
# 拼接視頻
final_clip = concatenate_videoclips(L)
# 生成目標(biāo)視頻文件
final_clip.to_videofile(self.video_output_temp, fps=self.fps, remove_temp=False)
最后一步是往視頻中添加背景音樂(lè)。
# 1.音頻文件
audioclip = AudioFileClip(self.bgm_path)
# 2.視頻文件
videoclip = VideoFileClip(self.video_output_temp)
# 3.獲取視頻和音頻的時(shí)長(zhǎng)
video_time = videoclip.duration
audio_time = audioclip.duration
print('視頻時(shí)長(zhǎng):%f,音頻時(shí)長(zhǎng):%f' % (video_time, audio_time))
# 4.對(duì)視頻或者音頻進(jìn)行裁剪
if video_time > audio_time:
# 視頻時(shí)長(zhǎng)>音頻時(shí)長(zhǎng),對(duì)視頻進(jìn)行截取
ideoclip_new = videoclip.subclip(0, audio_time)
audioclip_new = audioclip
else:
# 音頻時(shí)長(zhǎng)>視頻時(shí)長(zhǎng),對(duì)音頻進(jìn)行截取
videoclip_new = videoclip
audioclip_new = audioclip.subclip(0, video_time)
然后把音頻文件通過(guò) set_audio() 添加到視頻操作類(lèi)中,最后重新寫(xiě)入到一個(gè)新的視頻文件當(dāng)中。
# 5.視頻中加入音頻
video_with_new_audio = videoclip_new.set_audio(audioclip_new)
# 6.寫(xiě)入到新的視頻文件中
video_with_new_audio.write_videofile("mp4_with_audio.mp4",
codec='libx264',
audio_codec='aac',
temp_audiofile='temp-audio.m4a',
remove_temp=True
)
4
結(jié) 果 結(jié) 論
以上的腳本會(huì)對(duì)指定文件夾的的 GIF 動(dòng)畫(huà)文件分別生成一段普通視頻,然后把所有的視頻合成一段視頻,然后再添加一段 BGM 背景音樂(lè),最后寫(xiě)入到一個(gè)新的視頻文件中,如此,就完成了制作一個(gè) GIF 視頻的操作。
當(dāng)然,本文只是提供一個(gè)思路,讓 Python 爬取一些有趣好玩的 GIF 動(dòng)畫(huà)進(jìn)而批量做成視頻,上傳各大自媒體平臺(tái),應(yīng)該也能獲取到不錯(cuò)的閱讀量。
如果你覺(jué)得文章還不錯(cuò),請(qǐng)大家點(diǎn)贊分享下。你的肯定是我最大的鼓勵(lì)和支持。
源碼鏈接:
https://github.com/xingag/tools_python/tree/master/video_auto/%E5%88%B6%E4%BD%9CGIF%E8%A7%86%E9%A2%91
推薦↓↓↓
長(zhǎng)
按
關(guān)
注
?【16個(gè)技術(shù)公眾號(hào)】都在這里!
涵蓋:程序員大咖、源碼共讀、程序員共讀、數(shù)據(jù)結(jié)構(gòu)與算法、黑客技術(shù)和網(wǎng)絡(luò)安全、大數(shù)據(jù)科技、編程前端、Java、Python、Web編程開(kāi)發(fā)、Android、iOS開(kāi)發(fā)、Linux、數(shù)據(jù)庫(kù)研發(fā)、幽默程序員等。
相關(guān)案例查看更多
相關(guān)閱讀
- 網(wǎng)站開(kāi)發(fā)
- 小程序開(kāi)發(fā)聯(lián)系方式
- 網(wǎng)站優(yōu)化
- 云南網(wǎng)站建設(shè)專(zhuān)業(yè)品牌
- 網(wǎng)站小程序
- 迪慶小程序開(kāi)發(fā)
- 云南網(wǎng)站建設(shè)靠譜公司
- 昆明小程序哪家好
- APP
- 小程序生成海報(bào)
- 云南小程序開(kāi)發(fā)公司
- 網(wǎng)站制作哪家好
- 開(kāi)通微信小程序被騙
- 汽車(chē)報(bào)廢管理系統(tǒng)
- 云南旅游網(wǎng)站建設(shè)
- 昆明做網(wǎng)站建設(shè)的公司排名
- 南通小程序制作公司
- 微信小程序開(kāi)發(fā)入門(mén)課程
- 云南網(wǎng)站開(kāi)發(fā)
- 云南網(wǎng)站建設(shè)公司
- 云南軟件定制
- 云南建設(shè)廳網(wǎng)站首頁(yè)
- 做網(wǎng)站
- 汽車(chē)報(bào)廢回收管理系統(tǒng)
- 百度自然排名
- 云南小程序開(kāi)發(fā)報(bào)價(jià)
- 網(wǎng)站建設(shè)制作
- 網(wǎng)站建設(shè)首選
- 昆明網(wǎng)絡(luò)公司
- 網(wǎng)站開(kāi)發(fā)公司哪家好