【Python・OpenCV】ソーベル フィルタ(Sobel Filter)によるエッジ検出(cv2.Sobel)

※当サイトではアフィリエイト広告を利用しています

Python プログラミング 画像処理

【Python・OpenCV】ソーベル フィルタによるエッジ検出(cv2.Sobel)

2023-09-07

はじめに

ソーベル フィルタ(Sobel Filter)は画像処理でエッジ検出を行うための手法の一つです。X方向とY方向の勾配を計算し、それらの勾配の絶対値を組み合わせてエッジの強さを求めます。ソーベル フィルタは簡単に実装でき、小さなエッジやノイズに対しても感度が高い特徴があります。
本記事ではソーベル フィルタの特徴とOpenCVのcv2.Sobel関数の使い方について解説します。

(広告)OpenCV関連書籍をAmazonで探す

ソーベル フィルタ(Sobel Filter)とは

エッジ検出は、デジタル画像処理の中で画像内の物体や領域の境界、すなわち「エッジ」を検出するプロセスです。エッジは画像中の明るさや色の急激な変化を示す箇所であり、物体の形状や輪郭を特定するのに重要な情報源となります。
エッジ検出の目的は、画像内のエッジを特定し、それらのエッジの位置や変化の方向、強度などの情報を抽出することです。
ソーベル フィルタはエッジ検出においてよく使われる手法であり、以下のような場面で活用されます。

  1. 物体検出と認識
    ソーベル フィルタを用いることで、画像中の物体の輪郭を検出し、その輪郭を元に物体の形状や境界を認識することができます。例えば、自動運転車のカメラ画像から道路や車両の輪郭を検出する際に使用されます。
  2. 医療画像解析
    医療画像処理においても、ソーベル フィルタはX線、MRI、CTスキャンなどの画像から異常部位や器官の境界を検出するために使用されます。
  3. セキュリティ
    セキュリティ監視カメラの映像から動きを検出するためにもソーベル フィルタが使用されます。人や物体の動きを検出してアラートを発するシステムで利用されることがあります。
  4. 画像の前処理
    画像処理の前処理段階として、ソーベル フィルタはノイズの除去や画像の滑らかさを向上させるために使用されることがあります。エッジ検出を行うことで、後続の処理段階の品質を向上させることができます。

ソーベル フィルタは勾配情報を抽出するための一つの手法であり、水平方向と垂直方向の勾配を計算することでエッジの強度や向きを推定します。その結果、特徴抽出やテクスチャ解析、物体分割などに利用されます。

cv2.Sobel関数

解説

cv2.Sobel関数は、OpenCVでSobelフィルタを適用するために使用される関数です。

cv2.Sobel(入力画像, ddepth, dx, dy[, ksize[, scale[, delta[,borderType]]]]])

引数

名称説明
入力画像(必須)入力画像データ
ddepth(必須)出力画像のビット深度
dx(必須)x方向の微分次数。これにより、水平方向の勾配が計算されます。
dy(必須)y方向の微分次数。これにより、垂直方向の勾配が計算されます。
ksize(オプション)カーネルサイズ。Sobelフィルタの窓のサイズを指定します。奇数の値を指定することが一般的であり、大きな値を指定すると滑らかな勾配が得られます。(デフォルト:3)
scale(オプション)勾配の計算結果に適用されるスケーリング係数。一般的に、scaleを調整することで、得られるエッジ画像のコントラストを調整できます。大きな値を指定するとエッジが強調され、小さな値を指定するとエッジが弱くなります。ただし、値を非常に大きくすると、エッジ以外のノイズも強調される可能性があるため、適切な値を選ぶことが重要です。(デフォルト:1)
delta(オプション)出力画像に加えられる定数値。エッジを強調する効果があるため、deltaを調整することでエッジがクリアになることがあります。(デフォルト:0)
borderType(オプション)境界処理の方法を指定します。(デフォルト:cv2.BORDER_DEFAULT)

戻り値

戻り値はフィルタ適用後の画像データです。

使い方

cv2.Sobel関数を画像に適用するサンプルコードです。ここでは、カラー画像ではなくグレースケール画像を対象とします。

入力画像として、この画像を使用しています。cv2.imread関数でグレースケールに変換しました。

引用元
https://pixabay.com/ja/photos/%E5%BB%BA%E7%89%A9-%E6%A9%8B-%E5%B7%A5%E4%BA%8B-%E5%AF%BE%E7%A7%B0-5506574/

結果は下の図になります。入力画像(左上)に対してX方向(水平方向)の勾配検出結果(右上)、Y方向(水平方向)の勾配検出結果(左下)、X方向とY方向の合成(右下)です。

