プログラミング

pythonのwisperを使用して自動で文字起こし&テロップ作成のプログラムを公開

  • Pocket

どうもとしです。

今回は

なんて話をしていこうと思います。

動画を作成する際にテロップをつけるのって動画を見やすくするために重要な部分なんですが、、

いかんせん時間がかかる。

ということで今回はそれをAIとPythonを使用して自動でテロップを作成してしまいます。

流れとしては

●今回の流れ

1.ffmpegのインストール

2.whisperのインストール

3.ffmpegとwhisperを使用して動画の文字起こし

4.文字起こしからテロップのためのsrtファイルの作成

こういった流れでやっていこうと思います。

まず最初はffmpegのインストール方法について解説していきます。

ffmpegについて

このffmpegというのが何かというと、音声(動画)のデータを扱えるようにするためのソフトウェアになります。

今回はPythonのプログラムでテロップの自動作成をするため、Pythonの仮想環境であるAnaconda上にffmpegをインストールしていきます。

方法としては、、

自身のAnacondaの環境に入って

conda install -c conda-forge ffmpeg

上のコマンドを入力してあげるとインストールをすることが出来ます。

一定時間待機すると

こういった感じで本当にインストールをするか聞かれるので「y」を入力して続行してください。

インストールが完了したら使用できるかを確認するためにプロンプト上に

ffmpeg -version

とコマンドを入力して実行してみてください。

インストールしてAnaconda上で使用できる場合には、ffmpegのバージョンが表示されます。

whisperについて

ffmpegのインストールが完了したら今回のメインのwhisperのインストールをしていきます。

このwhisperはOpenAIが公開している音声を認識してテキストに変換するAIになります。

ちなみにこの音声を読み込むときに、上でインストールしたffmpegを使用しています。

whisperのインストール

whisperのインストールは今回はpipを使用してインストールしたいと思います。

先ほどffmpegをインストールした環境と同じAnacondaの環境のプロンプトで

pip install -U openai-whisper

こちらのコマンドでwhisperをインストールすることができます。

ちなみにinstallのあとについている【-U】はアップグレードという意味なので【–upgrade】でも大丈夫です。

●Uオプションをつける理由

このUオプションをつける理由ですが、whisperを使用するときに他のパッケージもインストールして使用されます。

その時に現在のAnacondaの環境内ですでにパッケージがインストールされている場合、、

このパッケージを一緒に最新版にして使えるようにするためです。

とは言っても、おそらくなくてもインストールできるはずなので【-U】については入れても入れなくても大丈夫だと思います。

もし自分の環境でwhisperをインストールしても動かなかったら、このアップグレードのUオプションをつけて試してみてください。

ということでffmpegとwhisperのインストールが完了したので実際に2つを使っていきたいと思います。

whisperを使って文字起こしをしてみる

まず最初にwhisperを使用して動画から文字起こしをしていきたいと思います。

こちらが文字起こしをするためのPythonプログラムになります。

import whisper

mov_path = "動画のパスを入力"
model = whisper.load_model("base")
result = model.transcribe(mov_path)

”動画のパスを入力”部分に文字起こしをしたい動画のパスを入力して起動するとresultという変数に文字起こしの結果が格納されます。

whisperの文字起こしの精度を変える

whisperはこれを書いている段階で文字起こしの精度として6段階の調整が出来るようになっています。

それを変えるには4行目の最期の方に書いてあるbaseの部分を変更します。

  • tiny
  • base
  • small
  • medium
  • large
  • turbo

この6段階でtinyが一番精度が悪くてturboに行くにつれてだんだん精度が上がっていきます。

baseで行う場合には10分前後の動画でだいたい1分くらいで文字起こしが終了します。

この時の精度としては日本語だとだいたい80%くらいの印象です。

smallの場合には10分ほど時間がかかりますが、90%以上合っている印象なので、、

・早く文字起こしを終わらせたい→base

・素早く正確に文字起こししたい→small

・時間がある場合→medium

こういった感じで使い分けるのが個人的におススメです。

ちなみにそれ以上に関しては時間がかかりすぎる印象なので、短い動画をやる場合に使用してみてください。

といった感じでwhisperで文字起こしをすることが出来たわけですが、、

今回この文字起こしの結果が欲しいわけではないですよね。

結果としてテロップを自動で挿入するためのSRTファイルが欲しいので、ここからはそのプログラムを作っていきます。

文字起こしからSRTファイルの作成

ちなみにSRTファイルはこういった形式のファイルになります。

1
00:00:00,000 --> 00:00:00,814
どうもとしです。

2
00:00:00,814 --> 00:00:04,071
今回AI×Python

3
00:00:04,071 --> 00:00:04,885
自動で動画からテロップを作成という

7
00:00:04,885 --> 00:00:05,700
テーマで話をしていきたいと思います

8
00:00:05,700 --> 00:00:07,346
AIっていうものを使うことによって

これがSRTファイルの中身ですね。

番号、何分何秒から何分何秒までに何を喋っているかっていうものをズラーと書いているファイルになります。

