opencv eleven ハフ円検出原理と高度な使用例 (最適化ステップを含む)

ハフ円検出は対象画像内に存在する円を検出することができますが、実際に使用する際のパラメータ調整は非常に難しいため、このブログ記事ではハフ円検出の原理、パラメータリスト、最適化の経験を分析してまとめます。複雑な背景でハフ円検出を実現するために、各パラメーターの調整基準が詳細にリストされています。

1. 原理の紹介

1.1 基本原則

相关知识:
ハフ円検出はハフ変換と密接に関係しており、ハフ変換は極座標系(半径と角度で記述される座標系)とデカルト座標系(通常の平面座標系)との相互変換に基づいています。達成。デカルト座標系上の点は、極座標系に変換すると線になり、その逆も同様です。
ここに画像の説明を挿入

ただし、ハフ変換に基づくハフ円検出方法は、計算量が非常に多く、実用には適していません。opencv の実装では、円の検出にハフ勾配アルゴリズムが使用されます。
参考リンク:https://www.cnblogs.com/bjxqmy/p/12333022.html

1.2 ハフ勾配法の原理

1. 元の画像に対して Canny エッジ検出を実行して、エッジ検出されたバイナリ画像を取得します。
2. 元の画像に対して Sobel オペレーターを 1 回実行して、すべてのピクセルの近傍勾配値を計算します。
3. 中心空間 N(a,b) を初期化し、すべて N(a,b)=0 にします。円の中心が画像内にある必要がある場合、a と b の値の範囲はそれぞれ画像の幅と高さに対応し、N(a,b) は合計で a*b があることを意味します。
4. Canny Edge バイナリ イメージ内のすべての非ゼロ ピクセルをトラバースし、固定検索半径範囲内で勾配方向 (Sobel オペレーターによって計算された垂直勾配と水平勾配に基づく接線の垂直方向) に沿って線を描画します。そして、通過したアキュムレータ内のすべての点 (a,b) について、線分 N(a,b)+=1 を分割します。
ここに画像の説明を挿入

5. N(a,b) を統計的に並べ替えて、円の中心の可能性を取得します (N(a,b) が大きいほど、それが円の中心である可能性が高くなります)。
ここに画像の説明を挿入
参考リンク:https://zhuanlan.zhihu.com/p/427270299

1.3 ハフ勾配法の欠点

1. ハフ勾配法では、ソーベル導関数を使用して局所勾配を計算します。その後の仮定は、局所的ないくつかの点に基づく接線と同等とみなすことができるというものであり、これは数値的に安定したアプローチではありません。これを行うと、ほとんどの場合正しい結果が得られますが、出力にノイズが発生する可能性があります。

2. エッジ画像の非ゼロ画素集合全体を各中心の候補部分とみなすため、勾配方向の探索半径範囲を適切に設定しないと、膨大な計算量が発生する。

3. ハフ勾配アルゴリズムは、逆正接の垂直線によって円中心の累積検出を実行するため、同心円がある場合、それらは同じ円の中心に累積され、累積値が最大の円のみが選択されます。

1.4 パラメータの詳細

ハフ円検出に使用するコードは次のとおりです。

method=cv2.HOUGH_GRADIENT
circles=cv2.HoughCircles(image, method, dp=1, minDist=10, param1=None, param2=None, minRadius=None, maxRadius=None)

そのパラメータ リストの詳細は次のとおりです:

Circles:HoughCircles の結果を保存するために使用され、タイプはリスト、リスト内のオブジェクト形式は x、y、r、入力画像、つまりソース
image:画像、8-ビット単一チャネル画像。カラー画像が使用されている場合は、グレースケール画像に変換する必要があります。
method:画像内の円を検出する方法を定義します。現在実装されている唯一のメソッドは cv2.HOUGH_GRADIENT;
dp:画像のピクセル解像度とパラメータ空間の解像度の比率です (公式ドキュメントでは、画像解像度とアキュムレータ解像度の比率が記述されており、パラメータ空間はアキュムレータであるとみなされています)格納されているのは通過ピクセル数です)、dp=1、パラメータ空間は画像ピクセル空間 (解像度) と同じ大きさ、dp=2、パラメータ空間の解像度は画像の半分のサイズのみです。ピクセル空間; #dp を設定する
minDist:と、円の中心の (x, y) 座標間の最小距離を検出する計算量を減らすことができます。minDist が小さすぎる場合、同様の中心を持つほとんどの円が保持されます。minDist が大きすぎる場合、同様の中心を持つ円がマージされます (2 つの円の中心間の距離が minDist 未満の場合、それらは同じ円であるとみなされます)。
param1:canny は、エッジ検出の上限しきい値です。下限しきい値は、上限しきい値の半分に自動的に設定されます。デフォルトは 100 です。;
param2:累積平面上の点が円の中心であるかどうかを判断するためのしきい値。この閾値より大きい場合のみ円と判定されます。値を小さくすると、より多くの円が検出されます。デフォルト値は 100、
minRadius:半径の最小サイズ (ピクセル単位) はデフォルト 0、
maxRadius:半径の最大サイズ (ピクセル単位) はデフォルト 0 です。

2. 実用化

2.1 基本的な実行コード

次のコードは、ハフ円検出用の画像の読み取りを実装し、下の図の車両の車輪の検出を試みます。ただし、パラメータ設定を調整して最適化する必要があります。

import cv2
import numpy as np
import time
if __name__ == "__main__":
    name="test.jpg"
    img = cv2.imread(name)
    t1=time.time()
    GrayImage=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    circles = cv2.HoughCircles(GrayImage, cv2.HOUGH_GRADIENT, 1, 40, param1=70, param2=30, minRadius=0,maxRadius=0)
    t2=time.time()
    print("运行时间:",t2-t1)

    circles = np.uint16(np.around(circles))
    for i in circles[0,:]:
        x,y,r=i[0],i[1],i[2]
        #draw the outer circle
        cv2.circle(img,(x,y),r,(0,255,0),2)
        cv2.circle(img,(x,y),2,(0,0,255),3)
    cv2.imshow("img",img)
    cv2.waitKey()

