Pythonライブラリ(Remgb):背景クリッピング
1.概要
画像処理として有名なライブラリとしてOpenCVがありますが使いこなすにはかなりの学習が必要です。
今回背景を簡単にくりぬけるライブラリが紹介されていたため実装してみました。
1-1.Unetとは
学習済みモデルより本ライブラリではU-netを利用していると思います。U-Netは2015年に登場したセマンティックセグメンテーションのモデルであり、画像中の画素(ピクセル)単位で物体検出する技術となります。
2.環境構築
手順としては①仮想環境作成、②ライブラリのインストール、③学習モデルのダウンロードとなります。
①はなくてもよいかもしれませんが私の環境では下記エラーが出たため作成することを推奨します。
OSError: Could not load shared object file: llvmlite.dll
2-1.仮想環境の作成
作成要領は下記記事に記載しているためコードのみ記載しました。内容は①仮想環境作成、②仮想環境へのログイン、③環境の確認です。
[Terminal ※私はAnaconda Promptを使用]
conda create -n rembg python
activate rembg
conda info -e
[OUT]
The following packages will be downloaded:
package | build
---------------------------|-----------------
certifi-2022.9.24 | py310haa95532_0 155 KB
pip-22.2.2 | py310haa95532_0 2.4 MB
python-3.10.6 | hbb2ffb3_0 13.8 MB
sqlite-3.39.3 | h2bbff1b_0 804 KB
xz-5.2.6 | h8cc25b3_0 240 KB
------------------------------------------------------------
Total: 17.4 MB
# conda environments:
#
base C:\Users\KIYO\Anaconda3
env_PyCaret_202205 C:\Users\KIYO\Anaconda3\envs\env_PyCaret_202205
esrgan C:\Users\KIYO\Anaconda3\envs\esrgan
rembg * C:\Users\KIYO\Anaconda3\envs\rembg
2-2.ライブラリのインポート
公式に記載の通りCPU版:pip install rembgとGPU版:pip install rembg[gpu]があります。速度的に気にならないためCPUでインストールしました。
[Terminal]
pip install rembg
2-3.モデルのダウンロード
公式GitHubより目的に応じた学習モデルがDLできます。
u2net (download - alternative, source): general use cases.
u2netp (download - alternative, source): A lightweight ver of u2net model.
u2net_human_seg (download - alternative, source): human segmentation.
u2net_cloth_seg (download - alternative, source): Cloths Parsing
ライブラリのインストール後にユーザーディレクトリに".u2net"フォルダがあるため、その中に学習済みモデルを保存しました。
[.u2netのパス]
C:/Users/KIYO/.u2net
【参考:ONNX(Open Neural Network Exchange)】
TensorflowやPytorchなど異なるフレームワークのモデルを同じ形式で使用することができるフォーマットです。
3.背景クリップ
rembgを使用して画像をくり抜いていきます。操作は下記数行だけです。
[IN]
from rembg import remove
from PIL import Image
path_input = 'konan.JPG'
path_output = 'konan_rembg.png'
img = Image.open(path_input) #PIL形式で読み込み
img_rembg = remove(img) #背景除去
img_rembg.save(path_output) #保存
[OUT]
結果をみる(PIL形式を配列表示)ためだけの関数作成して比較します。
[IN]
def image_grid(imgs, rows, cols):
assert len(imgs) == rows*cols #画像の枚数がrows*colsと一致するか確認
w, h = imgs[0].size #画像のサイズを取得
grid = Image.new('RGB', size=(cols*w, rows*h)) #新しい画像を作成
grid_w, grid_h = grid.size #新しい画像のサイズを取得
for i, img in enumerate(imgs):
grid.paste(img, box=(i%cols*w, i//cols*h)) #画像を貼り付ける
return grid
image_grid([img, img_rembg], rows=1, cols=2)
[OUT]
4.Pythonでやってみた:画像合成(コラ画像)
調整できるコードは下記記事にまとめました。各節では各コードの動作を見ることが出来ます。
4-1.位置指定して追加
(A)先ほどの背景をクリッピングした猫と(B)適当な背景画像を用いてOpenCVからコラ画像を作成しました。まだOpenCV側の動作を十分に理解できていないのでとりあえず追加できそうな所に追加しました。
【左上に追加】
[IN]
import cv2
from PIL import Image
path_base = 'space2.jpg'
path_rembg = 'konan_rembg.png'
img_base, img_rembg = cv2.imread(path_base), cv2.imread(path_rembg)
print(f'img_base:{img_base.shape}, img_rembg:{img_rembg.shape}')
img_resize = cv2.resize(img_rembg, dsize=None, fx=0.5, fy=0.5) #画像サイズを調整
print(f'img_resize:{img_resize.shape}')
#注目領域(ROI)(挿入エリア)を作成(左上の角)
rows,cols,channels = img_resize.shape
roi = img_base[0:rows, 0:cols ] #注目領域(ROI)の作成
#マスク、インバースマスクの作成
img2gray = cv2.cvtColor(img_resize,cv2.COLOR_BGR2GRAY)
ret, mask = cv2.threshold(img2gray, 10, 255, cv2.THRESH_BINARY)
mask_inv = cv2.bitwise_not(mask)
#ロゴ画像の注目領域(ROI)を黒くする
img_base_bg = cv2.bitwise_and(roi,roi,mask = mask_inv)
#ロゴ画像からロゴのみ(ROI)を抽出する
img2_fg = cv2.bitwise_and(img_resize ,img_resize ,mask = mask)
#ROI(置換領域)に追加画像(処理後)を追加
dst = cv2.add(img_base_bg,img2_fg)
img_base[0:rows, 0:cols ] = dst
#Numpy配列をPIL形式に変換
img_base = Image.fromarray(cv2.cvtColor(img_base, cv2.COLOR_BGR2RGB))
img_base
[OUT]
【右下に追加】
”roi = img_base[]”と”img_base[] = dst”の指定範囲を修正
[IN]
import cv2
from PIL import Image
path_base = 'space2.jpg'
path_rembg = 'konan_rembg.png'
img_base, img_rembg = cv2.imread(path_base), cv2.imread(path_rembg)
print(f'img_base:{img_base.shape}, img_rembg:{img_rembg.shape}')
img_resize = cv2.resize(img_rembg, dsize=None, fx=0.5, fy=0.5) #画像サイズを調整
print(f'img_resize:{img_resize.shape}')
#注目領域(ROI)(挿入エリア)を作成(右下の角)
rows,cols,channels = img_resize.shape
roi = img_base[img_base.shape[0]-rows:img_base.shape[0], img_base.shape[1]-cols:img_base.shape[1]] #注目領域(ROI)の作成
#マスク、インバースマスクの作成
img2gray = cv2.cvtColor(img_resize,cv2.COLOR_BGR2GRAY)
ret, mask = cv2.threshold(img2gray, 10, 255, cv2.THRESH_BINARY)
mask_inv = cv2.bitwise_not(mask)
#ロゴ画像の注目領域(ROI)を黒くする
img_base_bg = cv2.bitwise_and(roi,roi,mask = mask_inv)
#ロゴ画像からロゴのみ(ROI)を抽出する
img2_fg = cv2.bitwise_and(img_resize ,img_resize ,mask = mask)
#ROI(置換領域)に追加画像(処理後)を追加
dst = cv2.add(img_base_bg,img2_fg)
img_base[img_base.shape[0]-rows:img_base.shape[0], img_base.shape[1]-cols:img_base.shape[1]] = dst
#Numpy配列をPIL形式に変換
img_base = Image.fromarray(cv2.cvtColor(img_base, cv2.COLOR_BGR2RGB))
img_base
[OUT]
4-2.参考1:クリッピング時の動作確認
画像処理の動作がどのようになっているか参考までに可視化しました。
[IN]
import numpy as np
_imgs = [mask, mask_inv, img_base_bg, img2_fg, dst, img_base]
imgs = []
#Numpy配列をPIL形式に変換
for i in _imgs:
if type(i) == np.ndarray:
i = Image.fromarray(cv2.cvtColor(i, cv2.COLOR_BGR2RGB))
imgs.append(i)
else:
imgs.append(i)
image_grid(imgs, rows=2, cols=3)
[OUT]
4-3.参考2:失敗例の画像
参考までに何かに使えそうと思って持っていた画像ですがクリッピングできませんでした。このようにうまくいかないパターンも発生します。
参考資料
あとがき
どこまでコラ画像を簡単に作成できるか試したいので「Pythonでやってみたシリーズ」で作りたいけど、優先順位的には追ってかな・・・・・・