【AIで画像切り抜き】キレイなお姉たまを自宅へ呼ぼう

# ■ 0.はじめに
「**人物等のオブジェクト切り抜き**」をする場合、かつてはチマチマ画像を拡大し選択範囲を指定するなど、作業がとても大変でかつ職人芸でした。ところが、昨今、**AI技術**を使うことでこの作業をしなくても「**ボタン1発**」で切り抜きができるようになってきました。

これらはあとで紹介する「**webツールサイト**」などでも実施可能ですが、費用がかかるサイトが多いのが現状です…お金が無い貧乏人としては、自分でなんとかするしかありません。その昔、おもちゃが買ってもらえず、しかたなく、家にあった割り箸と輪ゴムで、ゴム鉄砲を作って遊んだことを思い出してしまいました😭。

そんな訳で、フリープログラムを使っての「**人物切り抜き**」、いってみましょう！
<img width=600 src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405376/608fadac-56e6-3702-0920-38108579e6d0.gif'>

# ■ 1.やること
キレイなお姉たまを「自宅のお部屋」へ呼びたいと思います😉。
<img width=320 src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405376/e9b5dfc9-ecb9-a032-c522-bfbd343158ea.png'>

汚部屋を掃除し、お部屋へ………準備万端です😊むふふふ。
<img width=320 src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405376/b86c8332-538b-1acc-2dbb-a2c230825ef3.png'>

# ■ 2.切り抜きの仕組み
**Github**でそれらしいツールを検索して、起動すれば「オブジェクト切り抜き」は簡単にできてしまうんですが、それではせっかくプログラムで実行している意味がないので、簡単に仕組みも調べておきます。

## Alpha Mattingとは
今回実施するオブジェクト切り抜きは「**Alpha Matting**」という手法を使います。

<img width=200 src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405376/b299fd94-4663-5d01-e798-85fb39a8fb2d.png'> <img width=200 src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405376/9fdc25da-f56b-d61b-f449-efb240e1831b.png'> <img width=200 src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405376/e0b3cb9e-f5d8-3947-96cd-8a34fe57d4a7.png'>

画像から前景のAlpha値を抽出し、背景と分離することを**Alpha Matting**と呼びます。Alpha値とは、各画素での不透明度を表すパラメータです。Alpha Mattingでは、「**ソース写真**」と「**Trimap**」と呼ばれる中間データを用いて処理を行います。

## Trimapとは
**Trimap**とは、前景であろう領域に白色、背景であろう領域に黒色、どちらか判断できない、または細かくて白と黒では塗り分けられない領域を灰色で塗り分けたものです。「T・R・I」とTrimapを作ってみました。いかがでしょうか😁？

<img width=200 src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405376/7ceb3326-d8a7-9ac2-14cb-2ec413732b76.png'> <img width=200 src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405376/0a2c3d44-78e3-9631-ac80-1c2560291604.png'> <img width=200 src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405376/14c18749-8a17-5a91-b3fb-d5e7370306a4.png'>


## ツール整理
今回使用するツールについても整理しておきます。本記事では**rembg**を使用します。**rembg**から**u2net**、**pymatting**のツールを使用しているようですので、そちらも参考になります。

