LoginSignup
24

More than 3 years have passed since last update.

OpenCVで画像の平滑化をしてみた

Last updated at Posted at 2020-04-22

はじめに

画像処理では、必ずしもキレイな画像を用意できるとは限りません。
不鮮明だったり、ノイズが入っていたりといったことも多くあります。
ノイズが入っている場合には、平滑化という手法を用いてそれを取り除くことがあります。
あるいはわざと不鮮明な画像を作り、ダミーデータとして使用する、ということもあります。

今回は、Pythonを使ってOpenCVによる画像の平滑化を行います。

平滑化とは

平滑化(へいかつか)、あるいはスムージング処理とは、簡単に言うと画像をぼかすことです。
画像をぼかすということは、画素値の変化を滑らかにすることとも言えます。
ノイズやエッジは、画素値の急激な変化です。
平滑化により、ノイズやエッジを消したり、目立たなくすることができます。

準備

環境はGoogle Colaboratoryを使用します。
Pythonのバージョンは以下です。

import platform
print("python " + platform.python_version())
# python 3.6.9

画像を表示してみよう

では、早速コードを書いていきましょう。
まずは、OpenCVをインポートします。

import cv2

さらに、Colaboratoryで画像を表示するため、以下もインポートします。

from google.colab.patches import cv2_imshow

サンプルの画像も用意しておきましょう。
今回は、Pixabayのフリー画像を使用します。

それでは、用意したサンプル画像を表示してみましょう。

img = cv2.imread(path) # pathは画像を置いている場所を指定
cv2_imshow(img)

image.png

また、後で必要になるため、ノイズ入りの画像も用意しておきます。
ここでは、「salt-and-pepper noise(ごま塩ノイズとも呼ばれる)」というノイズを画像に付加してみましょう。

# salt-and-pepper noise
# コードは以下を参照
# https://lp-tech.net/articles/nCvfb?page=2
import numpy as np

row, col, ch = img.shape
img_sp = cv2.imread(path)
# salt
pts_x = np.random.randint(0, col-1 , 1000)
pts_y = np.random.randint(0, row-1 , 1000)
img_sp[(pts_y,pts_x)] = (255, 255, 255)
# pepper
pts_x = np.random.randint(0, col-1 , 1000)
pts_y = np.random.randint(0, row-1 , 1000)
img_sp[(pts_y, pts_x)] = (0, 0, 0)
cv2_imshow(img_sp)

image.png

平滑化

一般的な平滑化

平滑化とは、簡単に言うと画像をぼかすことです。
OpenCVで画像を平滑化する最も簡単な方法は、cv2.blurを使用する方法です。
ここで、blurとは「ぼかし」という意味です。

それでは、平滑化した画像を表示してみましょう。
元画像と並べて表示してみます。

img_blur = cv2.blur(img, (3, 3))
imgs = cv2.hconcat([img, img_blur])
cv2_imshow(imgs)

image.png

左が元画像、右が平滑化した画像です。
右のほうが少しボケているのがわかると思います。

cv2.blurの引数は2つあります。
1つ目は、インプットとなる画像です。
2つ目は、カーネルと呼ばれるものです。画像の1点を決めたとき、周囲のどれだけの領域を含むかを表します。「箱の大きさ」だと考えてみて下さい。

上の例では(3, 3)となっており、これは画像の1点を中心とする3×3の領域を対象とすることを表します。
一般的な平滑化であるcv2.blurでは、このカーネル内の画素の平均値でカーネル内を塗りつぶします。
カーネルのサイズが大きくなればなるほど、画像のぼけ具合が強くなっていきます。

カーネルサイズを色々と変更してみた画像を表示してみましょう。

img1 = cv2.blur(img, (1, 1))
img2 = cv2.blur(img, (2, 2))
img3 = cv2.blur(img, (3, 3))
img4 = cv2.blur(img, (4, 4))
img5 = cv2.blur(img, (5, 5))
img6 = cv2.blur(img, (6, 6))

