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の値は試行錯誤した結果の値である。
結果
成功例
文字の縁取り部分まで綺麗に検出できている。 また、0,8,9などの文字中の空洞部分も比較的綺麗に見える!
失敗例
- 減算定数
減算定数が大きすぎることで文字の中心部分が潰れた。 これは検出に失敗したら減算定数を変化させてもう一度認識、とすれば対応できそう。
- モアレ
モアレが発生している画像だとノイズが多量にのってしまう。 フーリエ変換して高周波成分を取り除く、までやるのは難しいか … ?
まとめ
やはり適応的2値化処理は照明条件の変化に強く、綺麗に文字の検出ができる!
ただし、文字の縁も綺麗に残るので、文字の切り出し処理を修正しなければならない(嬉しい悲鳴)
ただし、モアレに非常に弱いことが判明した。 有効なモアレの除去方法が思いつかないため、モアレが発生している場合は従来の2値化処理を使うしかなさそうだ。
その場合は教師データを2値化の処理ごとに2つ用意しなければならない … 。
雑記
どこまでの画像を認識対象とするか、そろそろ限定しなければならない。 そろそろサイトの作成にも取り掛かりたい。