今回は、画像のエッジを検出するための様々な方法を分かりやすく解説していきます!
本記事では以下のことを解説しています。
- 転職のためのスキルアップとして効率的に学びたい
- 副業としてプログラミングができるようになりたい
- 独学での勉強に限界を感じている
これらに該当する方はプログラミングスクールがスキルアップの近道です!
是非参考にしてみてください。
未経験でも安心!
学生や30代の方にもおすすめなプログラミングスクールがあります!
エッジ検出とは
エッジ検出は、画像上の物体を検出しその輪郭を抽出する手法です。
Python OpenCVを用いてエッジ検出をする方法は以下の3つが挙げられます。それぞれエッジの検出方法が異なります。
- ラプラシアン処理
- Sobel処理
- Canny処理
1つずつ分かりやすく使い方を説明していきたいと思います!
ラプラシアン処理
まずはラプラシアン処理を用いてエッジ検出をする方法についてです。本記事では、理論的な部分は割愛しますが、二次微分(差分)系のフィルタになります。
ラプラシアン処理を行うためにはcv2.Laplacian()を使います。実際のコードは以下の通りです。
import cv2
def main():
image=cv2.imread("C:\Imagefile\egao.png")
edge_im=cv2.Laplacian(image,-1)
cv2.imshow("edge filter",edge_im)
cv2.waitKey()
cv2.destroyAllWindows()
if __name__=="__main__":
main()
(実行結果)
ここでcv2.Laplacian(image,-1)の第二引数では、出力画像のデータ型を指定します。一覧を以下の表に示します。
第二引数 | |
-1 | 原画像の配列を使用 |
cv2.CV_8S | int 8 |
cv2.CV_8U | unit 8 |
cv2.CV_16S | int 16 |
cv2.CV_16U | unit 16 |
cv2.CV_32S | int 32 |
cv2.CV_32F | float 32 |
cv2.CV_64F | float 64 |
基本的には、”-1” を使用すると良いと思います。
データ型が正しく指定されていないとこのように正しくエッジが検出されませんでした。
また、第三引数にカーネルサイズを指定することもできますがラプラシアン処理では変化が見られませんでした。カーネルサイズを指定する場合は、int型の数値を第三引数として入力します。
他方で、原画像のままラプラシアン処理を行うと、輝度に偏りが出ているため上手く検出されない場合があります。
そのような場合には、輝度平滑化処理を原画像に施してからエッジ検出を行うことで精度よく検出できるようになります。
輝度平滑化を行う場合は以下のコードを先に処理させます。ただし、輝度平滑化処理は、グレイスケール画像にのみ適用できる点に注意してください。
#クレイスケールで画像読み込み
image=cv2.imread("C:\Imagefile\egao.png",cv2.IMREAD_GRAYSCALE)
#輝度の平滑化
dst=cv2.equalizeHist(image)
(輝度平滑化後の実行結果)
Sobel処理
続いてSobel処理です。Sobel処理は、ガウシアン処理を用いて平滑化を行いつつエッジ検出をするものです。平滑化を行っているためノイズの影響を低減しつつエッジ検出を行うことができるという特徴があります。
import cv2
def main():
image=cv2.imread("C:\Imagefile\egao.png")
edge_im=cv2.Sobel(image,-1,0,1)
cv2.imshow("edge filter",edge_im)
cv2.waitKey()
cv2.destroyAllWindows()
if __name__=="__main__":
main()
(実行結果)
ここで、cv2.Sobel()はこのように記述しています。
edge_im=cv2.Sobel(image, bit, dx, dy, ksize)
第一引数
処理対象の画像を指定
第二引数
出力配列のデータ型を指定(基本は-1を指定)
(詳細はラプラシアン処理項目で紹介しています)
第三引数
x方向の微分次数を指定
第四引数
y方向の微分次数を指定
第五引数
カーネルサイズを指定(1,3,5,7のどれかを指定)
これらの引数を踏まえて、色々と値を変化させてみた結果を以下に示していきたいと思います!
まず、y方向の微分次数を「1」として、x方向の微分次数を「0」とした場合のエッジ検出結果はx方向を微分する場合と少し異なったエッジが検出されました。
xとyの両方向の微分次数を「1」とした場合には、エッジの強さが弱くなってしまいました。
ksizeのみを変更させた場合には、あまり変化は見られませんでした。
Canny処理
Canny処理は、画像中の強いエッジを検出し弱いエッジ(少数の画素で構成されたエッジ)は削除することができるエッジ検出手法です。
- エッジの輪郭を分かりやすく検出できる
- 誤検出が少ない
実際にどのように検出されるか見た方が早いと思いますので以下にコードを示します。
import cv2
def main():
image=cv2.imread("C:\Imagefile\egao.png")
edge_im=cv2.Canny(image,40.0,200.0)
cv2.imshow("edge filter",edge_im)
cv2.waitKey()
cv2.destroyAllWindows()
if __name__=="__main__":
main()
(実行結果)
このように検出できました。
第一引数
処理対象の画像を指定
第二引数
第1しきい値(最小しきい値)をfloat型で指定
第三引数
第2しきい値(最大しきい値)をfloat型で指定
最小しきい値と最大しきい値を任意に変化させてエッジ検出した結果を以下に示します。最小しきい値が小さすぎる場合にはエッジが誤検出されています。逆に最小しきい値が大きすぎる場合にはエッジが正しく検出されませんでした。
この二つの変数を正しく調整すると、(65.0, 200.0)の結果のようにエッジが正しく検出されるようになりました!
エッジ検出したい画像にもよると思いますが、今回用いたような単純な画像ではCanny処理が最も正確に輪郭検出できていることが分かりました。
もっとOpenCVやPythonについて学びたい人はコチラの記事を参考にしてみて下さい!
また、プログラミングをしていて疲れやすいなと感じる場合にはこちらを参考にしてみて下さい!
以上となります。最後まで見ていただきありがとうございました!