目次
概要
OpenCV の cv2.HoughCircles で円を検出する方法について紹介します。
cv2.HoughCircles
circles = cv2.HoughCircles(image, method, dp, minDist[, circles[, param1[, param2[, minRadius[, maxRadius]]]]])
公式リファレンス: cv2.HoughCircles
引数
名前 | 型 | デフォルト値 |
---|---|---|
image | ndarray | |
入力画像 (1チャンネル) | ||
method | HoughModes | |
ハフ変換の手法。現在、選択できる手法は cv2.HoughModes のみである。 | ||
dp | float | |
投票器の解像度 | ||
minDist | float | |
検出される円同士が最低限離れていなければならない距離。同じ円に対して重複して検出されるのを防ぐ役割がある。 | ||
param1 | float | |
Canny 法のヒステリシス処理の上限。ヒステリシス処理の下限はこの値の半分に設定される。 | ||
param2 | float | |
円の中心を検出する際の閾値。低い値にすると、円の誤検出が増え、高い値にすると未検出が増える可能性がある。 | ||
minRadius | int | |
検出する円の半径の下限を $[0, maxRadius]$ の範囲で指定する。 | ||
maxRadius | int | |
検出する円の半径の上限を $minRadius$ 以上の値で指定する。 |
返り値
名前 | 説明 | ||
---|---|---|---|
circles | 検出された円の一覧。各要素は (中心の $x$ 座標, 中心の $y$ 座標, 半径) のタプル。 |
サンプルコード
cv2.HoughLine()
と異なり、cv2.HoughCircles()
内で Canny 法も行うため、グレースケール画像を入力とします。
In [1]:
import cv2
from IPython.display import Image, display
def imshow(img):
"""ndarray 配列をインラインで Notebook 上に表示する。"""
ret, encoded = cv2.imencode(".jpg", img)
display(Image(encoded))
In [2]:
import cv2
import numpy as np
# 画像を読み込む。
img = cv2.imread("sample.jpg")
# グレースケールに変換する。
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# ハフ変換で円検出する。
circles = cv2.HoughCircles(
gray, cv2.HOUGH_GRADIENT, dp=1.0, minDist=10, param1=80, param2=100
)
circles = circles.squeeze(axis=1)
検出された円の一覧を形状が (NumCircles, 1, 3)
の ndarray で返します。
各要素は検出された円の中心 $(x, y)$ 及び円の半径 $r$ を表します。
In [3]:
# 検出結果を描画する。
if circles is not None:
for cx, cy, r in circles.astype(int):
# 円の円周を描画する。
cv2.circle(img, (cx, cy), r, (0, 255, 0), 2)
# 円の中心を描画する。
cv2.circle(img, (cx, cy), 2, (0, 255, 0), 2)
imshow(img)
ipywidgets でパラメータ調整する
ハフ変換はパラメータ調整が必須です。ipywidgets を使って GUI 上でパラメータ調整を行う方法について記載します。
In [4]:
import cv2
from IPython.display import Image, display
from ipywidgets import widgets
def imshow(img):
"""画像を Notebook 上に表示する。"""
ret, encoded = cv2.imencode(".png", img)
display(Image(encoded))
def hough_circle(img, dp, minDist, param1, param2, radius):
"""ハフ変換で円検出を行い、結果を表示する。"""
minRadius, maxRadius = radius
# グレースケールに変換する。
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# ハフ変換で円検出する。
circles = cv2.HoughCircles(
gray,
cv2.HOUGH_GRADIENT,
dp=dp,
minDist=minDist,
param1=param1,
param2=param2,
minRadius=minRadius,
maxRadius=maxRadius,
)
# 検出した円を描画する。
copied = img.copy()
if circles is not None:
for cx, cy, r in circles.squeeze(axis=0).astype(int):
# 円の円周を描画する。
cv2.circle(copied, (cx, cy), r, (0, 255, 0), 2)
# 円の中心を描画する。
cv2.circle(copied, (cx, cy), 2, (0, 255, 0), 2)
imshow(copied)
# パラメータ「dp」を設定するスライダー
dp_slider = widgets.FloatSlider(
min=0.1, max=10.0, step=0.1, value=1.0, description="dp: "
)
dp_slider.layout.width = "400px"
# パラメータ「minDist」を設定するスライダー
min_dist_slider = widgets.IntSlider(
min=1, max=500, step=1, value=10, description="minDist: "
)
min_dist_slider.layout.width = "400px"
# パラメータ「param1」を設定するスライダー
param1_slider = widgets.IntSlider(
min=1, max=300, value=80, step=1, description="param1:"
)
param1_slider.layout.width = "400px"
# パラメータ「param2」を設定するスライダー
param2_slider = widgets.IntSlider(
min=1, max=300, value=100, step=1, description="param2:"
)
param2_slider.layout.width = "400px"
# パラメータ「radius」を設定するスライダー
radius_slider = widgets.IntRangeSlider(
min=0, max=500, value=[0, 500], step=1, description="radius:"
)
radius_slider.layout.width = "400px"
# 画像を読み込む。
img = cv2.imread("sample.jpg")
# ウィジェットを表示する。
widgets.interactive(
hough_circle,
img=widgets.fixed(img),
dp=dp_slider,
minDist=min_dist_slider,
param1=param1_slider,
param2=param2_slider,
radius=radius_slider,
)
コメント