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班に所属してます

この記事をシェア

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

関連する記事

2023年3月30日
みやぎハッカソン2023に参加しました(ずんだ食べ食べ委員会)
mehm8128 icon mehm8128
2022年10月11日
アルゴリズム班にKaggle部を設立し、初心者向けデータ分析体験会を開催しました!
abap34 icon abap34
2021年4月18日
ベズー係数とN項の拡張ユークリッドの互除法
0214sh7 icon 0214sh7
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
記事一覧 タグ一覧 Google アナリティクスについて