質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

1回答

2664閲覧

Pythonを使って動画をアスキーアート化してターミナル上で再生したい。

34Noe

総合スコア3

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2021/07/13 11:15

前提・実現したいこと

まずPythonを使用して動画をフレームごとに切り分けて保存します。
その後アスキーアート化し、ターミナル上で上書きし続けながら出力するというものです。
###発生している問題
フレーム全てをアスキーアートへと変えることはできましたが、ターミナル上で上書きしながら出力し続けることができません。
そのためアスキーアートがターミナル上で流れるように出力(1枚1枚新しく表示)されてしまい、見づらいものになってしまいました。

特にこの二行が思った通りに動きません。
・sys.stdout.write("\r" + ascii_image)
・sys.stdout.flush()

###該当のソースコード

Pyhon3.7

1#指定したファイルから画像を読み込み、アスキーアートに変換し出力するプログラム 2import PIL.Image 3import cv2 4import sys 5import time 6 7ASCII_CHARS = ["@","#","S","%","?","*","+",";",":",",","."] 8 9#リサイズ 10def resize_image(image,new_width=100): 11 width,height = image.size 12 ratio = height / width 13 new_height = int(new_width * ratio) 14 resized_image = image.resize((new_width,new_height)) 15 return(resized_image) 16 17#グレースケール化 18def convert_grayscale(image): 19 grayscale_image = image.convert("L") 20 return(grayscale_image) 21 22#変換 23def pixels_to_ascii(image): 24 pixels = image.getdata() 25 characters = ''.join([ASCII_CHARS[pixel//25] for pixel in pixels]) 26 return(characters) 27 28 29def main(new_width=100): 30 31 for index in range(6565): 32 path = "frame/frame_" + str(index).zfill(4) +".jpg" 33 34 image = PIL.Image.open(path) 35 36 37 new_image_data = pixels_to_ascii(convert_grayscale(resize_image(image))) 38 39 pixel_count = len(new_image_data) 40 ascii_image = "\n".join([new_image_data[i:(i+new_width)] for i in range(0,pixel_count,new_width)]) #ascii化 41 42 43 sys.stdout.write("\r" + ascii_image) 44 sys.stdout.flush() 45 46 time.sleep(0.033) 47 48 49main()

Python3.7

1#こちらは動画からフレームごことに切り出すプログラム 2import cv2 3import os 4 5def save_all_frames(video_path="動画の名前と拡張子", dir_path="frame", basename="frame", ext='jpg'): 6 cap = cv2.VideoCapture(video_path) 7 8 if not cap.isOpened(): 9 return 10 11 os.makedirs(dir_path, exist_ok=True) 12 base_path = os.path.join(dir_path, basename) 13 14 digit = len(str(int(cap.get(cv2.CAP_PROP_FRAME_COUNT))))#総フレーム数の桁を取得 15 16 n = 0 17 18 while True: 19 ret, frame = cap.read() 20 if ret: 21 cv2.imwrite('{}_{}.{}'.format(base_path, str(n).zfill(digit), ext), frame)#画像で出力 22 n += 1 23 else: 24 return 25 26save_all_frames()

####補足
・アスキーアート化させたい画像はカレントディレクトリの一つ下のファイルに保存しています
/frame/frame_0000.jpg (0000から6565までの6566枚)

・1フレームあたりおよそ0.033秒ほどの表示時間で約30fpsほどです。

・参考にした動画 : リンク内容

至らない点も多々あるかと思いますがよろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

y_waiwai

2021/07/13 11:56

しつもんはなんでしょうか
guest

回答1

0

ベストアンサー

アスキーアートをコンソール上でアニメーションするコード例をいくつか見てみましたが、どれも各画像の描画の間にコンソール画面を白紙にする処理を入れています。いちど試してみてはいかがでしょうか。

それと画像の描画ごとに画像ファイルから読み込んでリサイズして白黒化してアスキーアート化する処理を行っていますが、負荷がどの程度なのか気になります。処理にかかる時間によっては思ったより画像の切り替えにモタったりすることもあるのではないかと思うのですが。
リアルタイム動画ではないので、先にテキストファイルに書き出しておいてから、描画の時はそこから読み込んでもいいのではないかと思います。
もっともこれは試してみたわけではないので、見当はずれかも知れません。

投稿2021/07/13 12:53

編集2021/07/13 12:56
etherbeg

総合スコア1195

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

34Noe

2021/07/13 14:48

一度コンソールを白紙にする処理を追加したところ思い通りに動くようになりました。ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問