Python : Hough circle 円の検出
最近、pythonについて書くことが減ってきて更新が遅れていますが、
不定期では更新していくつもりですので、今後ともよろしくお願いします。
さて、今回はHough circleについてです。
前に最小外接円での円の検出についても説明しましたが、
「最小外接円は、面積を求めてから、ここの重心を元に円を検出」
という検出方法になるため、下図のように円が重なっているものがあると
最小外接円で検出すると
このように面積でみるので、重なっちゃうと、1つになってしまうのですよね。
まぁ面積を見て、閾値を作ってこれは2こ、3こというふうに表示をすることは
可能ではあるものの基本的には検出できないのですよね。
というわけで、houghcircleというハフさんがつくったと思われる関数を使う
プログラムの書き方です。
まずはモジュールのインポート、opencvとnumpyを使います
import cv2
import numpy as np
次に画像を読み込み
frame = cv2.imread('circle1.jpg')
下処理します(Gray画像→エッジ処理(canny)
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
canny_gray = cv2.Canny(gray,100,200)
ここでcanny処理は実はしなくてもhough関数の中にc
annyを使う機能が入っているのですが、
あらかじめしておくと使う前の画像を見れるので
私はいつもcannyは先にやっておきます。
cimgという変数にhoughcircleで使う画像を入れておきます。
これも後々わかりやすくするためです。
cimg = canny_gray
Houghcircleの関数です。
circles = cv2.HoughCircles(cimg,cv2.HOUGH_GRADIENT,1,20,param1=120,param2=15,minRadius=10,maxRadius=30)
・cimgのところに画像を入れます。
・cv2.HOUGH_GRADIENT
この中身はよくわかっていないのですが、これをつかってエッジの勾配を見られるようです。こういう書き方と思って書いています。opencv,pythonのversionが違うと、cv2.がいらなかったりします
・1,20
ここはcanny関数の閾値です。
使う画像がすでにcannyのものの場合、入れる数字適当でいいです。
・param1 ; canny()エッジ検出機に渡される2つの閾値のうち、大きいほうの閾値0
・param2 ; 円の中心を検出する際の投票数の閾値、小さくなるほど、より誤検出が起こる可能性がある。
・minRadius ; 検出する円の最小値
・maxRadius ; 検出する円の最大値
後は、検出されたかの確認をして、unit16への返還をし、
1つずつ見つけて丸を書いていきます。
if circles is not None and len(circles) > 0:
#型をfloat32からunit16に変更:整数のタイプになるので、後々トラブルが減る。
circles = np.uint16(np.around(circles))
for i in circles[0,:]:
# 外側の円を描く
cv2.circle(frame,(i[0],i[1]),i[2],(0,255,0),2)
# 中心の円を描く
cv2.circle(frame,(i[0],i[1]),2,(0,0,255),2)
# 円の数を数える
j = j + 1
結果はこんな感じです。
見ての取りで、割と円の中心とはずれるのですが、ただ数を数えたいだけだとすると
割と良い感じです。
※この記事での画像はサイズを小さくしております。
もしそのまま使う場合は、一番最後に画像を置いておくのでこれをお使いください。
#opencvをインポートします。
import cv2
import numpy as np
#フォントの指定
fontType = cv2.FONT_HERSHEY_COMPLEX
#検出する画像の読み込み
frame = cv2.imread('circle1.jpg')
#1チャンネル(白黒画像に変換)
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
#Cannyにてエッジ検出処理(やらなくてもよい)
canny_gray = cv2.Canny(gray,100,200)
#houghで使う画像の指定、後で変えたりする際に変数してしておくと楽。
cimg = canny_gray
j = 1
#hough関数
circles = cv2.HoughCircles(cimg,cv2.HOUGH_GRADIENT,1,20,param1=120,param2=15,minRadius=10,maxRadius=30)
# param1 ; canny()エッジ検出機に渡される2つの閾値のうち、大きいほうの閾値0
# param2 ; 円の中心を検出する際の投票数の閾値、小さくなるほど、より誤検出が起こる可能性がある。
# minRadius ; 検出する円の最小値
# maxRadius ; 検出する円の最大値
#検出された際に動くようにする。
if circles is not None and len(circles) > 0:
#型をfloat32からunit16に変更:整数のタイプになるので、後々トラブルが減る。
circles = np.uint16(np.around(circles))
for i in circles[0,:]:
# 外側の円を描く
cv2.circle(frame,(i[0],i[1]),i[2],(0,255,0),2)
# 中心の円を描く
cv2.circle(frame,(i[0],i[1]),2,(0,0,255),2)
# 円の数を数える
j = j + 1
#円の合計数を表示
cv2.putText(frame,'Total :'+str(j), (30,30), fontType, 1, (0, 0, 0), 1, cv2.LINE_AA)
#結果画像の表示
cv2.imshow('',frame)
#結果の書き込み
cv2.imwrite('hough_circle.jpg',frame)
#キー入力を待つ
cv2.waitKey(0)
#全ての開いたウインドウ閉じる
cv2.destroyAllWindows()
今までにpythonについて書いた記事はここにリンクを貼ってあります。 興味があればぜひご覧ください。