SSIM

はじめに

 Structural Similarity (SSIM)という客観評価手法が地味に流行している気がする.というのも,H.264のフリーのエンコーダであるx264でその一部が採用されたとか.なるほど,たしかにログにはPSNRと一緒にSSIMも表示されてる.

 構造的類似性というからには,位置ずれなんかにもロバストなのかと思ったら,そうではないらしいことをゼミで知る.簡単に言うと,ブロックごとに,平均輝度,標準偏差,共分散を比較している.共分散で位置ずれがないことを評価している.

 というわけで,位置ずれはデメリットとして評価されます.

数式の説明

 論文がちゃんと公開されているようです(http://www.cns.nyu.edu/~lcv/ssim/).

 以下ではブロックごとに処理することとして,1ブロック分の計算について書きます.まず,平均は
\mu_x=\frac{1}{N}\sum_{i=1}^N x_i
となります.Nは画素数,x_iは輝度値(0~255)だと思います.次に,標準偏差
\sigma_x=\left( \frac{1}{N}\sum_{i=1}^N (x_i-\mu_x)^2 \right)^{1/2}
となります.最後に,共分散は
\sigma_{xy}=\frac{1}{N}\sum_{i=1}^N(x_i-\mu_x)(y_i-\mu_y)
となります.yは比較対象の画像を示しています.ここまでは,準備.

 ここで,それぞれの値について物理的な意味を考えたいと思います.

 まず,平均は文字通り輝度の平均値と言うことになります.平均輝度が近ければ画像は似ているでしょう.逆に,画像を明るくしたり暗くしてあれば評価値を下げることが出来ます.

 次に,標準偏差は輝度の振幅の大きさ,つまりどれぐらい輝度が変化しているかを表します.コントラストが悪いというのは振幅が小さいと言うことに対応づけられます(厳密ではないけど).これも,同じぐらいの振幅であれば画像が似ていると言えます.また,振幅の大きさだけを評価しているので,仮に画像が明るくなっていても評価値に影響を与えません.

 最後に,難関の共分散ですが,これは同じように振幅が変化しているかを示します(Structureの意図はここに込められているのでしょう).この値を最大にするのはどんな場合かを考えると,輝度の変化が同じ場合になります.このとき,平均輝度の影響は除去されています.また,標準偏差で正規化すれば,変化の仕方だけを評価できます.この部分がSSIMのキモになります.

 それでは,これらの値を使って単一の評価値にしていきましょう.まず,平均輝度が近いほど画像が類似していると定義したいので,\muを使って,
\left( \frac{\mu_x}{2\mu_y}+\frac{\mu_y}{2\mu_x} \right)^{-1}=\left( \frac{\mu_x^2+\mu_y^2}{2\mu_y\mu_x} \right)^{-1}\simeq\frac{2\mu_x\mu_y+C_1}{\mu_x^2+\mu_y^2+C_1}
としましょう.最初は比を取って足し算するわけですが,このままだとかならず1より大きくなってしまいます(2は\muが一致したときに評価値が1にする係数).そこで,逆数を取るというのが意図です.さらに,\muがゼロやゼロに非常に近いときに割り算が破綻するので,C_1を定数として加えます.同様に,標準偏差
\frac{2\sigma_x\sigma_y+C_2}{\sigma_x^2+\sigma_y^2+C_2}
としましょう.共分散も分散で正規化したいので
\frac{\sigma_{xy}+C_3}{\sigma_x\sigma_y+C_3}
としましょう.

 これらは入力画像と対象画像が一致するときに最大値の1になる.単純に掛け合わせてしまうことにすると,C_3=2C_2とすれば1カ所約分できます.というわけで,まとめると
\left( \frac{2\mu_x\mu_y+C_1}{\mu_x^2+\mu_y^2+C_1} \right)\left( \frac{2\sigma_{xy}+C_2}{\sigma_x^2+\sigma_y^2+C_2} \right)
となるわけです.

実装は

 理論としては上記の通りなのですが,実装はもうちょっと単純化(というか,工夫)しています.つまり,ブロックごとに求めてないです.ガウスフィルタで平滑化することで画素毎の平均値っぽいものを計算します.標準偏差は輝度の二乗の平均から平均値の二乗を引いて平方根を取れば求められます.共分散は輝度の積から標準偏差の積を引けば同様に求まります.最後の共分散はちょっと自信がないです(数式的にこうなるのか?).

 というわけで,平滑化と画素同士の積や差だけで求められます.それでも,十分重い処理だとは思いますけど.

mu1   = filter2(window, img1, 'valid');
mu2   = filter2(window, img2, 'valid');
mu1_sq = mu1.*mu1;
mu2_sq = mu2.*mu2;
mu1_mu2 = mu1.*mu2;
sigma1_sq = filter2(window, img1.*img1, 'valid') - mu1_sq;
sigma2_sq = filter2(window, img2.*img2, 'valid') - mu2_sq;
sigma12 = filter2(window, img1.*img2, 'valid') - mu1_mu2;

ssim_map = ((2*mu1_mu2 + C1).*(2*sigma12 + C2))
        ./((mu1_sq + mu2_sq + C1).*(sigma1_sq + sigma2_sq + C2));

位置ずれは……

 結局位置ずれは共分散の所に関係してきます.例えば,共分散が最大になるように位置をずらして評価値としたら,構造を評価しつつも位置ずれを許容できるんじゃないですかね.というようなことを次回書きたいと思います.うまくいくかはまだやってないので分からないですけど.

余談

 PSNRではなくてSSIMを指標として量子化マトリクスを最適化するのが,すごいコアな世界で流行ったっぽい.ただ,SSIMで量子化マトリクスを最適化してしまえば,今度はPSNRで従来の量子化マトリクス(均等量子化)と比較しても絶対敵わないはず.というわけで,変な方向に迷走している人達をちらほら見かけなくもない…….

 あと,色が滲むのを回避したければ,YUV420ではなくてYUV444とかRGBを使えば良いんじゃないかと思う.再生機側で頑張る方法もあって,YUV420のUV成分を高精度にアップスケーリングすれば良いらしい.これは松下の受け売りですが.(http://www.watch.impress.co.jp/av/docs/20071106/bd3.htm