私的AI研究会 > Tesseract2
文字認識の精度を上げるためには、認識エンジンに入力する画像の前処理が欠かせない。その方法を検討する
# 画像の前処理 def img_preproces(img): # グレイスケール演算 im_gray = 0.299 * img[:,:,2] + 0.587 * img[:,:,1] + 0.114 * img[:,:,0] im_gray8 = np.uint8(im_gray) # 大津アルゴリズムでは thresh, maxvalは無視されてしきい値は自動で設定される ret, im_gray8 = cv2.threshold(im_gray8, thresh=0, maxval=255, type=cv2.THRESH_BINARY + cv2.THRESH_OTSU) # すべてのチャンネル img[:,:,0] = im_gray8 img[:,:,1] = im_gray8 img[:,:,2] = im_gray8 return img
伝票の罫線が文字認識の精度低下の一因となる。OpenCV の「ハフ変換 (Hough Transform)」で直線を検出し消去する手法を考える。
image = cv2.imread(input_filename)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)・OpenCV 3チャンネルのカラーイメージをグレースケール 1チャンネルのイメージに変換する。
ret, gray = cv2.threshold(gray, thresh=0, maxval=255, type=cv2.THRESH_BINARY + cv2.THRESH_OTSU)・2値化アルゴリズムは種々あるがここでは「大津アルゴリズム」を使用する。
gray = cv2.bitwise_not(gray)・白と黒を逆転させると線が白く(明るく)なり特定がしやすくなる。
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)・ハフ変換では対象の画像に対して、パラメータ値の調整が必要。
# 線を消す(白で線を引く) no_lines_img = cv2.line(img3, (x1,y1), (x2,y2), (255,255,255), 3)・確出した直線を白で引く。
名前 | 型 |
デフォルト値 | |
image | ndarray |
入力画像 (1チャンネル) | |
rho | float |
投票の rho の解像度 (ピクセル) | |
theta | float |
投票の theta の解像度 (ピクセル) | |
threshold | int |
直線と判断する投票数 | |
minLineLength | float 0 |
この長さ未満の線分は検出対象外とする | |
maxLineGap | float π |
同じ直線上の点と解釈するギャップの最大値 |
名前 | 説明 |
lines | 検出された線分の一覧。各要素は (x1, y2, x2, y2) のタプル。1つも線分が見つからない場合は None を返す |
コマンドオプション | デフォールト設定 | 意味 |
-h, --help | ヘルプ表示 | |
-i, --image | calendar.png | 入力画像ファイル |
--thr | 100 | threshold 直線を動かして、その直線状に乗ってきた点の数がこの値を超えたら線とみなす |
--lin | 0 | minLineLength ここに指定された値以上の長さを持つ線の候補が見つかったら、それを線として検出する 0=auto 画像の横幅から自動設定 |
--gap | 0 | maxLineGap 2つの点が1つ線上にある場合に、点と点の間の間隔がここに指定した数より小さければ、同一の線とみなす 0=auto 画像の横幅から自動設定 |
-o, --out | result/ | 処理結果を出力するディレクトリ (ファイル出力なしの場合は'non') ※ディレクトリは存在する必要あり |
(py37) $ cd ~/workspace_py37/pyocr (py37) $ python3 delline_check.py --- Line delete with OpenCV --- OpenCV version 4.5.2 Line delete with OpenCV: Starting application... - Image File : calendar.png - Threshold : 100 - MinLineLength: 0 - MaxLineGap : 0 - Out directory: result/ Threshhold=100, MinLineLength=29, MaxLineGap=4, width=527, height=401 Save file dir 'result/' Finished.
入力画像の傾きが文字認識の精度低下の一因となる。OpenCV の「ハフ変換 (Hough Transform)」により傾斜の補正を行う。
image = cv2.imread(input_filename)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray_image,50,150,apertureSize = 3)
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)・ハフ変換では対象の画像に対して、パラメータ値の調整が必要。
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) 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による画像回転・回転後の画像の周囲は白で塗りつぶす設定にする。
コマンドオプション | デフォールト設定 | 意味 |
-h, --help | ヘルプ表示 | |
-i, --image | calendar.png | 入力画像ファイル |
--thr | 100 | threshold 直線を動かして、その直線状に乗ってきた点の数がこの値を超えたら線とみなす |
--lin | 200 | minLineLength ここに指定された値以上の長さを持つ線の候補が見つかったら、それを線として検出する |
--gap | 30 | maxLineGap 2つの点が1つ線上にある場合に、点と点の間の間隔がここに指定した数より小さければ、同一の線とみなす |
-o, --out | result/ | 処理結果を出力するディレクトリ (ファイル出力なしの場合は'non') ※ディレクトリは存在する必要あり |
(py37) $ cd ~/workspace_py37/pyocr (py37) $ python3 tilt_check.py --- Image tilt correction with OpenCV --- OpenCV version 4.5.2 Image tilt correction with OpenCV: Starting application... - Image File : tilt_sample.png - Threshold : 100 - MinLineLength: 200 - MaxLineGap : 30 - Out directory: result/ -20° 〜 +20° Horizontal Line count= 0, degree= 4.085616779974877 count= 1, degree= 1.2453642667683475 count= 2, degree= 1.5481576989779677 Rotete degree: 2.2930462485737304 Save file dir 'result/' Finished.
伝票の印影は文字認識の精度低下の一因となる。印影を消去する方法を検討する。
HSV色空間「色相(Hue)」「彩度(Saturation)」「明度(Value)」を考える。
意味 | 説明 | |
色相(H) | 色合い | 赤は 0度、黄色は 60度 というように角度で色合いが決まる |
彩度(S) | 色の鮮やかさ | 色相が同じ場合でも、彩度が高ければ鮮やかに見え、低ければグレーに見える。彩度がゼロの場合は無彩色[黒・灰色・白] |
明度(V) | 色の明るさ | 高いほど明るい色になる |
image = cv2.imread(input_filename)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# 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 で表現する。
# マスキング処理 masked_img = cv2.bitwise_and(img, img, mask=msk)
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
値の範囲 | OpenCV 値の範囲 (0~255) | |
Hue(赤) | 0~60, 300~360(°) | 0~30,150~179 |
Hue(緑) | 60~180(°) | 30~90 |
Hue(青) | 180~300(°) | 90~150 |
S | 25~100(%) | 64~255 |
V | 00~100(%) | 0~255 |
コマンドオプション | デフォールト設定 | 意味 |
-h, --help | ヘルプ表示 | |
-i, --image | color_circle.png | 入力画像ファイル |
-hn, --huemin | 320 | 抽出する色相(H)の最小値(0~360°) |
-hx, --huemax | 50 | 抽出する色相(H)の最大値(0~360°) |
-sn, --satmin | 5 | 抽出する彩度(S)の最小値(0~100%) |
-sx, --satmax | 100 | 抽出する彩度(S)の最大値(0~100%) |
-vn, --valmin | 50 | 抽出する輝度(V)の最小値(0~100%) |
-vx, --valmax | 100 | 抽出する輝度(V)の最大値(0~100%) |
--mode | 0 | 処理モード (0=指定色抽出, 1=指定色以外抽出, 2=印影除去) |
-o, --out | result/ | 処理結果を出力するディレクトリ (ファイル出力なしの場合は'non') ※ディレクトリは存在する必要あり |
(py37) $ cd ~/workspace_py37/pyocr (py37) $ python3 delcolor_check.py --- Color delete with OpenCV --- OpenCV version 4.5.2 Color delete with OpenCV: Starting application... - Image File : color_circle.png - Min Hue : 320 - Max Hue : 50 - Min Saturation: 5 - Max Saturation: 100 - Min Brightness: 50 - Max Brightness: 100 - Process mode : 0 - Out directory : result/ Input range: min= 320, max= 50 H area: min1= 0, max1= 25, min2= 160, max2= 179 S area: min= 13, max= 255 V area: min= 128, max= 255 Save file dir 'result/' Finished.・印影消去の例
(py37) $ cd ~/workspace_py37/pyocr (py37) $ python3 delcolor_check.py --mode 2 -i stamp1.png --- Color delete with OpenCV --- OpenCV version 4.5.2 Color delete with OpenCV: Starting application... - Image File : stamp1.png - Min Hue : 320 - Max Hue : 50 - Min Saturation: 5 - Max Saturation: 100 - Min Brightness: 50 - Max Brightness: 100 - Process mode : 2 - Out directory : result/ Input range: min= 320, max= 50 H area: min1= 0, max1= 25, min2= 160, max2= 179 S area: min= 13, max= 255 V area: min= 128, max= 255 Save file dir 'result/' Finished.
今回開発した OCR テストプログラム「ocrtest4.py」 の認識精度を調べる。
(py37) $ python3 ocrtest4.py -i [サンプルファイル名] -d b -o ./result/[結果出力ファイル名] --- OCR Test-4 list of line objects Display --- OpenCV version 4.5.2 OCR Test-4 list of line objects Display: Starting application... - Image File : [ファイル名] - Language : jpn - Preprocessing: n - Line delete : b - Confidence : 40 - Layout : 6 - Max size : 0 - Log frag : n - Program Title: y - Processed out: ./result/[結果出力ファイル名] :※ 画像をクリックすると拡大表示
画像ファイル | 同じサイズになるように拡大した入力画像 | デフォールト+罫線消去の結果 | スコア: 認識文字 |
'sample.png' キャプチャー 画面をキャプチャーした画像 (参考:サイズ 793x1122pixel) | 69: NS ホ ー ル ディ ング ス 株 式 会 社 御中 主 求 No. 20211011001 63: 評 日 2021 年 10 月 11 晶 96: 件 名 : ノー ト PC 用 メモ リー 96: 下記 の 通り 、 ご 請求 申し 上 げ ます 。 井筒 政弘 79: 〒533-0004 77: TEL: 080-1234-5678 92: 合計 金額 \8,500 (税込 ) 85: No. 岳 要 数 量 単価 金額 82: 1 PC4-25600(DDR4-3200) 16GB S0-DIMM 1 500 \8.500 59: 小計 \8.500 93: 井筒 政弘 ( イ ヅ ッ マサ ヒロ ) 86: l ー l | ||
'sample_jpg.jpg' JPEG Jpegフォーマットで保存された画像 拡大するとpeg特有のノイズがある (参考:サイズ 1240x1754pixel) | 88: 請 求 書 91: NS ホ ー ル ディ ング ス 株 式 会 社 御中 請求 No. 20211011001 96: 件 名 : ノー ト PC 用 メモ リー 96: 下記 の 通り 、 ご 請求 申し 上 げ ま す 。 井筒 政弘 92: 〒533-0004 90: 大 阪 市 東淀川 区 小松 2 丁目 22-22-222 92: TEL : 080-1234-5678 83: E-Mail : izutsum@venus.dti.ne.ip 93: 合計 金額 \8,500 (税込 ) 72: No. 摘要 数 量 単価 金額 70: 1 PC4-25600(DDR4-3200) 16GB S0-DIMM I 8.500 \8,500 82: 小計 \8,500 77: お 振込 先 90: 三菱 UFJ 銀行 吹田 支店 合計 \8,500 81: 普通 0123456 89: 井筒 政弘 ( イ ヅ ツ マサヒロ ) | ||
'sample0.png' PNG 150dpi 仮想プリンタに出力した画像 (参考:A4サイズ 1240x1754pixel) | 88: 請 求 書 90: NS ホ ー ル ディ ング ス 株 式 会 社 御中 請求 No. 20211011001 92: 請求 日 2021 年 10 月 11 日 96: 件 名 : ノー ト PC 用 メモ リー 96: 下記 の 通り 、 ご 請求 申し 上 げ ま す 。 井筒 政弘 92: 〒533-0004 89: 大 阪 市 東淀川 区 小松 2 丁目 22-22-222 92: TEL : 080-1234-5678 91: E-Mail : izutsum@venus.dti.ne.ip 93: 合計 金額 \8,500 (税込 ) 70: No. 摘要 数 量 単価 金額 80: 1 PC4-25600(DDR4-3200) 16GB SO-DIMM 1 8.500 \8,500 80: 小計 \8,500 92: お 振込 先 89: 三菱 UFJ 銀行 吹田 支店 合計 \8,500 79: 普通 0123456 91: 井筒 政弘 (イツ ヅ ツ マサ ヒロ ) | ||
'sample1.png' PNG 300dpi 仮想プリンタに出力した画像 (参考:A4サイズ 2479x3508pixel) | 92: 請 求 書 90: NS ホ ー ル ディ ング ス 株 式 会 社 御中 請求 No. 20211011001 83: 請求 日 2021 年 10 月 11 日 96: 件 名: ノー ト PC 用 メモ リー 79: 下記 の 通り 、 ご 請求 申し 上 げ ま す 。 井筒 政弘 91: 〒533-0004 91: 大 阪 市 東淀川 区 小松 2 丁目 22-22-222 91: TEL : 080-1234-5678 65: E-Mail : izutsum@venus.dti.ne.ip 92: 合計 金額 \8,500 (税込 ) 91: No. 摘要 数 量 単価 金額 91: 1 PC4-25600(DDR4-3200) 16GB SO-DIMM 1 8.500 \8.500 86: 小計 \8.500 92: お 振込 先 86: 三菱 UFJ 銀行 吹田 支店 合計 \8,500 65: 普通 0123456 93: 井筒 政弘 ( イ ヅ ツ マサ ヒロ ) 96: 備考 | ||
'sample2.png' PNG 600dpi 仮想プリンタに出力した画像 (参考:A4サイズ 4958x7017pixel) | 92: 請 求 書 92: NS ホ ー ル ディ ング ス 株 式 会 社 御中 請求 No. 20211011001 98: 請求 日 2021 年 10 月 11 日 96: 件 名 : ノー ト PC 用 メモ リー 79: 下記 の 通り 、 ご 請求 申し 上 げ ま す 。 井筒 政弘 91: 〒533-0004 91: 大 阪 市 東淀川 区 小松 2 丁目 22-22-222 91: TEL : 080-1234-5678 75: FE-Mail : izutsum@venus.dti.ne.jD 88: 合計 金額 \8,.500 (税込 ) 96: No. 摘要 数 量 単価 金額 90: 1 PC4-25600(DDR4-3200) 16GB SO-DIMM 1 8.500 \8.500 90: 小計 \8.500 90: お 振込 先 96: 三菱 UFJ 銀行 吹田 支店 合計 \8,500 63: 普通 0123456 90: 井筒 政弘 (イツ ヅ ツ マサ ヒロ ) 96: 備考 65: l |