OpenCV Reference

【OpenCV-Python】Sobel(エッジ検出)

OpenCVでソーベルフィルタ処理を行うには、Sobel()関数を用います。

ソーベルフィルタは、画像のエッジを検出することで、位置決めや寸法計測などに用いられます。

ソーベルフィルタ処理の構文

Sobel( src, ddepth, dx, dy[, dst[, ksize[, scale[, delta[, borderType]]]]] ) -> dst

引数

src 入力画像
ddepth 出力画像のビット深度
dx x方向に関する微分の次数
dy y方向に関する微分の次数
ksize カーネルのサイズ 1, 3, 5, 7 のいずれか
scale 出力する値の倍率
delta 出力する値に加算する値
borderType 外周処理の種類を指定


戻り値

dst ソーベルフィルタ処理された画像データ

サンプルプログラム

よくあるソーベルフィルタ処理のサンプルプログラムを以下に示します。

ソーベルフィルタはノイズの影響を受けやすい処理のため、最初にノイズ除去のため、メディアンフィルタ処理を施しています。


import cv2

src = cv2.imread("Text.bmp", cv2.IMREAD_UNCHANGED)

# ノイズ除去(メディアンフィルタ)
src_median = cv2.medianBlur(src, 5)
# ソーベルフィルタ
sobel_x = cv2.Sobel(src_median, cv2.CV_32F, 1, 0) # X方向
sobel_y = cv2.Sobel(src_median, cv2.CV_32F, 0, 1) # Y方向

# 立下りエッジ(白から黒へ変化する部分)がマイナスになるため絶対値を取る
# alphaの値は画像表示に合わせて倍率調整
sobel_x = cv2.convertScaleAbs(sobel_x, alpha = 0.5)
sobel_y = cv2.convertScaleAbs(sobel_y, alpha = 0.5)

# X方向とY方向を足し合わせる
sobel_xy = cv2.add(sobel_x, sobel_y)

# 二値化処理後の画像表示
cv2.imshow("Src Image", src)

cv2.imshow("SobelX", sobel_x)
cv2.imshow("SobelY", sobel_y)
cv2.imshow("SobelXY", sobel_xy)
cv2.waitKey()

実行結果

OpenCV Python Sobel エッジ検出

 

実際のSobelフィルタ処理の使い方

Sobleフィルタは最初にも書きましたが、被写体のエッジ部分を検出することで、位置決めや寸法計測に用います。

そのため、上記に示したようなエッジ部分を白く強調した画像は、ほとんど用いる事はありません。

さらに、上記のサンプルでは、Sobelフィルタ処理の絶対値を取得していますが、実際には、正、負の値が重要になります。

例えば、下図のようなバーコードの画像において、線の幅や位置を知りたいときは、黒い線の右側と左側を区別する必要があります。

画像を左側から右側に見た時、白から黒に変化する部分(立下りエッジ)では、X方向のソーベルフィルタ処理の値は負になります。

同様に黒から白に変化する部分(立上りエッジ)では、X方向のソーベルフィルタ処理の値は正になります。

OpenCV Python Sobel エッジ検出

上図の赤矢印の輝度値の一部分をグラフにすると、下図のようになります。

OpenCV Python Sobel エッジ検出

この輝度部分に関して、ソーベルフィルタ処理を行うと、

OpenCV Python Sobel エッジ検出

のようになり、ソーベルフィルタの値の正負を区別することで、立上りエッジと立下りエッジを認識することができるようになります。

この事を利用したサンプルを以下に示します。

import cv2

cv2.namedWindow("Image", cv2.WINDOW_NORMAL)

src = cv2.imread("image.jpg", cv2.IMREAD_GRAYSCALE) # 処理画像
src_disp = cv2.cvtColor(src, cv2.COLOR_GRAY2BGR) # 結果表示用カラー画像

# ソーベルフィルタ
sobel_x = cv2.Sobel(src, cv2.CV_32F, 1, 0) # X方向

# 中心付近の横1ライン分のデータ
sobel_value = sobel_x[112][:]

thre_high = 300 # 立上りエッジのしきい値
thre_low = -300 # 立下りエッジのしきい値

min = 0
max = 0

# 縦方向の中心付近のY座標
y = 112

for i in range(src.shape[1]):

    if sobel_x[y, i] > thre_high:
        if max < sobel_x[y, i]:
            max = sobel_x[y, i]
            max_x = i
    else:
        if max != 0:
            # 立上りエッジの描画
            cv2.line(src_disp, (max_x, 0), (max_x, src.shape[0] - 1), (255, 0, 0), 1)
            max = 0

    if sobel_x[y, i] < thre_low: if min > sobel_x[y, i]:
            min = sobel_x[y, i]
            min_x = i
    else:
        if min != 0:
            # 立下りエッジの描画
            cv2.line(src_disp, (min_x, 0), (min_x, src.shape[0] - 1), (0, 0, 255), 1)
            min = 0

cv2.imshow("Image", src_disp)
cv2.waitKey()

実行結果

OpenCV Python Sobel エッジ検出

 

今回用いている画像は、ノイズが少ないため、ノイズ除去を行っていませんが、ノイズが多い画像の場合、エッジをぼかさずにノイズを除去するため、エッジ方向に沿ったノイズ除去フィルタを行います。

例えば、上図の画像では、幅1画素、高さ7画素のカーネルでガウシアンフィルタ処理などを行います。

 

参照ページ

OpenCV: Image Filtering
エッジ抽出(Sobel,Prewittなど)
下図のように画像の輪郭(エッジ)を抽出する方法を紹介します。 → エッジ抽出前 エッジ抽出後 上図はソーベルフィルタの例です。 微分フィルタ 画像の輝度値に対して、隣り合う画素の輝度差が大きいほど、画像のエッジだと考えることができ、 画像の...
【OpenCV-Python】BorderTypes(画像の外周処理の設定)
blur(平滑化)やGaussianBlur(ガウシアンフィルタ)など、カーネルを使った画像フィルタ処理では、画像の最外周部分では、カーネルが画像からはみ出してしまうため、はみ出した部分を、どのように補うか?の設定の種類にBoarderTy...

コメント

タイトルとURLをコピーしました