feature image

2019年11月20日 | ブログ記事

AAっぽい動画を作る【Advent Calendar 2019 21日目】

この記事は、Advent Calendar 2019 21日目の記事です。

こんにちは19のhosshiiです。
今回はAA動画っぽいものを作っていきます。そんなの変換用のwebサイトに突っ込めば終わりじゃない?
pythonでやってますがpython初心者なのでかなり変なところもあると思います。許してくだしあ


実行環境

os macOS Catalina
python3.7.4

目標

動画をAAっぽいgifにする
movie2gif-1
こんな感じ

やってみる

今回動画変換するにあたって、

1.動画をフレームごとに切り出す
2.切り出した画像をAAっぽくした画像を作る
3.それを今度はもう一度つなげてgifにする

という手順でやってみたいと思います。

1.動画をフレームごとに切り出す

pillowというライブラリを使ってやっていきます。
pillowで動画を1フレームずつ読み込んでいきます。

cap = cv2.VideoCapture("ビデオファイルのパス")

でビデオを読み込んでいきます。

while(cap.isOpened()):
        video_file='./test2.mp4'
        image_dir='./image_dir/'
        image_file='img_%s.png'
        flag, frame = cap.read()  # 動画を1フレームずつ読み込む
        if not flag:
            break
        #################
        #切り出した画像の処理
        #################
        i += 1

まず最初にビデオのファイル名(video_file)を定義しています。
2行目で動画を1フレームずつ読み込んでいます。flagには読み込身が成功したかどうかが入って,画像データはframeに入っています。

2.切り出した画像の処理

#################
#切り出した画像の処理
#################

のところに書いていきます。

まず

image_pil = Image.fromarray(frame)
resize = image_pil.resize((200, 80), Image.LANCZOS)
gray_img = resize.convert('L')

で読み込んだ画像をグレースケールに変換していきます。次に

img_dot_array = np.array(gray_img)
norm_img_array = img_dot_array / 255
lines = [0]*gray_img.size[1]

で動画の明るさを0~1の範囲にしてそれを配列に格納します。そしてその格納した値に対を、AAに変換していきます

for i in range(0, gray_img.size[1]):
        print(' ')
        for j in range(0, gray_img.size[0]):
            if norm_img_array[i, j] > 0.9: # 明るさが0.9より上だったら#を割り当てる
                # print('#', end='')
                lines[i] = '#' if j == 0 else lines[i] + '#'
            elif norm_img_array[i, j] > 0.7: # 明るさが0.7より上だったらkを割り当てる
                # print('k', end='')
                lines[i] = 'k' if j == 0 else lines[i] + 'k'
            elif norm_img_array[i, j] > 0.5: # 明るさが0.5より上だったら>を割り当てる
                # print('>', end='')
                lines[i] = '>' if j == 0 else lines[i] + '>'
            elif norm_img_array[i, j] > 0.3: # 明るさが0.3より上だったら'を割り当てる
                # print('\'', end='')
                lines[i] = '\'' if j == 0 else lines[i] + '\''
            else:
                # print(' ', end='')
                lines[i] = ' ' if j == 0 else lines[i] + ' '
    print('\033[H')

ここでは、実際に明るさ(norm_img_array[i, j])に対して文字を割り当てています。今回の場合、明るさが0.9より大きい場合は#、0.7より大きい場合はk、0.5より大きい場合は>、0.3より大きい場合は'、それ以下の場合は空白を割り当てています。その割り当てた文字を、linesという配列に格納しています。(途中のコメントアウトしてあるprint関数(# print('\'', end=''))とかを有効にすればターミナルでもみれます。)

3.それを今度はもう一度つなげてgifにする

これもpillowでできます。

font = ImageFont.truetype(
        "フォントのパス", 17)
w, h = max(font.getsize(line) for line in lines)
img = Image.new("RGB", (w, h*len(lines)), "#000000")
draw = ImageDraw.Draw(img)

for i, line in enumerate(lines):
    # print(line)
    draw.text((0, i*h), line, fill="#ffffff")
images.append(img)

pillowの機能で配列を一行ずつ書いて、それをimages配列に格納しています。あとは全フレームに対して処理が終わったら

images[0].save('pillow_imagedraw.gif',save_all=True, append_images=images[1:], optimize=False, duration=40, loop=0)

これでimagesに格納したgifが保存されるはずです。

終わりに

pythonって色々あってすごいですね。
今回作ったやつはここにあります。

参考

https://qiita.com/yusukeasari/items/3eaddfbb3a25f37d8e08
https://qiita.com/scrpgil/items/1b227b309113d1381b3a
http://testpy.hatenablog.com/entry/2017/07/13/003000
https://qiita.com/yukid/items/a96a036564e1c93c3ae9


今日はd_etteiu8383さんの記事も投稿されているのでぜひそちらもご覧ください。
明日はAmanogawaさんの記事です。楽しみですね!

hosshii icon
この記事を書いた人
hosshii

SysAd班に所属してます

この記事をシェア

このエントリーをはてなブックマークに追加
共有

関連する記事

2019年12月21日
モデリングを始めてみたい君へ、MagicaVoxelのススメ
isak icon isak
2019年12月13日
ゲーム紹介「League of Legends」【AdC2019 44日目】
Yataka_ML icon Yataka_ML
2017年11月4日
文章をよしなに分散表現しよう
David icon David
2019年12月25日
TensorFlow.jsでwasmを使ってみるためにコントリビュートした【AdC2019 56日目】
sappi_red icon sappi_red
2019年12月25日
無料でDTM環境構築 電子音系編
liquid1224 icon liquid1224
2019年12月22日
部内製チャットサービス「traQ」UIのこれから 【AdC2019 53日目】
sigma icon sigma
記事一覧 タグ一覧 Google アナリティクスについて