【画像合成】OpenCVで積算によりノイズ除去をやってみた♪

顕微鏡や望遠鏡のデータ処理がしたくて、今回はノイズ除去と画像合成をやってみた。
OpenCVを使うと、それなりに簡単に出来そうではあるが、少し調べると最初の一歩的なものが多く、もう一息なのでまとめておく。

###そもそもやりたいこと
・顕微鏡や望遠鏡画像は、機材の振動やピンボケ、そして大気の揺らぎやその他外部要因でゆらぎやノイズが乗っている。そこで、それを除去して信号本来の絵や動画を得たいと思う

###今回やったこと
・まずは画像の合成により、画像に乗ったランダムノイズを除去する
①画像にランダムノイズをのせる
②ランダムノイズの乗った画像を積算する
③積算により徐々にノイズが減少する様子を動画にする
###①画像にランダムノイズをのせる
まずは、画像の合成は以下の様に実施できる。
【参考】
・[画像の算術演算](http://labs.eecs.tottori-u.ac.jp/sd/Member/oyamada/OpenCV/html/py_tutorials/py_core/py_image_arithmetics/py_image_arithmetics.html)

```py
import cv2
img1 = cv2.imread('cat.jpg')
img2 = cv2.imread('dog.jpg')
rows,cols,channels = img2.shape
roi = img1[0:rows, 0:cols ]
cv2.imshow('org1',img1)
cv2.imshow('org2',img2)
cv2.waitKey(0)
cv2.destroyAllWindows()
a =1
while True:
    dst = cv2.addWeighted(img2,a,roi,1-a,0)
    cv2.imshow('dst',dst)
    k=cv2.waitKey(0)&0xff
    if k ==ord('q'):
        break
    elif k ==ord('1'):
        a = 0.1        
    elif k ==ord('3'):
        a = 0.3
    elif k ==ord('5'):
        a = 0.5    
    elif k ==ord('7'):
        a = 0.7
    elif k ==ord('9'):
        a = 0.9
    elif k ==ord('0'):
        a = 1        
cv2.destroyAllWindows()
```
ちなみに、`dst = cv2.addWeighted(img2,a,roi,b,c)`の意味は

```py
dst = a*img2 + b*roi + c
```
なので、このように書き下してもいい。
※ここで注意したいのは、上記参考によれば、OpenCVではMaxで打ち切りなのに対して、numpyのaddはMaxを超えると、mod Maxとなるとのこと

猫画像と犬画像を合成すると、。。
![cat.jpg](https://qiita-image-store.s3.amazonaws.com/0/233744/05330ab6-3357-8a99-e758-dd14a6c7d679.jpeg)

![dog.jpg](https://qiita-image-store.s3.amazonaws.com/0/233744/0ecdf367-a248-f1b8-925a-5fe0661c55b9.jpeg)

結果は、キー入力a=0.5のとき以下の様になる。
![gosei.jpg](https://qiita-image-store.s3.amazonaws.com/0/233744/267778f0-731c-ed0b-6dcb-a2bf30ac68f3.jpeg)

ノイズを乗せる元画像はなんでもいいが、上記の猫画像とした
ノイズはGaussianノイズとした。
【参考】
・[画像にガウシアンノイズを加える with python2.7](https://qiita.com/Nobu12/items/bcaeeb9c45e87b9d547a)
・[deeplearning_tool/increase_picture.py](https://github.com/bohemian916/deeplearning_tool/blob/master/increase_picture.py)

```py
# -*- coding: utf-8 -*-
import cv2
import numpy as np
import sys
import os
import glob #今回使っていない

# ガウシアンノイズ
def addGaussianNoise(src):
    row,col,ch= src.shape
    mean = 0
    var = 0.5 #0.1
    sigma = 50 #15
    gauss = np.random.normal(mean,sigma,(row,col,ch))
    gauss = gauss.reshape(row,col,ch)
    a=1
    noisy = a*src + (4-a)*gauss
    return noisy

# プログラムが存在するディレクトリの代入
current_dir = os.getcwd()
print(current_dir)
# 画像が存在するディレクトリの代入→今回使っていない
image="cat.jpg"    
# 画像の読み込み
img = cv2.imread(image)
cv2.imshow('org1',img)
#cv2.waitKey(0)
cv2.destroyAllWindows()
for i in range(1000):
    # ノイズ付加
    after_image = addGaussianNoise(img)

    # 画像保存←上記の現ディレクトリ配下に保存   
    cv2.imwrite(current_dir+'\\after\\' + str(i) + '.jpg', after_image) 
    #cv2.imshow('noise',"../after/0.jpg")
    #cv2.waitKey(0)
    cv2.destroyAllWindows()
```
###②ランダムノイズの乗った画像を積算する

```py
# -*- coding: utf-8 -*-
import cv2
import numpy as np
import sys
import os

current_dir = os.getcwd()
print(current_dir)
dst = cv2.imread('0.jpg')
cv2.imshow('org1',dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

for i in range(1,1000):
    img = cv2.imread('{}.jpg'.format(i))
    cv2.imshow('org1',img)
    dst = cv2.addWeighted(dst,i/1000,img,1-i/1000,0)
    cv2.imshow('org2',dst)
    cv2.imwrite(current_dir+'\\after2\\' + str(i) + '.jpg', dst) 
    cv2.destroyAllWindows()
```

`dst = cv2.addWeighted(dst,i/1000,img,1-i/1000,0)`
で積算する画像を平等に平均している。
この１０００枚の画像を一個の動画に以下のプログラムで合成する。

```py
import cv2

def cv_fourcc(c1, c2, c3, c4):
        return (ord(c1) & 255) + ((ord(c2) & 255) << 8) + \
            ((ord(c3) & 255) << 16) + ((ord(c4) & 255) << 24)

def main():
    OUT_FILE_NAME = "combined_video.mp4"
    timer = cv2.getTickCount()
    fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')
    dst = cv2.imread('0.jpg')
    raws,cols,channels = dst.shape
    out = cv2.VideoWriter(OUT_FILE_NAME, int(fourcc), int(30), (int(cols), int(raws)))
    
    for i in range(1,1000):
        cv2.imshow('combined',dst)
        cv2.waitKey(1)&0xff
        cv2.destroyAllWindows()
        # 読み込んだフレームを書き込み
        img_dst = cv2.resize(dst, (int(cols), int(raws))) 
        out.write(img_dst)
        # 次のフレームを読み込み
        dst = cv2.imread('{}.jpg'.format(i))

if __name__ == '__main__':
    main()
```

結果は以下のとおり、ノイズが消えていく様子が動画になりました。
ただし、最終的に得られる画像は当初のものより若干暗いのでもう少し工夫が必要なようです。

[Gaussianノイズの乗った画像を積算によりノイズ除去♪](https://youtu.be/TLMwpIwjXME)
<a href="http://www.youtube.com/watch?feature=player_embedded&v=TLMwpIwjXME" target="_blank"><img src="http://img.youtube.com/vi/TLMwpIwjXME/0.jpg" 
 </a>
※画像をクリックするとYouTube動画につながります
![999.jpg](https://qiita-image-store.s3.amazonaws.com/0/233744/35b9f396-ef78-510b-93b5-8bc185dfa5cd.jpeg)
###まとめ
・OpenCVを使って、Gaussianノイズを積算で除去してみた
・除去の様子を動画にしてみた

・ゆらぎを考慮したノイズ除去に挑戦しようと思う