Python

画像 から 横線 のみ取得してみた!【 Python OpenCV 】

k.w

Python + OpenCV を使って、 画像 から 線 を取得をする場合、 横線 のみ取得したいという場合もあると思います。
直線を取得する”HoughLinesP”の使い方の基本をおさえることが出来ていれば応用で可能となります。今回は横線の取得に絞って紹介したいと思います。

縦線のみ取得はこちらから

[https://way2se.ringtrees.com/py_cv2-002/]

スポンサーリンク

サンプル画像

どこにでもあるような2次元表をサンプルとして取り上げます。
(サイズ → 横:313px 縦:132px)

使用するライブラリ説明

【HoughLinesP】

lines = cv2.HoughLinesP(img, rho, theta, threshold, minLineLength, maxLineGap)

  • img:取り込む画像。
  • rho:よくわかりませんが、デフォルト 1 で問題なさそう。
  • theta:ランダムに線を判断するための回転角。大きくすれば複雑な線を認識する。
  • threshold:文字などの非線を除外する閾値(の様なもの)
  • minLineLength:連なる点の集合の、最小値。この値以上を線としてみなす。
  • maxLineGap:どれだけ離れている点(線)を一つの線としてみなすか判断。

各引数をふった挙動事例は以下をご覧ください。

[https://way2se.ringtrees.com/py_cv2-004/]

サンプルソース(コード)

/* import設定 */
import os
import configparser as cfg
import glob
import cv2
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from operator import itemgetter

/* Config設定 */
cfg = cfg.ConfigParser()
cfg.read('config.ini', 'UTF-8')

/* File読み込みフォルダ指定 */
files = glob.glob(cfg.get('Folder', 'img_folder') + '/*.jpg', recursive=True)

/* File読み込み(複数可) */
for file in files:
    filename = os.path.basename(file)
    print('File:' + filename)
    img = cv2.imread(file, 0)
    height, width = img.shape
    minlength = width * 0.7
    gap = 0
    judge_img = cv2.bitwise_not(img)

    lines = []
    lines = cv2.HoughLinesP(judge_img, rho=1, theta=np.pi/360, threshold=100, minLineLength=minlength, maxLineGap=gap)

    line_list = []
    for line in lines:
        x1, y1, x2, y2 = line[0]
        /* 傾きを3px以内と判断 */
        if abs(y1 - y2) < 3:
            whiteline = 3
            lineadd_img = cv2.line(judge_img, (line[0][0], line[0][1]), (line[0][2], line[0][3]), (255, 255, 255), whiteline)
            x1 = line[0][0]
            y1 = line[0][1]
            x2 = line[0][2]
            y2 = line[0][3]
            line = (x1, y1, x2, y2)
            line_list.append(line)

    line_list.sort(key=itemgetter(1, 0, 2, 3))

    hoz_line = 0
    hoz_line_list = []
    y1 = 0
    for line in line_list:
        judge_y1 = line[1]
        if abs(judge_y1 - y1) < 2 and hoz_line_list != []:
            y1 = judge_y1
        else:
            y1 = judge_y1
            hoz_line = hoz_line + 1
            hoz_line_list.append(line)

    print('>>HZ_line:' + str(hoz_line))
    line_list = pd.DataFrame(hoz_line_list)
    print('line_list_pd')
    print(line_list)
    plt.imshow(lineadd_img)

※コンフィグ設定(11~13行目)については、以下参照ください。

[https://way2se.ringtrees.com/py_cfg-001/]

線を取得する場合はコードは、たったの一行!(29行目)。

今回は、横線取得が目的ですので、あらかじめ縦線を認識しないように調整すると良いです。

コツは、(今回の様な横長の図の場合でいえば)minLengthを大きくし、あらかじめ縦線を認識しないようにしました。
minLengthを大きくすると認識率が良かったです。(24行目)
長さ優先で取得するようなので、特性を理解して微調整してください。

取得した線がすべて横線であれば良いのですが、最終的には、平行な横線のみ取り扱うため、ふるいにかけています。(31行目~)

平行な横線の定義は、y1とy2が同じ値となります。

取り扱う画像によって、多少の傾きが発生しますので、少し余裕を持たせて判断しています。(35行目)

ふるいにかけた線を取得・蓄積し、抽出し完了です。(45行目)

上記、ソースを実行した際に結果です。
黄色の部分が線として認識している部分です。

取得した横線のカウントも行ってみました。
図では判断できない場合も、容易に確認できると思います。(47行目~)

ぜひ、トライして、各パラメータを振って意図通りに取得できるようになりましょう!

 

ABOUT ME
記事URLをコピーしました