Open CV(Python)で表の認識

2020/10/17 categories:Python| tags:Python|Open CV|

前回作成した表画像のセル認識プログラムの中で、表のセル認識部分についてもう少し詳しく書いてみました。

テスト画像

テスト用の画像は下記のPNG画像です。

表のセルの大きさはまちまちで、セル内の文字の位置もまちまちな画像にしました。この画像から矩形を認識しようと思います。

画像の読み込み

cv2.imread()で画像を読み込みます。

cv2_image = cv2.imread('table.png')

グレースケール画像へ変換

エッジ検出に使用するグレースケール画像をcv2.cvtColor()で取得します。

gray = cv2.cvtColor(cv2_image, cv2.COLOR_BGR2GRAY)

取得した画像

エッジ画像へ変換

cv2.Canny()を使用してグレースケール画像からエッジを検出します。

edge = cv2.Canny(gray, 1, 100, apertureSize=7)

エッジ画像を膨張

読み込んだ画像の表の罫線に太さがあったのでエッジ画像のエッジが2重になっていました。そこでエッジ画像をcv2.dilate()を使って膨張処理を行いました。

kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (6, 6))
edge2 = cv2.dilate(edge, kernel)

エッジ画像から輪郭を抽出

cv2.findContours()を使ってエッジ画像から輪郭を抽出します。

contours, hierarchy = cv2.findContours(edge2, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

cv2.approxPolyDP()を使って輪郭を折れ線のカーブに近似します。今回は表のセルを認識するために四角形のみを抽出したいので、折れ線カーブの点の数が4点のものだけ抽出します。

curves = []
for contour, hierarchy in zip(contours, hierarchy[0]):
    curve = cv2.approxPolyDP(contour, 0.01*cv2.arcLength(contour, True), True)
    if len(curve) == 4:
        curves.append(curve)

抽出した折れ線カーブをY、Xの座標順でソートします。

curves = sorted( curves, key=lambda x: (x.ravel()[1], x.ravel()[0]) )

検出した四角形を画像に描画する

cv2.rectangle()を使用して画像に選出した四角形を描画します。

rect_image = cv2_image.copy()
for i, curve in enumerate(curves):
    p1, p3 = curve[0][0], curve[2][0]
    x1, y1, x2, y2 = p1[0], p1[1], p3[0], p3[1]
    r, g, b = random.random()*255, random.random()*255, random.random()*255
    cv2.rectangle(rect_image, (x1, y1), (x2, y2), (b, g, r), thickness=2)

これで四角形として認識したエリアを確認できました。

ソースコード

## -*- coding: utf-8 -*-
import cv2
import random

def main():
    cv2_image = cv2.imread('table.png')
    
    gray = cv2.cvtColor(cv2_image, cv2.COLOR_BGR2GRAY)
    cv2.imwrite('gray.jpg', gray)

    edge = cv2.Canny(gray, 1, 100, apertureSize=7)
    cv2.imwrite('edge.jpg', edge)

    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (6, 6))
    edge2 = cv2.dilate(edge, kernel)
    cv2.imwrite('edge2.jpg', edge2)

    contours, hierarchy = cv2.findContours(edge2, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

    curves = []
    for contour, hierarchy in zip(contours, hierarchy[0]):
        curve = cv2.approxPolyDP(contour, 0.01*cv2.arcLength(contour, True), True)
        if len(curve) == 4:
            curves.append(curve)
    curves = sorted( curves, key=lambda x: (x.ravel()[1], x.ravel()[0]) )

    rect_image = cv2_image.copy()
    for i, curve in enumerate(curves):
        p1, p3 = curve[0][0], curve[2][0]
        x1, y1, x2, y2 = p1[0], p1[1], p3[0], p3[1]
        r, g, b = random.random()*255, random.random()*255, random.random()*255
        cv2.rectangle(rect_image, (x1, y1), (x2, y2), (b, g, r), thickness=2)
    cv2.imwrite('rect_image.jpg', rect_image)

if __name__ == "__main__":
    main()

Share post

Related Posts

コメント