|No.|ツール名|説明|ライセンス|
|:-:|:-|:-|:-|
|1|[u2net](https://github.com/xuebinqin/U-2-Net)|Trimapを生成するツール|Apache License 2.0|
|2|[pymatting](https://github.com/pymatting/pymatting)|Alpha Mattingを処理するツール|MIT License|
|3|[rembg](https://github.com/danielgatis/rembg)|「u2net」と「pymatting」を実行し、オブジェクト切り抜きをするツール|MIT License|

# ■ 3.Google Colabで実行
今回は、我らの学び屋「**Google Colab**」で実行したいと思います。実行環境は、もちろんGoogle Colabでなくても結構です。Google Colabで実行する場合、プログラムを改造した箇所やGoogle Colabへアップロードした画像は、時間が経つと**揮発してしまう**ので注意が必要です。

> Google Colabで実施したログは、こちらを参照してください。
> https://github.com/PoodleMaster/Qiita_rembg/blob/main/rembg.ipynb

## (1)画像切り抜きプログラムの準備
### ●インストール
pipコマンドでpypiからインストール可能です。まずは、pip自身をupdateしておきましょう。

``` :colab
!pip install -U pip
```

**rembg**の「Requirements」通りに下記ライブラリをインストール

```:colab
!pip install torch==1.7.1+cpu torchvision==0.8.2+cpu -f https://download.pytorch.org/whl/torch_stable.html
```

次に**rembg**をインストールしましょう。

```:colab
!pip install rembg
```

インストール後、次のようにランタイムの再起動を促されたら、実施してください。

``` :colab実行結果
Collecting rembg
  Downloading rembg-1.0.14.tar.gz (13 kB)
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
    Preparing wheel metadata ... done

　　　　　　　　　︙

WARNING: The following packages were previously imported in this runtime:
  [PIL,numpy]
You must restart the runtime in order to use newly installed versions.
```
>[`Restart Runtime`]ボタンを押下するか、[`ランタイム`] - [`ランタイムを再起動`]を押下

### ●切り抜き画像アップロード
切り抜き画像として、「**sample.png**」をアップロードします。

>手元にある画像ファイルを「/content」配下にドラッグアンドドロップして、GoogleColabへアップロードしてください。

きちんとアップロードされたか確認します。

``` python:colab
from IPython.display import Image, display_png
display_png(Image('sample.png'))
```
<img width=320 src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405376/e9b5dfc9-ecb9-a032-c522-bfbd343158ea.png'>

### ●rembg実行
それでは**rembg**を起動して切り抜きを行います！

``` python:colab
from rembg.bg import remove
import numpy as np
import io
from PIL import Image

input_path = 'sample.png'
output_path = 'cutout.png'

f = np.fromfile(input_path)
result = remove(f,
                alpha_matting=True,
                alpha_matting_foreground_threshold=240,
                alpha_matting_background_threshold=10,
                alpha_matting_erode_structure_size=6)
img = Image.open(io.BytesIO(result)).convert("RGBA")
img.save(output_path)
```

### ●rembg実行結果
あれ？エラーだ😓………

> Google Colabからpipインストールするとなぜか`rembg 1.0.14`がインストールされてしまいます。`2021/04/14時点`で、最新版は`rembg 1.0.26`となっています。最新版では、このエラーは発生しません。`rembg 1.0.26`が要求するpythonバージョンは`python 3.8以上～4未満`となっていますが、Google ColabのPythonバージョンは現時点で`Python 3.7.10`なので、それが原因かと思います。

``` :colab
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-2-64027dc30014> in <module>()
----> 1 from rembg.bg import remove
      2 import numpy as np
      3 import io
      4 from PIL import Image
      5 

1 frames
/usr/lib/python3.7/functools.py in lru_cache(maxsize, typed)
    488             maxsize = 0
    489     elif maxsize is not None:
--> 490         raise TypeError('Expected maxsize to be an integer or None')
    491 
    492     def decorating_function(user_function):

TypeError: Expected maxsize to be an integer or None
```

### ●プログラム変更1
とりあえず、ソースコードを修正して先に進みます………
上記エラーの場合、以下のプログラムを修正すれば動くようになります。
>/usr/local/lib/python3.7/dist-packages/rembg/bg.py
>bg.py, line 67

``` python:bg.py抜粋&nbsp;(&nbsp;67行目を変更&nbsp;)
@functools.lru_cache
     ↓↓↓↓
@functools.lru_cache(maxsize=None)
```

### ●プログラム変更2
**rembg**では、Trimap画像は保存されないので、ついでに「**trimap.png**」として画像を保存するように修正してしまいましょう！ちなみにTrimap画像はu2netの学習サイズである**320x320**で検出されるので、元の画像サイズへリサイズしています。
※「プログラム変更2」は必須ではありません。割愛してもOKです。

>/usr/local/lib/python3.7/dist-packages/rembg/bg.py
>bg.py, Line85
>
>mask = detect.predict(model, np.array(img)).convert("L")
>上記処理のすぐ下に、以下の処理(3行)を追加

``` python:追加処理
    output_path = '/content/trimap.png'
    mask = mask.resize(img.size)
    mask.save(output_path)
```

``` python:bg.py抜粋&nbsp;(&nbsp;trimapを保存するためにbg.pyに上記処理(3行)を追加&nbsp;)
def remove(
    data,
    model_name="u2net",
    alpha_matting=False,
    alpha_matting_foreground_threshold=240,
    alpha_matting_background_threshold=10,
    alpha_matting_erode_structure_size=10,
):
    model = get_model(model_name)
    img = Image.open(io.BytesIO(data)).convert("RGB")
    mask = detect.predict(model, np.array(img)).convert("L")

    output_path = '/content/trimap.png'    # ← ここの処理を追加
    mask = mask.resize(img.size)           # ← ここの処理を追加
    mask.save(output_path)                 # ← ここの処理を追加
```

### ●ランタイムの再起動
プログラムを変更したら、忘れずに**ランタイムの再起動**を実施してください。
>[`ランタイム`] - [`ランタイムを再起動`]を押下


## (2)画像切り抜きプログラムの実行
### ●rembg実行コード
プログラムを修正したので、再度、以下プログラムを実行して、切り抜きを行っていきます！
※remove関数に渡す引数「alpha matting_xxxx_xxxx」は、適当に変えて遊んでみてください。

``` python:colab
from rembg.bg import remove
import numpy as np
import io
from PIL import Image

input_path = 'sample.png'
output_path = 'cutout.png'

f = np.fromfile(input_path)
result = remove(f,
                alpha_matting=True,
                alpha_matting_foreground_threshold=240,
                alpha_matting_background_threshold=10,
                alpha_matting_erode_structure_size=6)
img = Image.open(io.BytesIO(result)).convert("RGBA")
img.save(output_path)
```
Trimap画像「**trimap.png**」と、AlphaMattingした画像「**cutout.png**」を表示して確認します。

``` python:colab
from IPython.display import Image, display_png
display_png(Image('trimap.png'))
display_png(Image('cutout.png'))
```
なんとか「切り抜き」はうまくいきました！あとはお姉たまを「僕んち」に呼ぶだけです😚！
<img width=320 src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405376/881ae6c9-01b1-5acb-3e3f-81aa8dca57de.png'> <img width=320 src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405376/64869ddd-9eef-bd8d-2c92-7f288cd06f47.png'>

## (3)写真合成
画像合成については、フリーの画像編集ツールなどでレイヤー貼り付けを行っても同様のことができますが、せっかくなのでこちらもプログラムで実行します。

### ●合成する背景をアップロード
合成する背景として、「**background.png**」と「**greenback.png**」の2つをアップロードします。

>手元にある画像ファイルを「/content」配下にドラッグアンドドロップして、GoogleColabへアップロードしてください。

きちんとアップロードされたか確認します。

``` python:colab
from IPython.display import Image, display_png
display_png(Image('background.png'))
display_png(Image('greenback.png'))
```

僕んちとグリーンバック画像です。
<img width=320 src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405376/fc47d56a-9501-c31b-cb53-1b04d9607a51.png'> <img width=320 src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405376/5fef1b06-84a6-c049-fabf-8f0bb6f54156.png'>

### ●「僕んち」背景と合成

``` python:colab
from PIL import Image

# 切り抜き画像
img = Image.open('cutout.png').convert('RGBA')

# 背景画像
bg = Image.open('background.png').convert('RGBA')

# 画像合成
img_clear = Image.new("RGBA", bg.size, (255, 255, 255, 0))
img_clear.paste(img, (200,250))
bg = Image.alpha_composite(bg, img_clear)

# 画像保存
bg.save('merge1.png')
```

作成された合成画像を表示します。

``` python:colab
from IPython.display import Image, display_png
display_png(Image('merge1.png'))
```
僕んちにキター😊！ワッショイ・ワッショイ♫
<img width=320 src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405376/5361a526-1dab-4ef4-cb15-f5e81820a571.png'>

### ●「グリーンバック」背景と合成
``` python:colab
from PIL import Image

# 切り抜き画像
img = Image.open('cutout.png').convert('RGBA')

# 背景画像
bg = Image.open('greenback.png').convert('RGBA')

# 画像合成
img_clear = Image.new("RGBA", bg.size, (255, 255, 255, 0))
img_clear.paste(img, (200,250))
bg = Image.alpha_composite(bg, img_clear)

# 画像保存
bg.save('merge2.png')
```

切り抜き画像とグリーンバック画像を合成した画像を表示します。

``` python:colab
from IPython.display import Image, display_png
display_png(Image('merge2.png'))
```

ゴチャゴチャしない背景（グリーンバック）で、うまく切り取れているか確認してみます。
少しエッジが甘いところがありますが、まぁまぁできていますね！
<img width=320 src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405376/f4acbfba-646e-f2a0-608d-f6764de0ef19.png'>

# ■ 4.オブジェクト切り抜きサイト紹介
プログラムを実行しなくても、webツールを実行することで切り抜きを行うこともできます。対価支払いについては、AIの開発などを続けて認識精度を向上させるためなのか、気軽さなのか分かりませんが、サブスクが多いですね。他にも有効なwebサイトがあったら教えてください。ちな、順不同です。

|サイト|切り抜き結果|個人的な感想|点数|
|:-|:-:|:-|-:|
|[Clipping Magic](https://ja.clippingmagic.com/)|<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405376/c7e39845-c763-d26b-b75b-55016abd818f.png'>|自動切り抜きもキレイだし、切り抜き後の調整ツールが秀悦でとても使いやすいです。ヘアツール、フォアグラウンド指定やバックグラウンドの範囲指定が自動でできたり、きめ細かな修正が簡単に実施可能です。有料でサンプルには透かしが入っています。|100|
|[remove.bg](https://www.remove.bg/ja)|<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405376/bcd6cd02-15a6-8e47-40df-a543c0883e0f.png'>|自動切り抜き後は、簡単な手動によるフォアグラウンドの範囲削除/復元ツールの様なものはありましたが、それだけでは切り抜きのきめ細かな調整はできません。有料ですが、小さなプリビュー画像は無料でダウンロード可能です。|80|
|[removal.ai](https://removal.ai/ja/)|<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405376/7552a984-9b3c-b247-da20-e15cc6e06896.png'>|手と首元の間を見るとremove.bgよりも良いかもしれません。自動切り抜き後のペイントツールが充実していますが、それより切り抜き調整ツールが欲しかった。有料ですが、小さなプリビュー画像は無料でダウンロード可能です。|81|
|[Photo Scissors](https://photoscissors.com/)|<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/405376/a4e4668c-6798-5003-2c48-096fa19435d8.png'>|自動切り抜き後にヘアーツール、フォアグラウンド指定ツールなどがあります。フォアグラウンドツールで同じ様な範囲が自動で選択されないところや、バックグラウンドが指定できないところなどから、Clipping Magicには及びません。有料ですが、小さなプリビュー画像は無料でダウンロード可能です。|85|

# ■ 5.以上
お疲れ様でした。

### ●Google Colabで実施したことについて
最新版の`rembg 1.0.26`は、`Python 3.8`以上という要求仕様でした。Google Colabは現時点では`Python 3.7.10`でしたので最新版は適合せず、古い`rembg 1.0.14`を使用することになってしまいました。ソースコードの修正もする必要があったので、こんなことなら、ローカルPCで`Anaconda`や`Pycharmのvenv`などで、`Python 3.8`環境を作った方が良かったです。**みなさんは気をつけてください！**

> **win10**で実施する場合は、Pythonの拡張モジュールをインストールする為に、以下のCコンパイラが必要となる場合があります。
> https://www.python.jp/install/windows/install_vstools2017.html

### ●画像切り抜きについて
実際に「**画像切り抜き**」をやってみて、髪の毛など切り抜きが難しいところでも、自動で難なく切り取りができてしまうのは、本当に**AIさま**の「おチカラ」はスゴイですね！今までできなかったことが、続々と自動でできるようになっています。ただ、処理はまだまだ完全ではないので、**Clipping Magic**の様に、いかに簡単に補正をできるようにするか、などの機能も合わせて必要だと思いました。

# ■ ライセンス
使用した写真の一部につきましては、写真のフリー素材サイトである[Photo AC](https://www.photo-ac.com/)の[利用規約](https://www.photo-ac.com/main/terms/)に沿って、利用しております。