以前、輪郭の内側の面積と周囲長の関係から円形度なる値を求め、円らしき領域を抽出する方法を行いました。
この考え方を応用して、今度は、矩形度(長方形らしさ)なる値を求めて、矩形らしき領域を抽出する方法を考えてみたいと思います。
矩形(長方形)は、名刺や本、コピー用紙のように、割と良く目にする図形なので、応用範囲は広いかと思います。ただし、今回紹介する方法は、四角形の被写体を斜めから撮影して、台形のようになってしまう画像には対応できません。
今回は、OpenCVを用いて、輪郭の内側の面積をcontourArea()関数で求め、輪郭を囲う最小の矩形領域の面積をminAreaRect()関数で求めて、この2つの面積の比で、矩形度なる値を求めます。
ただし、矩形度という言葉や計算方法が教科書的に存在するのかは不明です。(私が勝手に言ってます。)
この2つの面積が一致していれば完全に矩形(長方形)となります。
矩形度(小) | 矩形度(中) | 矩形度(大) |
サンプルプログラム
矩形度を求め、下図の中から矩形らしい部分を抽出するサンプルプログラムは以下の通りです。
(サンプルプログラム)
import cv2
import numpy as np
def rectangularity(contour):
'''
矩形度を求める
Parameters
----------
contour : ndarray
輪郭の(x,y)座標の配列
Returns
-------
矩形度
'''
# 面積
area = cv2.contourArea(contour)
# 傾いた外接する矩形領域
_, (width, height), _ = cv2.minAreaRect(contour)
# 矩形度を返す
return area / width / height
# 8ビット1チャンネルのグレースケールとして画像を読み込む
img = cv2.imread("image.jpg", cv2.IMREAD_GRAYSCALE)
# 白黒反転して二値化
ret, img = cv2.threshold(img, 128, 255, cv2.THRESH_BINARY_INV)
# 一番外側の輪郭のみを取得
contours, hierarchy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE )
# 画像表示用に入力画像をカラーデータに変換する
img_disp = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
# 全ての輪郭を描画
cv2.drawContours(img_disp, contours, -1, (0, 0, 255), 2)
# 輪郭の点の描画
for contour in contours:
# 傾いた外接する矩形領域の描画
rect = cv2.minAreaRect(contour)
box = cv2.boxPoints(rect)
box = np.intp(box)
cv2.drawContours(img_disp,[box],0,(0,255,255), 1)
# 矩形度の計算
val = rectangularity(contour)
# 輪郭の矩形領域
x,y,w,h = cv2.boundingRect(contour)
# 矩形度の描画
cv2.putText(img_disp, f"{val:.3f}", (x, y-10), cv2.FONT_HERSHEY_PLAIN, 2, (0, 255, 0), 1, cv2.LINE_AA)
# 円らしい領域(円形度が0.85以上)を囲う
if val > 0.85:
cv2.rectangle(img_disp,(x-10,y-10),(x+w+10,y+h+10),(255,0,0),2) # 少し外側を囲う
cv2.imshow("Image", img_disp)
# キー入力待ち(ここで画像が表示される)
cv2.waitKey()
実行結果