テキスト検出(SWT)について
以前 気合いで画像から文字だけを抽出する というようなクソ記事を書きましたが,もっと効果的な画像演算があることがわかりました.
おそらくtesseract OCRなどにも使われていると思います.
Stroke Width Transform(SWT)
言語やフォント,スケール,方向に関係なくテキストを検出できる画像演算です.
論文は以下のリンクにあります.
今回はSWTを使ってどの程度検出できるのかやって見たいと思います.
以前と同じ画像を使用し,さを見ます.
上の画像がグレーイスケールにした入力画像で, 下がSWTを適用した後の画像です.
かなり文字が,くっきりと摘出できているかと思います.
今回使用したコードは こちらの方のコードをフォークさせて使わせていただきました.
終わり
ロシア語筆記体の文字のセグメンテーションとかいつかやって見たいですね()
気合いで画像から文字だけを抽出する
現在画像処理をやっているので,その辺の知識を置いていこうと思います
今回使うライブラリです.
import matplotlib.pyplot as plt from PIL import ImageFont, ImageDraw, Image, ImageOps, ImageFilter import numpy as np from skimage import measure import cv2 %matplotlib inline
今回使う画像は下のものです.
では早速やっていきます. RGBカラーでは処理しづらいので,グレーイスケールに変換します.
sign_board = Image.open("sign_board_maker.jpg") gsign_board = sign_board.convert('L')
この際私はPillowでやっていますがopenCVを使う場合だと以下のようです
image = cv2.imread('hoge.jpg')
gimage = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
次に閾値を設定して, 2値に変換をします. この処理ではノイズの除去を目的としています.
gimg = np.asarray(gsign_board) threshold = cv2.threshold(gimg, 200, 255, cv2.THRESH_BINARY)[1]
この時点での結果がこちらです.
次に文字部分だけを抜き取ります.
labels = measure.label(threshold, neighbors=8, background=0) mask = np.zeros(threshold.shape, dtype='uint8') for (i, label) in enumerate(np.unique(labels)): if label ==0: continue labelMask = np.zeros(threshold.shape, dtype="uint8") labelMask[labels==label]=255 numpixels= cv2.countNonZero(labelMask) if numpixels > 200 and numpixels < 1000: mask = np.add(mask , labelMask) plt.imshow(mask)
結果が以下です.
measureで2値化下画像から繋がっている要素にラベリングをします.
そのラベルづけされた要素のpixel数が200より大きく1000より小さい場合のみmaskに追加しています.
古典的でダサいですが,これでも割と文字は抽出できます.
フォントサイズが固定であったりする場合などには有効な手法だと思います.
まとめ
計算リソースに制限がある場合や.実行時間を重視する場合はこのような手法が必要なのかなって思いました.