OpenCVで画像のエッジ検出をしてみた
はじめに
PythonでOpenCVによる画像のエッジ検出を行ってみました。
微分
微分とは、変化の割合を示すもので、以下の式で表されます。
f'(x) = \lim_{h\rightarrow 0}\frac{f(x+h)-f(x)}{h}
微分により、画像の画素値の変化を調べることができます。
エッジやノイズは、画素値が急激に変化する部分なので、この微分値が大きくなります。
準備
環境はGoogle Colaboratoryを使用します。
Pythonのバージョンは以下です。
import platform
print("python " + platform.python_version())
# python 3.6.9
画像を表示してみよう
では、早速コードを書いていきましょう。
まずは、OpenCVをインポートします。
import cv2
さらに、Colaboratoryで画像を表示するため、以下もインポートします。
from google.colab.patches import cv2_imshow
サンプルの画像も用意しておきましょう。
今回は、Pixabayのフリー画像を使用します。
それでは、用意したサンプル画像を表示してみましょう。
img = cv2.imread(path) # pathは画像を置いている場所を指定
cv2_imshow(img)
また、画像の微分では、グレースケール化した画像を使用しますので、こちらを用意しておきます。
グレースケールの画像は以下で表示できます。
img_gray = cv2.imread(path, 0)
cv2_imshow(img_gray)
画像の微分
それでは、画像を微分する方法について紹介していきます。
Sobelフィルター
まずは、Sobelフィルターを紹介します。
Sobelフィルターは一回微分であり、最も基本的な画像の微分方法といえるかと思います。
Sobelフィルターを使った画像は、以下で表示できます。
img_sobel = cv2.Sobel(img_gray, cv2.CV_32F, 1, 0, ksize=3)
cv2_imshow(img_sobel)
cv2.Sobelの引数は5つです。詳細は、公式のドキュメント等を参照下さい。
第3引数を1とするとx方向の微分、第4引数を1とするとy方向の微分を計算します。上の画像では、x方向(横方向)に微分した画像を表示しています。
第5引数は、カーネルサイズと呼ばれるものです。画像の1点を決めたとき、周囲のどれだけの領域を含むかを表します。「箱の大きさ」だと考えてみて下さい。
それでは、第3、第4引数を変えて、x方向およびy方向にそれぞれ微分した画像を表示してみましょう。
img_sobel_x = cv2.Sobel(img_gray, cv2.CV_32F, 1, 0, ksize=3)
img_sobel_y = cv2.Sobel(img_gray, cv2.CV_32F, 0, 1, ksize=3)
imgs = cv2.hconcat([img_sobel_x, img_sobel_y])
cv2_imshow(imgs)
左がx方向、右がy方向に微分した画像です。
x方向(横方向)の微分は縦方向のエッジが、y方向(縦方向)の微分は横方向のエッジが残ることがわかります。
このように、エッジに方向性がある場合にはSobelフィルターを用いるのが効果的です。
Laplacianフィルター
次は、Laplacianフィルターを紹介します。
Laplacianフィルターは二回微分であり、Sobelフィルターより細かいエッジ検出をしたい場合に効果的です。
念の為、Laplacianの式(二次元)を以下に示します。
\Delta f = \nabla \cdot \nabla f = \frac{\partial^2}{\partial^2 x}f + \frac{\partial^2}{\partial^2 y}f
Sobelフィルターとは異なり、微分する方向を指定する必要はありません。
Laplacianフィルターを使用した画像は以下になります。
img_lap = cv2.Laplacian(img_gray, cv2.CV_32F)
cv2_imshow(img_lap)
Sobelフィルターより、細かいエッジの検出ができているのがわかります。
また、エッジに特定の方向性がなく、Sobelフィルターが有効ではない場合にも使用することができます。
効果的なエッジ検出の手法
ここまで、SobelフィルターとLaplacianフィルターを用いて、エッジを検出してきました。
画像の画素値を微分することで、画素値の急激な変化であるエッジを検出することができます。
しかし、エッジだけでなくノイズも画素値の急激な変化です。
画像には、さまざまなノイズが入っている場合が多くあります。
このような画像に対しては、まず平滑化を行うことでノイズを除去する方法があります。
※平滑化については、以下を参照下さい。
Pythonを使ってOpenCVで画像を『平滑化』してみた
今回は、以下の手順でエッジ検出を行ってみます。
- グレースケール化
- 平滑化によりノイズを除去(Gaussianフィルターを使用)
- 画像の微分によりエッジ検出(Laplacianフィルターを使用)
img_gauss = cv2.GaussianBlur(img_gray, (3, 3), 3)
img_lap = cv2.Laplacian(img_gauss, cv2.CV_32F)
cv2_imshow(img_lap)
Canny
最後に、Cannyの方法を紹介します。
Cannyはエッジ検出のためのアルゴリズムです。
Cannyでは以下の複数のステップを踏んで、エッジ検出を行います。
- 平滑化によりノイズを除去(Gaussianフィルターを使用)
- 画像の微分によりエッジ検出(Sobelフィルターを使用)
- 極大値を検出し、エッジ以外を取り除く
- 2段階の閾値処理
より詳細は以下を参照下さい。
Canny法によるエッジ検出
それでは、Cannyを用いて画像を表示してみましょう。
img_canny = cv2.Canny(img_gray, 100, 200)
cv2_imshow(img_canny)
第2、第3引数は、2段階の閾値処理で用いる値です。
第2引数は閾値の最小値、第3引数は閾値の最大値を指定します。
まとめ
今回は、Pythonを使ってOpenCVにより画像のエッジ検出を行いました。
画像を微分する方法として、Sobelフィルター、Laplacianフィルター、Cannyの方法を紹介しました。
検出したいエッジの特徴によって、使い分けてみて下さい。
また、微分は画素値の急激な変化を検出する方法ですが、エッジだけでなくノイズにも反応します。
そのため、エッジのみ検出したい場合には、あらかじめノイズ除去を行う必要があります。
ノイズ除去には、平滑化を検討してみて下さい。
画像の微分や平滑化に関する詳細は、以下を参照下さい。
Author And Source
この問題について(OpenCVで画像のエッジ検出をしてみた), 我々は、より多くの情報をここで見つけました https://qiita.com/shoku-pan/items/328edcde833307b164f4著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .