pyvipsの使い方

# pyvipsとは
画像を高速かつ少メモリで処理するライブラリです
中身で行なっていることは、画像を処理するプログラムのパイプラインを作成し、最後に書き出すときに一気に全体を実行する形です。tensorflowのdefine-by-runと似ています。
このようにすることで、並列実行&画像全体をメモリに保持する必要がなくなります。
pyvipsに関しては、日本語記事がなかったので、ここにまとめます。

pyvips公式ドキュメント
https://libvips.github.io/pyvips/index.html

pyvipsのドキュメントだけでは情報が不十分の場合は、vipsのドキュメントを参照すると良いです
https://libvips.github.io/libvips/API/current/func-list.html

# インストール

```
$ conda install --channel conda-forge pyvips
```

それかもしくは

```
$ pip install --user pyvips
```

これだけで使用できたら成功

使用できない場合はvips自体が入ってない可能性があるので、https://github.com/libvips/libvips/releases から最新のvips (vips-#.#.#.tar.gz)をダウンロードし、解答して、その中で以下を行う

```
$ ./configure
$ make
$ sudo make install
```
`./configure`の実行時にprefixを指定すれば、sudoなしで実行も可能

# 画像の読み込み

```python
import pyvips

# ファイルから読み込み
image = pyvips.Image.new_from_file('some-image.jpg', access='sequential')

# 画像の書き出し
image.write_to_file('x.jpg')

```

jpg以外にも様々なファイル形式の画像をこれで読み込むことができる

## vipsで使用可能なファイル形式

- JPEG
- TIFF
- PNG
- FITS
- Matlab
- Analyze
- PFM
- Radiance
- OpenSlide

# numpy配列との相互変換

## numpy -> pyvips.Image
`pyvips.Image.new_from_memory`で行うことができます。
一度numpy画像をflattenしてから行っています

```python
# 型名変換
dtype_to_format = {
    'uint8': 'uchar',
    'int8': 'char',
    'uint16': 'ushort',
    'int16': 'short',
    'uint32': 'uint',
    'int32': 'int',
    'float32': 'float',
    'float64': 'double',
    'complex64': 'complex',
    'complex128': 'dpcomplex',
}

# np_3dがnumpy画像
height, width, bands = np_3d.shape
linear = np_3d.reshape(width * height * bands)
vi = pyvips.Image.new_from_memory(linear.data, width, height, bands,
                                  dtype_to_format[str(np_3d.dtype)])
```

## pyvips.Image -> numpy

```python
format_to_dtype = {
    'uchar': np.uint8,
    'char': np.int8,
    'ushort': np.uint16,
    'short': np.int16,
    'uint': np.uint32,
    'int': np.int32,
    'float': np.float32,
    'double': np.float64,
    'complex': np.complex64,
    'dpcomplex': np.complex128,
}

img = pyvips.Image.new_from_file('some-img.jpg', access='sequential')
np_3d = np.ndarray(buffer=img.write_to_memory(),
                   dtype=format_to_dtype[img.format],
                   shape=[img.height, img.width, img.bands
```

# 基本的な処理

## 四則演算
普通の四則演算は普通に可能

```python
img += [1, 2, 1]
```

画像同士の四則演算は以下のように`add/subtract /multiply/divide`で可能

```python
out = left.add(right)
```

## resize
[ドキュメント](https://libvips.github.io/pyvips/vimage.html#pyvips.Image.resize)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262908/453a1853-9842-4803-ec0b-1aaa700d392f.png)

- Example

```python
inter = pyvips.Interpolator.new('bicubic')
img_resize = img.resize(0.5, interpolate=inter)
```
### interpolationについて
https://libvips.github.io/pyvips/vinterpolate.html
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262908/f77d487d-b998-8dfa-54af-fd34b8e4c587.png)

使用可能なinterpolationの種類は、コマンドラインで`vips -l interpolat`を行うと確認できる

```
$ vips -l interpolate
VipsInterpolate (interpolate), VIPS interpolators
    VipsInterpolateNearest (nearest), nearest-neighbour interpolation
    VipsInterpolateBilinear (bilinear), bilinear interpolation
    VipsInterpolateBicubic (bicubic), bicubic interpolation (Catmull-Rom)
    VipsInterpolateLbb (lbb), reduced halo bicubic
    VipsInterpolateNohalo (nohalo), edge sharpening resampler with halo reduction
    VipsInterpolateVsqbs (vsqbs), B-Splines with antialiasing smoothing
```

