エッジとは物体同士や背景との境界のことを指し、エッジ検出とは一般に画像中の画素値の変化、輝度勾配が大きい部分を検出することでエッジを検出する画像処理を指します。
(画像は[フリー画像サイト](https://www.pakutaso.com/20191228360post-24995.html)から)cv2.Canny() とは
opencv で実装・提供されているエッジ検出関数。簡単にエッジ画像作成を行えるが、適切に使用するためには(主に)2つのパラメータを調整する必要がある。
対象の人
cv2.Canny()
を閾値なんとなく調整しながら使用してみるけどなんか思ったようにうまくいかない。画像的に限界なのか調整が下手なのかわからない。ちょっときちんとパラメータの意味理解しよう。
2つの調整パラメータ
cv2.Canny(gray_img, threshold1, threshold2)
簡単には、threshold1
と threshold2
どちらもエッジかどうかの判断の閾値を表していて、大きいほどエッジが検出されにくく、小さいほどエッジが検出されやすくなります。
(閾値が大きいと、より大きい輝度変化のときに初めてエッジと判定されるため。)
import cv2
gray_img = cv2.imread('sample.jpg', cv2.IMREAD_GRAYSCALE)
threshold1 = 0
threshold2 = 360
edge_img = cv2.Canny(gray_img, threshold1, threshold2)
cv2.imwrite('sample_edge.jpg', edge_img)
*他にも引数はあります。(公式ページ)
threshold2: maxVal
threshold2 のほうがまず直感的な値で、エッジかどうかの判断の閾値そのものです。
実際に threshold2 を徐々に小さくしてみると以下のようになります。
(理解しやすいため threshold1 には threshold2 と同じ値を入れています。)
threshold1: minVal
引数説明の前提として、Canny 法ではエッジは長い線であると考えており、エッジに隣接している部分はエッジになりやすいという考え方があります。(下図参考)
この考え方から2つ目の閾値(threshold1)を導入していて、簡単に言うと役割は「他エッジとの隣接部分(エッジになりやすい部分)における、エッジかどうかの判断のゆるい閾値」となります。
つまり threshold1 をゆるく(小さく)してみたとしても、元々周りに何も検出されていなかった場所にエッジが検出されるようにはなりません。
ゆるくすることで、元々 threshold2 により検出されたエッジの隣接部分がエッジになりやすくなる、すなわち直感的には、元々 threshold2 により検出されたエッジの線を長く伸ばす、といった感じになります。
実際に threshold1 を徐々に小さくしてみると以下のようになります。
まとめると
cv2.Canny(gray_img, threshold1, threshold2)
- threshold1: 他エッジとの隣接部分(エッジになりやすい部分)におけるエッジかどうかの判断のゆるい閾値
- threshold2: エッジかどうかの判断の閾値そのもの
エッジ検出のパラメータ調整をいい感じにする
以上のことから、上で説明したような順番がおすすめ。
- threhsold1 を threshold2 と同じ値となるようにしておく。
- threshold2 を検出されてほしいところにエッジが現れるように調整する。
- threshold1 を使用してエッジを育てる。