二値化画像のノイズ除去と背景透過

#はじめに
前に、[Pythonによる二値化画像処理の基本](https://qiita.com/jin237/items/04ca3d0b56e10065c4e4)という記事を書いた。この記事の発展となる。

#実行処理について
今回は記事の名前にもある通り、
__・ノイズの除去__
__・背景透過__
それに、
__・反転画像処理__
も実行

#ソースコード

```python

import cv2
import numpy as np

#画像の読み込み
img = cv2.imread('sample2-1.png')

#グレースケール変換
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)

#閾値の設定
threshold_value = 110

#配列の作成（output用）
threshold_img = gray.copy()

#実装(numpy)
threshold_img[gray < threshold_value] = 0
threshold_img[gray >= threshold_value] = 255

#Output:sample2-2
cv2.imwrite(f'C:\\Users\\[username]\\python\\project1\\sample2-2.png',threshold_img)

#グレースケール変換された画像の読み込み
img = cv2.imread("sample2-2.png")
#ノイズ除去処理
ksize=3
#中央値フィルタ
img_mask = cv2.medianBlur(img,ksize)
#白黒反転画像
img2 = cv2.bitwise_not(img_mask)

#output:sample2-3,2-4
cv2.imwrite("C:\\Users\\[username]\\python\\project1\\sample2-3.png",img_mask)
cv2.imwrite("C:\\Users\\[username]\\python\\project1\\sample2-4.png",img2)

#背景透過

from PIL import Image

# 画像の読み込み
org = Image.open( 'sample2-3.png' )

# サイズが同じ画像作成
trans = Image.new('RGBA', org.size, (0, 0, 0, 0))

#縦横のサイズ
width = org.size[0]
height = org.size[1]
#for文で処理
for x in range(width):
    for y in range(height):
        pixel = org.getpixel( (x, y) )
        
        # 白色処理なし
        if pixel[0] == 255 and pixel[1] == 255 and pixel[2] == 255:
            continue
        
        # 白色以外の書き込み
        trans.putpixel( (x, y), pixel )
        
# output:sample2-5
trans.save('sample2-5.png')
```

#内容説明
###import文からoutput:sample2-2まで
これは、上記にも記載した、[Pythonによる二値化画像処理の基本](https://qiita.com/jin237/items/04ca3d0b56e10065c4e4)のコードのほぼそのままである。
画像上、閾値のみ変更。

###ノイズ除去
```py
#ノイズ除去
ksize=3
#中央値フィルタ
img_mask = cv2.medianBlur(img,ksize)
```
この部分では、画像処理をする近傍の大きさ等を設定する場所である。

###白黒反転処理
```py
#白黒反転画像
img2 = cv2.bitwise_not(img_mask)
```
opencvに反転処理が組み込まれており、この文のみで反転処理が可能。ちなみに今回では。白黒でしているが、本来はカラー画像でも実行可能である。


###透過画像作成
```py
# 画像の読み込み
org = Image.open( 'sample2-3.png' )

# サイズが同じ画像作成
trans = Image.new('RGBA', org.size, (0, 0, 0, 0))

#縦横のサイズ
width = org.size[0]
height = org.size[1]
#for文で処理
for x in range(width):
    for y in range(height):
        pixel = org.getpixel( (x, y) )
        
        # 白色処理なし
        if pixel[0] == 255 and pixel[1] == 255 and pixel[2] == 255:
            continue
        
        # 白色以外の書き込み
        trans.putpixel( (x, y), pixel )
```

上記の＃の通りの処理であるので、説明は省略する。

これらの結果sample2-1~2-5までをのせる。

###元の画像(sample2-1.png)
![sample2-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533115/3ad5d3ca-0bd1-50fa-d1cd-4127c64c48a5.png)
この画像は、画像処理でよくつかわれるので見覚えのある人も多いと思う。レナと呼ばれる女性のヌード画像の一部である。
[レナについての説明　from Wikipedia](https://ja.wikipedia.org/wiki/%E3%83%AC%E3%83%8A_(%E7%94%BB%E5%83%8F%E3%83%87%E3%83%BC%E3%82%BF)
###二値化画像処理(sample2-2.png)
![sample2-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533115/edc3c8eb-7dc5-ee7f-7f97-cf41d7510fed.png)
###ノイズ除去処理(sample2-3.png)
![sample2-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533115/2cea6bc0-806a-f52a-6c24-a6d9a0fb45ad.png)
###白黒反転処理(sample2-4.png)
![sample2-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533115/5a15a9f5-ac7a-217f-1bd9-5064dce7c2c3.png)
###白色以外透過処理(sample2-5.png)
![sample2-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/533115/551f9282-3a0c-4cfd-94ef-f041baec6e71.png)
この記事上ではわかりにくいので、コードのコピーなどで自分でやってみるとよい。


#ソースコードの簡易化
先ほどのコードは一つ一つの処理を見やすくしていた。しかし、順番を変えることで、手順を減らすことができる。

```python

import cv2
import numpy as np
from PIL import Image

#画像の読み込み
img = cv2.imread('sample2-1.png')
#グレースケール変換
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
#閾値の設定
threshold_value = 110
#配列の作成（output用）
threshold_img = gray.copy()
#実装(numpy)
threshold_img[gray < threshold_value] = 0
threshold_img[gray >= threshold_value] = 255

#ノイズ除去処理
ksize=3
#中央値フィルタ
img_mask = cv2.medianBlur(img,ksize)

#白黒反転画像
img2 = cv2.bitwise_not(img_mask)

#背景透過
# 画像の読み込み
org = Image.open('sample2-3.png')

# サイズが同じ画像作成
trans = Image.new('RGBA', org.size, (0, 0, 0, 0))

#縦横のサイズ
width = org.size[0]
height = org.size[1]
#for文で処理
for x in range(width):
    for y in range(height):
        pixel = org.getpixel( (x, y) )
        
        # 白色処理なし
        if pixel[0] == 255 and pixel[1] == 255 and pixel[2] == 255:
            continue
        
        # 白色以外の書き込み
        trans.putpixel( (x, y), pixel )
        
#Output:sample2-2~2-5
cv2.imwrite(f'C:\\Users\\[username]\\python\\project1\\sample2-2.png',threshold_img)
cv2.imwrite("C:\\Users\\[username]\\python\\project1\\sample2-3.png",img_mask)
cv2.imwrite("C:\\Users\\[username]\\python\\project1\\sample2-4.png",img2)
trans.save('sample2-5.png')
```

一括処理であるときには、Errorが起きる可能性があるが、jupyter notebookでは実行可能であった。読み込みをせずに処理内での画像を直接読み込めるので、これくらいであれば誤差に近いが早くなるだろう。