OpenCVで使われるfilter2dとは?関数の定義からフィルタの仕組みを解説
今回はOpenCVで使われるfilter2dに関して、関数の定義からフィルタの仕組みを徹底解説致します。filter2d関数を学びたい、OpenCV初学者の方はおすすめです。ぜひ最後までご覧ください。
執筆者 - おすすめの記事3選
OpenCVで使われるfilter2dとは?
OpenCVで使われるfilter2dとは、自分好みのフィルタを用意して、フィルタを通して画像を出力する関数です。
具体的なイメージとしては、以下の「filter2d関数のイメージ画像」箇所を、イメージしてもらうと良いでしょう。
【サンプル画像】
【filter2d関数のイメージ画像】
自分好みのフィルタを通して画像を出力することで、以下の画像のように物体の輪郭だけを抽出すること等が実現できる。
フィルタを通して画像が出力される仕組み
早急にfilter2d関数の定義から利用法を知りたい方は、次章で紹介する「OpenCVで使われるfilter2d関数の定義」からご確認ください。
filter2d関数では、以下の5ステップを経て、画像の出力を行います。
- n x mのフィルタを用意します。(今回はn = 3, m = 3のフィルタを用意します。以下の「フィルタのサンプル画像」をご確認ください。)
- 画像内のあるn x mの画素に注目します。(画素に関しては、以下の「画素に関する説明を行う画像」を参照ください。)
- あるn x mの画素(2)内のある画素に注目する。(以下の「ある画素について注目する画像」箇所をご確認ください。)
- ある画素(3)の画素値を、フィルタを用いて変換します。(以下の「ある画素(3)の画素値をフィルタを用いて変換する画像」箇所をご確認ください。)
- 2~4を繰り返します。
【フィルタのサンプル画像】
【画素に関する説明を行う画像】
1枚の画像は、複数の画素の集まりで成り立っています。
【ある画素について注目する画像】
【ある画素(3)の画素値をフィルタを用いて変換する画像】
OpenCVで使われるfilter2d関数の定義
filter2d関数は
1# cv2(OpenCV)を利用する宣言を行う。
2import cv2
3import numpy as np
4
5# filter2d関数 : 自分好みのフィルタを用意して、フィルタを通して画像を出力する関数
6# filter2d関数 - 公式ドキュメント : https://docs.opencv.org/4.x/d4/d86/group__imgproc__filter.html#ga27c049795ce870216ddfb366086b5a04
7
8# 第一引数(必須) : 多次元配列(画像情報)
9
10##################################
11# 第二引数(必須) : 出力画像の型を指定する。以下の中からどれかを選択する。
12# 負の整数 : 入力画像と同じ型。
13# cv2.CV_16U : 符号なし16ビット(0~65536の画素値で画像を表現する。)
14# cv2.CV_16S : 符号あり16ビット(-32,768~32,767の画素値で画像を表現する。)
15# cv2.CV_32F : 32ビット浮動小数点数
16# cv2.CV_64F : 64ビット浮動小数点数
17
18# ※ 入力画像の型に合わせて、第二引数を選択ください。以下対応表になります。
19# 入力画像の型がcv2.CV_8Uの場合、-1 or cv2.CV_16S or cv2.CV_32F or cv2.CV_64Fを選択する。
20# 入力画像の型がcv2.CV_16U, cv2.CV_16Sの場合、-1 or cv2.CV_32F or cv2.CV_64Fを選択する。
21# 入力画像の型がcv2.CV_32Fの場合、-1 or cv2.CV_32F or cv2.CV_64Fを選択する。
22# 入力画像の型がcv2.CV_64Fの場合、-1 or cv2.CV_64Fを選択する。
23# 入力画像の型を調べる場合、print(img.dtype)でご確認ください。(参考 : https://docs.opencv.org/4.x/d4/d86/group__imgproc__filter.html#filter_depths)
24
25# ※ 出力画像の型で指定される、画素値の範囲を超えた画素は、フィルタを通して変換されずに無視されます。
26##################################
27
28# 第三引数(必須) : フィルタ。
29
30# <第四引数以降(任意 + 順不同)>
31#
32# anchor : あるn x mの画素内の、どの画素(あるn x mの画素(2)内のある画素)に注目するのか指定する。tuple型。
33# デフォルトでは(-1, -1)が設定され、自動的にn x mの画素内の中心を指すように設定される。
34# 例) : (1, 2) ⏩ n x mの画素内の、(1, 2)の画素に注目する。
35# 参考 : https://iryachi.stars.ne.jp/opencv-filter2d/
36
37# delta : ある画素(3)の画素値を、フィルタを用いて変換しますが、変換した後の画素値 = 変換した後の画素値 + deltaの値とするために、deltaの値を設定します。
38# 変換した後の画素値に対して、オフセットを設定するものと考えると良いでしょう。
39# オフセットとは? : https://wa3.i-3-i.info/word11923.html
40# デフォルトでは0が設定されます。double型。
41
42##################################
43# borderType : フィルタで演算されない、端の画素(画素値)に関してどのような処置を行うのか設定する。以下のどれかの定数を選択する。
44# cv2.BORDER_CONSTANT : デフォルト。端の画素(画素値)を固有値(0)で埋め込みます。(ある一行の画素値のイメージ(|は境界線) : 0,0,0,0|100,255,213,32|0,0,0,0)
45# cv2.BORDER_REPLICATE : フィルタが適用された端の画素(画素値)で埋め込みます。(ある一行の画素値のイメージ(|は境界線) : 100,100,100,100|100,255,213,32|32,32,32,32)
46# cv2.BORDER_REFLECT : フィルタが適用された画素(画素値)を反転したものを埋め込みます。(ある一行の画素値のイメージ(|は境界線) : 32,213,255,100|100,255,213,32|32,213,255,100)
47# cv2.BORDER_REFLECT_101 : フィルタが適用された端以外の画素(画素値)を反転したものを埋め込みます。(ある一行の画素値のイメージ(|は境界線) : 213,255|100,255,213,32|213,255)
48# borderType - 公式ドキュメント : https://docs.opencv.org/4.x/d2/de8/group__core__array.html#ga209f2f4869e304c82d07739337eae7c5
49# 参考 : https://iryachi.stars.ne.jp/opencv-filter2d/
50##################################
51
52# 戻り値 : 多次元配列(画像情報)
53
54dst = cv2.filter2D(img, 定数 or 負の整数, np.array([[数字, 数字, ...], [数字, 数字, ...], ...]), anchor=(0 <= x < n(フィルタの縦のサイズ), 0 <= y < m(フィルタの横のサイズ)), delta=数字, borderType=定数)
で定義されます。
例えば以下のようなコードを作成すると、
1import cv2
2import sys
3import numpy as np
4
5# imread : 画像ファイルを読み込んで、多次元配列(numpy.ndarray)にする。
6# imreadについて : https://kuroro.blog/python/wqh9VIEmRXS4ZAA7C4wd/
7# 第一引数 : 画像のファイルパス
8# 戻り値 : 行 x 列 x 色の三次元配列(numpy.ndarray)が返される。
9img = cv2.imread("xxx.xxx")
10
11# 画像ファイルが正常に読み込めなかった場合、プログラムを終了する。
12if img is None:
13 sys.exit("Could not read the image.")
14
15# filter2d関数 : 自分好みのフィルタを用意して、フィルタを通して画像を出力する関数
16
17# 第一引数(必須) : 多次元配列(numpy.ndarray)
18# 第二引数(必須) : 出力画像の型を指定する。
19# 第三引数(必須) : フィルタ。
20# 戻り値 : 多次元配列(numpy.ndarray)
21output = cv2.filter2D(img, -1, np.array([[1/9, 1/9, 1/9], [1/9, 1/9, 1/9], [1/9, 1/9, 1/9]]))
22
23# imwrite : 画像の保存を行う関数
24# 第一引数 : 保存先の画像ファイル名
25# 第二引数 : 多次元配列(numpy.ndarray)
26# <第二引数の例>
27# [
28# [
29# [234 237 228]
30# ...
31# [202 209 194]
32# ]
33# [
34# [10 27 16]
35# ...
36# [36 67 46]
37# ]
38# [
39# [34 51 40]
40# ...
41# [50 81 60]
42# ]
43# ]
44# imwriteについて : https://kuroro.blog/python/i0tNE1Mp8aEz8Z7n6Ggg/
45cv2.imwrite('output.jpg', output)
以下の画像のように、画像が描画されます。(少し画像にぼかしがかかって描画される。)
imreadに関しては、OpenCVで使われるimreadとは?使い方から配列が画像になる仕組みを解説でまとめていますので、詳しく知りたい方は是非ご確認ください。
imwriteに関しては、OpenCVで使われるimwriteとは?imwriteの定義から使用例をご紹介でまとめていますので、詳しく知りたい方は是非ご確認ください。
【6種類】代表的なフィルタの使い方を一挙紹介
先ほどはOpenCVで使われるfilter2d関数の定義から使い方までお伝えしました。今章では代表的なフィルタを6種類紹介し、各フィルタを通して画像を出力するための、filter2d関数の活用法を丁寧に解説いたします。
ガウシアンフィルタ
ガウシアンフィルタは画像をぼかすためのフィルタになります。
例えば以下のようなコードを作成すると、
1import cv2
2import sys
3import numpy as np
4
5# imread : 画像ファイルを読み込んで、多次元配列(numpy.ndarray)にする。
6# imreadについて : https://kuroro.blog/python/wqh9VIEmRXS4ZAA7C4wd/
7# 第一引数 : 画像のファイルパス
8# 戻り値 : 行 x 列 x 色の三次元配列(numpy.ndarray)が返される。
9img = cv2.imread("xxx.xxx")
10
11# 画像ファイルが正常に読み込めなかった場合、プログラムを終了する。
12if img is None:
13 sys.exit("Could not read the image.")
14
15# filter2d関数 : 自分好みのフィルタを用意して、フィルタを通して画像を出力する関数
16
17# 第一引数(必須) : 多次元配列(numpy.ndarray)
18# 第二引数(必須) : 出力画像の型を指定する。
19# 第三引数(必須) : フィルタ。
20# 戻り値 : 多次元配列(numpy.ndarray)
21output = cv2.filter2D(img, -1, np.array([[1/16, 1/8, 1/16], [1/8, 1/4, 1/8], [1/16, 1/8, 1/16]]))
22
23# imwrite : 画像の保存を行う関数
24# 第一引数 : 保存先の画像ファイル名
25# 第二引数 : 多次元配列(numpy.ndarray)
26# <第二引数の例>
27# [
28# [
29# [234 237 228]
30# ...
31# [202 209 194]
32# ]
33# [
34# [10 27 16]
35# ...
36# [36 67 46]
37# ]
38# [
39# [34 51 40]
40# ...
41# [50 81 60]
42# ]
43# ]
44# imwriteについて : https://kuroro.blog/python/i0tNE1Mp8aEz8Z7n6Ggg/
45cv2.imwrite('output.jpg', output)
以下の画像のように、ガウシアンフィルタを通して画像を出力します。
【元画像】
【ガウシアンフィルタを通した画像】
filter2d関数を利用する以外にも、ガウシアンフィルタを利用する方法があります。GaussianBlur関数を利用することです。GaussianBlur関数に関しては、【4選】OpenCVを用いて画像をぼかす方法からサンプルコードまで徹底解説!?の「GaussianBlur関数を用いて画像をぼかしてみる」箇所でまとめていますので、詳しく知りたい方は是非ご確認ください。
一次微分フィルタ
一次微分フィルタは、画像の輝度勾配(エッジ)を検出するために利用するフィルタです。
輝度勾配(エッジ) : 隣りあう画素に関して、画素と画素の色の差分((例) 明るい画素(色)の隣に、暗い画素(色))が大きい箇所(エッジ)を意味する。
例えば以下のようなコードを作成すると、
1import cv2
2import sys
3import numpy as np
4
5# imread : 画像ファイルを読み込んで、多次元配列(numpy.ndarray)にする。
6# imreadについて : https://kuroro.blog/python/wqh9VIEmRXS4ZAA7C4wd/
7# 第一引数 : 画像のファイルパス
8# 戻り値 : 行 x 列 x 色の三次元配列(numpy.ndarray)が返される。
9img = cv2.imread("xxx.xxx")
10
11# 画像ファイルが正常に読み込めなかった場合、プログラムを終了する。
12if img is None:
13 sys.exit("Could not read the image.")
14
15# filter2d関数 : 自分好みのフィルタを用意して、フィルタを通して画像を出力する関数
16
17# 第一引数(必須) : 多次元配列(numpy.ndarray)
18# 第二引数(必須) : 出力画像の型を指定する。
19# 第三引数(必須) : フィルタ。
20# 戻り値 : 多次元配列(numpy.ndarray)
21outputA = cv2.filter2D(img, cv2.CV_64F, np.array([[0, -1, 0], [0, 0, 0], [0, 1, 0]]))
22outputB = cv2.filter2D(img, cv2.CV_64F, np.array([[0, 0, 0], [-1, 0, 1], [0, 0, 0]]))
23
24dst = np.sqrt(outputA ** 2 + outputB ** 2)
25
26# imwrite : 画像の保存を行う関数
27# 第一引数 : 保存先の画像ファイル名
28# 第二引数 : 多次元配列(numpy.ndarray)
29# <第二引数の例>
30# [
31# [
32# [234 237 228]
33# ...
34# [202 209 194]
35# ]
36# [
37# [10 27 16]
38# ...
39# [36 67 46]
40# ]
41# [
42# [34 51 40]
43# ...
44# [50 81 60]
45# ]
46# ]
47# imwriteについて : https://kuroro.blog/python/i0tNE1Mp8aEz8Z7n6Ggg/
48cv2.imwrite('output.jpg', dst)
以下の画像のように、一次微分フィルタを通して画像を出力します。
【元画像】
【一次微分フィルタを通した画像】
プレヴィットフィルタ
プレヴィットフィルタは、画像の輝度勾配(エッジ)を検出するために利用するフィルタです。
例えば以下のようなコードを作成すると、
1import cv2
2import sys
3import numpy as np
4
5# imread : 画像ファイルを読み込んで、多次元配列(numpy.ndarray)にする。
6# imreadについて : https://kuroro.blog/python/wqh9VIEmRXS4ZAA7C4wd/
7# 第一引数 : 画像のファイルパス
8# 戻り値 : 行 x 列 x 色の三次元配列(numpy.ndarray)が返される。
9img = cv2.imread("xxx.xxx")
10
11# 画像ファイルが正常に読み込めなかった場合、プログラムを終了する。
12if img is None:
13 sys.exit("Could not read the image.")
14
15# filter2d関数 : 自分好みのフィルタを用意して、フィルタを通して画像を出力する関数
16
17# 第一引数(必須) : 多次元配列(numpy.ndarray)
18# 第二引数(必須) : 出力画像の型を指定する。
19# 第三引数(必須) : フィルタ。
20# 戻り値 : 多次元配列(numpy.ndarray)
21outputA = cv2.filter2D(img, cv2.CV_64F, np.array([[-1, 0, 1], [-1, 0, 1], [-1, 0, 1]]))
22outputB = cv2.filter2D(img, cv2.CV_64F, np.array([[-1, -1, -1], [0, 0, 0], [1, 1, 1]]))
23
24dst = np.sqrt(outputA ** 2 + outputB ** 2)
25
26# imwrite : 画像の保存を行う関数
27# 第一引数 : 保存先の画像ファイル名
28# 第二引数 : 多次元配列(numpy.ndarray)
29# <第二引数の例>
30# [
31# [
32# [234 237 228]
33# ...
34# [202 209 194]
35# ]
36# [
37# [10 27 16]
38# ...
39# [36 67 46]
40# ]
41# [
42# [34 51 40]
43# ...
44# [50 81 60]
45# ]
46# ]
47# imwriteについて : https://kuroro.blog/python/i0tNE1Mp8aEz8Z7n6Ggg/
48cv2.imwrite('output.jpg', dst)
以下の画像のように、プレヴィットフィルタを通して画像を出力します。
【元画像】
【プレヴィットフィルタを通した画像】
Sobelフィルタ
Sobelフィルタは、画像の輝度勾配(エッジ)を検出するために利用するフィルタです。
例えば以下のようなコードを作成すると、
1import cv2
2import sys
3import numpy as np
4
5# imread : 画像ファイルを読み込んで、多次元配列(numpy.ndarray)にする。
6# imreadについて : https://kuroro.blog/python/wqh9VIEmRXS4ZAA7C4wd/
7# 第一引数 : 画像のファイルパス
8# 戻り値 : 行 x 列 x 色の三次元配列(numpy.ndarray)が返される。
9img = cv2.imread("xxx.xxx")
10
11# 画像ファイルが正常に読み込めなかった場合、プログラムを終了する。
12if img is None:
13 sys.exit("Could not read the image.")
14
15# filter2d関数 : 自分好みのフィルタを用意して、フィルタを通して画像を出力する関数
16
17# 第一引数(必須) : 多次元配列(numpy.ndarray)
18# 第二引数(必須) : 出力画像の型を指定する。
19# 第三引数(必須) : フィルタ。
20# 戻り値 : 多次元配列(numpy.ndarray)
21outputA = cv2.filter2D(img, cv2.CV_64F, np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]]))
22outputB = cv2.filter2D(img, cv2.CV_64F, np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]]))
23
24dst = np.sqrt(outputA ** 2 + outputB ** 2)
25
26# imwrite : 画像の保存を行う関数
27# 第一引数 : 保存先の画像ファイル名
28# 第二引数 : 多次元配列(numpy.ndarray)
29# <第二引数の例>
30# [
31# [
32# [234 237 228]
33# ...
34# [202 209 194]
35# ]
36# [
37# [10 27 16]
38# ...
39# [36 67 46]
40# ]
41# [
42# [34 51 40]
43# ...
44# [50 81 60]
45# ]
46# ]
47# imwriteについて : https://kuroro.blog/python/i0tNE1Mp8aEz8Z7n6Ggg/
48cv2.imwrite('output.jpg', dst)
以下の画像のように、Sobelフィルタを通して画像を出力します。
【元画像】
【Sobelフィルタを通した画像】
filter2d関数を利用する以外にも、Sobelフィルタを利用する方法があります。Sobel関数を利用することです。Sobel関数に関しては、OpenCVで使われるsobelとは?利用法からSobelフィルタの理論等を解説でまとめていますので、詳しく知りたい方は是非ご確認ください。
ラプラシアンフィルタ
ラプラシアンフィルタは、画像の輝度勾配(エッジ)を検出するために利用するフィルタです。
例えば以下のようなコードを作成すると、
1import cv2
2import sys
3import numpy as np
4
5# imread : 画像ファイルを読み込んで、多次元配列(numpy.ndarray)にする。
6# imreadについて : https://kuroro.blog/python/wqh9VIEmRXS4ZAA7C4wd/
7# 第一引数 : 画像のファイルパス
8# 戻り値 : 行 x 列 x 色の三次元配列(numpy.ndarray)が返される。
9img = cv2.imread("xxx.xxx")
10
11# 画像ファイルが正常に読み込めなかった場合、プログラムを終了する。
12if img is None:
13 sys.exit("Could not read the image.")
14
15# filter2d関数 : 自分好みのフィルタを用意して、フィルタを通して画像を出力する関数
16
17# 第一引数(必須) : 多次元配列(numpy.ndarray)
18# 第二引数(必須) : 出力画像の型を指定する。
19# 第三引数(必須) : フィルタ。
20# 戻り値 : 多次元配列(numpy.ndarray)
21output = cv2.filter2D(img, cv2.CV_64F, np.array([[1, 1, 1], [1, -8, 1], [1, 1, 1]]))
22
23# imwrite : 画像の保存を行う関数
24# 第一引数 : 保存先の画像ファイル名
25# 第二引数 : 多次元配列(numpy.ndarray)
26# <第二引数の例>
27# [
28# [
29# [234 237 228]
30# ...
31# [202 209 194]
32# ]
33# [
34# [10 27 16]
35# ...
36# [36 67 46]
37# ]
38# [
39# [34 51 40]
40# ...
41# [50 81 60]
42# ]
43# ]
44# imwriteについて : https://kuroro.blog/python/i0tNE1Mp8aEz8Z7n6Ggg/
45cv2.imwrite('output.jpg', output)
以下の画像のように、ラプラシアンフィルタを通して画像を出力します。
【元画像】
【ラプラシアンフィルタを通した画像】
エンボスフィルタ
エンボスフィルタは、画像の輝度勾配(エッジ)を検出するために利用するフィルタです。
例えば以下のようなコードを作成すると、
1import cv2
2import sys
3import numpy as np
4
5# imread : 画像ファイルを読み込んで、多次元配列(numpy.ndarray)にする。
6# imreadについて : https://kuroro.blog/python/wqh9VIEmRXS4ZAA7C4wd/
7# 第一引数 : 画像のファイルパス
8# 戻り値 : 行 x 列 x 色の三次元配列(numpy.ndarray)が返される。
9img = cv2.imread("xxx.xxx")
10
11# 画像ファイルが正常に読み込めなかった場合、プログラムを終了する。
12if img is None:
13 sys.exit("Could not read the image.")
14
15# filter2d関数 : 自分好みのフィルタを用意して、フィルタを通して画像を出力する関数
16
17# 第一引数(必須) : 多次元配列(numpy.ndarray)
18# 第二引数(必須) : 出力画像の型を指定する。
19# 第三引数(必須) : フィルタ。
20# 戻り値 : 多次元配列(numpy.ndarray)
21outputA = cv2.filter2D(img, cv2.CV_64F, np.array([[0, 0, 0], [-1, 0, 1], [0, 0, 0]]))
22outputB = cv2.filter2D(img, cv2.CV_64F, np.array([[0, -1, 0], [0, 0, 0], [0, 1, 0]]))
23
24dst = np.sqrt(outputA ** 2 + outputB ** 2)
25
26# imwrite : 画像の保存を行う関数
27# 第一引数 : 保存先の画像ファイル名
28# 第二引数 : 多次元配列(numpy.ndarray)
29# <第二引数の例>
30# [
31# [
32# [234 237 228]
33# ...
34# [202 209 194]
35# ]
36# [
37# [10 27 16]
38# ...
39# [36 67 46]
40# ]
41# [
42# [34 51 40]
43# ...
44# [50 81 60]
45# ]
46# ]
47# imwriteについて : https://kuroro.blog/python/i0tNE1Mp8aEz8Z7n6Ggg/
48cv2.imwrite('output.jpg', dst)
以下の画像のように、エンボスフィルタを通して画像を出力します。
【元画像】
【エンボスフィルタを通した画像】
まとめ
- OpenCVで使われるfilter2dとは、自分好みのフィルタを用意して、フィルタを通して画像を出力する関数を意味する。
参考文献
- フィルタとは?
- 輪郭とは?
- filter2d関数 - 公式ドキュメント
- オフセットとは?
- borderType - 公式ドキュメント
- ぼかしとは?
- OpenCVで使われるfilter2D関数に関するサンプルコード
- ガウシアンフィルタとは?
- 一次微分フィルタとは?
- プレヴィットフィルタとは?
- Sobelフィルタとは?
- ラプラシアンフィルタとは?
- エンボスフィルタとは?