OpenCV 入門 (14) OpenCV 13 エッジ検出を素早く学ぶ

作者: シオウ

1. エッジ検出の概要

エッジ検出は画像処理とコンピュータ ビジョンにおける基本的な問題であり、エッジ検出の目的は、デジタル画像内で明白な明るさの変化がある点を識別することです。画像プロパティの大幅な変化は、深度の不連続、表面方向の不連続、マテリアルのプロパティの変更、シーンの照明の変更など、重要なイベントやプロパティの変更を反映していることがよくあります。エッジ検出機能は、抽出における研究分野です。画像エッジ検出により、データ量が大幅に削減され、無関係と考えられる情報が削除され、画像の重要な構造的属性が保持されます。

エッジ検出には多くの方法がありますが、そのほとんどは 2 つのカテゴリに分類できます。1 つは検索に基づくもの、もう 1 つはゼロクロッシングに基づくものです。検索ベースの方法では、画像の一次導関数の最大値と最小値を見つけて境界を検出し、通常は最大勾配の方向に境界を特定します。ゼロクロッシングに基づく方法は、画像の二次導関数のゼロクロッシングを探すことによって境界を見つけます。これは通常、ラプラシアン ゼロクロッシング ポイントまたは非線形差分表現のゼロクロッシング ポイントです。

人間の視覚系による物体認識のプロセスは 2 つのステップに分かれています: 最初に画像のエッジを背景から分離し、次に画像の詳細を調べて画像の輪郭を識別します。コンピューター ビジョンは人間の視覚を模倣するプロセスです。

したがって、物体のエッジを検出する際には、まず輪郭点を大まかに検出し、次に最初に検出された輪郭点を結合ルールによって接続し、欠落している境界点を検出して接続し、偽の境界点を除去します。画像のエッジは画像の重要な特徴であり、コンピューター ビジョン、パターン認識などの基礎となります。したがって、エッジ検出は画像処理における重要なリンクです。
しかし、実際のシーン画像のエッジはさまざまな種類のエッジとそのぼやけた結果の組み合わせであることが多く、実際の画像信号にはノイズが含まれるため、画像処理におけるエッジ検出は困難な問題です。ノイズもエッジも高周波信号であるため、周波数帯域による選択は困難です。

エッジとは、画像周囲のピクセルグレースケールが階段状または屋根状に変化するピクセルの集合を指し、対象と背景、対象と対象、領域と領域、プリミティブとプリミティブの間に存在します。エッジには方向と振幅の2つの特徴があり、エッジに沿った方向では画素値の変化が比較的緩やかですが、エッジに垂直な方向では画素値の変化が比較的激しく、階段状や斜面状に現れることがあります。

したがって、エッジは 2 つのタイプに分けることができます: 1 つは両側のピクセルのグレースケール値が大きく異なるステップ エッジ、もう 1 つはグレースケールが変化する分岐点に位置する屋根状のエッジです。値は増加から減少へと増加します。階段エッジの場合、2 次の方向微分値はエッジでゼロ交差を持ちます。屋根状のエッジの場合、2 次方向微分値はエッジで極値を取ります。

画像エッジ検出技術は、画像処理やコンピュータビジョンの分野における最も基本的な問題であり、古典的な技術問題の一つでもあります。画像のエッジ情報を迅速かつ正確に抽出する方法は国内外で常に研究の焦点となっていますが、同時にエッジ検出は画像処理における難しい問題でもあります。初期の古典的なアルゴリズムには、エッジ オペレーター法、サーフェス フィッティング法、テンプレート マッチング法、しきい値法などが含まれます。

近年、数学理論と人工知能技術の発展に伴い、Roberts、Laplacan、Canny、その他の画像エッジ検出方法など、多くの新しいエッジ検出方法が登場しました。これらの手法の適用は、高レベルの特徴抽出、特徴記述、物体認識、画像理解に大きな影響を与えます。しかし、画像処理のプロセスでは、投影、混合、歪み、ノイズが画像のぼやけや変形を引き起こすため、人々は優れた特性を備えたエッジ検出オペレーターを構築することに熱心に取り組んできました。

画像エッジ検出には主に次の 5 つのステップが含まれます。

(1) 画像取得
(2) 画像フィルタリング
(3) 画像強調
(4) 画像検出
(5) 画像位置決め

元の画像をテストします:

ここに画像の説明を挿入します

2.ロバーツオペレータエッジ検出

