OpenCV のエッジ検出について (canny)
はじめに
OpenCV のcannyを使ったエッジ検出処理ついて調べたことをまとめた。
とりあえず関数を試してみたい方
実験用プログラム OpenCV_test の GitHubリポジトリ
URL
https://github.com/iryachi/OpenCV_test
実行ファイルだけ
https://github.com/iryachi/OpenCV_test/releases
使い方
https://iryachi.stars.ne.jp/opencv_test_imple/
内部処理
内部でやっていることは以下の感じ
・Gaussian フィルタをかけて平滑化。
・Sobel フィルタをかけてエッジ抽出。
・閾値によって、エッジが鮮明で繋がっているものを選別。
注意点
8ビット整数の入力とした場合でも内部処理は拡張されて行われるので、閾値の設定が 255 を超える。
出力時に入力と同じ形式に変換されるので、8ビットだと 0, 255 の二値データみたいになりやすい。
canny関数について
関数1
void cv::Canny(InputArray image,
OutputArray edges,
double threshold1,
double threshold2,
int apertureSize = 3,
bool L2gradient = false
)
引数
image | InputArray | 入力画像 | グレースケールの画像 |
edges | OutputArray | 出力画像 | グレースケールの画像 |
threshold1 | double | 閾値1 | この値より小さいエッジの値はエッジではないと判断 |
threshold2 | double | 閾値2 | この値より大きいものをエッジと判断。 この値より小さくても、閾値より大きいものは、閾値2より大きいものと繋がっていればエッジと判断。 |
apertureSize | int | アパーチャサイズ | Sobelフィルタをかける時のアパーチャサイズ。 |
L2gradient | bool | L2 モードフラグ | 傾きの大きさ計算するのにL2 モード と L1 モードのどちらを使うか。 L1 : |dI/dx| + |dI/dy| L2 : √((dI/dx)2 + (dI/dy)2)) |
関数2
void cv::Canny(InputArray dx,
InputArray dy,
OutputArray edges,
double threshold1,
double threshold2,
bool L2gradient = false )
引数
dx | InputArray | 入力画像 | x方向(水平)にSobelフィルタをかけた後の画像 |
dy | InputArray | 入力画像 | y方向(垂直)にSobelフィルタをかけた後の画像 |
edges | OutputArray | 出力画像 | エッジ抽出後の画像 |
threshold1 | double | 閾値1 | この値より小さいエッジの値はエッジではないと判断 |
threshold2 | double | 閾値2 | この値より大きいものをエッジと判断。 この値より小さくても、閾値より大きいものは、閾値2より大きいものと繋がっていればエッジと判断。 |
L2gradient | bool | L2 モードフラグ | 傾きの大きさ計算するのにL2 モード と L1 モードのどちらを使うか。 L1 : |dI/dx| + |dI/dy| L2 : √((dI/dx)2 + (dI/dy)2)) |
処理例
元画像
縦線:線ごとに数値を変更
横線:0 – 255 までのグラデーション と
途中に切れ目を入れたもの
関数1, apercherSize = 3, threshold2 = 0, threshold1 を変更
エッジの緩やかなものから順番に消えている。
関数1,threshold1 = 1200, threshold2 を変更
threshold1 が 0 の時は上段のグラデーションは消えていないが、
threshold2 を変更すると徐々に消えている。
おわりに
“繋がっている場合はエッジとみなす" という考え方がわかるまで難しいと感じた。
影がかかってるけど輪郭を抽出したい場合とかに使用できると思う。
ディスカッション
コメント一覧
まだ、コメントがありません