スタック画像をnumpy配列へいれる

CTやMRI画像のように、xy二次元画像がz枚入っているデータセットを、numpyにいれるやり方。
`opencv`と`PIL`と`scikit-kimage`を使う三種類のやり方がある
32bitグレースケールは、`PIL`か`skimage`を使う。

## openCV

```python

import cv2
import glob
import numpy as np

volume = []
files = sorted(glob.glob("./data/*.tif"))
for myFile in files:
    image = cv2.imread(myFile)
    volume.append(image)
```
xy画像は`./data`に入っている。
これを一枚ずつ`image`に入れては三次元配列`volume`に`append`している。

確認は、

```python
print(np.array(volume).shape)
```
などでできる。

任意のスライス番号の画像の表示は、例えば、

```python
import matplotlib.pyplot as plt

plt.imshow(volume[300])
plt.show()
```

## PIL (pillow)

openCVの時と、画像の読み込みが違うだけ。
RGBの順番が変わらないので、カラー画像のときはおすすめ。

```python
from PIL import Image
import glob
import numpy as np
import matplotlib.pyplot as plt

volume = []
files = sorted(glob.glob("./data/*.tif"))
for myFile in files:
    image = Image.open(myFile)
    image = np.asarray(image, dtype=np.uint8)
    volume.append(image)

plt.imshow(volume[300],interpolation = 'none')
plt.show()
```

上の例では、300枚目のスライスを表示する。
なお、`np.uint8`で型指定している。(RGBなど）

32bitグレースケールの場合は、

```python
from PIL import Image
import glob
import numpy as np

Nz=0
volume = []
files = sorted(glob.glob("./data/*.tif"))
for z in files:
    Nz = Nz + 1
    image = Image.open(z)
    image = np.asarray(image, dtype=np.float32)
    volume.append(image)

Ny = image.shape[0]
Nx = image.shape[1]
volume = np.ravel(volume).reshape(Nz,Ny,Nx)
```

`numpy`の配列に直接書き込むと遅くなる模様なので、
Python標準のlist配列にいったん変換してappendするべし。
https://qiita.com/discexOmnes/items/f84b54201aced12fec80


## scikit-image

今のところ一番気に入っている。
速度は`PIL`とかわらない。
ここでも先程と同じく、直接`numpy`で書き込まないのがミソ。

```python
from skimage.io import imread
import glob
import numpy as np

files = sorted(glob.glob("./data/*.tif"))
volume = imread(files[0])
Nz = len(files)
Ny,Nx = volume.shape
volume = volume.tolist()
for z in files[1:]:
    volume.extend(imread(z))

volume = np.array(volume,dtype='float32').reshape(Nz,Ny,Nx)
```

画像表示は、300枚目の画像を輝度0~100で表示するには、、、

```python
from skimage.io import imshow,show

imshow(volume[300],cmap='gray',vmin=0,vmax=100)
show()
```

このあたりは、関数化してしまうのが便利。
ただし、ファイルが一枚しかないスタック画像にも対応させるためにも、
`Nz>=1`としておくのが無難。

```python
def loadvolume(folder):
    files = sorted(glob.glob(folder + "/*.tif"))
    PV = imread(files[0])
    Nz = len(files)
    Ny,Nx = PV.shape
    PV = PV.tolist()
    if (Nz>=1) :
        for z in files[1:]:
            PV.extend(imread(z))
####
    PV = np.array(PV,dtype='float32').reshape(Nz,Ny,Nx)
    return(PV,Nx,Ny,Nz)
```
もちろん利用方法は、
```python
PV,Nx,Ny,Nz = loadvolume('folderpath')
```
です。

## Color画像の読み込み(scikit-image)

以下のように、カラーの次元に注意する。

```python
def ReadVolumeColor(dirname):
    files = sorted(glob.glob(dirname+'/*.tif'))
    volume = imread(files[0])
    Nz = len(files)
    Ny,Nx,_ = volume.shape
    volume = volume.tolist()
    for z in files[1:]:
        volume.extend(imread(z))
    volume = np.array(volume,dtype='uint8').reshape(Nz,Ny,Nx,3)
    return(volume)
```





# ファイルへの書き出し

## PIL
```python
for z in range(Nz):
    Image.fromarray(volume[z]).save(str("./data2") + "/" + str(z).zfill(4) + ".tif")
```

## scikit-image
```python
from skimage.io import imsave

for z in range(Nz):
    imsave('path/'+str(z).zfill(4)+'.tif',volume[z])
```



# 参考
https://stackoverflow.com/questions/37747021/create-numpy-array-of-images