相互差分アルゴリズムとしても知られる Roberts オペレーターは、相互差分に基づく勾配アルゴリズムであり、局所的な差分計算を通じてエッジ ラインを検出します。このアルゴリズムは、急峻な低ノイズ画像の処理によく使用され、画像のエッジがプラス 45 度またはマイナス 45 度に近い場合、このアルゴリズムの方が良好な処理結果が得られます。欠点は、エッジの位置決めがあまり正確ではなく、抽出されたエッジの線が太くなることです。

Roberts オペレーターの実装は、主に OpenCV の filter2D 関数を通じて完了します。この関数の主な機能は、コンボリューション カーネルを通じて画像にコンボリューション演算を実装することであり、次のように宣言されます。

    def filter2D(src, ddepth, kernel, dst=None, anchor=None, delta=None,
borderType=None)

パラメータ
src は入力画像、
d Depth はターゲット画像の必要な深度を表し、
kernel は畳み込みカーネルを表します。

コード例:

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt 
 
# 读取图像
img = cv.imread('test.jpg', cv.COLOR_BGR2GRAY)
rgb_img = cv.cvtColor(img, cv.COLOR_BGR2RGB)

# 灰度化处理图像
grayImage = cv.cvtColor(img, cv.COLOR_BGR2GRAY)

# Roberts 算子
kernelx = np.array([[-1, 0], [0, 1]], dtype=int)
kernely = np.array([[0, -1], [1, 0]], dtype=int)

x = cv.filter2D(grayImage, cv.CV_16S, kernelx)
y = cv.filter2D(grayImage, cv.CV_16S, kernely)

# 转 uint8 ,图像融合
absX = cv.convertScaleAbs(x)
absY = cv.convertScaleAbs(y)
Roberts = cv.addWeighted(absX, 0.5, absY, 0.5, 0)

# 显示图形
titles = ['src', 'Roberts operator']
images = [rgb_img, Roberts]

for i in range(2):
    plt.subplot(1, 2, i + 1), plt.imshow(images[i], 'gray')
    plt.title(titles[i])
    plt.xticks([]), plt.yticks([])
plt.show()

上記のコードでは、Roberts 演算子を実装する関数 Roberts を定義し、そのメソッドは数式によって実装されます。Roberts を呼び出す前に、まずライブラリ関数 GaussianBlur を使用してガウス フィルタリングを実行します。

出力結果:

ここに画像の説明を挿入します

3.ソーベルオペレーターエッジ検出

ソーベル オペレーターは、離散微分法によって画像のエッジを取得するエッジ検出オペレーターです。ソーベル オペレーター (Sobel オペレーター) は、ピクセルの上下左右の近傍のグレースケール重み付けアルゴリズムを使用して、エッジ点での望ましい結果 エッジ検出には極値の原理が使用されます。この方法は、より良い検出結果を生み出すだけでなく、ノイズに対する平滑化効果もあり、より正確なエッジ方向情報を提供できます。技術的には、離散差分演算子を使用して画像の明るさ関数の勾配近似を計算しますが、Sobel 演算子が画像の被写体と背景を厳密に区別しないという欠点があります。

言い換えれば、ソーベル オペレーターは画像のグレースケールに基づいて処理を行いません。これは、ソーベル オペレーターが人間の視覚生理学的特性を厳密にシミュレートしていないため、画像の輪郭の抽出が不十分な場合があるためです。

OpenCV には、画像からソーベル エッジを抽出するための Sobel 関数が用意されており、この関数は次のように宣言されます。

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

コード例:

import cv2 as cv
import matplotlib.pyplot as plt

# 读取图像
img = cv.imread('test.jpg', cv.COLOR_BGR2GRAY)
rgb_img = cv.cvtColor(img, cv.COLOR_BGR2RGB)

# 灰度化处理图像
grayImage = cv.cvtColor(img, cv.COLOR_BGR2GRAY)

# Sobel 算子
x = cv.Sobel(grayImage, cv.CV_16S, 1, 0)
y = cv.Sobel(grayImage, cv.CV_16S, 0, 1)

# 转 uint8 ,图像融合
absX = cv.convertScaleAbs(x)
absY = cv.convertScaleAbs(y)
Sobel = cv.addWeighted(absX, 0.5, absY, 0.5, 0)

# 用来正常显示中文标签
plt.rcParams['font.sans-serif'] = ['SimHei']

