つれづれなる備忘録

日々の発見をあるがままに綴る

Pythonによるデータ処理13 ~ ウェーブレット変換6

 今回は多段のウェーブレット変換による画像サイズとメモリ削減の効果について検証してみる。

atatat.hatenablog.com

1. 準備

前回までと同様に標準画像データベースのboatを読み込み、変数をgrayとする。さらに型をint16に変換してgray2とする。

import numpy as np
from scipy import signal
import matplotlib.pyplot as plt
%matplotlib inline
import pywt
from scipy.sparse import csr_matrix

from google.colab import files
uploaded_file = files.upload()

uploaded_file_name = next(iter(uploaded_file))
orig = cv2.imread(uploaded_file_name)
gray = cv2.cvtColor(orig, cv2.COLOR_BGR2GRAY)

gray2 = gray.astype(np.int16)

"Boat"
Boat

2. 多段の2Dウェーブレット変換

前回まで2Dウェーブレット変換はpywt.idwt2を使用していた多段の2Dウェーブレット変換の場合はpywt.wavedec2(gray2, 'haar', level=2)を使用する。引数のlevelで段数を指定するが今回は2段とする。

coeffs = pywt.wavedec2(gray2, 'haar', level=2)
LL = coeffs[0]
(LH, HL, HH) = coeffs[1]
(LH2, HL2, HH2) = coeffs[2]

plt.figure(figsize=(12,5))
plt.subplot(2,4,1)
plt.imshow(LL,cmap='gray')
plt.subplot(2,4,2)
plt.imshow(LH,cmap='gray')
plt.subplot(2,4,3)
plt.imshow(HL,cmap='gray')
plt.subplot(2,4,4)
plt.imshow(HH,cmap='gray')
plt.subplot(2,4,5)
plt.imshow(LH2,cmap='gray')
plt.subplot(2,4,6)
plt.imshow(HL2,cmap='gray')
plt.subplot(2,4,7)
plt.imshow(HH2,cmap='gray')

係数の階層も増え、coeffs[0]はApproximation, coeffs[1]は高次情報でサイズは64x64になっている。次にcoeffs[2]も同様の高次情報だがサイズは128x128。ここで画像のベースになるApproximationのサイズが2Dウェーブレット変換では128x128が2段では64x64になっている効果分だけ圧縮率が上がることが期待できる。

"2段2Dウェーブレット変換"
2段2Dウェーブレット変換

前回と同様に高次情報は適当な閾値のマスクをかける。今回は高次情報の行列が増えるため、高次情報の型もfloat64からint16に変換した。

LL2 = LL.astype(np.int16)
MLH=(np.abs(LH)>20)
MHL=(np.abs(HL)>20)
MHH=(np.abs(HH)>20)
MLH2=(np.abs(LH2)>20)
MHL2=(np.abs(HL2)>20)
MHH2=(np.abs(HH2)>20)

LHn=LH*MLH
HLn=HL*MHL
HHn=HH*MHH

LH2n=LH2*MLH2
HL2n=HL2*MHL2
HH2n=HH2*MHH2

LHn=LHn.astype(np.int16)
HLn=HLn.astype(np.int16)
HHn=HHn.astype(np.int16)

LH2n=LH2n.astype(np.int16)
HL2n=HL2n.astype(np.int16)
HH2n=HH2n.astype(np.int16)

plt.figure(figsize=(12,5))
plt.subplot(2,4,1)
plt.imshow(LL2,cmap='gray')
plt.subplot(2,4,2)
plt.imshow(LHn,cmap='gray')
plt.subplot(2,4,3)
plt.imshow(HLn,cmap='gray')
plt.subplot(2,4,4)
plt.imshow(HHn,cmap='gray')
plt.subplot(2,4,5)
plt.imshow(LH2n,cmap='gray')
plt.subplot(2,4,6)
plt.imshow(HL2n,cmap='gray')
plt.subplot(2,4,7)
plt.imshow(HH2n,cmap='gray')

"バイナリマスク適用後"
バイナリマスク適用後

3. メモリ削減の効果

スパース行列により非ゼロの要素のみを保持したときのサイズ、メモリサイズを前回と同様に算出する。

def get_size_csr(csr):
  return csr.data.nbytes+csr.indices.nbytes+csr.indptr.nbytes
cLH = csr_matrix(LHn)
cHL = csr_matrix(HLn)
cHH = csr_matrix(HHn)

cLH2 = csr_matrix(LH2n)
cHL2 = csr_matrix(HL2n)
cHH2 = csr_matrix(HH2n)
csize=np.size(cLH)+np.size(cHL)+np.size(cHH)+np.size(LL2)+np.size(cLH2)+np.size(cHL2)+np.size(cHH2)

print('Original size: ',np.size(gray2))
print('Compressed size: ',csize)
print('Original memory: ',gray2.nbytes)
sparse_mem = get_size_csr(cLH)+get_size_csr(cHH)+get_size_csr(cHL)+LL2.nbytes+get_size_csr(cLH2)+get_size_csr(cHH2)+get_size_csr(cHL2)
print('Compressed memory: ',sparse_mem)

>Original size:  65536
>Compressed size:  9215
>Original memory:  131072
>Compressed memory:  41234

元の画像に対しては、要素数で1/6、メモリで1/3程度の圧縮になっている。2Dウェーブレット変換では要素数は18677でメモリは46034 (前回float64の場合71456)なので、要素数で1/2、メモリでは10%減の効果になっている。

3. 多段2D逆ウェーブレット変換による復元

スパース行列をアレイに戻して、多段の逆2Dウェーブレット変換を実行して画像を復元する。多段の逆2Dウェーブレット変換はpywt.waverec2を用いる。

rLH = cLH.toarray()
rHL = cHL.toarray()
rHH = cHH.toarray()

rLH2 = cLH2.toarray()
rHL2 = cHL2.toarray()
rHH2 = cHH2.toarray()
recovm2=pywt.waverec2([LL2,(rLH,rHL,rHH),(rLH2,rHL2,rHH2)],'haar')

plt.figure(figsize=(14,8))
plt.subplot(1,3,1)
plt.imshow(gray2,cmap='gray',vmax=255,vmin=0)
plt.title('original')

plt.subplot(1,3,2)
plt.imshow(LL,cmap='gray')
plt.title('Approximation')

plt.subplot(1,3,3)
plt.imshow(recovm2,cmap='gray',vmax=255,vmin=0)
plt.title('Recovered')

画像が復元できていることが確認できる。ベース画像のApproximationと比較すると高次情報によりクリアになっていることがわかる。

"多段ウェーブレット逆変換による復元"
多段ウェーブレット逆変換による復元

128x128の高次情報を省略することができれば、さらにメモリの削減効果が期待できる。とりあえず128x128の高次情報なしで復元すると少し画質が荒くなってしまい、綺麗に再現するには128x128の高次情報が必要になる。

tt=np.zeros([128,128])
recovm3=pywt.waverec2([LL2,(rLH,rHL,rHH),(tt,tt,tt)],'haar')

plt.figure(figsize=(10,5))
plt.subplot(1,2,1)
plt.imshow(recovm2,cmap='gray',vmax=255,vmin=0)
plt.title('Recovered')

plt.subplot(1,2,2)
plt.imshow(recovm3,cmap='gray',vmax=255,vmin=0)
plt.title('Only 1st decomp')

"成分による復元画像の差"
成分による復元画像の差

4. まとめ

今回は2段の2Dウェーブレット変換を用いた画像圧縮の効果を確認した。要素数としては削減できるが、2Dウェーブレット変換と比較するとメモリの圧縮効果は小さいことがわかった。