PyWaveletsとOpenCVで画像のWavelet変換

#やりたいこと
画像処理を最近学び始め、
画像に対してウェーブレット変換を行ってみたいなぁと思っていたところ、
下記の素晴らしい記事を見つけました。

[mokemokechicken様：Pythonで画像をWavelet変換するサンプル](http://qiita.com/mokemokechicken/items/f9d732f1610dd351010c)

しかし、記事作者様の[mokemokechicken様](http://qiita.com/mokemokechicken)も述べている通り
**「画像の縦横サイズが同じじゃないと上手くいかない」**という課題がありました。

そこで今回は[mokemokechicken様](http://qiita.com/mokemokechicken)のサンプルコードを参考にさせて頂きながら、
OpenCVで画像を読み込むことで、**「入力画像の縦横サイズがどのような場合でも」**画像に対するウェーブレット変換ができるようにしました。
（カッコよく書いてますが、OpenCVで画像の読み込みしたくてコードをいじってたらうまいこと出来てしまったというオチです）

#必要なもの
・PyWavelets
・numpy
・OpenCV

#PyWaveletsに関する簡単な解説
URL : http://www.pybytes.com/pywavelets/ref/2d-dwt-and-idwt.html

*pywt.dwt2*という関数を用いることで、２次元配列（今回は画像）に対する
２次元ウェーブレット変換が簡単に行えますが、

複数階層の２次元ウェーブレット変換ができるように拡張された関数が、
*pywt.wavedec2*として用意されており、今回はこちらの関数を扱いました。

#サンプルコード
今回はlenaに対してwavelet変換しています

```py3
import pywt
import numpy as np
import cv2

def image_normalization(src_img):
    """
    白飛び防止のための正規化処理
    cv2.imshowでwavelet変換された画像を表示するときに必要（大きい値を持つ画像の時だけ）
    """
    norm_img = (src_img - np.min(src_img)) / (np.max(src_img) - np.min(src_img))
    return norm_img

def merge_images(cA, cH_V_D):
    """numpy.array を４つ(左上、(右上、左下、右下))連結させる"""
    cH, cV, cD = cH_V_D
    cH = image_normalization(cH) # 外してもok
    cV = image_normalization(cV) # 外してもok
    cD = image_normalization(cD) # 外してもok
    cA = cA[0:cH.shape[0], 0:cV.shape[1]] # 元画像が2の累乗でない場合、端数ができることがあるので、サイズを合わせる。小さい方に合わせます。
    return np.vstack((np.hstack((cA,cH)), np.hstack((cV, cD)))) # 左上、右上、左下、右下、で画素をくっつける

def coeffs_visualization(cof):
    norm_cof0 = cof[0]
    norm_cof0 = image_normalization(norm_cof0) # 外してもok
    merge = norm_cof0
    for i in range(1, len(cof)):
        merge = merge_images(merge, cof[i])  # ４つの画像を合わせていく
    cv2.imshow('', merge)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

def wavelet_transform_for_image(src_image, level, M_WAVELET="db1", mode="sym"):
    data = src_image.astype(np.float64)
    coeffs = pywt.wavedec2(data, M_WAVELET, level=level, mode=mode)
    return coeffs

if __name__ == "__main__":

    filename = 'lena.jpg'
    LEVEL = 3

    # 'haar', 'db', 'sym' etc...
    # URL: http://pywavelets.readthedocs.io/en/latest/ref/wavelets.html
    MOTHER_WAVELET = "db1"

    im = cv2.imread(filename)

    print('LEVEL :', LEVEL)
    print('MOTHER_WAVELET', MOTHER_WAVELET)
    print('original image size: ', im.shape)

    """
    各BGRチャネル毎に変換
    cv2.imreadはB,G,Rの順番で画像を吐き出すので注意
    """
    B = 0
    G = 1
    R = 2
    coeffs_B = wavelet_transform_for_image(im[:, :, B], LEVEL, M_WAVELET=MOTHER_WAVELET)
    coeffs_G = wavelet_transform_for_image(im[:, :, G], LEVEL, M_WAVELET=MOTHER_WAVELET)
    coeffs_R = wavelet_transform_for_image(im[:, :, R], LEVEL, M_WAVELET=MOTHER_WAVELET)

    coeffs_visualization(coeffs_B)
    # coeffs_visualization(coeffs_G)
    # coeffs_visualization(coeffs_R)
```

#実行結果
元画像(lena.jpg)
![lena のコピー.jpg](https://qiita-image-store.s3.amazonaws.com/0/174968/a441ae3c-92f4-e69e-8aa5-0b06e57ac3a2.jpeg)

wavelet係数を画像化したもの（Bチャンネル）
<img width="512" alt="スクリーンショット 2017-04-09 18.43.08.png" src="https://qiita-image-store.s3.amazonaws.com/0/174968/bca853ff-0394-c2e3-45e2-0644e198ec75.png">


#最後に
何か訂正箇所などありましたらご意見いただければと思います。