この記事は、Advent Calendar 2019 21日目の記事です。
こんにちは19のhosshiiです。
今回はAA動画っぽいものを作っていきます。そんなの変換用のwebサイトに突っ込めば終わりじゃない?
pythonでやってますがpython初心者なのでかなり変なところもあると思います。許してくだしあ
実行環境
os macOS Catalina
python3.7.4
目標
動画をAAっぽいgifにする
こんな感じ
やってみる
今回動画変換するにあたって、
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さんの記事です。楽しみですね!