OpenCVで使われるcannyとは?利用法からCanny法の理論などを徹底解説
今回はOpenCVで使われるcannyに関して、利用法からCanny法の理論などを徹底解説致します。Canny法に関して詳しく知りたい、エッジ検出を試してみたい方はおすすめです。ぜひ最後までご覧ください。
執筆者 - おすすめの記事3選
OpenCVで使われるcannyとは?
OpenCVで使われるcannyとは、Canny法を用いて、エッジ検出を行うための関数を意味します。
エッジ検出 : 画像内の物体の形状を調べるために、明るいところと暗いところの境目を強調して、取り出すこと。
要するに、Canny法を利用して、画像内に含まれる物体を検出するために、canny関数を利用します。
具体的なイメージとしては、以下の「canny関数のイメージ画像」の白色で描画される箇所を、検出するイメージを持ってもらうと良いでしょう。
元画像
canny関数のイメージ画像
【3ステップ】Canny法の理論を徹底解説
早急にcanny関数の定義から利用法を知りたい方は、次章で紹介する「OpenCVで使われるcanny関数の定義」からご確認ください。
Canny法は、以下の3ステップを経て、エッジ検出を行います。
ノイズ削減
始めに画像を平滑化してノイズを削減します。平滑化するためにガウシアンフィルタを使います。
平滑化 : 大きく乖離している画素(データ)を、平均化、あるいは除去することにより、合理性を保つこと。
ガウシアンフィルタのイメージ説明
1枚の画像は、複数の画素の集まりで成り立っています。
画素に関する説明を行う画像
ガウシアンフィルタでは、画像を構成する画素に注目して、画像の平滑化を行います。以下の手順を繰り返し行います。
- 1つの画素に注目する。(以下の「ガウシアンフィルタをわかりやすく解説するための画像」の赤色箇所とする。)
- 注目した画素から、5 x 5の画素領域に注目する。(以下の「ガウシアンフィルタをわかりやすく解説するための画像」の黄緑色箇所とする。)
- 注目の画素(1)と5 x 5の画素領域(2)の1つを比較していき、どれくらい色の違い(差分)があるのか計算する。
- 「ガウシアンフィルタをわかりやすく解説するための画像」の重みづけ情報(1/256や36/256など)を利用して、ノイズを取り除く。 (((2 * 画素A-画素B) x 各重みつけ情報)を足し合わせた値を、注目の画素(1)とする。)
- 1~4を繰り返す。
ガウシアンフィルタをわかりやすく解説するための画像
画像の輝度勾配(エッジ)を見つける
輝度勾配 : 隣りあう画素に関して、画素と画素の色の差分((例) 明るい画素(色)の隣に、暗い画素(色))が大きい箇所(エッジ)を意味する。
次に「画像の輝度勾配(エッジ)を見つける」作業を行います。ノイズ削減した画像に対して、Sobelフィルタを用いて、輝度勾配(エッジ)になりうる箇所を洗い出します。
Sobelフィルタのイメージ説明
Sobelフィルタでは、ガウシアンフィルタと同じく、画像を構成する画素に注目して、輝度勾配(エッジ)になりうる箇所を洗い出します。以下の手順を繰り返し行います。
- 1つの画素に注目する。(以下の「横方向Sobelフィルタを利用する(手順2の説明)画像」の赤色箇所とする。)
- 横方向Sobelフィルタを利用して、画素の値を変換する。
- 縦方向Sobelフィルタを利用して、画素の値を変換する。
- 2, 3の画素の値を合成する。
- 1~4を繰り返す。
- 隣りあう画素の値を利用して、エッジの角度、エッジの強さ(値)をそれぞれ洗い出す。(参考)
横方向Sobelフィルタを利用する(手順2の説明)画像
縦方向Sobelフィルタを利用する(手順3の説明)画像
ヒステリシスを使ったしきい値処理
最後にヒステリシスを使った、しきい値処理(エッジとしてみなすかどうか)を行います。
ヒステリシスのイメージ説明
ヒステリシスでは、Sobelフィルタで求めた各エッジの強さ(値)を利用して、エッジとみなすべきか判定します。以下の手順を繰り返します。
- 2つのしきい値「最大しきい値」と「最小しきい値」を用意する。
- とあるエッジの強さ(値)に注目する。
- 「最小しきい値」よりも2(とあるエッジの強さ(値))が大きいか調べる。
- 「最小しきい値」よりも2(とあるエッジの強さ(値))が大きい場合が続いている間に、「最大しきい値」よりも大きい2(とあるエッジの強さ(値))の履歴を取っておく。
- 「最小しきい値」よりも2(とあるエッジの強さ(値))が小さい場合が現れたら、履歴が存在するのか確かめる。
- 履歴が存在する場合、「最小しきい値」よりも2(とあるエッジの強さ(値))が大きい場合が続いている間をエッジとしてみなす。履歴をリセットする。
- 履歴が存在しない場合、「最小しきい値」よりも2(とあるエッジの強さ(値))が大きい場合が続いている間をエッジとしてみなさない。履歴をリセットする。
- 2~7を繰り返す。
以上のことを踏まえて、ヒステリシスを用いてエッジ検出の調整をいい感じに行うためには、
- 「最小しきい値」と「最大しきい値」の値を同じにする。(小さな数から始める。)
- 「最小しきい値」を少しづつ大きくして、エッジの数を減らす。
- 「最大しきい値」を少しづつ大きくして、エッジとみなさないものを増やす。
の順番で調整すると良いでしょう。
OpenCVで使われるcanny関数の定義
canny関数は、
1# cv2(OpenCV)を利用する宣言を行う。
2import cv2
3
4# 第一引数(必須) : 多次元配列(numpy.ndarray)
5# 第二引数(必須) : ヒステリシスを使ったしきい値処理に使う「最小しきい値」を指定。詳しくは、「【3ステップ】Canny法の理論を徹底解説」の、ヒステリシスを使ったしきい値処理の項目をご確認ください。
6# 第三引数(必須) : ヒステリシスを使ったしきい値処理に使う「最大しきい値」を指定。詳しくは、「【3ステップ】Canny法の理論を徹底解説」の、ヒステリシスを使ったしきい値処理の項目をご確認ください。
7# 第四引数(任意) : Sobelフィルタのサイズを指定。デフォルト3。詳しくは、「【3ステップ】Canny法の理論を徹底解説」の画像の輝度勾配(エッジ)を見つけるの項目をご確認ください。
8# 戻り値 : 多次元配列(numpy.ndarray)
9img = cv2.Canny(img, 数字, 数字, 数字)
で定義されます。
例えば以下のようなコードを作成すると、
1import cv2
2import sys
3
4# imread : 画像ファイルを読み込んで、多次元配列(numpy.ndarray)にする。
5# imreadについて : https://kuroro.blog/python/wqh9VIEmRXS4ZAA7C4wd/
6# 第一引数 : 画像のファイルパス
7# 戻り値 : 行 x 列 x 色の三次元配列(numpy.ndarray)が返される。
8img = cv2.imread('./xxx.xxx')
9
10# 画像ファイルが正常に読み込めなかった場合、プログラムを終了する。
11if img is None:
12 sys.exit("Could not read the image.")
13
14# Canny : Canny法を用いて、エッジ検出を行う関数。
15# 第一引数(必須) : 多次元配列(numpy.ndarray)
16# 第二引数(必須) : ヒステリシスを使ったしきい値処理に使う「最小しきい値」を指定。
17# 第三引数(必須) : ヒステリシスを使ったしきい値処理に使う「最大しきい値」を指定。
18# 戻り値 : 多次元配列(numpy.ndarray)
19img = cv2.Canny(img, 100, 200)
20
21# imwrite : 画像の保存を行う関数
22# 第一引数 : 保存先の画像ファイル名
23# 第二引数 : 多次元配列(numpy.ndarray)
24# <第二引数の例>
25# [
26# [
27# [234 237 228]
28# ...
29# [202 209 194]
30# ]
31# [
32# [10 27 16]
33# ...
34# [36 67 46]
35# ]
36# [
37# [34 51 40]
38# ...
39# [50 81 60]
40# ]
41# ]
42# imwriteについて : https://kuroro.blog/python/i0tNE1Mp8aEz8Z7n6Ggg/
43cv2.imwrite('output.jpg', img)
以下の画像のように、画像が描画されます。
元画像
canny関数を利用して保存される画像
imreadに関しては、OpenCVで使われるimreadとは?使い方から配列が画像になる仕組みを解説でまとめていますので、詳しく知りたい方は是非ご確認ください。
imwriteに関しては、OpenCVで使われるimwriteとは?imwriteの定義から使用例をご紹介でまとめていますので、詳しく知りたい方は是非ご確認ください。
まとめ
- OpenCVで使われるcannyとは、Canny法を用いて、エッジ検出を行うための関数を意味する。