numpyで画像の分割と連結

Deep Learning等で大きな画像をいくつかに分割したり、分割した画像を結合させたりすることがよくあるが、まとまった記事がなさそうだったのでメモ。

# 動作環境

- Ubuntu 16.04
- Python 3.5.2
- numpy 1.13.3
- opencv-python 3.2

# 画像の分割（vsplit、hsplit）

画像の分割にはnumpyのvsplit（縦方向分割）とhsplit（横方向分割）を使用する。注意点としては分割する画像の画素数が分割数で割り切れること。詳細は[リファレンスマニュアル](https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.split.html)を参照のこと。

使用している変数の説明

| 変数名|役割|
|:------|------------------:|:------------------:|
|img|入力画像（OpenCVで読み込んだものを想定）|
|size|分割したい画素数（今回は64x64の画像にしたいので64）|
|v_size|（縦方向分割用）sizeで割り切れるよう画素の端数を切り捨てた値|
|h_size|（横方向分割用）sizeで割り切れるよう画素の端数を切り捨てた値|
|v_split|np.vsplitに入力する分割数|
|h_split|np.hsplitに入力する分割数|

使用する画像

![org.jpeg](https://qiita-image-store.s3.amazonaws.com/0/227399/635dced0-896a-81d7-d98e-af43db82693f.jpeg)

![org.jpeg](https://qiita-image-store.s3.amazonaws.com/0/227399/19500bae-76a0-4064-41e5-e43576f4e591.jpeg)


## 縦方向だけの分割

```python3
　　import numpy as np

    v_size = img.shape[0] // size * size
    h_size = img.shape[1]
    img = img[:v_size, :h_size]

    v_split = img.shape[0] // size
    out_img = []
    out_img.extend(np.vsplit(img, v_split))
```

## 結果

![vsplit_demo_2.PNG](https://qiita-image-store.s3.amazonaws.com/0/227399/49a21126-dabb-0ace-a46a-5961b5e76a3e.png)

![vsplit_demo_3.PNG](https://qiita-image-store.s3.amazonaws.com/0/227399/64d47b3e-2b67-7be0-a2f8-3084c1d76c4c.png)



## 横方向だけの分割

```python3
　　import numpy as np

    v_size = img.shape[0] 
    h_size = img.shape[1] // size * size
    img = img[:v_size, :h_size]

    h_split = img.shape[1] // size
    out_img = []
    out_img.extend(np.hsplit(img, h_split))
```

## 結果

![hsplit_demo_2.PNG](https://qiita-image-store.s3.amazonaws.com/0/227399/d9c2b6c1-ab59-8886-0880-5cb4398e2e31.png)

![hsplit_demo_3.PNG](https://qiita-image-store.s3.amazonaws.com/0/227399/e82d021b-5c69-6ff0-8e0a-5d61f4642fdb.png)

## 縦横の分割

```python3
　　import numpy as np

    v_size = img.shape[0] // size * size
    h_size = img.shape[1] // size * size
    img = img[:v_size, :h_size]

    v_split = img.shape[0] // size
    h_split = img.shape[1] // size
    out_img = []
    [out_img.extend(np.hsplit(h_img, h_split))
      for h_img in np.vsplit(img, v_split)]
```

## 結果

![hvsplit_demo_2.PNG](https://qiita-image-store.s3.amazonaws.com/0/227399/160f1781-a167-b5bf-bc2c-ba5363490c4f.png)

![hvsplit_demo_3.PNG](https://qiita-image-store.s3.amazonaws.com/0/227399/c38476c5-a319-f58e-cfcc-46931900edff.png)


## 複数枚の縦横の分割

```python3
　　import numpy as np

    v_size = imgs[0].shape[0] // size * size
    h_size = imgs[0].shape[1] // size * size
    imgs = [i[:v_size, :h_size] for i in imgs]

    v_split = imgs[0].shape[0] // size
    h_split = imgs[0].shape[1] // size
    out_imgs = []
    [[out_imgs.extend(np.hsplit(h_img, h_split))
      for h_img in np.vsplit(img, v_split)] for img in imgs]
```

# 画像の結合（vstack、hstack）

分割した画像を結合するときはnumpyのvstack（縦方向結合）とhstack（横方向結合）を使用する。詳細は分割と同様に[リファレンスマニュアル](https://docs.scipy.org/doc/numpy-1.13.0/reference/generated/numpy.split.html)を参照のこと。今回はそのまま結合しても面白くないので、画像をシャッフルして結合する。

```python3
    shuffle = np.random.permutation(range(len(img)))
    img = np.vstack((
        np.hstack(img[shuffle[0:5]]),
        np.hstack(img[shuffle[5:10]]),
        np.hstack(img[shuffle[10:15]]),
    ))
```
imgを直接シャッフルしていないのは汎用性を持たせるため。

## 結果

![shuffle.jpg](https://qiita-image-store.s3.amazonaws.com/0/227399/c05d402f-ba08-e39e-8690-0d33147eb1ed.jpeg)