【4選】OpenCVを用いて画像をぼかす方法からサンプルコードまで徹底解説!?
今回はOpenCVを用いて画像をぼかす方法を4選に絞り、サンプルコードを交えながらわかりやすく解説致します。画像をぼかしてみたい、OpenCVを使い始めた方へおすすめです。ぜひ最後までご覧ください。
執筆者 - おすすめの記事3選
画像をぼかすとは?
画像をぼかすとは、輪郭や色の濃淡の境目をきわだたせないで、ぼんやりさせることを意味します。難しい言葉で言うと、「平滑化」すると呼ばれます。
具体的なイメージとしては、以下の「サンプル画像へぼかしを加えたイメージ画像」箇所を、イメージしてもらうと良いでしょう。
【サンプル画像】
【サンプル画像へぼかしを加えたイメージ画像】
画像へぼかしを加えることで、
- 主役をきわだたせられる
- 背景が整理される
- 画像に距離感が生まれる
などの効果が期待できます。
【4選】OpenCVを用いて画像をぼかす方法
OpenCVを用いて画像をぼかす方法として
- blur
- GaussianBlur
- medianBlur
- bilateralFilter
関数の4種類が挙げられます。順にみていきましょう。
blur関数を用いて画像をぼかしてみる
blur関数は、以下の手順を踏まえて画像をぼかす関数です。
- あるn x mの画素(n, mは1以上の整数)について注目する。(画素に関しては、以下の「画素に関する説明を行う画像」を参照ください。今回は、n, mを3, 3と定義します。)
- あるn x mの画素(1)内のある画素に注目する。(以下の「ある画素について注目する画像」箇所をご確認ください。)
- ある画素(2)の画素値を、あるn x mの画素(1)の平均値とする。(以下の「ある画素について注目する画像」の場合、32の画素値を(3 + 75 + 81 + 22 + 45 + 32 + 65 + 42 + 67) / 9 = 48へ変更します。)
- 1~3を繰り返す。
【画素に関する説明を行う画像】
1枚の画像は、複数の画素の集まりで成り立っています。
【ある画素について注目する画像】
blur関数の定義としては、
1# cv2(OpenCV)を利用する宣言を行う。
2import cv2
3
4# blur関数 : 画像をぼかす関数
5# blur関数 - 公式ドキュメント : https://docs.opencv.org/3.4/d4/d86/group__imgproc__filter.html#ga8c45db9afe636703801b0b2e440fce37
6
7# 第一引数(必須) : 多次元配列(画像情報)
8
9# 第二引数(必須) : ぼかすために必要な、n x mの画素領域を指定する。tuple型。
10# tuple型とは? : https://atmarkit.itmedia.co.jp/ait/articles/1906/14/news015.html
11# 例) : (2, 3) ⏩ n x mの画素領域を2 x 3とする。
12
13# <第三引数以降(任意)>
14# anchor : 第二引数(n x mの画素領域)内の、どの画素(あるn x mの画素(1)内のある画素)に注目するのか指定する。tuple型。
15# デフォルトでは(-1, -1)が設定され、自動的に第二引数(n x mの画素領域)の中心を指すように設定される。
16# 例) : (1, 2) ⏩ 第二引数(n x mの画素領域)内の、(1, 2)の画素に注目する。
17
18# 戻り値 : 多次元配列(画像情報)
19
20cv2.blur(img, (n(1以上の整数), m(1以上の整数)), anchor=(0 <= x < n(第二引数)の整数, 0 <= y < m(第二引数)の整数))
で成り立ちます。
例えば以下のようなコードを作成すると、
1import cv2
2import sys
3
4# blur関数を実行する関数
5def exec_blur(img):
6 # blur関数 : 画像をぼかす関数
7 # 第一引数(必須) : 多次元配列(numpy.ndarray)
8 # 第二引数(必須) : ぼかすために必要な、n x mの画素領域を指定する。
9 # 戻り値 : 多次元配列(numpy.ndarray)
10 return cv2.blur(img, (10, 10))
11
12# imread : 画像ファイルを読み込んで、多次元配列(numpy.ndarray)にする。
13# imreadについて : https://kuroro.blog/python/wqh9VIEmRXS4ZAA7C4wd/
14# 第一引数 : 画像のファイルパス
15# 戻り値 : 行 x 列 x 色の三次元配列(numpy.ndarray)が返される。
16img = cv2.imread("xxx.xxx")
17
18# 画像ファイルが正常に読み込めなかった場合、プログラムを終了する。
19if img is None:
20 sys.exit("Could not read the image.")
21
22# hconcat : 画像を連結する関数
23imgs = cv2.hconcat([img, exec_blur(img)])
24
25# imwrite : 画像の保存を行う関数
26# 第一引数 : 保存先の画像ファイル名
27# 第二引数 : 多次元配列(numpy.ndarray)
28# <第二引数の例>
29# [
30# [
31# [234 237 228]
32# ...
33# [202 209 194]
34# ]
35# [
36# [10 27 16]
37# ...
38# [36 67 46]
39# ]
40# [
41# [34 51 40]
42# ...
43# [50 81 60]
44# ]
45# ]
46# imwriteについて : https://kuroro.blog/python/i0tNE1Mp8aEz8Z7n6Ggg/
47cv2.imwrite('output.jpg', imgs)
以下の画像のように、画像が描画されます。
imreadに関しては、OpenCVで使われるimreadとは?使い方から配列が画像になる仕組みを解説でまとめていますので、詳しく知りたい方は是非ご確認ください。
imwriteに関しては、OpenCVで使われるimwriteとは?imwriteの定義から使用例をご紹介でまとめていますので、詳しく知りたい方は是非ご確認ください。
GaussianBlur関数を用いて画像をぼかしてみる
GaussianBlur関数は、以下の手順を踏まえて画像をぼかす関数です。
- n x mの画素領域(n, mは1以上の奇数)に注目する。(今回n, mを5, 5とする。以下の「GaussianBlur関数をわかりやすく解説するための画像」の黄緑色箇所とする。)
- n x mの画素領域(1)の1つとn x mの中心画素を比較していき、どれくらい色の違い(差分)があるのか計算する。(n x mの中心画素は、以下の「GaussianBlur関数をわかりやすく解説するための画像」の赤色箇所とする。)
- 「GaussianBlur関数をわかりやすく解説するための画像」の重みづけ情報(1/256や36/256など)を利用して、ぼかしを加える。 (((2 * 画素A-画素B) x 各重みつけ情報)を足し合わせた値を、n x mの中心画素とする。)
- 1~4を繰り返す。
【GaussianBlur関数をわかりやすく解説するための画像】
GaussianBlur関数の定義としては、
1# cv2(OpenCV)を利用する宣言を行う。
2import cv2
3
4# GaussianBlur関数 : 画像をぼかす関数
5# GaussianBlur関数 - 公式ドキュメント : https://docs.opencv.org/3.4/d4/d86/group__imgproc__filter.html#gaabe8c836e97159a9193fb0b11ac52cf1
6
7# 第一引数(必須) : 多次元配列(画像情報)
8
9# 第二引数(必須) : ぼかすために必要な、n x mの画素領域を指定する。tuple型。
10# tuple型とは? : https://atmarkit.itmedia.co.jp/ait/articles/1906/14/news015.html
11# 例) : (1, 3) ⏩ n x mの画素領域を1 x 3とする。
12
13# 第三引数(必須) : 画像のx軸(横)方向へのぼかしを調節する値を設定する。
14# 値が小さいほど、よりn x mの中心画素に強いぼかしが入り、逆に、値が大きいほど、より均一にn x mの画素全体にぼかしが入ります。
15# 0とした場合、第二引数の値から自動的に算出される。
16
17# 第四引数(任意) : 画像のy軸(縦)方向へのぼかしを調節する値を設定する。
18# 値が小さいほど、よりn x mの中心画素に強いぼかしが入り、逆に、値が大きいほど、より均一にn x mの画素全体にぼかしが入ります。
19# 第四引数が入力されない場合、第三引数の情報を元に、自動的に値が設定されます。
20
21# 戻り値 : 多次元配列(画像情報)
22
23cv2.GaussianBlur(img, (n(1以上の奇数), m(1以上の奇数)), 数字, 数字)
で成り立ちます。
例えば以下のようなコードを作成すると、
1import cv2
2import sys
3
4# GaussianBlur関数を実行する関数
5def exec_gaussian_blur(img):
6 # GaussianBlur関数 : 画像をぼかす関数
7 # 第一引数(必須) : 多次元配列(numpy.ndarray)
8 # 第二引数(必須) : ぼかすために必要な、n x mの画素領域を指定する。
9 # 第三引数(必須) : 画像のx軸(横)方向へのぼかしを調節する値を設定する。
10 # 第四引数(任意) : 画像のy軸(縦)方向へのぼかしを調節する値を設定する。
11 # 戻り値 : 多次元配列(numpy.ndarray)
12 return cv2.GaussianBlur(img, (5, 5), 10, 10)
13
14# imread : 画像ファイルを読み込んで、多次元配列(numpy.ndarray)にする。
15# imreadについて : https://kuroro.blog/python/wqh9VIEmRXS4ZAA7C4wd/
16# 第一引数 : 画像のファイルパス
17# 戻り値 : 行 x 列 x 色の三次元配列(numpy.ndarray)が返される。
18img = cv2.imread("xxx.jpg")
19
20# 画像ファイルが正常に読み込めなかった場合、プログラムを終了する。
21if img is None:
22 sys.exit("Could not read the image.")
23
24# hconcat : 画像を連結する関数
25imgs = cv2.hconcat([img, exec_gaussian_blur(img)])
26
27# imwrite : 画像の保存を行う関数
28# 第一引数 : 保存先の画像ファイル名
29# 第二引数 : 多次元配列(numpy.ndarray)
30# <第二引数の例>
31# [
32# [
33# [234 237 228]
34# ...
35# [202 209 194]
36# ]
37# [
38# [10 27 16]
39# ...
40# [36 67 46]
41# ]
42# [
43# [34 51 40]
44# ...
45# [50 81 60]
46# ]
47# ]
48# imwriteについて : https://kuroro.blog/python/i0tNE1Mp8aEz8Z7n6Ggg/
49cv2.imwrite('output.jpg', imgs)
以下の画像のように、画像が描画されます。
medianBlur関数を用いて画像をぼかしてみる
medianBlur関数は、以下の手順を踏まえて画像をぼかす関数です。
- n x nの画素(nは1以上の奇数)について注目する。(今回nを3とする。以下の「medianBlur関数をわかりやすく解説するための画像」の緑色箇所とする。)
- n x nの中心の画素に注目する。(以下の「medianBlur関数をわかりやすく解説するための画像」の赤色箇所とする。)
- n x nの中心の画素の画素値を、n x nの画素の中央値に変換する。(以下の「medianBlur関数をわかりやすく解説するための画像」の場合、34の画素値を42へ変更します。)
- 1~3を繰り返す。
【medianBlur関数をわかりやすく解説するための画像】
medianBlur関数の定義としては、
1# cv2(OpenCV)を利用する宣言を行う。
2import cv2
3
4# medianBlur関数 : 画像をぼかす関数
5# medianBlur関数 - 公式ドキュメント : https://docs.opencv.org/3.4/d4/d86/group__imgproc__filter.html#ga564869aa33e58769b4469101aac458f9
6
7# 第一引数(必須) : 多次元配列(画像情報)
8# 第二引数(必須) : n x nの画素領域を指定する。
9
10# 戻り値 : 多次元配列(画像情報)
11cv2.medianBlur(img, n(1以上の奇数))
で成り立ちます。
例えば以下のようなコードを作成すると、
1import cv2
2import sys
3
4# medianBlur関数を実行する関数
5def exec_median_blur(img):
6 # medianBlur関数 : 画像をぼかす関数
7 # 第一引数(必須) : 多次元配列(numpy.ndarray)
8 # 第二引数(必須) : n x nの画素領域を指定する。
9 # 戻り値 : 多次元配列(numpy.ndarray)
10 return cv2.medianBlur(img, 5)
11
12# imread : 画像ファイルを読み込んで、多次元配列(numpy.ndarray)にする。
13# imreadについて : https://kuroro.blog/python/wqh9VIEmRXS4ZAA7C4wd/
14# 第一引数 : 画像のファイルパス
15# 戻り値 : 行 x 列 x 色の三次元配列(numpy.ndarray)が返される。
16img = cv2.imread("xxx.jpg")
17
18# 画像ファイルが正常に読み込めなかった場合、プログラムを終了する。
19if img is None:
20 sys.exit("Could not read the image.")
21
22# hconcat : 画像を連結する関数
23imgs = cv2.hconcat([img, exec_median_blur(img)])
24
25# imwrite : 画像の保存を行う関数
26# 第一引数 : 保存先の画像ファイル名
27# 第二引数 : 多次元配列(numpy.ndarray)
28# <第二引数の例>
29# [
30# [
31# [234 237 228]
32# ...
33# [202 209 194]
34# ]
35# [
36# [10 27 16]
37# ...
38# [36 67 46]
39# ]
40# [
41# [34 51 40]
42# ...
43# [50 81 60]
44# ]
45# ]
46# imwriteについて : https://kuroro.blog/python/i0tNE1Mp8aEz8Z7n6Ggg/
47cv2.imwrite('output.jpg', imgs)
以下の画像のように、画像が描画されます。
bilateralFilter関数を用いて画像をぼかしてみる
bilateralFilter関数は、GaussianBlur関数のぼかし技術を駆使しながら、エッジを残すことのできる関数です。
GaussianBlur関数の動作に加えて、エッジを残すための処理を行うため、他の関数よりも処理速度が遅いです。
bilateralFilter関数の定義としては、
1# cv2(OpenCV)を利用する宣言を行う。
2import cv2
3
4# bilateralFilter関数 : 画像をぼかす関数
5# bilateralFilter関数 - 公式ドキュメント : https://docs.opencv.org/3.4/d4/d86/group__imgproc__filter.html#ga9d7064d478c95d60003cf839430737ed
6
7# 第一引数(必須) : 多次元配列(画像情報)
8
9# 第二引数(必須) : 中心画素をぼかすために、利用する画素領域を指定する。int型。
10# 0以下の整数が入力される場合、第四引数の値をもとに自動計算される。
11# 値が大きくなるほど、ぼかしが強くなる。
12
13# 第三引数(必須) : 第二引数で指定する画素領域内で、中心の画素値と周辺の画素値の比較を行いますが、その画素値の差を許容できる値とするのか、しきい値を指定します。double型。
14# しきい値とは? : https://wa3.i-3-i.info/word15002.html
15# 値を大きくすると、中心の画素値と差分の大きい周辺の画素値を許容すること(均一的にぼかす方向)に繋がります。
16
17# 第四引数(必須) : 中心画素をぼかすために、利用する画素領域を指定する。double型。
18# ただし、第二引数が0以下の場合にのみ、働きます。
19# > 参考:公式ドキュメントより引用 : When d > 0, it specifies the neighborhood size regardless of sigmaSpace. Otherwise, d is proportional to sigmaSpace.
20
21# 戻り値 : 多次元配列(画像情報)
22cv2.bilateralFilter(img, 整数, 数字, 数字)
で成り立ちます。
例えば以下のようなコードを作成すると、
1import cv2
2import sys
3
4# bilateralFilter関数を実行する関数
5def exec_bilateral_filter(img):
6 # bilateralFilter関数 : 画像をぼかす関数
7 # 第一引数(必須) : 多次元配列(numpy.ndarray)
8 # 第二引数(必須) : 中心画素をぼかすために、利用する画素領域を指定する。
9 # 第三引数(必須) : 第二引数で指定する画素領域内で、中心の画素値と周辺の画素値の比較を行いますが、その画素値の差を許容できる値とするのか、しきい値を指定します。
10 # 第四引数(必須) : 中心画素をぼかすために、利用する画素領域を指定する。
11 # 戻り値 : 多次元配列(numpy.ndarray)
12 return cv2.bilateralFilter(img, 40, 50, 50)
13
14# imread : 画像ファイルを読み込んで、多次元配列(numpy.ndarray)にする。
15# imreadについて : https://kuroro.blog/python/wqh9VIEmRXS4ZAA7C4wd/
16# 第一引数 : 画像のファイルパス
17# 戻り値 : 行 x 列 x 色の三次元配列(numpy.ndarray)が返される。
18img = cv2.imread("xxx.jpg")
19
20# 画像ファイルが正常に読み込めなかった場合、プログラムを終了する。
21if img is None:
22 sys.exit("Could not read the image.")
23
24# hconcat : 画像を連結する関数
25imgs = cv2.hconcat([img, exec_bilateral_filter(img)])
26
27# imwrite : 画像の保存を行う関数
28# 第一引数 : 保存先の画像ファイル名
29# 第二引数 : 多次元配列(numpy.ndarray)
30# <第二引数の例>
31# [
32# [
33# [234 237 228]
34# ...
35# [202 209 194]
36# ]
37# [
38# [10 27 16]
39# ...
40# [36 67 46]
41# ]
42# [
43# [34 51 40]
44# ...
45# [50 81 60]
46# ]
47# ]
48# imwriteについて : https://kuroro.blog/python/i0tNE1Mp8aEz8Z7n6Ggg/
49cv2.imwrite('output.jpg', imgs)
以下の画像のように、画像が描画されます。
bilateralFilter関数の値入力に困った場合
bilateralFilter関数の第二引数~第四引数へ具体的にどのような値を入れるべきか、悩んでいる方も多いかと思います。
上記の問題を解決するために、筆者の場合ipywidgetsというJupyter Notebookで使える拡張機能を使って、第二引数~第四引数の値を調整しています。
【ipywidgetsを利用するために準備したこと】
- Jupyterを入れる。(
pip install jupyter
で対応) - numpyを入れる。(
pip install numpy
で対応) - 筆者はVsCodeを利用しているため、VsCodeから空のJupyter Notebookを作成
上記で作成した空のJupyter Notebookへ、以下のコードを貼り付けて、実行(▶️を選択)してみてください。
1import cv2
2from IPython.display import Image, display
3from ipywidgets import widgets
4
5def imshow(img):
6 """画像をJupyter Notebook上に表示する。"""
7 _, encoded = cv2.imencode(".jpg", img)
8 display(Image(encoded))
9
10def execute(d, sigmaColor, sigmaSpace):
11 print('d: ' + str(d))
12 print('sigmaColor: ' + str(sigmaColor))
13 print('sigmaSpace: ' + str(sigmaSpace))
14
15 img_blur = cv2.bilateralFilter(img, d, sigmaColor, sigmaSpace)
16 imshow(img_blur)
17
18# imread : 画像ファイルを読み込んで、多次元配列(numpy.ndarray)にする。
19# imreadについて : https://kuroro.blog/python/wqh9VIEmRXS4ZAA7C4wd/
20# 第一引数 : 画像のファイルパス
21# 戻り値 : 多次元配列(numpy.ndarray)が返される。
22# ※ 画像を設定ください。
23img = cv2.imread("xxx.jpg")
24
25# 部品情報を格納する。
26parts = {}
27
28# bilateralFilterの第二引数を調整するスライダー
29# 参考 : https://ipywidgets.readthedocs.io/en/latest/examples/Widget%20List.html?highlight=IntSlider#IntSlider
30# min : 第二引数の最小値
31# mix : 第二引数の最大値
32# step : 第二引数の増減値
33# value : 第二引数の初期値
34# description : スライダーの説明文
35parts["d"] = widgets.IntSlider(
36 min=-500,
37 max=500,
38 step=1,
39 value=0,
40 description="d: "
41)
42
43# bilateralFilterの第三引数を調整するスライダー
44# 参考 : https://ipywidgets.readthedocs.io/en/latest/examples/Widget%20List.html?highlight=IntSlider#FloatSlider
45# min : 第三引数の最小値
46# mix : 第三引数の最大値
47# step : 第三引数の増減値
48# value : 第三引数の初期値
49# description : スライダーの説明文
50parts["sigmaColor"] = widgets.FloatSlider(
51 min=-100,
52 max=100,
53 step=1.5,
54 value=0,
55 description="sigmaColor: "
56)
57
58# bilateralFilterの第四引数を調整するスライダー
59# 参考 : https://ipywidgets.readthedocs.io/en/latest/examples/Widget%20List.html?highlight=IntSlider#FloatSlider
60# min : 第三引数の最小値
61# mix : 第三引数の最大値
62# step : 第三引数の増減値
63# value : 第三引数の初期値
64# description : スライダーの説明文
65parts["sigmaSpace"] = widgets.FloatSlider(
66 min=-500,
67 max=500,
68 step=3.5,
69 value=0,
70 description="sigmaSpace: "
71)
72
73# 部品の大きさを設定する。
74for part in parts.values():
75 part.layout.width = "400px"
76
77widgets.interactive(execute, **parts)
すると以下の画像のような画面が現れます。
実際に部品(スライダー)を動かしてみると、それぞれの値に応じて画像にぼかしを加えて、画像が変更されます。(※ 画像のぼかしのために、画像表示に時間がかかることがあります。)
まとめ
- 画像をぼかすとは、輪郭や色の濃淡の境目をきわだたせないで、ぼんやりさせることを意味します。
- 難しい言葉で言うと、「平滑化」すると言われる。
- 画像にぼかしを加えることで、主役をきわだたせられる・背景が整理される・画像に距離感が生まれる等の効果があります。
参考文献
- 輪郭とは?
- 濃淡とは?
- きわだたせとは?
- ぼんやりとは?
- 平滑化とは?
- ぼかすとは?
- 画素とは?
- blur関数 - 公式ドキュメント
- GaussianBlur関数 - 公式ドキュメント
- medianBlur関数 - 公式ドキュメント
- bilateralFilter関数 - 公式ドキュメント
- tuple型とは?
- 中央値とは?
- エッジとは?
- しきい値とは?
- ipywidgets - 公式ドキュメント
- OpenCVを用いて画像へぼかしを加えるサンプルコード