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

備忘録

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

adaptiveThresholdさん見直し

Python 画像処理 ウンドボ

2値化の処理を探っているとき、cv2.adaptivethreshold()があまり使えないように思っていたが、ただ単に自分のチューニング不足だった。

cv2.adaptivethreshold(image, method, blocksize, c)

画像のしきい値処理 — OpenCV-Python Tutorials 1 documentation

Block Size - しきい値計算に使用する近傍領域のサイズ.1より大きい奇数を指定する必要があります.

C - 計算されたしきい値から引く定数です

Cの存在意義を理解していなかったが、文字領域の抽出においてはこいつを適切にチューニングする必要があった。

OpenCvSharpをつかう その15(適応的閾値処理) - schima.hatenablog.com

減算定数の意味

最後の減算定数は何のためにあるのでしょうか。

(中略)

文字が有る領域: 周囲の画素値はバラエティ豊か(白地に黒い細い線、で構成されるので)

文字が無い領域: 周囲の画素値はほぼ同じ(周りじゅうが白)

周り中が似たような色のとき、減算定数が有ることで、減算後は対象ピクセル閾値を上回ることになり、白くなります。

これにより、背景領域では多少のノイズ・色の揺らぎに負けずに白で塗りつぶしやすくし、文字領域では黒いエッジを残しやすくなります。賢いですね。

なるほど賢いので早速実験してみた。

コード

def binalizeByAdaptive(img):
    r = img.copy()

    # R, G値のみ取り出しグレースケール化
    green = r[:,:,1]
    red = r[:,:,2]
    redGreen = cv2.addWeighted(red, 0.5, green, 0.5, 0)

    # binalize
    th_red = cv2.adaptiveThreshold(redGreen,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\
            cv2.THRESH_BINARY_INV,21,20)
    
    # cleaning noise by opening
    kernel = np.ones((1,1),np.uint8)
    th_red = cv2.morphologyEx(th_red, cv2.MORPH_OPEN, kernel)

    cv2.imshow("binalize", th_red)
    # cv2.waitKey(0)

    return th_red

blockSize, Cの値は試行錯誤した結果の値である。

結果

成功例

f:id:reverent_f:20170124185128p:plain:w250 f:id:reverent_f:20170124185130p:plain:w250

文字の縁取り部分まで綺麗に検出できている。 また、0,8,9などの文字中の空洞部分も比較的綺麗に見える!

失敗例

  • 減算定数

f:id:reverent_f:20170124185156p:plain:w250

減算定数が大きすぎることで文字の中心部分が潰れた。 これは検出に失敗したら減算定数を変化させてもう一度認識、とすれば対応できそう。

  • モアレ

f:id:reverent_f:20170124185235p:plain:w250 f:id:reverent_f:20170124185238p:plain:w250

モアレが発生している画像だとノイズが多量にのってしまう。 フーリエ変換して高周波成分を取り除く、までやるのは難しいか … ?

まとめ

やはり適応的2値化処理は照明条件の変化に強く、綺麗に文字の検出ができる!

ただし、文字の縁も綺麗に残るので、文字の切り出し処理を修正しなければならない(嬉しい悲鳴)

ただし、モアレに非常に弱いことが判明した。 有効なモアレの除去方法が思いつかないため、モアレが発生している場合は従来の2値化処理を使うしかなさそうだ。

その場合は教師データを2値化の処理ごとに2つ用意しなければならない … 。

雑記

どこまでの画像を認識対象とするか、そろそろ限定しなければならない。 そろそろサイトの作成にも取り掛かりたい。