python自動製做gif並添加文字

引言

    最近租的房子快到期了,哎,由於去年是第一次找房子租,結果遇到了一個東北黑中介,押一付三,房子有啥問題,燈壞了,下水道堵了,原來籤合同的時候說的客氣,說是立刻就會上門解決,結果實際上我每次找他,都是各類推脫,最後不了了之。所有是我本身想辦法解決的。如今又打電話催着我要搬走,押金也不打算退給我了。真的是rlgl。我反對地域黑,可是之後東北的中介一輩子黑。(再次聲明,不是地域黑,我也有認識的人很好的東北的朋友。)今天我又看到了有錢能夠隨心所欲的經典gif,因此我心血來潮想作一個本身的東北黑中介版的隨心所欲gif。原本我想找一個沒有文字的gif,而後找一個軟件添加文字,而後合成gif的。結果在網上搜索了一下,沒有找到合適的原版gif,只找到了一個有文字的gif。到是有軟件能夠手動添加文字合成gif的,可是若是要首先把原來的文字去除,而後再一點點添加,手動要作大量的工做,非常麻煩。我再嘗試了半個小時還沒弄好就放棄了(可是我想應該有比較簡便的方法,只是我懶得再本身去找了)。最後我想既然做爲一個程序員,能不能經過代碼去實現這個功能呢?固然能夠啦。我最熟悉的是python,天然優先考慮上python了。以前接觸過PIL這個庫,我記得它有給圖片添加文字的功能,並且最近不是纔剛剛看了moviepy這個庫,它能夠很容易合成gif,把這兩個結合到一塊兒不就很容易實現我想要的目標了嗎?一不作二不休,開搞!

1. 處理gif以及基本思路

    我找到的原始的gif以下圖1所示:

圖1 原始"隨心所欲"gif(來自微博)

若是你的電腦已經安裝了ffmpeg的話,那麼將gif分割成單幀的序列圖片是很是容易的,運行下面的命令:python

ffmpeg -i 隨心所欲.gif %d.jpg

就能夠將隨心所欲.gif分割成1.jpg,2.jpg,...。固然你也能夠直接使用python的PIL庫來處理gif,使用以下的代碼便可:程序員

from PIL import Image,ImageSequence
gif = Image.open("隨心所欲.gif")
for i,frame in enumerate(ImageSequence.Iterator(gif),1):
    frame.save("%d.jpg" % i)

或者你也可使用以前介紹過的moviepy庫(具體能夠參考我以前的一篇博客),若是你對opencv比較熟悉的話,天然也可使用opencv來處理。這裏就不詳細說了。
    獲得gif的幀序列圖像以後,簡單來講一下後面處理的思路。由於原來的gif有些幀是有文字的,咱們要想添加本身的文字,就必需要把原來的文字去除掉,而後換成本身的。因此後面基本的思路就是:shell

  • 找出那些有文字出現的幀,把文字去除;
  • 原來的文字去除以後,替換成本身的合適的文字,造成新的幀圖像;
  • 將新的幀圖像合成爲新的gif(這裏使用moviepy合成)。

2. 實現代碼以及簡要解析

具體實現代碼以下:函數

# -*- coding:utf-8 -*-
import matplotlib.pyplot as plt 
from PIL import Image,ImageDraw,ImageFont
from scipy.misc import imread,imsave,imresize
import numpy as np 
import os
from glob import glob
from moviepy.editor import ImageSequenceClip
# 消除文字的圖片序號
modify_img_index = list(range(11,14))+list(range(27,37)) + list(range(44,61)) + list(range(62,81)) \
                    + list(range(82,94)) + list(range(97,106)) + list(range(112,132)) + list(range(146,168))
text_info = [('好啊',(120,140))]*(14-11) + \
            [('就算你今天找人來抗議',(40,140))]*(37-27)  + \
            [('就算你的理由再完美',(50,140))] *(61-44)  + \
            [('我想不退錢就不退錢',(50,140))] *(81-62) + \
            [('畢竟我是東北黑中介',(50,140))] *(94-82) + \
            [('東北黑中介了不得啊',(50,140))] *(106-97) + \
            [('sorry,東北黑中介真的能夠隨心所欲',(5,140))]*(132-112) + \
            [('之後讓他每天鬧',(60,140))]*(158-146) + \
            [('每天鬧',(110,140))]*(169-158)
index_to_text = dict(zip(modify_img_index,text_info))
# 保存圖片文件夾
save_dir = "output"
if not os.path.exists(save_dir):
    os.mkdir(save_dir)
