OpenCV 4.13.0
Open Source Computer Vision
読み込み中...
検索中...
見つかりません
🤖 AIによる機械翻訳(非公式) — これは OpenCV 4.13.0 公式リファレンス(英語)を AI (Claude) で自動翻訳したものです。訳に誤りを含む場合があります。正確な情報は 公式英語版(原文) を参照してください。
画像の勾配

目標

この章では次のことを学ぶ:

理論

OpenCVは3種類の勾配フィルタ(ハイパスフィルタ)、Sobel、Scharr、Laplacianを提供している。それぞれを順に見ていく。

1. SobelおよびScharr微分

Sobelオペレータはガウシアン平滑化と微分を組み合わせた演算であり、ノイズに対してより頑健である。微分を取る方向を縦か横か(それぞれ引数 yorder と xorder で)指定できる。また引数 ksize でカーネルのサイズも指定できる。ksize = -1 の場合、3x3のScharrフィルタが使われ、3x3のSobelフィルタよりも良い結果が得られる。使われるカーネルについてはドキュメントを参照のこと。

2. Laplacian微分

次の関係式で与えられる画像のラプラシアンを計算する。\(\Delta src = \frac{\partial ^2{src}}{\partial x^2} + \frac{\partial ^2{src}}{\partial y^2}\) ここで各微分はSobel微分を用いて求められる。ksize = 1 の場合、フィルタリングには次のカーネルが使われる:

\[kernel = \begin{bmatrix} 0 & 1 & 0 \\ 1 & -4 & 1 \\ 0 & 1 & 0 \end{bmatrix}\]

コード

以下のコードはすべてのオペレータを一つの図にまとめて示す。すべてのカーネルは5x5サイズである。np.uint8型で結果を得るために、出力画像のビット深度には-1を渡している。

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('dave.jpg', cv.IMREAD_GRAYSCALE)
assert img is not None, "file could not be read, check with os.path.exists()"
laplacian = cv.Laplacian(img,cv.CV_64F)
sobelx = cv.Sobel(img,cv.CV_64F,1,0,ksize=5)
sobely = cv.Sobel(img,cv.CV_64F,0,1,ksize=5)
plt.subplot(2,2,1),plt.imshow(img,cmap = 'gray')
plt.title('Original'), plt.xticks([]), plt.yticks([])
plt.subplot(2,2,2),plt.imshow(laplacian,cmap = 'gray')
plt.title('Laplacian'), plt.xticks([]), plt.yticks([])
plt.subplot(2,2,3),plt.imshow(sobelx,cmap = 'gray')
plt.title('Sobel X'), plt.xticks([]), plt.yticks([])
plt.subplot(2,2,4),plt.imshow(sobely,cmap = 'gray')
plt.title('Sobel Y'), plt.xticks([]), plt.yticks([])
plt.show()
Mat imread(const String &filename, int flags=IMREAD_COLOR_BGR)
Loads an image from a file.
void Sobel(InputArray src, OutputArray dst, int ddepth, int dx, int dy, int ksize=3, double scale=1, double delta=0, int borderType=BORDER_DEFAULT)
Calculates the first, second, third, or mixed image derivatives using an extended Sobel operator.
void Laplacian(InputArray src, OutputArray dst, int ddepth, int ksize=1, double scale=1, double delta=0, int borderType=BORDER_DEFAULT)
Calculates the Laplacian of an image.

結果:

image

一つの重要な注意点!

先ほどの例では、出力のデータ型は cv.CV_8U すなわち np.uint8 だった。しかしこれには少し問題がある。黒から白への変化は正の傾き(正の値を持つ)として扱われ、白から黒への変化は負の傾き(負の値を持つ)として扱われる。そのため np.uint8 にデータを変換すると、負の傾きはすべてゼロになる。簡単に言えば、そのエッジを取りこぼしてしまう。

両方のエッジを検出したい場合は、出力のデータ型を cv.CV_16S や cv.CV_64F などのより大きな型に保ち、その絶対値を取ってから cv.CV_8U に戻すのがよい。以下のコードは、水平方向のSobelフィルタについてこの手順と結果の違いを示している。

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('box.png', cv.IMREAD_GRAYSCALE)
assert img is not None, "file could not be read, check with os.path.exists()"
# Output dtype = cv.CV_8U
sobelx8u = cv.Sobel(img,cv.CV_8U,1,0,ksize=5)
# Output dtype = cv.CV_64F. Then take its absolute and convert to cv.CV_8U
sobelx64f = cv.Sobel(img,cv.CV_64F,1,0,ksize=5)
abs_sobel64f = np.absolute(sobelx64f)
sobel_8u = np.uint8(abs_sobel64f)
plt.subplot(1,3,1),plt.imshow(img,cmap = 'gray')
plt.title('Original'), plt.xticks([]), plt.yticks([])
plt.subplot(1,3,2),plt.imshow(sobelx8u,cmap = 'gray')
plt.title('Sobel CV_8U'), plt.xticks([]), plt.yticks([])
plt.subplot(1,3,3),plt.imshow(sobel_8u,cmap = 'gray')
plt.title('Sobel abs(CV_64F)'), plt.xticks([]), plt.yticks([])
plt.show()

結果を以下に示す。

image