【Python】動画をフレームごとの画像にして出力するスクリプトを作った話

Code

はじまり

…. PiPiPiPi ….! PiPiPiPi …!!

135ml
135ml

うるせえなあ! ああ、もう朝か。 うわー今日も仕事めんどくせえなあ。

とりあえず、飯食うかあ。

・・・・・・

135ml
135ml

おはよー。

リサちゃん
リサちゃん

おはヨークシンシティ編はグリードアイランド編の前~。

ペンギン
ペンギン

おはようこそ実力至上主義の教室へのアニメの1期が放送されたのは4年前~。

135ml
135ml

もうそんな前になるのか・・・。
ところで、お前なんでそんな目がバキバキなんだ?

ペンギン
ペンギン

あー、徹夜してムフフなビデオを見ていたからなー。そりゃ充血するわな。

135ml
135ml

相変わらずだな・・・。おー、今日も天達は元気だなー。

ペンギン
ペンギン

最近さー、ムフフなビデオの見たいカットを探すのに時間が掛かって困ってるんだよねー。
「あのカットが見たいだけなのに!」って感じで。

135ml
135ml

ほー、画像で見たいってことなのか。

ペンギン
ペンギン

うん、恍惚とした表情が見たいだけなんだ。

135ml
135ml

はあ・・・。まあ、動画から画像を切り出すツールを以前に作ったことがあるなあ。

ペンギン
ペンギン

な!? それは本当か!? 是非提供して欲しいぞ!!

135ml
135ml

おー、じゃあ今回は、そのツールの紹介をするかあ。刮目せよ!

リサちゃん
リサちゃん

はい、目玉焼きできたよ~。

ツールの紹介

さて、今回使う機能は、ExtractImage()という関数になります。

スクリプトを起動すると、ファイルを選択するダイアログが表示されます。今回は、このビデオを画像にします。

選択すると、画像を保存するフォルダの名前を入力します。※日本語(SJIS)は使えません!

そして、画像化が始まると順次保存されたファイルの名前を出力します。

画像化が終わると、保存したフォルダを確認するように促すメッセージが表示されて、スクリプトが終了します。

先程の動画があるフォルダを見ると、確かに先程入力したフォルダがあります。

そのフォルダの中を確認すると、確かに画像が入っています。おおよそ1秒毎に切り取っています。

スクリプトの紹介

こちらが今回のスクリプトです。そこまで複雑なスクリプトではないと思います。

ImageEditor.py

def ExtractImage(video_name):
    '''
    video_name    : String absolutely path of selected file
    extracted_dir : String absolutely path of directory has selected file
    frame_count   : Integer number of frame of selected video
    fps           : Integer number of fps of selected video
    num_of_image  : Integer number of extracted images from video
    '''
    # Error Handling
    if video_name == '':
        print("ERROR: No file is selected.")
        sys.exit(0)

    extracted_dir = DirEditor.MakeDirectory(video_name)

    # Error Handling
    basefilename_without_ext = os.path.splitext(os.path.basename(__file__))[0]
    if InputController.CheckWhetherSjisExists(extracted_dir, basefilename_without_ext) == True:
        sys.exit(0)

    cap = cv2.VideoCapture(video_name)
    # width
    width = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
    # height
    height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
    # number of frame
    frame_count = cap.get(cv2.CAP_PROP_FRAME_COUNT)
    # fps
    fps = cap.get(cv2.CAP_PROP_FPS)
    print("movie's width: ", width, ", height: ", height)

    for num_of_image in range(1, int(frame_count), int(fps)):
        # set a property, where frame in this case, in the VideoCapture
        cap.set(cv2.CAP_PROP_POS_FRAMES, num_of_image)
        # read the next video frame to extract image file ("cap.read()[1]" is arrays of image's pixels.)
        cv2.imwrite("{dirname}{sep}image{num:0=3}.jpg".format(dirname=extracted_dir,sep=sep,num=int((num_of_image-1)/int(fps))), cap.read()[1])
        # cv2.imwrite("{video_dir}image{:0=3}.jpg".format(int((num_of_image-1)/int(fps))), cap.read()[1])
        print("saved: image{num:0=3}.jpg".format(num=int((num_of_image-1)/int(fps))))
    print('Check directory "{dirname}"'.format(dirname=extracted_dir))
    cap.release()

for文では、フレーム数をFPSで増分しているので、おおよそ1秒毎のフレームを出力する挙動になっています。解説する点はこれくらいですかね(笑)

おしまい

ペンギン
ペンギン

おお・・・、これで全て切り抜けるじゃねえか!

135ml
135ml

うーん、ムフフなビデオに使う意味があるのかは知らんが・・・、使い方次第だな。

ペンギン
ペンギン

へっへっへ、これは捗るなあ・・・! 今日は大変だなあ・・・!

135ml
135ml

まあ、ヨダレ拭けよ。

ペンギン
ペンギン

ズズズッ・・・。フーッ。

135ml
135ml

他の用途としては、今回みたいに問題集が動画として掲載されている場合に、その問題集を画像として持っておけるようになります。

ペンギン
ペンギン

なるほどねえ。 バリッボリッ。
ん? 俺は今何を食ったのだ?

135ml
135ml

煎餅じゃね? 僕の皿にもあるし。

リサちゃん
リサちゃん

う~ん、目玉焼きだねえ。

135ml
135ml

・・・・・・・・。

ペンギン
ペンギン

・・・・・・・・。

以上になります!

このツールで画像にした後は・・・

このツールで画像として出力した後は、以下のツールで切り出してみてはいかがでしょうか?

こちらのツールもPythonで動きます!

さらに、一気にトリミングした複数の画像の重複を除きたい場合は、以下のツールで重複を排除してみてはいかがでしょうか?

こちらのツールもPythonで動くものになっています!

おまけ

ペンギン
ペンギン

今回作ったソースは、以下のリポジトリのLandmasterLibraryに挙げています。

GitHub - landmaster135/pyclone-tornado: The memorandum for Python.
The memorandum for Python. Contribute to landmaster135/pyclone-tornado development by creating an account on GitHub.

コメント

タイトルとURLをコピーしました