【Python】OpenCVで画像のぼかしと平滑化

Pythonの応用
スポンサーリンク

OpenCVを使ったPythonの画像処理について、さまざまな効果やフィルタを画像に適用することができます。

これは画像のピクセル値に、ある種の数学ベースの関数を適用した処理となっていますが、それらの深い定義については詳しくはここでは触れません。数学が得意な人はドキュメントなどで確認しましょう。

ここでは、こちらのドキュメントの内容を扱って行こうと思います。

http://lang.sist.chukyo-u.ac.jp/classes/OpenCV/py_tutorials/py_imgproc/py_filtering/py_filtering.html

画像処理の効果やフィルタの機能のぼかしや平滑化について触れていきます。

スポンサーリンク

画像を読み込む関数を作る

ちょっと必要無いかもしれませんが、実行に無関係の警告表示が出ないように次のコードをここでは書いて置きます。でも、特に必要無いかもしれません。

import warnings
warnings.filterwarnings('ignore')

ここで読み込む画像は、こちらの画像でwall.jpgとしています。

さて、画像を読み込むにあたって、今回は画像の読み込み処理の関数を作ってまとめておきたいと思います。これで何度も簡単に読み込むことができます。

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

まず、これまでと同様に各種ライブラリーをインポートしまています。これはもう何も考えず定形と言ってもいいくらいですね。

ここで画像読み込みの関数を次のように定義してみます。

def load_img():
    img = cv2.imread('images/wall.jpg').astype(np.float32) / 255
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    return img

load_img()と関数を定義します。imread()でimagesフォルダに入っているwall.jpgを読み込んでいます。astype()でデータ型をキャストしています。255で割っているのは、0から255で表される画像データを0から1の範囲に変換するためです。cvtColor()でカラーをBGRからRGBに変換しています。

次に画像の表示の関数を定義してみます。

def display_img(img):
    fig = plt.figure(figsize=(12,10))
    ax = fig.add_subplot(111)
    ax.imshow(img)

関数名をdisplay_img()と定義して、imgを引数にとり、画像を読み込みます。figure()で画像のアスペクト比を指定して、add_subplot()で表示の位置を指定します。111は画像の左上を意味します。imshow()で画像を表示します。

実際に画像を表示してみましょう。

i = load_img()
display_img(i)

load_img()で画像を読み込んでオブジェクト化し、display_img(i)で表示します。

スポンサーリンク

ガンマ補正で画像の明るさを変えてみる

それは画像の明るさを変えてみましょう。ガンマ値を変更して明るさを変更することができます。ガンマ値の詳細な定義はここでは触れませんので調べて見てください。

img = load_img()
gamma = 1/4
effected_image = np.power(img, gamma)
display_img(effected_image)

load_img()で画像を読み込んでいます。gamma値を1/4にして、power()を使って画像データをこのガンマ値でべき乗しています。

表示するとこうなります。

ガンマ値を変えてみましょう。

img = load_img()
gamma = 2
effected_image = np.power(img, gamma)
display_img(effected_image)

gamma値を今度は2にして処理してみました。

表示するとこうなります。

このように明るさを補正することができました。このガンマ値を色々変えてみると画像がさらに白っぽく明るくなったり、黒っぽく暗くなったりします。

スポンサーリンク

2次元の畳み込み演算フィルタリング

画像に対してローパスフィルタを適用するとノイズ除去や画像にぼかしを入れることができます。ここでは2次元の畳み込みとして知られるフィッティング操作を使用すしてみます。

まず画像を読み込んで次の操作をしてみます。

img = load_img()
font = cv2.FONT_HERSHEY_COMPLEX
cv2.putText(img,text='OpenCV',org=(50,250), fontFace=font,fontScale= 4,color=(255,0,0),thickness=2)
display_img(img)

lead_img()で画像を読み込んだら、フォントを選択して、putText()を使って文字を画像の載せてみます。文字列は「OpenCV」でorgで表示の位置を指定。フォントを指定して文字サイズを4、カラーを赤、太さを2にして表示します。

