OpenCVで円検出をハフ変換により行う【HoughCircles】

OpenCVで円検出をハフ変換により行う【HoughCircles】 プログラミング

OpenCVで円検出する方法を探していますか?
その場合、ハフ変換によるHoughCirclesをよく目にすることでしょう。

たまに「最小外接円」を推している場合もあります。
しかし、ハフ変換によるHoughCirclesを検証することになるはずです。

情報量が、圧倒的に異なりますからね。
と言っても、「OpenCVにおける円検出」自体の情報がもともと少ないのですけど。

では、優勢なハフ変換によるHoughCirclesを検証した結果はどうなるでしょうか?

「使いモノにならない」
「条件さえ決めれば、使えるかも」

結果は、このどちらかにくっきりと分かれるでしょう。

本記事の内容

  • ハフ変換を用いて円を検出するHoughCircles関数
  • HoughCircles関数を試す
  • HoughCircles関数の実用度を検証
  • 【結論】HoughCircles関数は使える?使えない?

それでは、上記に沿って解説していきます。

ハフ変換を用いて円を検出するHoughCircles関数

HoughCirclesは、OpenCVで円検出を行うための関数です。

HoughCircles(image, method, dp, minDist, param1, param2, minRadius, maxRadius)

パラメータ一覧

image入力画像 (シングルチャンネル)
methodハフ変換の手法
現状、cv2.HOUGH_GRADIENTのみ設定可
dp処理時の画像解像度レベル
1:解像度変更なし、2:解像度を半分に変更
minDist検出される円の中心同士の最小距離
param1

Canny() エッジ検出器に渡される2つの閾値の大きい方
低いほど、誤検出が生じる
param2円の中心を検出する際の投票数の閾値
低いほど、誤検出が生じる
minRadius検出される円の最小半径
maxRadius検出される円の最大半径

実際にHoughCircles関数を利用しているコードは、以下。

import cv2
import numpy as np

INPUT_IMG = "input.png"

src = cv2.imread(INPUT_IMG)
gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
gray = cv2.medianBlur(gray, 5)


circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT,dp=1,minDist=70,
                            param1=100,param2=55,minRadius=10,maxRadius=0)

circles = np.uint16(np.around(circles))

for i in circles[0,:]:
    # draw the outer circle
    cv2.circle(src,(i[0],i[1]),i[2],(0,255,0),2)
    # draw the center of the circle
    cv2.circle(src,(i[0],i[1]),2,(0,0,255),3)


cv2.imshow('result', src)
cv2.waitKey(0)
cv2.destroyAllWindows()

cv2.imwrite('output.png', src)

用意した画像は以下。
まずは、この画像imread関数で読み込みます。

サイズは、500 x 364。

cvtColor関数により、読み込んだ画像をグレースケール化します。

さらに、グレースケール化した画像をmedianBlur関数でぼかします。

この画像をHoughCircles関数の入力画像とします。
あとは、HoughCircles関数で出力された円情報をもとに円を描画していきます。

円を描画するのは、グレースケール化する前のオリジナル画像に対してです。
円が描画された最終画像は、以下。

これは、ハフ変換を用いて円を上手く検出できたケースです。
もちろん、HoughCircles関数のパラメータを調整しています。

では、以降ではHoughCircles関数の現実を見ていきます。

HoughCircles関数の実用度を検証

画像を変えて、先ほどのプログラムを実行してみましょう。
極力、同じようなテイストの画像です。

HoughCircles関数のパラメータは、そのままで。
用いる画像は、以下。
サイズは、500 x 333。

プログラムを実行した結果の画像は、以下。

HoughCircles関数のパラメータを変更せずに、円検出ができました。
いい感じですね。

ここまでは、HoughCircles関数のいいところを見てきました。
そして、対象とした画像は同じサイズで同じテイストでした。

しかし、次の要素が異なる場合に結果はどうなるのでしょうか?

  • サイズ
  • テイスト

それぞれを確認していきます。

サイズが異なる場合

画像のサイズを変更してみましょう。
2倍(1000x 666)の大きさの画像にします。

HoughCircles関数のパラメータを変更せずに実行した結果は、以下。
実物は1000 x 666のサイズですが、500 x 333にリサイズしています。

ダメですね。
私たちには見えないものまで、円として検出しています。

widthで表すと300~800までは、円検出が上手くできました。
パラメータ調整したベースとなるwidthが、500です。

今回の結果だけを見ると、次のことが言えます。
「サイズ比率が0.6~1.6なら、パラメータ調整なしでそのまま使える」と。

では、次に全く異なるテイストの画像に変更してみましょう。

テイストが異なる場合

この場合、サイズは500 x 364に近いモノにします。
このサイズは、パラメータ調整をしたベースとなる画像のサイズです。

背景色が異なる

これの結果は、以下。

背景色が白から黒に変わっても、円検出を上手くできています。
円(お金)自体のサイズも同じことが、好結果の要因なのでしょうか?

円の大きさが異なる

結果は、以下。

円検出ができています。
HoughCircles関数のパラメータmaxRadiusで指定しなければ、円のサイズが大きくても問題ないようです。

角度が異なる

人間の目で見れば、円に見えます。
さて、その結果は・・・

全然ダメですね。
真上や真正面からじゃないと、円検出は厳しいのかもしれません。

重なり合う

真正面から重なり合う場合はどうでしょうか?

完全に混乱していますね。
大量に重なり合う場合は、全く使えないです。

【結論】HoughCircles関数は使える?使えない?

上記の結果を見れば、各自で結論を出せるはずです。
ただ、その結論は冒頭で示したように分かれるでしょう。

ポイントは、条件をクリアした画像を用意できるかどうかでしょうね。
その条件とは、画像サイズ、角度(真上・真正面)、対象物の配置などです。

画像(写真)を取る角度によって、円ではなくなってしまいます。
そのため、真上・真正面から対象物を撮影することが必須となります。

配置も重要な要素です。
対象物同士の距離も重要ですが、重ねることもアウトです。
よって、対象物同士は適度な距離を取り、重さならないようにする必要があります。

上記で述べた条件をクリアした画像であれば、HoughCircles関数は十分に使えるでしょう。
しかし、条件を一つでもクリアできないとHoughCircles関数は使いモノになりません。

現状、HoughCircles関数を触ってみた上での意見となります。
OpenCVを用いて円検出を行う上での参考になれば、幸いです。

タイトルとURLをコピーしました