ITや趣味など気軽に投稿しています。

【Python】OpenCVで画像をぼかす

画像のぼかし(ブラー)処理は、ノイズ除去や画像の前処理として広く活用されます。OpenCVには複数のぼかし手法が用意されており、用途に応じて使い分けることが重要です。

この記事では、フィルタ(カーネル)の基本概念から、OpenCVが提供する4種類のぼかし関数までを解説します。

事前準備

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

image = cv2.imread('input/fox.jpg')
height, width = image.shape[:2]
image = cv2.resize(image, (round(width / 4), round(height / 4)))
キツネ

フィルタ(カーネル)とは

画像処理におけるフィルタの正体は、奇数サイズの二次元正方行列(3×3、5×5など)です。これはカーネルとも呼ばれます。

\\ begin {equation *} \\ begin {bmatrix} 1&1&1 \\\\ 1&1&1 \\\\ 1&1&1 \\ end {bmatrix} \\ end {equation *}

このカーネルを画像の各ピクセルに対して畳み込み(convolution)演算することで、画像にさまざまな効果を与えます。

自作カーネルによる画像処理

自作カーネルでフィルタリングする場合はcv2.filter2D()を使用します。

cv2.filter2D(src, ddepth, kernel[, dst[, anchor[, delta[, borderType]]]])

引数

引数説明
ddepth出力画像の深度(データ型)。-1で入力画像と同じ型
kernelフィルタ(カーネル)。NumPy配列で指定
anchorカーネルのアンカーポイント。デフォルトは(-1, -1)(中心)
deltaフィルタリング結果に加算する値
borderType画像の端の処理方法

Identity Kernel(恒等写像)

元の値と同じ値を返すカーネルです。変換前後で画像は変わりません。

Identity Kernel
# Identity Kernel作成
kernel1 = np.array([[0, 0, 0],
                    [0, 1, 0],
                    [0, 0, 0]])
# カーネル適用
identity = cv2.filter2D(src=image, ddepth=-1, kernel=kernel1)
Identity Kernel適用結果

Box blur(ぼかし)

すべての要素が同じ値のカーネルを使うと、画像をぼかすことができます。

# blur Kernel作成
kernel1 = np.ones((5, 5), np.float32) / 25
# カーネル適用
blur = cv2.filter2D(src=image, ddepth=-1, kernel=kernel1)
Blur Kernel適用結果

Sharpen(先鋭化)

画像の輪郭をくっきりさせる(シャープにする)カーネルです。

# Sharpen Kernel作成
kernel1 = np.array([[0, -1, 0],
                    [-1, 5, -1],
                    [0, -1, 0]])
# カーネル適用
sharpen = cv2.filter2D(src=image, ddepth=-1, kernel=kernel1)
Sharpen Kernel適用結果

OpenCVの関数でフィルタリングする

OpenCVにはフィルタリング用の関数があらかじめ用意されています。一般的な用途では、自作カーネルよりもこれらの関数を使用するのが効率的です。

ぼかし(cv2.blur())

cv2.blur()は単純な平均化フィルタで、画像全体を均一にぼかします。

cv2.blur(src, ksize[, dst[, anchor[, borderType]]])
引数説明
ksizeカーネルのサイズ
anchorアンカーポイント。デフォルトは(-1, -1)
borderType画像の端の処理方法
blur = cv2.blur(src=image, ksize=(5, 5))
cv2.blur() 適用結果

ガウシアンぼかし(cv2.GaussianBlur())

ガウシアンぼかしは加重平均を用いたフィルタリングです。カーネルの中心からの距離に基づいて重みづけされ、中心に近いほど影響が大きくなります。

cv2.blur()が均一なぼかしであるのに対し、cv2.GaussianBlur()は重みづけにより見た目が自然なぼかしが得られます。ただし、重みづけ計算を行う分、処理速度は低下します。

cv2.GaussianBlur(src, ksize, sigmaX[, dst[, sigmaY[, borderType]]])
引数説明
ksizeカーネルのサイズ
sigmaXX軸方向のガウス関数の標準偏差
sigmaYY軸方向のガウス関数の標準偏差
blur = cv2.GaussianBlur(src=image, ksize=(5, 5), sigmaX=0, sigmaY=0)
cv2.GaussianBlur() 適用結果

中央値ぼかし(cv2.medianBlur())

中央値ぼかしは、各ピクセルをカーネル領域内のピクセルの中央値に置き換える手法です。ごま塩ノイズと呼ばれるような画像のざらつきを除去する場合に効果的です。

cv2.medianBlur(src, ksize[, dst])
引数説明
ksizeカーネルのサイズ(正の奇数)
median = cv2.medianBlur(src=image, ksize=5)
cv2.medianBlur() 適用結果

Bilateralフィルタ(cv2.bilateralFilter())

通常のぼかしではエッジ(輪郭)部分もぼかされてしまいます。Bilateralフィルタを使えば、エッジを極力残しながら画像をぼかすことができます。

cv2.bilateralFilter(src, d, sigmaColor, sigmaSpace[, dst[, borderType]])
引数説明
dフィルタリングに使用するピクセル近傍の直径
sigmaColor色空間におけるフィルタの標準偏差
sigmaSpace座標空間におけるフィルタの標準偏差

sigmaの値が10未満ではぼかし効果が小さく、150以上にすると漫画風のテイストになります。

bilateral_filter = cv2.bilateralFilter(src=image, d=9, sigmaColor=75, sigmaSpace=75)
cv2.bilateralFilter() 適用結果

エッジを維持したままぼかしが適用されていることが確認できます。

まとめ

今回は、OpenCVで画像をぼかす方法を紹介しました。

  • cv2.blur(): 単純な平均化フィルタ。画像全体を均一にぼかす
  • cv2.GaussianBlur(): 加重平均による自然なぼかし。中心ほど影響が大きい
  • cv2.medianBlur(): 中央値によるぼかし。ごま塩ノイズの除去に有効
  • cv2.bilateralFilter(): エッジを残しながらぼかす

処理が複雑なほど処理速度は低下するため、精度と速度のバランスを考慮して手法を選択してください。