エッジ検出は,画像中で明るさが急に変化するエッジ部分を取り出すためのフィルタ.画像中から特徴や図形を検出したりするための前処理として利用される.
微分フィルタ
連続関数の場合,関数f(x)の微分f’(x)は次式で表される.
デジタル画像の場合,離散値の集合として表されるため,上式右辺は注目画素とその隣接画素との差分で置き換えられるが,隣接画素を右側にとるか,左側にとるかで,差分値は異なる.
微分フィルタはエッジ部分を検出できるが,同時に画像に含まれるノイズに対しても敏感に反応する.そこで,ノイズを抑えながらエッジを検出するため,以下のように処理する.
この考えに基づく,代表的な1次微分フィルタに,Sobelフィルタがある.
また,微分を2回繰り返す,2次微分フィルタもある.代表的な2次微分フィルタに,Laplacianフィルタがある.
//05Sobel.cpp
#include <opencv2\opencv.hpp>
int main()
{
cv::Mat gray, sobelX, sobelY;
// 画像を読み込み
cv::Mat im = cv::imread("lenna_inpaint_ns.png");
// グレースケール変換
cvtColor(im, gray, cv::COLOR_BGR2GRAY); //カラー画像をグレースケール変換 (R1~)
// cvtColor(im, gray, CV_BGR2GRAY); //カラー画像をグレースケール変換 (~H30)
// SobelフィルタでX方向エッジ検出
Sobel(gray, sobelX, CV_32F, 1, 0);
// SobelフィルタでY方向エッジ検出
Sobel(gray, sobelY, CV_32F, 0, 1);
// 16bit符号有データを8bit符号無データに変換
convertScaleAbs(sobelX, sobelX, 1, 0);
convertScaleAbs(sobelY, sobelY, 1, 0);
// ウィンドウに画像表示
imshow("sobelX", sobelX);
imshow("sobelY", sobelY);
cv::waitKey(0); // 任意のキーが押されるまで待機
return 0;
}
//06Laplacian.cpp
#include <opencv2\opencv.hpp>
int main()
{
cv::Mat gray, lap1, lap3, lap5, lap7;
// 画像を読み込み
cv::Mat im = cv::imread("lenna_inpaint_ns.png");
// グレースケール変換
cvtColor(im, gray, cv::COLOR_BGR2GRAY); //カラー画像をグレースケール変換 (R1~)
// cvtColor(im, gray, CV_BGR2GRAY); //カラー画像をグレースケール変換 (~H30)
// Laplacianフィルタ(ksize=1)
Laplacian(gray, lap1, CV_32F, 1);
// Laplacianフィルタ(ksize=3)
Laplacian(gray, lap3, CV_32F, 3);
// Laplacianフィルタ(ksize=5)
Laplacian(gray, lap5, CV_32F, 5);
// Laplacianフィルタ(ksize=7)
Laplacian(gray, lap7, CV_32F, 7);
convertScaleAbs(lap1, lap1, 1, 0);
convertScaleAbs(lap3, lap3, 1, 0);
convertScaleAbs(lap5, lap5, 1, 0);
convertScaleAbs(lap7, lap7, 1, 0);
imshow("Laplacian1", lap1);
imshow("Laplacian3", lap3);
imshow("Laplacian5", lap5);
imshow("Laplacian7", lap7);
cv::waitKey(0); // 任意のキーが押されるまで待機
return 0;
}
上記で示したエッジ検出フィルタ以外の,エッジ検出フィルタ(Cannyなど)を試してみよう.また,それぞれのエッジ検出フィルタの理論や結果の違いを整理しておこう.