備忘録

弱小院生のメモ

adaptiveThresholdさん見直し

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つ用意しなければならない … 。

雑記

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