はじめに
OCRで読み込ませる時に、画像の枠線や罫線がノイズとなり、邪魔をして正しく読み込めないときがあります。
ここでは、そのような線を検出し、削除してみたいと思います。
ハフ変換という関数を利用するのですが、ハフ変換ってなんぞや?という感じで、ここでは説明しませんので、ググってください…。
では、やることについて1つずつ説明し、最後にすべてのソースをくっつけてみます。
直線の検出方法
HoughLinesP 関数を使い、白と黒だけの2値画像から検出
下記のステップでやってみます
0.画像の読み込み
- グレースケールに変換
- ネガポジ変換で反転
- ハフ変換でラインの検出
- 線の色付け
0. 画像の読み込み
- 対象となる画像です
img = cv2.imread("calendar.png")
1. グレースケールに変換
グレースケールに変換します。
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imwrite("calendar_mod.png", gray)
2. ネガポジ変換で反転
この変換で白と黒を逆転させ、白黒はっきりさせます。
こうすることで、線が白く(明るく)なり、特定がしやすくなります。
gray2 = cv2.bitwise_not(gray)
cv2.imwrite("calendar_mod2.png", gray)
3. ハフ変換でラインの検出
ハフ変換自体難しく、ここでハマりました。
ここでは対象の画像に対して、パラメータ値の調整が必要になります。
- rho, theta はデフォルトを利用
- threshold は、直線を動かして、その直線状に乗ってきた点の数がこの値を超えたら線とみなす
- minLineLength は、ここに指定された値以上の長さを持つ線の候補が見つかったら、それを線として検出する
- maxLineGapは、2つの点が1つ線上にある場合に、点と点の間の間隔がここに指定した数より小さければ、同一の線とみなす
minLineLengthの値を大きい場合
lines = cv2.HoughLinesP(gray2, rho=1, theta=np.pi/360, threshold=80, minLineLength=400, maxLineGap=5)
print(lines)
- lineの座標 x1, y1, x2, y2 が7セットだけ返ってきました。
[[[ 11 391 515 391]]
[[ 11 139 515 139]]
[[ 11 13 515 13]]
[[ 11 328 515 328]]
[[ 11 265 515 265]]
[[ 11 76 515 76]]
[[ 11 202 515 202]]]
- 下図の赤線7本になります。(線の色付けは次項参照)
- minLineLengthの値が縦線の長さを超えてしまってるため、縦線が検出されていません。
minLineLengthの値を小さい場合
lines = cv2.HoughLinesP(gray2, rho=1, theta=np.pi/360, threshold=80, minLineLength=30, maxLineGap=5)
- 今度は文字部分までが線と認識されてしまいました。
調整の上、今回の画像はこのくらい
lines = cv2.HoughLinesP(gray2, rho=1, theta=np.pi/360, threshold=80, minLineLength=80, maxLineGap=5)
4. 線の色付け
赤線で線を引く
上記にもあるとおり、線の座標が返ってくるので、色を付けるのがこちらになります。
複数の線座標が取れるので、ループで回して、line関数に設定していきます。
その結果が上記の赤線の図です。
for line in lines:
x1, y1, x2, y2 = line[0]
# 赤線を引く
red_line_img = cv2.line(img, (x1,y1), (x2,y2), (0,0,255), 3)
cv2.imwrite("calendar_mod3.png", red_line_img)
線を消す
逆に線を消すには、白で線を塗りつぶせば良いのです。
for line in lines:
x1, y1, x2, y2 = line[0]
# 線を消す(白で線を引く)
no_lines_img = cv2.line(img, (x1,y1), (x2,y2), (255,255,255), 3)
cv2.imwrite("calendar_mod4.png", no_lines_img)
まとめ
上記のソースをまとめるとこのようになります。
import cv2
import numpy as np
# カレンダー
img = cv2.imread("calendar.png")
img2 = img.copy()
img3 = img.copy()
# グレースケール
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imwrite("calendar_mod.png", gray)
## 反転 ネガポジ変換
gray2 = cv2.bitwise_not(gray)
cv2.imwrite("calendar_mod2.png", gray2)
lines = cv2.HoughLinesP(gray2, rho=1, theta=np.pi/360, threshold=80, minLineLength=80, maxLineGap=5)
for line in lines:
x1, y1, x2, y2 = line[0]
# 赤線を引く
red_lines_img = cv2.line(img2, (x1,y1), (x2,y2), (0,0,255), 3)
cv2.imwrite("calendar_mod3.png", red_lines_img)
# 線を消す(白で線を引く)
no_lines_img = cv2.line(img3, (x1,y1), (x2,y2), (255,255,255), 3)
cv2.imwrite("calendar_mod4.png", no_lines_img)