手元の環境ではnearest, bilinear, bicubic, lbb, nohalo, vsqbsが使用可能

- Example

```python
inter = pyvips.Interpolator.new('nohalo')
```


## padding
`embed`で行うことが可能
https://libvips.github.io/pyvips/vimage.html#pyvips.Image.embed
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262908/9b4091ba-da57-a3f9-a396-bc9add58e9c6.png)

- Example
画像の上下に`pad_h`ずつ、左右に`pad_w`ずつpaddingする場合 (padding部分の色は黒にする)

```python
img_pad = img.embed(pad_w, pad_h, img.width+pad_w*2, img.height+pad_h*2, background=0)
```

## crop 
https://libvips.github.io/pyvips/vimage.html#pyvips.Image.crop
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262908/ca1f7dc6-6660-944d-e91a-7ff2c7ec7015.png)

- Example

横方向にはxからx+widthまで、縦方向にはyからy+heightまでcropするとき
(numpyなら、`img_np[y:y+height, x:x+width, :]`とする処理）

```python
img_crop = img.crop(x, y, width, height)
```

## 回転
90,180,270度回転が可能

```python
img90 = img.rot90()
img180 = img.rot180()
img270 = img.rot270()
```

## flip

```python
# 左右にflip
img_hor = img.fliphor()
# 上下にflip
img_ver = img.flipver()
```

## 画像の作成
`black`で全て黒の画像を作成できる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262908/476c61e9-6ded-b81c-27d6-d557cf09289a.png)

```python
img_black = pyvips.Image.black(width, height, bands=3)
```


## アルファチャンネルの追加
画像の透過度のアルファを追加することができます

```python
img = img.addalpha()
```

## affine
任意のaffine変換を行うことも可能
引数の'matrix'にaffine行列を設定することでできる
https://libvips.github.io/pyvips/vimage.html?highlight=add#pyvips.Image.affine

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262908/915ec164-30ed-294a-9498-35faba138f88.png)

## merge
二つの画像をマージできる
**引数**

- sec : 二つ目の画像（マージされる画像）
- direction : 水平方向なら`'horizontal'`, 垂直方向なら`'vertical'`
- dx, dy : どれくらい離してmergeするか
- mblend : 最大でどれくらい画像を混合させるか


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262908/fdff9b70-2c59-cd6c-db83-797dc16b2c06.png)





# フィルタリング
## conv

https://libvips.github.io/pyvips/vimage.html#pyvips.Image.conv
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262908/68e585f1-03f2-b3db-4368-7e8976aa12f2.png)

- Example

`mask`で畳み込みする場合
`precision`は、計算結果をどの型に丸めるかということ
今回はintegerにしているので、整数値に丸める

```python
mask = pyvips.Image.new_from_array([[-1, -1, -1],
                                    [-1, 16, -1],
                                    [-1, -1, -1]
                                   ], scale=8)
image = image.conv(mask, precision='integer')
```

## sobel
sobelフィルタを適用

```python
img_sobel = img.sobel()
```

## gaussblur
ガウシアンフィルタを作用させて、blurをかける（ぼやけさせる）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262908/e1ecd778-ea88-b606-7798-355bb56e0b90.png)

- Example 

`sigma`でガウス分布の分散を変更
`min_ampl`はデフォルトで0.2

```python
img_blur = img.gaussblur(1, 0.2)
```

## canny
canny edgeフィルタを作用
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262908/4d1f13a4-2f79-9dd1-73e7-c6a82e614813.png)





# 数学関数
pyvips.Imageには基本的な数学関数が用意されている

- sin(), asin()
- cos(), acos()
- tan(), atan()
- log(), log10()
- exp(), exp10()
- median()
- real(), imag() : 画像が複素数の場合、実部と虚部を出力
- floor(), ceil() : 繰り上げ繰り下げ


# 描画
## draw_image
`sub`の画像をimageに書き込む
書き込む場所の始点を(x,y)にする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262908/f23a4508-4398-633e-e38e-3c11de9ec564.png)

## draw_line
(x1,y1)から(x2,y2)まで線を描画
色はinkで指定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262908/3fd498a6-b3bb-62e5-e182-0b0dcc81d474.png)

## draw_mask
(x,y)を始点として、maskの部分をinkの色で塗りつぶす
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262908/0a927455-d68b-74e3-ace4-f789ea745441.png)

## draw_rect
(left, top, width, height)で指定した四角形をinkの色で描画
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/262908/d5f6dd09-2996-3944-5532-f024bb1596cf.png)