画像に文字列が表示されているのがわかります。

カーネルを作成

画像を処理するためのカーネル(フィルタ)を作成します。

kernel = np.ones(shape=(5,5),dtype=np.float32)/25
kernel

これで5×5サイズの平均値フィルタが作られます。

処理する画像のそれぞれの画素に対し、その画素を中心にした周辺5×5の画素に対して、全部の画素値の合計を求めて25で割り、これを全画素に対して適用して画像をフィルタリングするという操作をします。

filter2D()を使って、画像とkernelの計算をします。

dst = cv2.filter2D(img,-1,kernel)
display_img(dst)

-1の部分は出力画像のbit深度と言われていて、負の値を与えると入力画像と同じものを指定すると意味になっています。

画像が変換されているのがわかります。全体にぼかしが入っています。文字列のところも元の画像は文字の真ん中に隙間が見えますが、それがぼやけてなくなって見えるのがわかります。

スポンサーリンク

画像の平滑化

OpenCVには4種類の画像のぼかし方があります。

平均 – blur()

画像を平均するには正規化された箱型フィルタを使います。カーネルの範囲内にある全画素の画素値の平均をとります。

ここではblur()を使います。

まず、これまでと同様に画像を読み込んでみます。

img = load_img()
font = cv2.FONT_HERSHEY_COMPLEX
cv2.putText(img,text='OpenCV',org=(50,250), fontFace=font,fontScale= 4,color=(255,0,0),thickness=2)
display_img(img)

表示される画面自体は上でやったものと同じなのでここでは省略します。以降の作業でも省略します。実際には表示して以下の操作の結果と画像を比較してみるのもいいでしょう。

blurred_img = cv2.blur(img,ksize=(5,5))
display_img(blurred_img)

blur()を使ってimgを処理しています。ksizeはkernelのサイズで、ここでは5×5の箱型フィルタを指定しています。

表示するとこうなります。

ガウシアンフィルタ – GaussianBlur()

ガウシアンフィルタは注目画素との距離に応じて重みを変えるガウシアンカーネルを使います。「ガウスぼかし」とか画像処理ソフトで言われますね。

ここでは、GaussianBlur()を使います。

blurred_img = cv2.GaussianBlur(img,(5,5),10)
display_img(blurred_img)

GaussianBlur()を使って読み込んだimgを処理しています。(5,5)はガウシアンカーネルサイズの指定です。カーネルの縦幅と横幅(どちらも奇数)を指定します。10の部分はガウシアンカーネルのXとY方向の標準偏差で、ここを大きくするとぼかしが強くなります。

中央値フィルタ – medianBlur()

中央値フィルタの出力は原画像の中から選ばれるので、ごま塩ノイズのような特異なノイズを処理するのに適しています。

ここではmedianBlur()を使います。

median = cv2.medianBlur(img,5)
display_img(median)

ここではカーネルサイズを5としています。medianBlur()では奇数でなければいけません。これが1だと画像に変化はありません。

もっとノイズのある画像で試して見るともっと違いがわかると思います。

バイラテラルフィルタ – bilateralFilter()

バイラテラルフィルタは画素値の差を考慮した2つのガウシアンフィルタを使います。色空間に注目したものと注目した画像との距離に注目したものとを考慮してフィルタリングします。その結果、バイラテラルフィルタはエッジを保存しながら画像をぼかすことができます。これまでのフィルタはエッジまでぼかしてしまいますので、この点が違いますね。

ここではbilateralFilter()を使います。

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

注目画素をぼかすために使われる領域のカーネルのサイズにここでは9を指定しています。次の75はそれぞれ色空間についての標準偏差、距離についての標準偏差となっています。

これまでのものよりも、クッキリした部分を残してぼかしが入っているのがわかります。

スポンサーリンク

最後に

ここではOpenCVを使ってPythonで画像を処理する方法について、ぼかしや平滑化について見てきました。

filter2D()、blur()、GaussianBlur()、medianBlur()、bilateralFilter()と扱いましたが、それぞれの違いについて理解しておきましょう。

タイトルとURLをコピーしました