ITや趣味など気軽に投稿しています。

【Python】OpenCVで画像から物体の輪郭を検出する

画像中の物体の境界を検出する輪郭検出は、画像処理の基本的なテクニックの一つです。輪郭とは、画像内の同じ色や明るさを持つ境界ピクセルを結んだ線のことです。

この記事では、OpenCVのcv2.findContours()を使って物体の輪郭を検出し、cv2.drawContours()で描画する方法を解説します。

輪郭検出の手順

輪郭検出は、以下の4つのステップで行います。

  1. 入力画像のグレースケール化

画像を読み込み、グレースケールに変換します。これは次の閾値処理のための準備です。

  1. 閾値処理

閾値処理を行い、物体と背景を明確に分離します。検出したい物体は白(255)、背景は黒(0)に変換されます(二値化)。

  1. 輪郭を検出する

cv2.findContours()で、二値化した画像から輪郭を検出します。

  1. 元の画像に輪郭を描画する

cv2.drawContours()で、検出した輪郭を元の画像に描画します。

Pythonで実装する

コード全体と結果

import cv2
import matplotlib.pyplot as plt
import japanize_matplotlib

# 入力画像
image = cv2.imread('input/cup.jpg')

# 画像のサイズ縮小
height = image.shape[0]
width = image.shape[1]
image = cv2.resize(image, (round(width / 4), round(height / 4)))

# グレースケール化
image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# 閾値処理
ret, thresh = cv2.threshold(image_gray, 95, 255, cv2.THRESH_BINARY)

# 輪郭検出
contours1, hierarchy1 = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# 輪郭の描画
img_contours = cv2.drawContours(
    cv2.cvtColor(image_gray, cv2.COLOR_BGR2RGB), contours1, -1, (0, 255, 0), 2, cv2.LINE_AA
)

# 表示
plt.figure(figsize=(10, 6))
plt.subplot(1, 2, 1)
plt.imshow(image)
plt.title('Original')
plt.axis("off")
plt.subplot(1, 2, 2)
plt.imshow(img_contours)
plt.title('輪郭検出')
plt.axis("off")
plt.show()
輪郭検出結果

前処理

画像の読み込み後、cv2.cvtColor()でグレースケールに変換し、cv2.threshold()で閾値処理を実行します。

# グレースケール化
image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# 閾値処理(95より大きいピクセルは255に、それ以外は0に)
ret, thresh = cv2.threshold(image_gray, 95, 255, cv2.THRESH_BINARY)

注意: 画像によって最適な前処理は異なります。閾値の値や前処理の手法は、対象画像に合わせて調整する必要があります。

輪郭検出(cv2.findContours())

cv2.findContours(image, mode, method[, contours[, hierarchy[, offset]]])
引数説明
mode輪郭の検索モード(階層の扱い方)
method輪郭の近似方法
contours検出された輪郭を格納するList
hierarchy輪郭の階層情報を格納するNumPy配列
offsetすべての輪郭点を指定の値だけシフトする
contours1, hierarchy1 = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

戻り値として、contours1に輪郭情報が格納されます。

輪郭描画(cv2.drawContours())

cv2.drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset]]]]])
引数説明
contours描画する輪郭を格納するList
contourIdx描画する輪郭のインデックス(-1で全輪郭を描画)
hierarchy輪郭の階層情報
maxLevel描画する最大階層
cv2.drawContours(image, contours1, -1, (0, 255, 0), 2, cv2.LINE_AA)

contourIdx-1を指定すると、すべての輪郭が描画されます。

まとめ

今回は、OpenCVで物体の輪郭を検出・描画する方法を紹介しました。

  • 輪郭検出には前処理(グレースケール化 + 閾値処理)が重要
  • cv2.findContours()で輪郭を検出する
  • cv2.drawContours()で検出した輪郭を画像に描画する
  • 精度を高めるために、画像に合わせた前処理の調整が必要