元の画像の内容は次のとおりです。
画像の説明を追加してください

2.2 最適化計画

上記のコードを実行すると、膨大な量の計算が行われるため、コンピューターが直接フリーズします。(理由1:画像処理の最適化不足、理由2:ハフ円パラメータが無理)

2.2.1 画像の最適化

画像の最適化とは、3 点で円を形成できるため、ハフ円検出の過程で干渉点を減らすことです。

エッジノイズフィルタリング

1. 画像のメディアン|平均フィルター最適化を実行して、画像内のエッジ ノイズを低減します。
追加したコードは以下の通りで、最終的に16秒以内に結果が出ました

    #GrayImage= cv2.medianBlur(GrayImage,7)#中值滤波 滤除背景噪声
    GrayImage= cv2.blur(GrayImage,(7,7))#均值滤波 滤除背景噪声

ここに画像の説明を挿入

計算量の削減

2. ハフ円検出を行う場合、画像サイズは検出精度にほとんど影響を与えないため、画像サイズを最適化します。ただし、画像を (縮小した後に) ダウンサンプリングすると、計算量を大幅に削減できます。
追加したコードは以下の通りで、0.76秒以内に結果が得られますが、あまり正確ではありません。若缩放到0.25倍,则可在0.06秒内跑出结果

    GrayImage=cv2.resize(GrayImage,None,fx=0.5,fy=0.5)

ここに画像の説明を挿入

完全な円を保つ

この手順は必要ありません。
スチールコイルの中心検出など特殊な場合には、重力によりスチールコイルの側円が楕円形に押し込まれるため、y方向(垂直方向)に伸ばす必要があります。次のコードに示すように、画像は y 方向に 1.2 倍に引き伸ばされ、スチール コイルの側楕円が真円に引き伸ばされます。
img=cv2.resize(img,None,fx=1,fy=1.2)

2.2.2 検出パラメータの最適化

取得半径の最適化

上の画像を分析すると、検出された円が多すぎることがわかり、ホイールのピクセル半径範囲の予備推定値は 20 ~ 80 であることがわかります ( 通过多次设置范围,确定车轮像素在20~80之间)。
この時のハフ円検出パラメータは以下の通りです。minRadius=20,maxRadius=80

circles = cv2.HoughCircles(GrayImage, cv2.HOUGH_GRADIENT, 1, minDist=40, param1=70, param2=30, minRadius=20,maxRadius=80)

このときの検出効果は、コードが結果を実行するのに 0.03 秒 (従来の 20 倍) しかかからないため、ハフ円の検索半径が制限されます。
ここに画像の説明を挿入

円中心累積の最適化

前のステップでの最適化後も、実際には存在しない円が検出されます。これは、累積円中心(中心の円弧上の累積値。累積値がこのしきい値を超えた場合に円とみなされます)の設定が不適切であることが原因です。
この時のハフ円検出パラメータは以下の通りです。param2=50, minRadius=20,maxRadius=80

circles = cv2.HoughCircles(GrayImage, cv2.HOUGH_GRADIENT, 1, minDist=4, param1=70, param2=50, minRadius=20,maxRadius=80)

このとき、検出効果は次のようになり、結果は 0.03 秒で実行されるだけ (前のステップと同じ) であるため、ハフ円の検索半径は制限されます。
ここに画像の説明を挿入

円中心距離の最適化

上記の手順を経た後、一部の円では中心が非常に近い複数の円が検出されることがわかりました。原先的圆心距设置很合理,但为了出优化效果,故将上一步的圆心距离设置的很小これは、検出ステップにおける最小円中心距離の設定が無理なことが原因です。
この時のハフ円検出パラメータは以下の通りです。minDist=20, param2=50, minRadius=20,maxRadius=80
この時の検出効果は以下の通りで、ホイール領域の位置決めが良好に行えます。
ここに画像の説明を挿入

最高の完全なコード

额外说明:若对检测到的圆效果存在疑惑时,可以自行对原图进行cany求边缘,以校验参数param1设置的是否合理param1 の値は、キャニー操作の効果 (キャニー エッジ検出の上限閾値) に応じて調整されます。この値は効果にほとんど影響を与えないため、通常、この値を調整する必要はありません。

import cv2
import numpy as np
import time
if __name__ == "__main__":
    name="test.jpg"
    img = cv2.imread(name)
    t1=time.time()
    img=cv2.resize(img,None,fx=0.5,fy=0.5)
    GrayImage=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    #GrayImage= cv2.medianBlur(GrayImage,7)#中值滤波 滤除背景噪声
    GrayImage= cv2.blur(GrayImage,(7,7))#均值滤波 滤除背景噪声
    circles = cv2.HoughCircles(GrayImage, cv2.HOUGH_GRADIENT, 1, minDist=20, param1=70, param2=50, minRadius=20,maxRadius=80)
    t2=time.time()
    print("运行时间:",t2-t1)#只统计霍夫圆检测时间
	
	#这里进行圆绘制
    circles = np.uint16(np.around(circles))
    for i in circles[0,:]:
        x,y,r=i[0],i[1],i[2]
        #draw the outer circle
        cv2.circle(img,(x,y),r,(0,255,0),2)
        cv2.circle(img,(x,y),2,(0,0,255),3)
    cv2.imshow("img1",img)
    cv2.waitKey()

おすすめ

転載: blog.csdn.net/m0_74259636/article/details/132655935