# 显示图形
titles = ['原始图像', 'Sobel 算子']
images = [rgb_img, Sobel]

for i in range(2):
    plt.subplot(1, 2, i + 1), plt.imshow(images[i], 'gray')
    plt.title(titles[i])
    plt.xticks([]), plt.yticks([])
plt.show()

出力結果:
ここに画像の説明を挿入します

4. Prewitt オペレーターエッジ検出

Prewitt エッジ オペレーターは、エッジ テンプレート オペレーターです。テンプレート オペレーターは、理想的なエッジ オペレーター画像で構成されます。エッジ テンプレートは、画像を順番に検出するために使用されます。検出された領域に最も類似したテンプレートが最大値を与えます。Prewitt オペレーターは、ソーベルに似ており、グレースケールを使用します。画素の上下左右の隣接点を比較し、その差分がエッジで極値となることでエッジを検出する。ノイズを平滑化する効果があり、位置決め精度は十分ではありません。

Prewitt_X オペレーターは、実際には最初に画像の垂直方向に非正規化平均スムージングを実行し、次に水平方向の差分を実行しますが、Prewitt_Y オペレーターは実際に最初に画像の水平方向に非正規化平均スムージングを実行します。次に垂直微分を実行します。これが、Prewitt オペレーターがノイズを抑制できる理由です。同様に、対角線上の Prewitt 演算子も取得できます。

コード例:

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

# 读取图像
img = cv.imread('test.jpg', cv.COLOR_BGR2GRAY)
rgb_img = cv.cvtColor(img, cv.COLOR_BGR2RGB)

# 灰度化处理图像
grayImage = cv.cvtColor(img, cv.COLOR_BGR2GRAY)

# Prewitt 算子
kernelx = np.array([[1,1,1],[0,0,0],[-1,-1,-1]],dtype=int)
kernely = np.array([[-1,0,1],[-1,0,1],[-1,0,1]],dtype=int)

x = cv.filter2D(grayImage, cv.CV_16S, kernelx)
y = cv.filter2D(grayImage, cv.CV_16S, kernely)

# 转 uint8 ,图像融合
absX = cv.convertScaleAbs(x)
absY = cv.convertScaleAbs(y)
Prewitt = cv.addWeighted(absX, 0.5, absY, 0.5, 0)

# 用来正常显示中文标签
plt.rcParams['font.sans-serif'] = ['SimHei']

# 显示图形
titles = ['原始图像', 'Prewitt 算子']
images = [rgb_img, Prewitt]

for i in range(2):
    plt.subplot(1, 2, i + 1), plt.imshow(images[i], 'gray')
    plt.title(titles[i])
    plt.xticks([]), plt.yticks([])
plt.show()

出力結果:

ここに画像の説明を挿入します

5.LoGオペレータエッジ検出

LoG エッジ検出オペレーターは、David Courtnay Marr と Ellen Hildreth によって共同提案されました (1980 年)。したがって、エッジ検出アルゴリズムまたは Marr & Hildreth 演算子とも呼ばれます。このアルゴリズムは、最初に画像に対してガウス フィルタリングを実行し、次にそのラプラシアン (ラプラシアン) の 2 次導関数を求めます。つまり、画像とガウス関数のラプラシアンがフィルタリングされます。

最後に、フィルタリング結果のゼロクロスを検出することで、画像またはオブジェクトのエッジを取得できます。したがって、業界ではラプラシアン オブ ガウス (LoG) 演算子とも呼ばれます。

コード例:

import cv2 as cv
import matplotlib.pyplot as plt

# 读取图像
img = cv.imread("test.jpg")
rgb_img = cv.cvtColor(img, cv.COLOR_BGR2RGB)

gray_img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)

# 先通过高斯滤波降噪
gaussian = cv.GaussianBlur(gray_img, (3, 3), 0)

# 再通过拉普拉斯算子做边缘检测
dst = cv.Laplacian(gaussian, cv.CV_16S, ksize=3)
LOG = cv.convertScaleAbs(dst)

# 用来正常显示中文标签
plt.rcParams['font.sans-serif'] = ['SimHei']

# 显示图形
titles = ['原始图像', 'LOG 算子']
images = [rgb_img, LOG]

for i in range(2):
    plt.subplot(1, 2, i + 1), plt.imshow(images[i], 'gray')
    plt.title(titles[i])
    plt.xticks([]), plt.yticks([])
plt.show()
 

