読者です 読者をやめる 読者になる 読者になる

Tesseract OCRを使ってアニメのキャプチャから字幕情報を取り出してみる

Python プログラミング

まず初めに書いて置きますが、僕は画像処理プログラムを書くのは得意ではないので読みにくかったらもうしわけありません。

最近アニメのキャプチャを整理するために字幕情報を自動で抜き出す必要が出てきました。今回は、 Tesseract OCR を使って画像から字幕を抽出しようと思います。

Tesseract OCRとは

Tesseract OCRGoogle で公開されているオープンソースOCR エンジンです。詳しいことは以下のスライドに書かれています。

Tesseract ocr

仕様を完全には把握してないですが、実際に使ってみると次のような特性があることがわかりました。

OpenCV との連携ができるっぽいけど今回は PIL で処理します。学習機能に強いらしいですがここでは特に扱いません。

字幕の抽出

紫吹蘭ちゃんの画像を例に処理を行うことにします。 f:id:fushime2:20151103152455j:plain

この画像をそのまま OCR にかけると以下のような結果になります(実際にはグレースケール化させた)。

】繍

食ペな。
, /

前述したように、この OCR はノイズに弱いです。結果をみると誤認識をしていたりうまく読み取れていないことがわかります。一般にアニメのキャプチャにはノイズ(字幕以外の部分)が多いので、できるだけ読み取りやすいようにそれらを消すような前処理が必須となってきます。今回は、画像の切り取り -> 二値化をする、という処理を行うことにしました。

# -*- coding: utf-8 -*-
from PIL import Image
import tesseract

# 処理用の画像をつくる
def make_image():
    MID = 200

    # 画像の読み込み
    image = Image.open("input.jpg")

    # 切り取り
    width, height = image.size
    resized_image = image.crop((int(width*0.1), int(height*0.7), int(width*0.9), int(height*0.95)))
    
    # グレースケール化
    gImage = resized_image.convert("L")

    # 二値化
    width, height = gImage.size
    for w in xrange(width):
        for h in xrange(height):
            level = gImage.getpixel((w, h))
            if level > MID:
                gImage.putpixel((w, h), 255)
            else:
                gImage.putpixel((w, h), 0)
    
    # 保存
    gImage.save("tmp.jpg", "JPEG")

def main():
    make_image()

    # tesseractオブジェクトの作成
    api = tesseract.TessBaseAPI()
    api.Init(".", "jpn", tesseract.OEM_DEFAULT)
    api.SetPageSegMode(tesseract.PSM_AUTO)
    
    # 画像ファイルの読み込み
    IMAGE_NAME = "tmp.jpg"
    image = open(IMAGE_NAME, "rb").read()
    
    # OCR処理
    text = tesseract.ProcessPagesBuffer(image, len(image), api)
    print text 
    
    # 画像の出力
    s = Image.open("tmp.jpg")
    s.show()

if __name__ == "__main__":
    main()

切り抜きのサイズはかなり適当です。持ってるキャプチャは字幕背景が薄い黒で文字が白*なので、プログラムのような閾値で二値化すると文字の部分だけ強調されるようになることが多かったです。

* 主人公やメインキャラは黄色だったり他の色だったりするので今回は対象外。

結果

生成画像 f:id:fushime2:20151103152637j:plain 実行結果

'ナニ
まずは わかめ食ペな。

な。

前処理をしなかったときと比べると精度が上がってるように思えます。他の画像での結果は省略しますが、このプログラムだと平仮名/片仮名はそれなりの精度で読み取れるけど漢字に弱いことがわかりました。また、ノイズ処理が不十分なため誤認識も少なくないです。まだ実用的じゃない><

これ以上精度を上げるには OpenCV を使って字幕部分だけを切り抜くなどの処理が必要になってきそうです。画像処理の気力があれば少し改良するかも知れません。