質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Q&A

解決済

2回答

18833閲覧

OpenCVでの表のセルの認識方法

hizuh

総合スコア14

OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

0グッド

5クリップ

投稿2018/10/11 03:24

実現したいこと

画像データから、表のセルの位置(四隅の座標)を取得したいと考えています。

例えば、画像に次のような表があった場合、

ABC
DEF
GHI

セルAの四隅の座標
セルBの四隅の座標



セルIの四隅の座標

というデータを取得したいです。

いろいろなサイトで調べた結果、OpenCVでセルの輪郭を抽出すればできそうなところまでは
わかったのですが、具体的にどのような処理を行えばいいのかわからず、困っています。

OpenCV、もしくは、別の方法で、画像データからセルの座標を認識する方法をご教授
いただけないでしょうか。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

手順

以下の方針で行うのはどうでしょうか。

  1. Canny でエッジ検出する。
  2. findContours() で輪郭抽出する。
  3. 輪郭の面積、頂点数などいくつかの基準で対象外の輪郭をフィルタする。
  4. 輪郭を囲む長方形を計算する。
  5. 長方形の4点の座標を表示する。

サンプルコード

python

1import cv2 2import numpy as np 3 4img = cv2.imread('form.png') 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) 14# 輪郭抽出 15_, contours, hierarchy = cv2.findContours(edges, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) 16# 面積でフィルタリング 17rects = [] 18for cnt, hrchy in zip(contours, hierarchy[0]): 19 if cv2.contourArea(cnt) < 3000: 20 continue # 面積が小さいものは除く 21 if hrchy[3] == -1: 22 continue # ルートノードは除く 23 # 輪郭を囲む長方形を計算する。 24 rect = cv2.minAreaRect(cnt) 25 rect_points = cv2.boxPoints(rect).astype(int) 26 rects.append(rect_points) 27 28# x-y 順でソート 29rects = sorted(rects, key=lambda x: (x[0][1], x[0][0])) 30 31# 描画する。 32for i, rect in enumerate(rects): 33 color = np.random.randint(0, 255, 3).tolist() 34 cv2.drawContours(img, rects, i, color, 2) 35 cv2.putText(img, str(i), tuple(rect[0]), cv2.FONT_HERSHEY_SIMPLEX, 0.8, color, 3) 36 37 print('rect:\n', rect) 38 39cv2.imwrite('img.png', img)

output

1rect: 2 [[ 57 146] 3 [ 57 100] 4 [140 100] 5 [140 146]] 6rect: 7 [[145 146] 8 [145 100] 9 [318 100] 10 [318 146]] 11rect: 12 [[321 146] 13 [321 100] 14 [406 100] 15 [406 146]]

結果画像

イメージ説明
元画像

イメージ説明
認識結果

投稿2018/10/11 04:46

編集2018/10/11 07:51
tiitoi

総合スコア21954

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hizuh

2018/10/15 16:25

ありがとうございます! 回答いただいた内容が、まさしく実現したい内容です。 対象にしたい画像が、サンプル画像のようなきれいな表だけではないため、 サンプルコードを基にいろいろと試してみたいと思います。 本当にありがとうございました。
guest

0

直面している問題固有の前提条件や知識があるならばそれを活用できないかを考えてみてはどうでしょうか
(というか,そういう前提条件の情報があるなら先に出した方が,活用しやすい回答が得られやすくなるかと)
例えば

  1. 処理対象画像の状態はどんな?

エクセルのスクリーンショットを撮ったような「綺麗な」絵なのか,印刷物をカメラ撮影したような絵なのか,etc...
2. 表の色に関する知識は使える?
{罫線の色,セル内の背景の色,セル内の文字等の色}との関係性とか
3. "表"の仕様的な話は?
セル内の文字等と,セルの輪郭との間には必ず間隔があるとか

みたいな事柄は定まっていないのでしょうか?

例えば…

  • 【上記3が真であって,且つ,上記2に関しては「文字と罫線は黒くて,セル内部の背景色は白や灰色だよ」】みたいな前提があるならば,理想的な話をすれば「2値化処理した後に一番大きい黒い塊を探す」だけでもう罫線だけを抽出できるかもしれませんよね.

(→すなわち,文字等の領域を全て棄却できるから,あとは単純にセルを閉領域として検出すればいい)

  • 上記1がカメラ撮影側で,しかも【表をかなり斜め方向から撮影することがあります】とかいう話だと,画像上でのセルが長方形であることを常には期待できないという話になるし.
  • 【tiitoi氏が提示している絵のような形で(エクセル上でセル連結したような感じの)セルが存在する「ことはなくて」質問文にあるようなシンプルな表だけ考えれば良いんです】という話なのであれば,それに特化した方法を考えられるかもしれない.(縦横の直線を先に検出してその交点座標をベースにセルを見つけるみたいな方向とか)

投稿2018/10/12 05:45

fana

総合スコア11632

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hizuh

2018/10/15 16:28

回答ありがとうございます。 表の画像の処理に関して、どのような観点で考えればよいのか、とても参考になりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問