でっ、このファイルを動画編集ソフトで読みこむと決めた時間にテロップとして挿入されるという超便利なものになります。

このSRTファイルは僕のところでは作成するために3つのステップで作っています。

●SRTファイル書き出しの3ステップ

ステップ1:句読点や文字数で文字起こしの結果を分割

ステップ2:SRTファイルのタイムスタンプの作成

ステップ3:SRTファイルの書き出し

1つずつ解説していきますね。

文字起こしの結果を分割

まずはステップ1の文字起こしの結果を句読点や文字数で分割するというステップです。

これが必要な理由としてはwhisperで文字起こしをしただけでは、長い文章になっている場合があるんですね。

でっ、それだと動画にテロップとして入れる場合って一回に表示できるテロップの文字数が決まっているわけなのではみ出してしまいます。

なので句読点などの区切りが良い部分であったり、文字数というので結果を分割するということをします。

コードはこちらになります。(関数で作成しています)

def split_text_by_punctuation_and_length(text, max_length=27):
    # 句読点、感嘆符、スペースで分割
    sentences = re.split(r'(?<=[。、!?!?\s])', text)
    result = []
    buffer = ""
    for sentence in sentences:
        for char in sentence:
            buffer += char
            # バッファの文字数が最大値を超えた場合、次に移行
            if len(buffer) >= max_length:
                result.append(buffer)
                buffer = ""
        # 文章単位の句読点で分割
        if buffer:
            result.append(buffer)
            buffer = ""
    return result

流れとしては

  1. 句読点、感嘆符、スペースで分割
  2. 一定文字数を超えた場合には次のテロップに移行

こういった感じでやっています。

僕のところのテロップの設定だと横の幅がだいたい27文字入るので分割の文字数を27で設定しています。

使用するときに引数でmax_lengthを渡してあげれば自分の設定で使用することが出来ます。

ただこの方法だとちょっと区切りがおかしくなって自分自身で直さないといけなかったりもします。

でも自分で全部文字をうつよりも何倍も効率よくテロップを作成できます。

SRTファイル用にタイムスタンプを変換

次がSRTファイル用にタイムスタンプを変換する方法です。

whisperで文字起こしをした際に実はどの時間からどの時間までというのは一緒に出力されています。

ただSRTファイルの形式ではないため、それをSRTファイルの形式にするのがこの関数になります。

def format_time(seconds):
    """秒をSRTフォーマットのタイムスタンプに変換"""
    millis = int((seconds % 1) * 1000)
    seconds = int(seconds)
    hours = seconds // 3600
    minutes = (seconds % 3600) // 60
    seconds = seconds % 60
    return f"{hours:02}:{minutes:02}:{seconds:02},{millis:03}"

でっ、ここまで出来たらあとは書き出しをするだけです。

SRTファイルの書き出し

書き出しについてはSRTファイルの形式に沿ってファイルを作成して書き出します。

プログラムはこちらになります。

def write_srt(segments, srt_path):
    """SRTファイルに書き出し"""
    with open(srt_path, "w", encoding="utf-8") as srt_file:
        for i, (start, end, text) in enumerate(segments):
            srt_file.write(f"{i + 1}\n")
            srt_file.write(f"{format_time(start)} --> {format_time(end)}\n")
            srt_file.write(f"{text}\n\n")

引数のsegmentsはステップ1で作成したもので、srt_pathは出力するSRTファイルのファイルパスを渡しています。

ここまで出来たらあとはこの3つの関数を実行する関数を作成します。

分割からSRTファイル書き出しの関数

def transcribe_with_custom_split(result, out_srt_path):
    # 出力セグメントを処理して分割
    max_chars = 27
    segments = result['segments']
    formatted_segments = []

    for segment in segments:
        start = segment["start"]
        end = segment["end"]
        text = segment["text"]

        # 一定文字数ごとに句読点,スペースで分割
        split_texts = split_text_by_punctuation_and_length(text, max_chars)

        # 各分割部分に新しいタイムスタンプを割り当て
        duration = (end - start) / len(split_texts)
        for i, sub_text in enumerate(split_texts):
            sub_start = start + i * duration
            sub_end = sub_start + duration
            formatted_segments.append((sub_start, sub_end, sub_text))
    # SRTファイルに書き出し
    write_srt(formatted_segments, out_srt_path)

最初にmax_charsとして分割する最大の文字数を決定して分割。

そのあとに分割した場合には時間がずれるのでそれを修正してformatted_segmentsというリストに格納。

最後にformatted_segmentsからSRTファイルを作成して書き出すという流れになっています。

SRTファイルのメリット

こんな感じでSRTファイルを作成してテロップを入れることが出来ます。

個人的に感じる大きなメリットとしてはテキストファイルと同じように文字を置換できることです。

例えばJavaScriptっていう言葉ですね。

やっぱりこういった言葉って英語ではなくてカタカナになってしまうことが多いです。

だけど一括でジャバスクリプト→JavaScriptみたいな感じで置換できるのでかなり効率よくテロップを作成することが出来ます。

