5.27. 円と矩形の検出¶
線とセグメントは、キャプチャしたフレーム内の直線的なエッジを捉えますが、カメラが探す実世界の特徴の多くは直線ではありません。机の上に置かれた硬貨は円です。印刷されたラベル、付箋、斜めから見た箱の上面は四辺形です。image モジュールは、それぞれに専用の検出器を備えています。円には Hough 風の探索、四辺形には AprilTag 由来の探索です。
どちらの手法も、線検出器と同じテンプレートに従います。threshold は検出に必要な投票数を制御し、roi は探索範囲を絞り込み、返されるオブジェクトは位置と信頼度の大きさの両方を持ちます。ただし、パラメータ空間や適切なデフォルト値は十分に異なるため、それぞれ明示的に説明する価値があります。
5.27.1. Hough 円¶
find_circles() は Hough 変換の円バージョンを実行します。Sobel 前処理パスから得られた各エッジピクセルは、それを通過しうるすべての円に投票します。十分な投票を集めた円が返されます。
circles = img.find_circles(threshold=3500,
x_margin=10, y_margin=10, r_margin=10,
r_min=10, r_max=80, r_step=2)
for c in circles:
img.draw_circle((c.x, c.y, c.r), color=(255, 0, 0))
threshold は、候補となる円に沿った Sobel エッジの大きさの合計の最小値です。大きな円ほど多くのピクセルをなぞるため、通過するにはより高いしきい値が必要です。半径 20 ピクセルの硬貨を見つける値は、半径 100 ピクセルのエッジ周辺のノイズにも反応してしまい、逆に大きな硬貨に合わせた値では小さな硬貨を見逃します。目標とする半径の範囲が分かっている場合、適切なしきい値は円周に比例します。おおよそ threshold = 50 * 2 * pi * r が妥当な出発点となり、適切な値は短時間の調整パスで決まります。
r_min、r_max、r_step は半径の探索範囲を設定します。範囲を指定しないと、検出器は数ピクセルから画像の幅の半分までのすべての半径を探索することになり、これは遅いうえに誤検出の温床になります。r_min と r_max を、予想される目標サイズを十分な余裕をもって挟むように設定すると(例えば、約 20 ピクセルと分かっている硬貨に対して r_min=15, r_max=25)、処理量が大幅に減り、投票の信号対雑音比が向上します。r_step は探索の粒度を制御します。ステップを大きくすると高速になりますが、真の半径がサンプリングされた 2 つの値の間に入る円を見逃すことがあります。デフォルトの r_step=2 は妥当な妥協点です。
x_margin、y_margin、r_margin は、線検出で theta_margin や rho_margin が行うのと同じように、近接した検出のマージを制御します。画像内の 1 つの物理的な円は、中心と半径が数ピクセル以内で一致する候補円のクラスタに投票します。マージンは、結果リストを構築する前に各クラスタをそのピークに集約します。マージンを大きくすると、より少なく、より確信度の高い検出が返されます。マージンを小さくすると、ニアデュプリケート(ほぼ重複)の可能性を伴うより多くの検出が返されます。
x_stride と y_stride は、他の検出器と同じように投票スキャンのステップを設定します。デフォルトの 2 と 1 はほとんどの画像で十分です。両方を 4 まで上げるのは、大きな円が含まれていると分かっている画像での標準的な速度のトレードオフです。
返される各 Circle は x、y、r(中心と半径)と magnitude(投票総数。並べ替えやフィルタリングの信頼度スコアとして有用)を持ちます。検出結果をフレームに描画し直すのは 1 回の呼び出しで済みます。draw_circle() は (x, y, r) の 3 要素タプルを受け取り、これは結果から直接 (c.x, c.y, c.r) として利用できます。
5.27.2. 矩形¶
find_rects() は AprilTag パイプラインから四辺形検出器を借用しています。タグの周囲の黒い正方形を見つけるのと同じルーチンが、汎用の矩形検出器として独立して公開されています。
rects = img.find_rects(threshold=12000)
for r in rects:
img.draw_rectangle(r.rect, color=(0, 255, 0))
for corner in r.corners:
img.draw_circle((corner[0], corner[1], 4),
color=(0, 255, 0))
threshold は、矩形の周囲のエッジの大きさの合計の最小値です。十分に照明されたフレーム内で印刷された白地に黒の矩形は、10000 を容易に超えます。テクスチャのある背景上の薄い矩形では、誤検出を許容して感度を高めるために 2000 まで下げる必要があるかもしれません。円検出器と同様に、適切な値は対象とするターゲットを視野に入れた短時間の調整パスで決まります。
この検出器は射影的です。辺が直線であれば、必ずしも平行や軸に揃っていなくても四辺形を見つけます。斜めから見たラベルは画像内では台形に見えますが、矩形検出器はそれを正しく見つけます。軸に揃った矩形は、4 つの角がたまたま直角の箱を形成する退化したケースにすぎません。roi は探索範囲を制限します。残りのキーワード引数は AprilTag パイプラインのデフォルト値をとり、調整が必要になることはめったにありません。
返される各 Rect は、軸に揃ったバウンディングボックスを持ちます。x、y、w、h に加えて、draw_rectangle() が期待する rect の 4 要素タプルです。そして、検出された 4 つの角を corners として持ちます。バウンディングボックスはおおまかな位置とサイズのためにアプリケーションが使用するものです。角は射影的な四辺形そのものを表します。カメラが平らなターゲットを斜めから見ていて、アプリケーションがキーストーン(台形歪み)を補正する必要がある場合(ラベルの文字を読む、平らなパッチから色をサンプリングするなど)、角は corners= キーワードを使って rotation_corr() に直接渡され(レンズと遠近補正 を参照)、出力は次の解析にすぐ使える補正済みの矩形になります。
警告
この検出器は AprilTag パイプラインが必要とするもの、つまり白い紙の上の黒いタグの輪郭のような、強く高コントラストな境界をもつ四辺形に合わせて調整されているため、すべての矩形を見つけるパスではありません。コントラストが弱い、エッジにテクスチャがある、または周囲がごちゃごちゃしている矩形は、まったく検出されないことがあります。どの程度うまく機能するかは状況に依存します。これを中心にパイプラインを構築する前に、実際のターゲットに対して早めにテストしてください。
5.27.3. 検出器が誤動作するとき¶
特に円は、入力に対する事前フィルタの恩恵を受けます。ノイズの多いフレームでは多数の散らばったエッジピクセルが生じ、それらがすべて投票するため、結果として得られる Hough 空間には広くぼやけたピークができ、マージャはそれらを分離するのに苦労します。find_circles() の前に gaussian() や mean() パスをかけるとノイズが滑らかになり、真のエッジはそのまま残ります。検出器はより短時間でよりクリーンなピークを返します。
矩形の場合、よくある失敗モードはその逆です。矩形と背景のコントラストが低いと、エッジの大きさの合計が threshold を超えません。histeq() パスで明るさの範囲を 0 から 255 までの全域に再分配すると、検出器が必要とするコントラストが回復します。(コントラストは画像のどこかに存在していなければなりません。ヒストグラム平坦化は、すでにそこにあるものを増幅できるだけです。)