imgs_1 = cv2.hconcat([img1, img2, img3])
imgs_2 = cv2.hconcat([img4, img5, img6])
imgs = cv2.vconcat([imgs_1, imgs_2])
cv2_imshow(imgs)

image.png

左上から順に、カーネルサイズを大きくしていった画像になります。
画像のぼけ具合がどんどん強くなっているのがわかりますね。

Gaussianフィルタ

一般的な平滑化の他にも、OpenCVではいくつかの平滑化処理が可能です。

次は、Gaussianフィルタというものを紹介します。
一般的な平滑化では、カーネル内の画素を平均値という一定値で塗りつぶしました。
Gaussianフィルタでは、カーネルの中心からの距離に応じて値が変わります。
中心での値が一番大きく、離れるにつれて値は小さくなります。
その様子がガウス関数(Gaussian)と呼ばれる関数に従うので、Gaussianフィルタと呼ばれます。
ガウス関数の式は以下です。

\frac{1}{\sqrt{2\pi\sigma^2}}\exp\Bigl(-\frac{x^2}{2\sigma^2}\Bigr) \\

また、ガウス関数のグラフは以下のようになります。

image.png

それでは、ガウシアンフィルタを用いて画像を平滑化してみましょう。
こちらも、元画像と並べて表示してみます。

img_gauss = cv2.GaussianBlur(img, (3, 3), 3)
imgs = cv2.hconcat([img, img_gauss])
cv2_imshow(imgs)

image.png

cv2.GaussianBlurの引数は3つです。
最初の2つは、cv2.blur同様、インプット画像とカーネルサイズです。
3つ目の引数は、ガウス関数の$\sigma$(シグマ)に相当します。
$\sigma$が小さいと、ピークは高くなる代わりに広がりは狭くなります。
逆に$\sigma$が大きくなると、広がりは大きくなりますが、ピークは低くなります。

medianフィルタ

次は、medianフィルタを紹介します。
medianとは「中央値」のことで、指定したカーネル内に含まれる画素から中央値を取り出し、その値でカーネル全体を塗りつぶします。
一般的な平滑化と異なるのは、平均化された画素値ではなく、必ず存在する画素値を使用するという点になります。

medianフィルタを使用した画像を元画像と比較してみましょう。

img_med = cv2.medianBlur(img, 3)
imgs = cv2.hconcat([img, img_med])
cv2_imshow(imgs)

image.png

cv2.medianBlurの引数は2つで、インプット画像とカーネルサイズです。
上記では、2つ目の引数を3としていますが、これは3×3のカーネルを表しています。

このmedianフィルタは、salt-and-pepper noiseの除去に威力を発揮します。
実際に、ノイズ入りの画像に対してmedianフィルタをかけた結果は以下になります。

image.png

きれいに除去できているのがわかりますね。

bilateralフィルタ

最後に、bilateral(バイラテラル)フィルタを紹介します。

bilateralとは、「両方ともある」といった意味ですが、このフィルタはエッジをうまく残すことができます。
今までの平滑化フィルタは、エッジなどのピークも含めてぼかしていました。
bilateralフィルタは、画像をぼかしつつ、エッジも残すことができる便利なフィルタです。
元画像とあわせて出力してみましょう。

img_bi = cv2.bilateralFilter(img, 9, 75, 75)
imgs = cv2.hconcat([img, img_bi])
cv2_imshow(imgs)

image.png

全体的に滑らかになっているにも関わらず、エッジ部分はしっかりと残しているのがわかりますね。

cv2.bilateralFilterの引数の詳細は省きます。OpenCVの公式ドキュメントなどを参照下さい。

まとめ

今回は、Pythonを使ってOpenCVにより画像の平滑化を行いました。

画像処理でノイズの除去が必要になった際には、平滑化を試してみて下さい。

平滑化に関するさらに詳しい内容は、以下が参考になります。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24