なんもわからんな

気合いで画像から文字だけを抽出する

現在画像処理をやっているので,その辺の知識を置いていこうと思います

今回使うライブラリです.

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

今回使う画像は下のものです.

http://fontsandcolors.com/wp-content/uploads/2016/06/sign_board_maker.jpg

では早速やっていきます. 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]

この時点での結果がこちらです. f:id:yakuta55:20180402105016p:plain

次に文字部分だけを抜き取ります.

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に追加しています.
古典的でダサいですが,これでも割と文字は抽出できます.

f:id:yakuta55:20180402105750p:plain フォントサイズが固定であったりする場合などには有効な手法だと思います.

まとめ

計算リソースに制限がある場合や.実行時間を重視する場合はこのような手法が必要なのかなって思いました.

参考文献

3.3. Scikit-image: 画像処理 — Scipy lecture notes

OpenCV.jp