私的AI研究会 > Tesseract2

文字認識エンジンのための画像処理

 文字認識の精度を上げるためには、認識エンジンに入力する画像の前処理が欠かせない。その方法を検討する

※ 最終更新:2021/12/22 

入力画像の前処理

カラー・モノクロ変換

罫線を消去する

 伝票の罫線が文字認識の精度低下の一因となる。OpenCV の「ハフ変換 (Hough Transform)」で直線を検出し消去する手法を考える。

  1. 元画像を読み込む
        image = cv2.imread(input_filename)
  2. グレースケールに変換する
        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    ・OpenCV 3チャンネルのカラーイメージをグレースケール 1チャンネルのイメージに変換する。
    ・ここでは OpenCVの関数を使っているが前記輝度返還と内容は同じ。
  3. 2値化
        ret, gray = cv2.threshold(gray, thresh=0, maxval=255, type=cv2.THRESH_BINARY + cv2.THRESH_OTSU)
    ・2値化アルゴリズムは種々あるがここでは「大津アルゴリズム」を使用する。
    ・大津アルゴリズムでは 2値化の閾値は画像から自動的に決定される。
  4. ネガポジ反転
        gray = cv2.bitwise_not(gray)
    ・白と黒を逆転させると線が白く(明るく)なり特定がしやすくなる。
  5. ハフ変換でラインを検出
        lines = cv2.HoughLinesP(gray, rho=1, theta=np.pi/360, threshold=thr, minLineLength=lln, maxLineGap=gap)
    
        if lines is not None:
            for line in lines:
                x1, y1, x2, y2 = line[0]
    
                # 赤線を引く
                red_lines_img = cv2.line(img2, (x1,y1), (x2,y2), (0,0,255), 3)
    ・ハフ変換では対象の画像に対して、パラメータ値の調整が必要。
    ・パラメータ決定のためのアプリケーションを作成した。(後述)
    ・確認のため検出した直線を赤で引く。
  6. 検出した線を消す
                # 線を消す(白で線を引く)
                no_lines_img = cv2.line(img3, (x1,y1), (x2,y2), (255,255,255), 3)
    ・確出した直線を白で引く。
    ・罫線を消去した画像が得られる。

罫線消去のためのパラメータ確認プログラム「delline_check.py」

