opencv チュートリアルチャレンジ4 画像の平滑化

画像の平滑化 — OpenCV-Python Tutorials 1 documentation

元画像には、adaptiveThreshold を適用後の画像を使用しました。

平均

cv2.blur()

void blur(const Mat& src, Mat& dst, Size ksize, Point anchor=Point(-1, -1), int borderType=BORDER_DEFAULT)
正規化されたボックスフィルタを用いて画像を平滑化します.

パラメタ:   
src – 入力画像.
dst – src と同じサイズ,同じ型の出力画像.
ksize – 平滑化カーネルサイズ.
anchor – アンカー点.デフォルト値の Point(-1,-1) は,アンカーがカーネルの中心にあることを意味します.
borderType – 画像外のピクセルを外挿するために利用される境界モード.

やってみる

#!/usr/bin/env python
# -*- coding: utf-8 -*
import cv2
import numpy as np

img = cv2.imread('170519-144402.jpg')

img = cv2.blur(img,(5,5))
cv2.imshow('blur', img)
cv2.imwrite('blur.png', img)

cv2.waitKey(0)
cv2.destroyAllWindows()

これが f:id:pongsuke:20170519145649j:plain

こう f:id:pongsuke:20170522172659p:plain

cv2.boxFilter()

関数 boxFilter は,カーネルを用いて画像の平滑化を行います

void boxFilter(const Mat& src, Mat& dst, int ddepth, Size ksize, Point anchor=Point(-1, -1), bool normalize=true, int borderType=BORDER_DEFAULT)
ボックスフィルタを用いて画像を平滑化します.

パラメタ:   
src – 入力画像.
dst – src と同じサイズ,同じ型の出力画像.
ddepth – 出力画像に求めるビット深度.かな?
ksize – 平滑化カーネルのサイズ.
anchor – アンカー点.デフォルト値の Point(-1,-1) は,アンカーがカーネル中心にあることを意味します.
normalize – カーネルが面積で正規化されているか否かを指定します.
borderType – 画像外のピクセルを外挿するために利用される境界モード

やってみる

#!/usr/bin/env python
# -*- coding: utf-8 -*
import cv2
import numpy as np

img = cv2.imread('170519-144402.jpg')


#cv2.boxFilter(img, 0, (7,7), img, (-1,-1), False, cv2.BORDER_DEFAULT)
img = cv2.boxFilter(img, 0, (7,7))
cv2.imshow('boxFilter', img)
cv2.imwrite('boxFilter.png', img)

cv2.waitKey(0)
cv2.destroyAllWindows()

これが f:id:pongsuke:20170519145649j:plain

こう f:id:pongsuke:20170522172714p:plain

ガウシアンフィルタ

箱型フィルタがカーネル内のフィルタ係数が一様だったのに対して,ガウシアンフィルタは注目画素との距離に応じて重みを変えるガウシアンカーネルを採用します. cv2.GaussianBlur() 関数を使います.カーネルの縦幅と横幅(どちらも奇数)に加え,ガウシアンの標準偏差値sigmaX(横方向)とsigmaY(縦方向)を指定する必要があります.sigmaXしか指定されなければ,sigmaYはsigmaXと同じだとみなされます.どちらの値も0にした場合,カーネルのサイズから自動的に計算されます.ガウシアンフィルタは白色雑音の除去に適しています.

img = cv2.GaussianBlur(img,(5,5),0)

これが f:id:pongsuke:20170522173051p:plain

こう f:id:pongsuke:20170522173104p:plain

中央値フィルタ

cv2.medianBlur() 関数はカーネル内の全画素の中央値を計算します.ごま塩ノイズのようなノイズに対して効果的です.箱型フィルタとガウシアンフィルタの出力結果は原画像中には存在しない画素値を出力とするのに対して,中央値フィルタの出力は常に原画像中から選ばれています.そのためごま塩ノイズのような特異なノイズに対して効果的です.カーネルサイズは奇数でなければいけません.

img = cv2.medianBlur(img,5)

これが f:id:pongsuke:20170522173051p:plain

こう f:id:pongsuke:20170522173150p:plain

バイラテラルフィルタ

前述したように,フィルタリングは一般的にエッジまでぼかしてしまいますが, cv2.bilateralFilter() によって使えるバイラテラルフィルタはエッジを保存しながら画像をぼかすことができます.しかし,上記のフィルタリングに比べて処理速度が遅いという欠点があります.既に紹介したガウシアンフィルタは注目がその近傍領域に対して重み付け平均した値を出力します.これはガウシアンフィルタが注目画素の近傍の画素のみを考慮した関数であることを意味します.近傍領域内の画素が似たような値を持っているか否か,注目画素がエッジ上に存在するか否かなどは考慮されません.結果としてガウシアンフィルタはエッジの劣化が不可避です.

バイラテラルフィルタも同様にガウシアンフィルタを採用していますが,画素値の差を考慮した関数として別のガウシアンフィルタも同時に使用します.一つ目のガウシアンフィルタはフィルタリングに使用する画素は ‘空間的に近い位置にある’ことを保証してくれます.一方で,二つ目のガウシアンフィルタは注目画素に似た画素値を持つ画素の値のみ考慮してフィルタリングすることを保証します.結果としてバイラテラルフィルタはエッジを保存した画像のぼかしを実現できることになります.

img = cv2.bilateralFilter(img,9,75,75)

これが f:id:pongsuke:20170522173051p:plain

こう f:id:pongsuke:20170522173312p:plain

ん?ほぼ一緒?

adaptiveThreshold 適用後だと、既に処理が終わっている感じなのかな?