このアルゴリズムは、まず画像に対してガウス フィルタリングを実行し、次にラプラシアンの 2 次導関数を求め、2 次導関数のゼロクロス点に基づいて画像の境界を検出します。つまり、画像は次の検出によって取得されます。フィルタリング結果のゼロクロッシング、またはオブジェクトのエッジ。LoG オペレータは実際にはガウス フィルタリングとラプラシアン フィルタリングを組み合わせたもので、まずノイズを平滑化してからエッジ検出を実行します。

出力結果:

ここに画像の説明を挿入します

6. Canny オペレーターエッジ検出

Canny エッジ検出は、マルチレベルのエッジ検出アルゴリズムを使用してエッジを検出する方法です。1986 年、John F. Canny は、エッジ検出の実行方法を詳しく説明した有名な論文「エッジ検出への計算的アプローチ」を発表しました。OpenCV は、Canny エッジ検出を実装する関数 cv2.Canny() を提供します。

ステップ:

ガウス フィルターを使用して画像を滑らかにし、ノイズを除去します。
画像内の各ピクセルの勾配強度と方向を計算します。
非最大抑制を使用してエッジ検出によって引き起こされるスプリアスを除去します。
二重しきい値検出 (二重しきい値) を使用して、実際の応答としきい値を決定します。潜在的なエッジ。
エッジ検出は、孤立した弱いエッジを抑制することによって最終的に完了します。

6.1 ガウスフィルターを適用して画像ノイズを除去する

画像のエッジはノイズ干渉の影響を非常に受けやすいため、誤ったエッジ情報の検出を避けるために、通常は画像をフィルタリングしてノイズを除去する必要があります。フィルタリングの目的は、より正確なエッジを取得するために、弱いテクスチャを持つ一部の非エッジ領域を滑らかにすることです。実際の処理では、通常、画像のノイズを除去するためにガウス フィルタリングが使用されます。

ここに画像の説明を挿入します
ここに画像の説明を挿入します

6.2 勾配の計算

ここでは、エッジの方向に対して垂直なグラデーションの方向に焦点を当てます。エッジ検出オペレーターは、水平方向に Gx を、垂直方向に Gy を返します。勾配の大きさ G と方向 Θ (角度値として表される) は次のとおりです。

ここに画像の説明を挿入します
グラデーションの方向は常にエッジに対して垂直であり、最も近い値は通常、水平 (左、右)、垂直 (上、下)、斜め (右上、左上、左下、下) の 8 つの異なる方向です。右)。

したがって、勾配を計算すると、勾配の大きさと角度 (勾配の方向を表す) の 2 つの値が得られます。

ここに画像の説明を挿入します

6.3 非最大抑制

グラデーションの大きさと方向を取得した後、画像内のピクセルを走査し、エッジ以外の点をすべて削除します。具体的な実装では、ピクセルを 1 つずつ走査して、現在のピクセルが同じ勾配方向の周囲のピクセルの最大値であるかどうかを判断し、その判断結果に基づいてポイントを抑制するかどうかを決定します。上記の説明からわかるように、このステップはエッジリファインメントプロセスです。

ここに画像の説明を挿入します
ここに画像の説明を挿入します

6.4 デュアルしきい値を適用してエッジを決定する

上記の手順を完了すると、画像内の強いエッジは現在取得したエッジ画像内にすでに存在します。ただし、一部の仮想エッジがエッジ画像内に存在する場合もあります。これらの仮想エッジは、実際の画像またはノイズによって生成される可能性があります。後者については、それを排除する必要があります。

2 つのしきい値を設定します。1 つは高しきい値 maxVal、もう 1 つは低しきい値 minVal です。現在のエッジ画素の勾配値(勾配振幅を指す、以下同じ)と2つの閾値との関係に応じてエッジ属性を判定する。

ここに画像の説明を挿入します

6.5 コード例

import cv2
import numpy as np
# 读取图片, 并转换成灰度图
img = cv2.imread("test.jpg", cv2.IMREAD_GRAYSCALE)

# Canny边缘检测
out1 = cv2.Canny(img, 50, 150)
out2 = cv2.Canny(img, 100, 150)

# 合并
canny = np.hstack((out1, out2))

# 展示图片
cv2.imshow("src", img)
cv2.imshow("canny", canny)
cv2.waitKey(0)
cv2.destroyAllWindows()

出力結果:

ここに画像の説明を挿入します

おすすめ

転載: blog.csdn.net/qq_41600018/article/details/129570190