アイカツ画像をツイートするTwitter botを作った

https://twitter.com/aikatsu_image

アイカツの画像をツイートする bot です。所持してるアイカツ画像を PC に溜めておくのも宝の持ち腐れ感があったので作りました。

bot のプログラムは python で書いて、Windows のタスクスケジューラで実行させています。tweepy というモジュールを使うと数行で書けて凄い。Twitter API を使うのは面白そうなのでもう少し遊んでみたいと思った一瞬でした。

ところでデスクトップ PC 上で動かすと常時起動が必要なので Raspberry PI とかが欲しいですね。サーバーを借りるようなものでもないと思うので…。

追記(2015/12/19)

RasPI 上で動かすことにしました。cron が使えて便利です。あと省電力。

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

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

最近アニメのキャプチャを整理するために字幕情報を自動で抜き出す必要が出てきました。今回は、 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 を使って字幕部分だけを切り抜くなどの処理が必要になってきそうです。画像処理の気力があれば少し改良するかも知れません。

AOJ0516: Maximum Sum(累積和, しゃくとり法)

Maximum Sum | Aizu Online Judge

累積和としゃくとり法を知らなかったのでメモ。計算量を考えずに全探索までしていたので書いておく。 最悪 O(n2) で最大 n = 100000 だから全探索はダメ(指数記号が出せない…)。

続きを読む

アイカツ!キャラのPixiv内におけるR-18率

2015/08/16 時点での結果。ダンディバが圧倒的だった。

name total R18 ratio[%]
黒沢凛 357 58 16.3
氷上スミレ 1105 177 16.0
風沢そら 543 74 13.6
新条ひなき 483 65 13.5
姫里マリア 381 51 13.4
三ノ輪ヒカリ 208 27 13.0
天羽まどか 394 48 12.2
夏樹みくる 459 54 11.8
藤原みやび 147 17 11.6
神崎美月 679 61 8.98
大空あかり 2043 149 7.29
紅林珠璃 416 29 6.97
アイカツ! 19998 1377 6.89
服部ユウ 292 20 6.85
紫吹蘭 2409 157 6.52
北大路さくら 665 40 6.02
霧矢あおい 3195 187 5.85
藤堂ユリカ 2922 151 5.17
冴草きい 909 47 5.17
星宮いちご 4686 230 4.91
栗栖ここね 123 6 4.88
一ノ瀬かえで 780 37 4.74
神谷しおん 285 13 4.56
音城セイラ 829 36 4.34
有栖川おとめ 1199 44 3.67

csv https://docs.google.com/spreadsheets/d/1DVIDZV8a7a1wDwyjJwmm5oNDurRyQ3pzAuY_yTSve9M/edit?usp=sharing

AOJ0030: Sum of Integers 

Sum of Integers | Aizu Online Judge
深さ優先探索の問題。C++ で書いたものを Python に翻訳して分かった気になるアレ。

#!/usr/bin/env python

def dfs(pos, t, sum):
    global cnt
    if t == n:
        if sum == s:
            cnt += 1
        return
    if pos > 9:
        return
 
    dfs(pos+1, t, sum)
    dfs(pos+1, t+1, sum + pos)
 
 
while True:
    n, s = map(int, raw_input().split())
    if n==0 and s==0: break
 
    cnt = 0
    dfs(0, 0, 0)
    print cnt

蟻本の DFS の説明の理解に時間がかかったし、遷移の仕方が直感的にわからないから演習を詰むしかなさそう。
DP でも解けるらしいけどもっとわからん。