Python : Hough circle 円の検出

最近、pythonについて書くことが減ってきて更新が遅れていますが、

不定期では更新していくつもりですので、今後ともよろしくお願いします。

さて、今回はHough circleについてです。

前に最小外接円での円の検出についても説明しましたが、

「最小外接円は、面積を求めてから、ここの重心を元に円を検出」

という検出方法になるため、下図のように円が重なっているものがあると

f:id:Kangkang1981:20200405171356j:plain

最小外接円で検出すると

f:id:Kangkang1981:20200405171431j:plain
このように面積でみるので、重なっちゃうと、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

 

結果はこんな感じです。

f:id:Kangkang1981:20200405173337j:plain

見ての取りで、割と円の中心とはずれるのですが、ただ数を数えたいだけだとすると

割と良い感じです。

 

※この記事での画像はサイズを小さくしております。

もしそのまま使う場合は、一番最後に画像を置いておくのでこれをお使いください。

 

#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について書いた記事はここにリンクを貼ってあります。 興味があればぜひご覧ください。

 

f:id:Kangkang1981:20200405173949j:plain