SSIMを修正してみた

<h1>お願い</h1>
stereo matching lossを計算する為にSSIM(Structure Similarity)を使おうと思って、[git](https://github.com/mrharicot/monodepth/blob/b76bee4bd12610b482163871b7ff93e931cb5331/monodepth_model.py#L98)で探したやつを使っていたらあまり学習がうまくいかなかったので、よく見たらアルゴリズムが間違ってるポイ事に気づき自分で修正してみた。

このGithubは論文の著者のgitで論文もかなり有名なので、間違ってるか疑わしいのでもしgitのコードがただしかったり、僕の修正が間違ってたら指摘して頂けると幸いです！


<h2>本家のコード</h2>
sigmaの計算が全部間違ってる気がする

```
    def SSIM(self, x, y):
        C1 = 0.01 ** 2
        C2 = 0.03 ** 2

        mu_x = slim.avg_pool2d(x, 3, 1, 'VALID')
        mu_y = slim.avg_pool2d(y, 3, 1, 'VALID')

        sigma_x  = slim.avg_pool2d(x ** 2, 3, 1, 'VALID') - mu_x ** 2
        sigma_y  = slim.avg_pool2d(y ** 2, 3, 1, 'VALID') - mu_y ** 2
        sigma_xy = slim.avg_pool2d(x * y , 3, 1, 'VALID') - mu_x * mu_y

        SSIM_n = (2 * mu_x * mu_y + C1) * (2 * sigma_xy + C2)
        SSIM_d = (mu_x ** 2 + mu_y ** 2 + C1) * (sigma_x + sigma_y + C2)

        SSIM = SSIM_n / SSIM_d

        return tf.clip_by_value((1 - SSIM) / 2, 0, 1)
````

<h2>修正後のコード</h2>
色々と変更を加えてしまったのですが基本的変更はsigmaの所だけ

```
    def SSIM(self, x, y,window_size=3):
        C1 = 0.01 ** 2
        C2 = 0.03 ** 2
        clip_size = (window_size -1)/2

        mu_x = nn.functional.avg_pool2d(x, window_size, 1, padding=0)
        mu_y = nn.functional.avg_pool2d(y, window_size, 1, padding=0)

        x = x[:,:,clip_size:-clip_size,clip_size:-clip_size]
        y = y[:,:,clip_size:-clip_size,clip_size:-clip_size]

        sigma_x = nn.functional.avg_pool2d((x  - mu_x)**2, window_size, 1, padding=0)
        sigma_y = nn.functional.avg_pool2d((y - mu_y)** 2, window_size, 1, padding=0)
        
        sigma_xy = (
            nn.functional.avg_pool2d((x- mu_x) * (y-mu_y), window_size, 1, padding=0)
        )

        mu_x = mu_x[:,:,clip_size:-clip_size,clip_size:-clip_size]
        mu_y = mu_y[:,:,clip_size:-clip_size,clip_size:-clip_size]

        SSIM_n = (2 * mu_x * mu_y + C1) * (2 * sigma_xy + C2)
        SSIM_d = (mu_x ** 2 + mu_y ** 2 + C1) * (sigma_x + sigma_y + C2)

        SSIM = SSIM_n / SSIM_d

        loss = torch.clamp((1 - SSIM) , 0, 2)
        save_image(loss, 'SSIM_GRAY.png')

        return  torch.mean(loss)

```


<h2>Stereo Matchingの精度を計算する場合</h2>
入力の左画像
![gray_left.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/00ce76ad-0a4c-ad84-6fa2-cf75a2524f2c.png)


右の画像を推定したDisparityを使ってワープさせた画像</h2>
僕の目には全く同じように見えるけど、SSIMはどうなるのか
![gray_estLeft.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/d392b6cd-2cb2-1e5d-35cc-edd308f913fd.png)


SSIMのloss
textureが無い領域が白っぽくなってる。きっとdisparityの推定精度が低かったのだろう。
![SSIM_GRAY.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/998bd09b-84cc-f8d6-6540-4e8d1d2c391a.png)


*白い所がlossが高い。黒い所がlossが0


<h2>入力を同じ画像にした場合</h2>

もちろんlossは0！
![SSIM_GRAY.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/0b004e29-662f-1d79-3cc2-e3567ec2ee9e.png)



<h2>左の画像と右の画像を入力した場合</h2>

物体がある場所はきちんとlossがが出てますね。
車のフロントガラスは一部黒くなってるので左右の画像で同じ輝度だという事が分かる。
![SSIM_GRAY.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/50e29941-2f25-a534-89ec-f69b04552297.png)


<h2>window sizeを5にした場合</h2>

![SSIM_GRAY.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/c7e651a9-fc2f-d066-b13c-28e06b6554f9.png)

<h2>window sizeを7にした場合</h2>

![SSIM_GRAY.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/89757a47-0abf-e835-1da1-964804b513d9.png)

<h2>window sizeを9にした場合</h2>
![SSIM_GRAY.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/cc4c5689-3880-2290-1080-8715d831e1cf.png)


<h1>結論</h1>
なにが正しいのか正直確認するのが難しいのですが、コメント頂けると幸いです！

<h1>参考文献</h1>
https://github.com/mrharicot/monodepth/blob/b76bee4bd12610b482163871b7ff93e931cb5331/monodepth_model.py#L98
Structural similarity
https://en.wikipedia.org/wiki/Structural_similarity