画像の傾きを補正する

 入力画像の傾きが文字認識の精度低下の一因となる。OpenCV の「ハフ変換 (Hough Transform)」により傾斜の補正を行う。

  1. 元画像を読み込む
        image = cv2.imread(input_filename)
  2. グレースケールに変換する
        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
  3. Canny 法でエッジを抽出した2値画像を作成
        edges = cv2.Canny(gray_image,50,150,apertureSize = 3)
  4. ハフ変換でラインを検出
        lines = cv2.HoughLinesP(gray, rho=1, theta=np.pi/360, threshold=thr, minLineLength=lln, maxLineGap=gap)
    
        if lines is not None:
            for line in lines:
                x1, y1, x2, y2 = line[0]
    
                # 赤線を引く
                red_lines_img = cv2.line(img2, (x1,y1), (x2,y2), (0,0,255), 2)
    ・ハフ変換では対象の画像に対して、パラメータ値の調整が必要。
    ・パラメータ決定のためのアプリケーションを作成した。(後述)
    ・確認のため検出した直線を赤で引く。

  5. 画像の傾き検出
                arg = math.degrees(math.atan2((y2-y1), (x2-x1)))
                HORIZONTAL = 0
                DIFF = 20 # 許容誤差 -> -20 - +20 を本来の水平線と考える
                #arg != 0を条件に追加し、傾きの平均を0に寄りにくくした。
                if arg != 0 and arg > HORIZONTAL - DIFF and arg < HORIZONTAL + DIFF : 
                    print(' count= {}, degree= {}'.format(count, arg))
                    sum_arg += arg;
                    count += 1
        if count == 0:
            return HORIZONTAL
        else:
            return (sum_arg / count);   # 座標系の違いからこの値が補正すべき角度になる
    ・-20°~ +20°の範囲の直線から画像の傾きを得る。
    ・OpenCVの画像上の座標は左上を原点として右方向にx軸、下方向にy軸が伸びていく座標で、math ライブラリの座標とはy軸の向きが逆である。
    ・結果的に上記の演算では補正する回転角度を直接得ていることになる。

  6. 得られた値から画像を回転する
    # 画像の回転(OpenCV)
    def rotate_img(img, angle):
        # 画像サイズ(横, 縦)から中心座標を求める
        size = tuple([img.shape[1], img.shape[0]])
        center = tuple([size[0] // 2, size[1] // 2])
        # 回転の変換行列を求める(画像の中心, 回転角度, 拡大率)
        mat = cv2.getRotationMatrix2D(center, angle, scale=1.0)
        # アフィン変換(画像, 変換行列, 出力サイズ, 補完アルゴリズム)
        rot_img = cv2.warpAffine(img, mat, size, flags=cv2.INTER_CUBIC,borderValue=(255, 255, 255))
        return rot_img
    ---------------------------
        # 傾き補正
        arg = get_degree(img, f_name, f_ext, outdir)
        tilt_img = rotate_img(img, arg)                     # OpenCVによる画像回転(高速)
    ・画像の回転は SciPyのndimageによる手法もあるが OpenCVのほうが高速のよう。
        tilt_img = ndimage.rotate(img, arg, reshape=False)  # SciPyのndimageによる画像回転
    ・回転後の画像の周囲は白で塗りつぶす設定にする。

画像の傾き補正確認プログラム「titl_check.py」

画像の色を消去する

 伝票の印影は文字認識の精度低下の一因となる。印影を消去する方法を検討する。
 HSV色空間「色相(Hue)」「彩度(Saturation)」「明度(Value)」を考える。

意味説明
色相(H)色合い赤は 0度、黄色は 60度 というように角度で色合いが決まる
彩度(S)色の鮮やかさ色相が同じ場合でも、彩度が高ければ鮮やかに見え、低ければグレーに見える。彩度がゼロの場合は無彩色[黒・灰色・白]
明度(V)色の明るさ高いほど明るい色になる
  1. 元画像を読み込む
        image = cv2.imread(input_filename)
  2. HSV色空間に変換
        hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
  3. HSV色の領域からマスク画像を作成
        # HSVの値域 1
        hsv_min = np.array([hmin1,smin,vmin])
        hsv_max = np.array([hmax1,smax,vmax])
        mask = cv2.inRange(hsv, hsv_min, hsv_max)
    
        # HSVの値域 2
        if hmin2 < 180 and hmax2 < 180:
            hsv_min = np.array([hmin2,smin,vmin])
            hsv_max = np.array([hmax2,smax,vmax])
            mask2 = cv2.inRange(hsv, hsv_min, hsv_max)
            mask = mask + mask2
    
        # mask 領域のマスク (255:指定、0:指定以外)
        # mask_inv 領域のマスク反転 (0:指定、255:指定以外)
    ・「0°を挟んだ指定」は min > max で表現する。
    ・R・G・B の領域を指定した結果を例にする。

  4. マスク画像を使って元画像を処理する
        # マスキング処理
        masked_img = cv2.bitwise_and(img, img, mask=msk)
  5. 抽出した色領域を白にする
        if mode == 2:
            # 特定の色を別の色に置換する
            before_color = [0, 0, 0]
            after_color = [255, 255, 255]
            masked_img[np.where((masked_img == before_color).all(axis=2))] = after_color
  6. この機能を使って印影を消去する

画像の色消去(抽出)確認プログラム「delcolor_check.py」

 

OCR テストプログラムの認識精度

 今回開発した OCR テストプログラム「ocrtest4.py」 の認識精度を調べる。

サンプル画像の認識結果

 

更新履歴

参考資料

 

Last-modified: 2022-02-08 (火) 14:23:46