OpenCVで円検出する方法を探していますか?
その場合、ハフ変換によるHoughCirclesをよく目にすることでしょう。
たまに「最小外接円」を推している場合もあります。
しかし、ハフ変換によるHoughCirclesを検証することになるはずです。
情報量が、圧倒的に異なりますからね。
と言っても、「OpenCVにおける円検出」自体の情報がもともと少ないのですけど。
では、優勢なハフ変換によるHoughCirclesを検証した結果はどうなるでしょうか?
「使いモノにならない」
「条件さえ決めれば、使えるかも」
結果は、このどちらかにくっきりと分かれるでしょう。
本記事の内容
- ハフ変換を用いて円を検出するHoughCircles関数
- HoughCircles関数を試す
- HoughCircles関数の実用度を検証
- 【結論】HoughCircles関数は使える?使えない?
それでは、上記に沿って解説していきます。
ハフ変換を用いて円を検出するHoughCircles関数
HoughCirclesは、OpenCVで円検出を行うための関数です。
パラメータ一覧
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を用いて円検出を行う上での参考になれば、幸いです。