ちなみに僕はあまり活舌が良くないので、jQueryと発音したものが「ジャイクエリ」となっていました(笑

でっ、これはAIのめちゃくちゃいいところなのですが、、

同じような発音の場合には同じ言葉として文字起こししてくれます。

なのでジャイクエリ→jQueryと置換すればいいだけなので、めちゃくちゃ楽でした。

書き出しが終わったら

  1. テキストとして動画を聞きながら間違いを直す
  2. 全体的に直したら動画編集ソフトに取り込む
  3. 動画編集ソフトで細かい調整

こういった手順でやると効率がいいのでお勧めです。

完成したプログラム

でっ、ここまでで文字起こしからSRTファイルまでの書き出しが出来たわけですが、、

これだとちょっと普段使いには使いにくい部分があるので、

  • 動画ファイル名の取得
  • SRTファイル名の取得

ここら辺も追加して完成したプログラムを載せておきます。

import os
import re
import whisper


def get_file_path():
    movie_file_path = input('今回読み込ませるフルパスを入力してください\nmovie file name:').replace('"', '')
    file_name = os.path.splitext(os.path.basename(movie_file_path))[0]
    out_srt_path = f'{file_name}.srt'
    return movie_file_path, out_srt_path


def format_time(seconds):
    """秒をSRTフォーマットのタイムスタンプに変換"""
    millis = int((seconds % 1) * 1000)
    seconds = int(seconds)
    hours = seconds // 3600
    minutes = (seconds % 3600) // 60
    seconds = seconds % 60
    return f"{hours:02}:{minutes:02}:{seconds:02},{millis:03}"


def split_text_by_punctuation_and_length(text, max_length=27):
    # 句読点,でまず分割
    sentences = re.split(r'(?<=[。、!?!?\s])', text)
    result = []
    buffer = ""
    for sentence in sentences:
        for char in sentence:
            buffer += char
            # バッファの文字数が最大値を超えた場合、次に移行
            if len(buffer) >= max_length:
                result.append(buffer)
                buffer = ""
        # 文章単位の句読点で分割
        if buffer:
            result.append(buffer)
            buffer = ""
    return result


def write_srt(segments, srt_path):
    """SRTファイルに書き出し"""
    with open(srt_path, "w", encoding="utf-8") as srt_file:
        for i, (start, end, text) in enumerate(segments):
            srt_file.write(f"{i + 1}\n")
            srt_file.write(f"{format_time(start)} --> {format_time(end)}\n")
            srt_file.write(f"{text}\n\n")


def transcribe_with_custom_split(result, out_srt_path):
    # 出力セグメントを処理して分割
    max_chars = 27
    segments = result['segments']
    formatted_segments = []

    for segment in segments:
        start = segment["start"]
        end = segment["end"]
        text = segment["text"]

        # 一定文字数ごとに句読点,スペースで分割
        split_texts = split_text_by_punctuation_and_length(text, max_chars)

        # 各分割部分に新しいタイムスタンプを割り当て
        duration = (end - start) / len(split_texts)
        for i, sub_text in enumerate(split_texts):
            sub_start = start + i * duration
            sub_end = sub_start + duration
            formatted_segments.append((sub_start, sub_end, sub_text))
    # SRTファイルに書き出し
    write_srt(formatted_segments, out_srt_path)


mov_path, srt_path = get_file_path()
model = whisper.load_model("base")
split_result = model.transcribe(mov_path)
transcribe_with_custom_split(split_result, srt_path)
print('SRTファイルの書き出しが完了しました')

ファイルでもおいておきますね。

Pythonファイルの使い方

変更箇所としては53行目にある変数max_charsを自分で分割したい数字にしてください。

そのあとにffmpegとwhisperがインストールされている環境で実行してください。

そうするとプロンプト上で動画のフルパスを入れるように指示されます。

文字起こししたい動画のフルパスを入力すると後は自動で文字起こしからSRTファイルの作成まで行ってくれます。

現在の段階では精度が『base』に設定されているので、もう少し精度を上げたい場合にはsmall、mediumあたりで試してみてくださいね。

まとめ

今回AIのwhisperとffmpegを使用してPythonで動画から自動でテロップを作成するプログラムを作成してみました。

AIがどう動いているかっていうものは、すごく難しい部分です。

でも活用するとたった80行くらいで簡単にこういったものが作れるって本当にAIってすごいものですよね。

AIを活用すると今までできないと思われていたようなことも、実現可能になります。

ぜひAIとかPythonっていうものを勉強して自分自身でプログラムってものを組めるようになってもらえればと思います。

  • Pocket

無料相談受付中

マーケティング×プログラミング

・事業を伸ばしたい!
・個人で稼いでみたい!
・プログラミングで成果を上げたい!


こういった悩みを僕の経験と知識から解消します。

「プログラミングの●●をもっと知りたい!」という相談も受け付けています!

※僕の今までの実際の収益画像も載せています

無料相談はこちら


●最新:記事一覧

トップページ


●カテゴリー別:記事一覧

一覧ページ

コメントを残す


*