new_color = np.array([50,50,50]) # 消除文字以後的顏色
fontsize = 18
fontcolor = (0,255,255)
fps = 10
resize_scale = 1.5 # 新圖的寬和高是原來的多少倍
# 消除文字的x,y邊界座標
y_begin = 10
y_end = 280
x_begin = 140
x_end = 160
# 所有文件列表(無序)
img_names = glob("*.jpg")
#print(img_names)
def modify():
    # 遍歷每個圖像
    for img_name in img_names:
        img = imread(img_name)
        h,w = img.shape[0],img.shape[1]
        #plt.imshow(img)
        img_new = np.copy(img)
        index = int(img_name.split(".")[0])
        # 若是圖片有文字,須要修改
        if index in modify_img_index:
            # 消除文字
            img_new[x_begin:x_end,y_begin:y_end] = new_color
            text,pos = index_to_text[index]
            img_new = drawtext(Image.fromarray(img_new),text,pos,fontsize,fontcolor)
            #保存新的圖片
            # imsave(os.path.join(save_dir,img_name),img_new)
            if resize_scale != 1:
                # resize
                img_new = img_new.resize((int(w*resize_scale),int(h*resize_scale)))
                img_new.save(os.path.join(save_dir,img_name))
            print("Modify and save %s!" % img_name)
        else:
            # 沒有文字,不須要修改,直接保存原來的圖片
            if resize_scale != 1:
                img = imresize(img,resize_scale)
                imsave(os.path.join(save_dir,img_name),img)
            print("Save %s!" % img_name)
def drawtext(img,text,pos,fontsize,fontcolor):
    '''
    draw text for img
    @param img:image to draw text
    @param text:text to draw
    @param pos:where to draw the text((x,y))
    @param fontsize: font size
    @param fontcolor: font color
    '''
    font = ImageFont.truetype("simsun.ttc",fontsize)
    draw = ImageDraw.Draw(img)
    draw.text(pos,text,fontcolor,font = font)
    # plt.imshow(img)
    # plt.show()
    return img 
def test_drawtext():
    img_name = "4.jpg"
    img = Image.open(img_name)
    #text = "好啊"
    text = "東北黑中介了不得啊"
    pos = (40,140)
    fontsize = 20
    fontcolor = (0,255,255)
    drawtext(img,text,pos,fontsize,fontcolor)
# 利用圖像序列生成gif
def generate_gif(img_names,save_path,fps = 10):
    # img_names:list of image names
    clip = ImageSequenceClip(img_names,fps = fps)
    clip.write_gif(save_path)
    print("Write %s successfully!" % save_path)

# 主函數
def main():
    modify()
    save_gif_path = os.path.join(save_dir,"東北黑中介.gif")
    img_names = sorted(glob(os.path.join(save_dir,"*.jpg")),key = lambda x: int(x.split(".")[0].split("/")[1]))
    generate_gif(img_names,save_gif_path,fps)

#test_drawtext()
if __name__ == '__main__':
    main()

上面的代碼思路其實仍是比較清楚的。主要麻煩的地方就在於,咱們無法自動確認哪些幀出現了文字,因此在這裏我採用手動觀察圖像(有167張圖)的方式,肯定了出現文字的幀序列區間;而後對於這些幀序列區間,其文字替換成我本身的文字。還有一個問題就是,我要消除文字,就要知道文字的位置,其實這個能夠歸結爲一個目標檢測的問題,或者說是一個OCR問題(OCR的第一步,定位文字),可是OCR作起來仍是很麻煩的,這裏暫時不說,後面有空我會專門討論OCR問題。這裏比較好的地方在於,全部的文字出現的高度位置幾乎是同樣的,只是寬度方向的位置不同(有的字多,有的字少),這裏我仍是採用手動觀察標註的辦法,能夠藉助於matplotlib顯示圖像,用鼠標點擊圖像的某一點,它會顯示該點的(x,y)座標和像素值,這樣咱們就能夠手動肯定要消除的文字的位置,以及消除文字要填充的顏色了。按照這個思路,咱們能夠獲得一些消除原來文字,添加新文字以後的圖像以下圖2所示:
code


圖2 原始幀和消除文字後添加新文字的幀(上是原始幀,下是處理以後的新幀)

    最終合成的新的gif以下圖3所示:

圖3 最終合成的gif

3. 小結

    本文主要利用python的PIL庫(用於處理圖像,添加文字等)和moviepy(用於生成gif)自動生成了gif並添加了文字。可是還有一些問題,好比文字自動定位並識別沒有解決。這些問題留到後面介紹OCR技術的時候再和你們介紹。若是隻是簡單地嘗試合成gif,你們不妨本身動手試一試。

全文完,感謝閱讀!

相關文章
相關標籤/搜索