以前の質問をもとに表の認識の実験をしております
https://teratail.com/questions/151317
そこで以下のソースで表の枠を認識してみました。
python
1import cv2 2import numpy as np 3 4img = cv2.imread('no300.jpg') 5 6# BGR -> グレースケール 7gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 8# エッジ抽出 (Canny) 9edges = cv2.Canny(gray, 1, 100, apertureSize=3) 10cv2.imwrite('edges.png', edges) 11# 膨張処理 12kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3)) 13edges = cv2.dilate(edges, kernel) 14cv2.imwrite('edges2.png', edges) 15# 輪郭抽出 16contours,hierarchy = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) 17# 面積でフィルタリング 18rects = [] 19for cnt, hrchy in zip(contours, hierarchy[0]): 20 if cv2.contourArea(cnt) < 2000: 21 continue # 面積が小さいものは除く 22 if hrchy[3] == -1: 23 continue # ルートノードは除く 24 # 輪郭を囲む長方形を計算する。 25 rect = cv2.minAreaRect(cnt) 26 rect_points = cv2.boxPoints(rect).astype(int) 27 rects.append(rect_points) 28 29# x-y 順でソート 30rects = sorted(rects, key=lambda x: (x[0][1], x[0][0])) 31 32# 描画する。 33for i, rect in enumerate(rects): 34 cv2.drawContours(img, rects, i, (0,0,255), 2) 35 36cv2.imwrite('img.png', img)
###解決したいこと
住所、氏名、生年月日のあたりに意図しない斜めになった四角の枠が認識されています。
これを認識しない方法はございませんでしょうか。
試したこと
cv2.contourArea(cnt) < 2000:
の部分を調整してみますが、大きくしすぎると欲しいデータまで消えてしまいます。
よろしくお願いします。
斜めの物が出てくる原因の確認くらいはご自身でされるべきではないでしょうか.
(やっているならその情報を書いた方が良いし.)
特にこれ系の処理方法の検討中なのであれば,各処理(このコードで言えば,エッジ検出や膨張処理,輪郭抽出等)の結果を可視化しておくくらいのことは必須でしょう.
最終結果だけを見て場当たり的に面積閾値でどうこうするのではなく,まずは各段階の結果が想定と異っていないか等を見るべきです.
ご指摘ありがとうございます。
各工程、edges.png、edges2.pngで確認し、膨張処理のgetStructuringElementのパラメーターなど変えて試していました。
その結果を受けて面積でフィルタリングしております。
その部分の試したことは記入漏れでした。
途中の工程のpng画像を見ても、その周辺に私の目では輪郭となるような部分があるように思えませんでした。
そこで質問させていただいた次第です。
よろしくお願いします。
輪郭形状に対してminAreaRectを使ったら,斜めのやつが出てくるという現象になっている
→では,該当の輪郭形状とは一体どうなっているのか? 欲しい枠の形をしているのかいないのか.
→もし,枠の形をしているのにminAreaRectの結果が斜めになるという話なら,minAreaRectはあなたの目的に対しては使えないという話になる.
→変な形の輪郭になっているのなら,その原因は何か?という話になる.
findContoursへの入力画像を見て,その要因を探る.
→本当に変な形が存在するならばそれ→その形ができる原因は…?
→変な形は無いのに何故か変な形のcontourが得られるという話なら,相応のことを考えねばならない.
minAreaRectの結果矩形の4つの辺は与えた輪郭の一部に重なっているハズなので,例えばその結果例の斜めになっている結果群のうちの一番右上に位置している横方向にでかいやつ(左側が「殿」を含んでいるやつ)とかは,輪郭自体が変な形に取れてしまっているのでは?と思える.
斜めの長方形が抽出された原因はわかりませんが、抽出結果から斜めの輪郭を弾くなら、cv2.minAreaRect() で輪郭に外接する回転した長方形が得られるので、その回転角度で判定すればよいと思います。
fana様
おそらく輪郭と認識する情報が入っているからと思われますので、エッジ抽出のあたりから考え直す必要があると考えております。
tiitoi様
フィルタリング対象に角度も追加することで少なくとも今回のパターンでの誤認識が減ると思います。
ご回答ありがとうございます。
cannyフィルタの後でdilateを入れているのは,
(1)単純に短距離のエッジの途切れを埋める目的
の他に,
(2)絵の上での太い線に対して(その線の両側に)2重にエッジが出るようなものをくっつける(太い1本にする:= → ━)という役割
があるのかな?等と勝手に推測しますが,このとき,結果としてくっつく部分とくっつかない(隙間がある状態になる)部分とが存在すると,変な輪郭形状が生まれるような気もします.
これ,cannyとか必要なんですかね?
(この例だけもしれませんが,割と綺麗な絵ですし)2値化して即輪郭抽出とかの方が,やりたいことに対して正直な実装だったりしませんか?
私が初心者ということもあり、以下をそのまま使わせていただいています
https://teratail.com/questions/151317
ただ、2値化しての実験もしてみましたが、
im = cv2.imread('no300.jpg')
im_gray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
retval, im_bw = cv2.threshold(im_gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
contours, hierarchy = cv2.findContours(im_bw, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
個人番号部分の線が繋がらなかったりしました。
そこで以前の質問があったものを見て、やってみたらうまくつながった次第です。
2値化したものの線が途切れていました。
やり方次第で線が繋がるかもしれません。
線を太くするなどの工夫が必要です。
>>2値化して即輪郭抽出とかの方が,やりたいことに対して正直な実装だったりしませんか?
そのように思います。
ありがとうございました。
> 2値化したものの線が途切れていました。
2値化の閾値を自分で与えるとか,閾値決定方法を変えるとか.adaptiveThresholdをブロックサイズでかめで(例えば,画像サイズの半分とか1/4とかそういうレベルで)かけてみるとか.
あとは(cannyのときと同様に)途切れがちょびっとだけならモルフォロジで塞ぐとか.
回答2件
あなたの回答
tips
プレビュー

