今回は、OpenCVでフィルタを使って画像のエッジ抽出をしてみました。
エッジ抽出に使われるフィルタはPrewittフィルタやSobelフィルタ、ラプラシアンフィルタなどいくつか種類がありますが、今回はSobelフィルタを使ってみます。
今回の環境
・OS : Windows10(64bit)
・Visual Studio 2015 Community
・OpenCV 4.2.0
(上記全て環境構築済)
今回はOpenCVは環境済の状態でスタートするので、OpenCVの環境構築は以下の記事などを参照してください。
過去記事①:Nugetを使ってOpenCVの環境構築(Visual Studio 2015)
過去記事②:Visual Studio 2015でOpenCV 3.4環境構築(Windows10)
Sobelフィルタとは
Sobelフィルタは以下の図のようなフィルタで、特定方向の輪郭抽出が可能なフィルタです。

-1、0、1のように特定の方向に正負の重みづけをすることで、出力画像では画素値が大きく変化している部分の絶対値が大きくなるため、エッジを抽出することが可能です。
類似するフィルタとして、Prewittフィルタ(Sobelフィルタと同じ1次微分フィルタ)、ラプラシアンフィルタ(2次微分フィルタ)があります。
今回はこのSobelフィルタをOpenCVとC++で実装してみました。
ソースコード
以下に、Sobelフィルタでエッジを求めるプログラムを示します。
#include <opencv2/opencv.hpp> | |
int main() { | |
// 画像の入力 | |
cv::Mat input_image = cv::imread("input.jpg", 0); | |
cv::Mat sobel_image, output_image; | |
/* Sobelフィルタ (3×3) | |
-1 0 1 | |
-2 0 2 | |
-1 0 1 */ | |
// Sobelフィルタの処理(入力画像,出力画像,出力タイプ,x方向の微分次数,y方向の微分次数,フィルタサイズ) | |
cv::Sobel(input_image, sobel_image, CV_32F, 1, 0, 3); // x方向の微分フィルタ | |
// cv::Sobel(input_image, sobel_image, CV_32F, 0, 1, 3); // y方向の微分フィルタ | |
// convertScaleAbs(=スケーリング後に絶対値を計算し,結果を8ビットに変換) | |
cv::convertScaleAbs(sobel_image, output_image, 1, 0); | |
// 閾値以上の場合にエッジ(=白)と見なす(入力画像,出力画像,閾値,最大値,閾値タイプ) | |
// cv::threshold(output_image, output_image, 64, 255, cv::THRESH_BINARY); | |
// 画像の保存と表示 | |
cv::imwrite("output.jpg", output_image); | |
cv::imshow("Sobel_Filter_Result", output_image); | |
cv::waitKey(0); | |
return 0; | |
} |
OpenCVには以下のようなSobel関数が実装されているため、非常に簡易にSobelフィルタを用いたエッジ抽出が可能になります。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
cv::Sobel(input_image, sobel_image, CV_32F, 1, 0, 3); // x方向の微分フィルタ
また、Sobelフィルタを掛けると画素値は負になる可能性もあるため、以下のように最終的には絶対値を取って正規化することで、8bitの画素値に変換します。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
cv::convertScaleAbs(sobel_image, output_image, 1, 0);
以下が上記のソースコードでx方向のSobelフィルタを掛けてみた結果です。


確かにエッジが抽出できていることがわかります。
まとめ
今回はOpenCVでエッジの抽出を実施してみました。
他にエッジ抽出ができるフィルタとしてラプラシアンフィルタを紹介した記事もありますので、興味のある方はこちらもご覧ください。