OpenCV 4.13.0
Open Source Computer Vision
読み込み中...
検索中...
見つかりません
🤖 AIによる機械翻訳(非公式) — これは OpenCV 4.13.0 公式リファレンス(英語)を AI (Claude) で自動翻訳したものです。訳に誤りを含む場合があります。正確な情報は 公式英語版(原文) を参照してください。
Cannyエッジ検出

目標

この章では、次のことを学ぶ

  • Canny エッジ検出の概念
  • そのための OpenCV 関数: cv.Canny()

理論

Cannyエッジ検出は、広く用いられているエッジ検出アルゴリズムである。John F. Cannyによって開発された。

  1. これは複数段階からなるアルゴリズムであり、各段階を順に見ていく。
  2. ノイズ低減

    エッジ検出は画像中のノイズの影響を受けやすいため、最初のステップでは 5x5 のガウシアンフィルタで画像中のノイズを除去する。これは前の章ですでに見たとおりである。

  3. 画像の強度勾配の算出

    平滑化された画像を水平方向と垂直方向の両方で Sobel カーネルによりフィルタリングし、水平方向 ( \(G_x\)) と垂直方向 ( \(G_y\)) の一次微分を得る。これら 2 つの画像から、各ピクセルについて以下のようにエッジ勾配と方向を求めることができる:

    \[ Edge\_Gradient \; (G) = \sqrt{G_x^2 + G_y^2} \\ Angle \; (\theta) = \tan^{-1} \bigg(\frac{G_y}{G_x}\bigg) \]

    勾配の方向は常にエッジに対して垂直である。これは垂直、水平、および 2 つの対角方向を表す 4 つの角度のいずれかに丸められる。

  4. 非最大抑制

    勾配の大きさと方向を得た後、エッジを構成しないと考えられる不要なピクセルを除去するために画像全体をスキャンする。このために、各ピクセルにおいて、そのピクセルが勾配方向の近傍で局所最大であるかどうかを確認する。以下の画像を確認すること:

image

点 A はエッジ上(垂直方向)にある。勾配方向はエッジに垂直である。点 B と C は勾配方向にある。したがって、点 A が局所最大を形成するかどうかを点 B および C と比較して確認する。もしそうであれば次の段階に進められ、そうでなければ抑制される(ゼロにされる)。

要するに、得られる結果は「細いエッジ」を持つ二値画像である。

  1. ヒステリシスしきい値処理

    この段階では、どれが本当にエッジで、どれがエッジでないかを判定する。このために、minVal と maxVal という 2 つのしきい値が必要である。強度勾配が maxVal より大きいエッジは確実にエッジであり、minVal より小さいものは確実に非エッジであるため破棄される。これら 2 つのしきい値の間にあるものは、その連結性に基づいてエッジか非エッジに分類される。「確実なエッジ」のピクセルと連結していれば、エッジの一部とみなされる。そうでなければ、これらも破棄される。以下の画像を参照のこと:

image

エッジ A は maxVal より上にあるため、「確実なエッジ」とみなされる。エッジ C は maxVal より下にあるが、エッジ A と連結しているため、これも有効なエッジとみなされ、曲線全体が得られる。しかしエッジ B は、minVal より上にあり、エッジ C と同じ領域にあるものの、どの「確実なエッジ」とも連結していないため破棄される。したがって、正しい結果を得るためには minVal と maxVal を適切に選択することが非常に重要である。

この段階では、エッジは長い線であるという仮定に基づいて、小さなピクセルノイズも除去する。

そして最終的に得られるのは、画像中の強いエッジである。

OpenCVにおけるCannyエッジ検出

OpenCVは上記のすべてを単一の関数 cv.Canny() にまとめている。その使い方を見ていく。第1引数は入力画像である。第2、第3引数はそれぞれ minVal と maxVal である。第4引数は aperture_size である。これは画像勾配を求めるために使われるSobelカーネルのサイズである。デフォルトは3である。最後の引数は L2gradient であり、勾配の大きさを求める式を指定する。Trueの場合、上で述べたより正確な式を使用し、そうでない場合は次の関数を使用する: \(Edge\_Gradient \; (G) = |G_x| + |G_y|\)。デフォルトはFalseである。

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('messi5.jpg', cv.IMREAD_GRAYSCALE)
assert img is not None, "file could not be read, check with os.path.exists()"
edges = cv.Canny(img,100,200)
plt.subplot(121),plt.imshow(img,cmap = 'gray')
plt.title('Original Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(edges,cmap = 'gray')
plt.title('Edge Image'), plt.xticks([]), plt.yticks([])
plt.show()
Mat imread(const String &filename, int flags=IMREAD_COLOR_BGR)
Loads an image from a file.
void Canny(InputArray image, OutputArray edges, double threshold1, double threshold2, int apertureSize=3, bool L2gradient=false)
Finds edges in an image using the Canny algorithm canny86 .

以下の結果を参照のこと。

image

追加リソース

  1. Wikipedia のCannyエッジ検出器
  2. Bill Green著 Cannyエッジ検出チュートリアル、2002年。

演習

  1. 2つのトラックバーでしきい値を変えられるCannyエッジ検出を行う小さなアプリケーションを書いてみよう。こうすることで、しきい値の効果を理解できる。