今回の自作ツールは、「画像の背景切り抜きツール」です。背景切り抜きツールはいくつかの製品がWebサービスとして公開されており、お試しの無料版は存在するものの、基本は有料です。
しかし、Pythonを使えば有料版と遜色のない品質での切り抜きが可能で、多くのお試し版で設けられている画像サイズの制限もありません。
Pythonで画像の背景切り抜きを行いたい方は、是非本記事を参考にトライしてみてください。
自作ツールを作るためのポイントと今後公開予定の自作ツール一覧を「【実践】Pythonで事務処理向け自作ツールを作ろう!」で紹介していますので、併せてご覧ください。
画像の背景切り抜きツールの紹介
今回紹介する背景切り抜きツールは、指定したフォルダに置かれている画像ファイルの背景をまとめて切り抜き、出力フォルダに書き出してくれます。
- 指定したフォルダに置かれた画像ファイル全てに対して、背景切り抜きを行います。
- 入力フォルダ、出力ファルダに入力した内容は保持され、次回起動時に復元されます。
画面レイアウトと使い方
画面を見ればすぐわかると思いますが、以下の3ステップで背景を切り抜くことができます。
- 入力フォルダ名の欄に、切り抜きたい画像が保存されているフォルダを指定する
- 出力フォルダ名の欄に、切り抜いた結果を保存したいフォルダを指定する
- 背景の切り抜きボタンをクリックする
実行結果
プログラムのダウンロードと動作環境の設定
Pythonのインストールが必要です。既に構築済みの方は無視して下さい。詳細は下記の個別記事をご覧ください。
自作ツールのためのポータブルPython開発・実行環境を作ろう! | プログラム実行時に必要 |
WinPythonにVSCode Portable版を入れよう! | プログラム修正時に必要 |
Python 環境に下記のライブラリをインストールします。 command.bat を実行後、下記のコマンドを実行します。
pip install rembg
pip install customtkinter
pip install Pillow
pip install tkinterdnd2
下記のリンクからZipファイルをダウンロード&解凍します。次に、Python環境の任意の場所にフォルダを作成し、そこに解凍したファイル(6個)をコピーしてください。
画像の背景切り抜きツール
実行方法
次の手順で実行してください。
- WinPython のインストールフォルダ内にある command.bat を実行
- ダウンロードしたプログラムファイルをコピーした場所にカレントディレクトリを移動
- Python ui.py を実行
Python ui.py
しばらくすると下記の画面が表示されます。初回起動時は入力フォルダ、出力フォルダともに、カレントフォルダ(ui.py が置かれているフォルダ)が表示されます。
背景切り抜き中はコマンドプロンプトにファイル名が表示されます。
画像の背景切り抜きツールの設計
以下は、プログラム作成にあたって必要事項を取りまとめた内容になります。とりあえず背景の切り抜きが行いたい方は、以降の章は無視して頂いて構いません。
ただ、プログラミングにおいての参考になりますので、もしよければ最後までお付き合いください。
仕様
画面項目 | 説明 |
---|---|
入力フォルダ名 | 切り抜きたい画像が置かれたフォルダを指定。 フォルダをドラッグ&ドロップで指定することも可能 |
出力フォルダ名 | 切り抜いた画像の保存先フォルダを指定。 フォルダをドラッグ&ドロップで指定することも可能 |
背景切り抜きボタン | 画像の背景切り抜きを実行 |
実現方法
- 画面はCustomTkinter で作成
- 背景切り抜きは rembg ライブラリを使用(詳細は rembg公式ページ を参照)
プログラムの構成
本プログラムは5つの py ファイルで構成しています。この程度の規模なら1つのpyファイルにまとめても良いのですが、再利用性や拡張性を考慮し、あえて機能単位にファイルを分割しました。
モジュール名 | 役割 |
---|---|
ui.py | ユーザインターフェースを担当 |
manage.py | 画面の入力情報を用いて、get_filesとbg_remove_from_folder |
bg_remove.py | 画像から背景を切り抜く処理 |
customtkinter | ファイル選択やフォルダ選択、ドラッグ&ドロップを実現するための補助 |
appconfig.py | 画面に入力された値をJson形式のファイルに保存/読込する |
処理手順の簡易フロー
ソースコード
ui.py
import os
import customtkinter as ctk
from customtkintercontrols import App
from customtkintercontrols import FolderSelectionControl
from appconfig import AppConfig
import manager
# -----------------------------------------------
# コールバック関数の定義
# -----------------------------------------------
# ウィンドウを閉じる時に呼ばれる関数
def close_window():
# 画面入力値を保存
conf.set("input_folder",input_folder.get())
conf.set("output_folder",output_folder.get())
conf.write()
# プログラムの終了
app.quit()
# 変換ボタンが押された時に呼ばれる関数
def remove():
manager.bg_remove_from_folder(input_folder.get(),output_folder.get())
# -----------------------------------------------
# メインウインドウの定義
# -----------------------------------------------
# 前回入力値の保存・復元用インスタンスの生成
conf = AppConfig("./config.json")
# メインウィンドウの作成
app = App()
app.minsize(width=400, height=200)
app.maxsize(width=1200, height=200)
app.geometry(f"600x200")
app.title("画像の背景切り抜きツール")
# customtkinterをダークモードに設定
ctk.set_appearance_mode("light")
# ウィンドウを閉じる時に呼びたい関数を登録
app.protocol("WM_DELETE_WINDOW", close_window)
# -----------------------------------------------
# 画面レイアウト(ウィジェット)の定義
# -----------------------------------------------
# フォルダ選択ダイアログを配置
input_folder = FolderSelectionControl(app)
input_folder.label.configure(text="入力フォルダ名")
input_folder.pack(padx=10,pady=10,fill="x")
# フォルダ選択ダイアログを配置
output_folder = FolderSelectionControl(app)
output_folder.label.configure(text="出力フォルダ名")
output_folder.pack(padx=10,pady=10,fill="x")
# 実行ボタンの配置
split_button = ctk.CTkButton(app,text="背景切り抜き",height=40,width=450,command=remove)
split_button.pack(padx=20,pady=10)
# -----------------------------------------------
# 前回実行時の画面入力値を復元
# -----------------------------------------------
input_folder.set(conf.get("input_folder"))
if input_folder.get() == "":
input_folder.set(os.getcwd())
output_folder.set(conf.get("output_folder"))
if output_folder.get() == "":
output_folder.set(os.getcwd())
# -----------------------------------------------
# CustomTkinterの起動
# -----------------------------------------------
# メインループを開始
app.mainloop()
manager.py
import os
import glob
from bg_remove import bg_remove
def get_files(folder,recursive=False,include_hidden=True):
"""
指定されたフォルダ内のファイルを再帰的に取得する関数
:param folder: フォルダのパス
:param recursive: 再帰的に取得するかどうかのフラグ
:param include_hidden: 隠しファイルを含めるかどうかのフラグ
:return: ファイルのリスト
"""
if os.path.isdir(folder):
folder = os.path.join(folder,"*")
if recursive:
dir,name = os.path.split(folder)
folder = os.path.join(dir,"**",name)
return glob.glob(folder,recursive=recursive,include_hidden=include_hidden)
def bg_remove_from_folder(input_folder,output_folder):
"""
指定されたフォルダ内のファイルの背景を切り抜きます
:param input_folder: 入力フォルダのパス
:param output_folder: 出力フォルダのパス
"""
files = get_files(input_folder)
for file in files:
_,name = os.path.split(file)
path = os.path.join(output_folder,name)
bg_remove(file,path)
print(file)
bg_remove.py
from rembg import remove
from PIL import Image
import numpy as np
def bg_remove(input_path, output_path):
"""
指定されたファイルの背景を切り抜きます
:param input_path: 入力ファイルのパス
:param output_path: 出力ファイルのパス
"""
# 入力画像を開く
input_image = Image.open(input_path)
# 画像をRGBAモードに変換(背景を切り抜くためにはアルファチャンネルが必要)
if input_image.mode != 'RGBA':
input_image = input_image.convert('RGBA')
# 画像データをnumpy配列に変換
input_array = np.array(input_image)
# 背景を除去
output_array = remove(input_array)
# numpy配列をPIL画像に変換
output_image = Image.fromarray(output_array)
# 画像をPNG形式で保存(透明度を保持するため)
output_image.save(output_path, 'PNG')
まとめ
今回は、「画像の背景切り抜きツール」について、使い方から環境構築に至るまでの手順を解説しました。また、実際に私がこのツールを作るにあたって、事前に検討した内容も併せて紹介しました。
今回は非常にシンプルな構成であるため、ソースコードは理解しやすいかと思います。
プログラムは再利用を考えて機能単位で分割していますので、画面だけ別のものに置き換えるのも容易です。
今回の記事を参考に、自分だけの背景切り抜きツールを作成してみてください。
コメント