入力画像はカラーですが、画像読み込み時にグレースケール画像として読み込んでいます。

建物の形状の輪郭や壁の筋模様が検出できていることが 確認できます。

import cv2
import numpy as np
import matplotlib.pyplot as plt

# 画像の読み込み
image = cv2.imread("image.jpg", cv2.IMREAD_GRAYSCALE)

# ノイズ除去(メディアンフィルタ)
image = cv2.medianBlur(image, 5)

# Sobelフィルタを適用
sobel_x = cv2.Sobel(image, cv2.CV_32F, 1, 0, ksize=3)               # 水平方向の勾配
sobel_y = cv2.Sobel(image, cv2.CV_32F, 0, 1, ksize=3)               # 垂直方向の勾配

# 勾配の絶対値を計算
sobel_x = cv2.convertScaleAbs(sobel_x)
sobel_y = cv2.convertScaleAbs(sobel_y)

# 水平方向と垂直方向の勾配を組み合わせて合成勾配を計算
sobel_combined = cv2.addWeighted(sobel_x, 0.5, sobel_y, 0.5, 0)

# 画像とエッジ画像を表示
plt.rcParams["figure.figsize"] = [12,7.5]                           # ウィンドウサイズを設定
title = "cv2.Sobel: codevace.com"
plt.figure(title)                                                   # ウィンドウタイトルを設定
plt.subplots_adjust(left=0.05, right=0.95, bottom=0.05, top=0.95)   # 余白を設定
plt.subplot(221)                                                    # 2行2列の1番目の領域にプロットを設定
plt.imshow(image, cmap='gray')                                      # 入力画像をグレースケールで表示
plt.title('Original Image')                                         # 画像タイトル設定
plt.axis("off")                                                     # 軸目盛、軸ラベルを消す
plt.subplot(222)                                                    # 2行2列の2番目の領域にプロットを設定
plt.imshow(sobel_x, cmap='gray')                                    # X方向のエッジ検出結果画像をグレースケールで表示
plt.title('Sobel X')                                                # 画像タイトル設定
plt.axis("off")                                                     # 軸目盛、軸ラベルを消す
plt.subplot(223)                                                    # 2行2列の3番目の領域にプロットを設定
plt.imshow(sobel_y, cmap='gray')                                    # Y方向のエッジ検出結果画像をグレースケールで表示
plt.title('Sobel Y')                                                # 画像タイトル設定
plt.axis("off")                                                     # 軸目盛、軸ラベルを消す
plt.subplot(224)                                                    # 2行2列の4番目の領域にプロットを設定
plt.imshow(sobel_combined, cmap='gray')                             # X方向のエッジ検出結果画像をグレースケールで表示
plt.title('Sobel Combined')                                         # 画像タイトル設定
plt.axis("off")                                                     # 軸目盛、軸ラベルを消す
plt.show()

Sobelフィルタ処理後に勾配の絶対値を計算しています。Sobelフィルタを適用することで得られる勾配情報は、正負の値を持ちます。これは、画像の輝度変化が明から暗、あるいは暗から明に変わる箇所で勾配が逆転します。+(プラス)またはー(マイナス)でエッジの向きを表しているためです。エッジの強度を把握するために、勾配の強度情報の絶対値を用いることで、エッジの強さを正の数値として扱いやすくしています。

したがって、通常はSobelフィルタの適用結果から水平方向と垂直方向の勾配成分を取得し、それらの絶対値を計算してから、これらを合成してエッジの強さを示す合成勾配を得ることで、エッジ情報の最大値が得られます。

ポイント

cv2.Sobel関数で得られた結果はcv2.convertScaleAbs関数で絶対値計算後に、合成勾配を得ることでエッジ情報の最大値が取得できます。

合成勾配の計算に使用しているcv2.addWeighted関数については、こちらの記事で紹介していますので、よろしかったら参考にして下さい。

参考記事

結果の表示についてはMatplotlibを利用しています。画像を表示した場合に、見やすい工夫をしていますので、こちらもご参考にして下さい。

おわりに

エッジ検出の手法で一般的に利用される、ソーベル フィルタ(Sobel Filter)について解説しました。
本ブログでは他のエッジ検出の方法も紹介しています。ご参考にして頂けると幸いです。

ご質問や取り上げて欲しい内容などがありましたら、コメントを頂けると嬉しいです。
最後までご覧いただきありがとうございました。

■(広告)OpenCVの参考書としてどうぞ!■

参考リンク

-Python, プログラミング, 画像処理
-