備忘録

イケイケエンジニアになるために自己嫌悪と戦う大学院生のメモ兼モチベーション維持。

文字位置切り抜き

学習用の画像を集めていくうちに文字位置の切り抜きに失敗することが多くなり、 このままではロバストな認識は行えないということで改善を試みた。

スコア部分の切り抜き

画像によってヘッダの認識にずれがあり、切り出したスコア部分に欠けが生じることがあった。

この処理で欠けると後の処理では回復できないので、かなり大きめに領域を取得する。

f:id:reverent_f:20170114200349p:plain

2値化

P-タイル法を試してみたが、安定しないので今まで通り R値とG値の合算結果に大津のアルゴリズムを適用して2値化する。

f:id:reverent_f:20170114200617p:plain

スコア文字部分の絞り込み

大きく切り抜いた分だけ余計な領域が発生する。 幸い、切り抜きたい文字の周りには黒い余白が現れるためこれを手掛かりに絞り込みを行う。

  1. 画像の上下左右に固定幅の白枠をつける

このとき、元から画像に存在している枠によって、目的文字部分と(あれば)右の余計なコンボ数部分が隔てられる。

2.白枠で縁取られた領域のうち最大部分を切り抜く

    # 白枠で縁取られた面積最大の領域を探す
    image, contours, hierarchy = cv2.findContours(l_img,cv2.RETR_CCOMP,cv2.CHAIN_APPROX_SIMPLE)
    contourImg = cv2.cvtColor(l_img, cv2.COLOR_GRAY2BGR)
    bgr_total = contourImg.copy()

    inner_contours = []
    for index, contour in enumerate(contours):
        if hierarchy[0][index][2] == -1:
            inner_contours.append(contour)

    approxes = []
    max_box = None
    for contour in inner_contours:
        # 矩形補完
        epsilon = 0.01*cv2.arcLength(contour,True)
        approx = cv2.approxPolyDP(contour,epsilon,True)
        area = cv2.contourArea(approx)

        if max_box is None or cv2.contourArea(max_box) < cv2.contourArea(approx):
            max_box = approx
        if(area > 20):
            approxes.append(approx)
            x,y,w,h = cv2.boundingRect(contour)

f:id:reverent_f:20170114201337p:plain

各文字特定

以前の記事で書いたヒストグラムを使った処理によって文字候補をリストアップする。 以前までの処理では文字以外の部分もリストアップされていたが、文字候補部分のアスペクト比からさらに候補を絞り込む。

f:id:reverent_f:20170114201559p:plain

以前より閾値を厳しく設定し、文字候補に漏れがあっても文字同士が連結しないようにする。

候補から外れた文字部分の補完

文字候補として外れてしまった文字(上図なら 7 )を文字の位置関係から推測する。

ほとんどの場合スコア先頭に来る 0 , 9 は上記の処理で文字候補から外れることはほぼ無い。 そこで、スコア先頭文字は確実に候補中にあるとして、右方向に8文字あると仮定し補完する。 先頭5文字と後半3文字でフォントサイズが異なることに気をつける。 細かい推測方法は省略する。

f:id:reverent_f:20170114201818p:plain f:id:reverent_f:20170114202302p:plain f:id:reverent_f:20170114202305p:plain

整形

あとは各文字の上下の余白を削除・等サイズにリサイズして完成

まとめ

やっとこれで学習用データの切り出しができるようになった! 文字位置の特定がロバストにできればTesseractを使う必要はないので(各文字の画像を検出器にかければいいので)、文字の認識はkNNかKerasあたりをつかったDeepLearningでやる予定。