MATOBA Logo

【ダウンロード】 写真の背景除去を完全自動化する方法 【自動化アプリ】

【ダウンロード】 写真の背景除去を完全自動化する方法 【自動化アプリ】

はなしの流れ

画像を正方形化する自動アプリの開発を通して、ChatGPTをつかったオリジナルアプリのアップデートを体験しましょう。

  1. もとの背景色にそろえる(背景の違和感をなくすアプローチ)
  2. 被写体を検出して背景を消去する(さらに高度なアプローチ)

はじめに

猫の怒り表情

……この前の正方形にした画像、ライオンの上司に見せたら「背景が真っ白なのが気に食わない」って言われたのにゃ。あまりの横暴にこっちの頭が真っ白になったのにゃ。

マトバオーの困惑表情
マトバオー

まあね。せっかく作ったのに駄目ってのはよくあることだよ。でも、その作ったものは丸ごと無駄にはならない。ちゃんと、次回のアップデートの糧になるんだ。今回は、猫のプログラムを改善しながら、気に入らない部分のアップデートを行う方法を共有するね。

この記事では、前回作成した「画像を正方形にするアプリ」をアップデートしながら、思い通りの機能を持つアプリにしていく過程を紹介します。アプリを動かすための土台がまだできていない人は以下のリンクを参照してください。

ノンプログラマのためのChatGPT自動化入門

ノンプログラマのためのChatGPT自動化入門

あらゆる面倒で退屈な作業をChatGPTに自動化してもらう方法を、プログラミング未経験者向けにまとめました。たとえば、画像のリサイズやPDFの結合、WordのPDF化やExcelへの自動入力などを自動化することができます。さあ、退屈なことはChatGPTにやらせよう!

最終的には、こんな風に背景をスッキリ消して、被写体だけをキレイに正方形の画像にしてくれるアプリが完成します!ダウンロードできる形でも配布していますので、ぜひ見ていってください!

最終的に完成する画像正方形化アプリの比較

最終的に完成する画像正方形化アプリの比較

もとの背景色にそろえる

マトバオーの通常表情
マトバオー

まずは簡単な方法から試してみよう。背景が真っ白なせいで元の画像と馴染まないなら、「元の画像の背景色に近い色」を背景にすればいいんじゃないかな?

猫の通常表情

でも、画像の背景色なんてどうやって調べるのにゃ?

マトバオーのウインク表情
マトバオー

例えば、「画像のフチ(外周)の色の平均」を背景色に使う、というアイデアはどうだろう。早速、前回のプロンプトテンプレートを使ってChatGPTにお願いしてみよう。

ChatGPTへの依頼

画像正方形化アプリアップデート依頼 (背景色をそろえる)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
実行ディレクトリに、inputフォルダとoutputフォルダがあります。input内のファイルを処理してoutputに出力するPythonプログラムを書いてください。

【条件】
- 必ず単一スクリプト./app.pyで完結させてください。実行コマンドは「python app.py」です。pdf2imageのような外部依存が存在するライブラリの使用も禁止です。
- ライブラリの導入が必要な場合は./requirements.txtの内容も書いてください。このときバージョンの指定は行わないでください。
- ./input、./output、./_app以外を対象とするCRUD含めいかなる操作も禁止です。./inputはRのみ許可します。./outputはCのみ許可します。./_appはCRUDすべて許可します。
- 仕様に忠実かつ必要十分にしてください。明示的に設定項目が必要と指令された場合は、./input/settings.txtを作成したり、Tkinter GUIで都度設定変更できるようにするなどしてください。
- 特に./input、./outputディレクトリは適切な構造化により視認性を保つようにしてください。
- ./_appはユーザーが参照する必要のない一時ファイルやデータベースファイルの作成など自由に使ってください。
- README.txtの内容も示してください。

###

【仕様】
前回作成したプログラムをアップデートしてください。
前回は、白い背景を使用していましたが、もとの背景となじまない問題が発生しています。元の画像のフチの色の平均を背景として使うようにアップデートしてください。
import os
from PIL import Image

# 入力と出力のディレクトリ
INPUT_DIR = './input'
OUTPUT_DIR = './output'

def make_square_image(image: Image.Image) -> Image.Image:
    """画像を正方形のキャンバスに貼り付ける"""
    # 画像の幅と高さを取得
    width, height = image.size

    # 正方形にするためのキャンバスのサイズ(最大の辺の長さに合わせる)
    new_size = max(width, height)

    # 新しいキャンバスを作成 (白い背景)
    new_image = Image.new("RGB", (new_size, new_size), (255, 255, 255))

    # 画像を中央に貼り付け
    left = (new_size - width) // 2
    top = (new_size - height) // 2
    new_image.paste(image, (left, top))

    return new_image

def process_images():
    """inputディレクトリ内の画像を処理し、outputディレクトリに保存する"""
    # inputフォルダ内のファイルリストを取得
    for filename in os.listdir(INPUT_DIR):
        input_path = os.path.join(INPUT_DIR, filename)
        if os.path.isfile(input_path):
            # 画像ファイルを開く
            try:
                with Image.open(input_path) as img:
                    # 画像を正方形に変換
                    square_img = make_square_image(img)

                    # 出力ファイルパスを生成
                    output_path = os.path.join(OUTPUT_DIR, filename)
                    
                    # 画像を保存
                    square_img.save(output_path)
                    print(f"{filename} を処理しました。")
            except Exception as e:
                print(f"{filename} の処理中にエラーが発生しました: {e}")

if __name__ == "__main__":
    process_images()
text
マトバオーの通常表情
マトバオー

プログラムのアップデートを依頼するときは、【仕様】に、①依頼内容と②現在のプログラムの内容を送る必要がある。ここだと、①依頼内容が「前回作成したプログラムをアップデートしてください。前回は、白い背景を使用していましたが、もとの背景となじまない問題が発生しています。元の画像のフチの色の平均を背景として使うようにアップデートしてください。」で、②現在のプログラムがその下だね。app.pyをコピペでいいよ。

ChatGPTからの返答

app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import os
from PIL import Image

# ディレクトリ設定
INPUT_DIR = './input'
OUTPUT_DIR = './output'
APP_DIR = './_app'

def get_border_average_color(image: Image.Image) -> tuple:
    """画像の上下左右フチの平均色を取得する"""
    pixels = image.load()
    width, height = image.size

    border_pixels = []

    # 上下のライン
    for x in range(width):
        border_pixels.append(pixels[x, 0])
        border_pixels.append(pixels[x, height - 1])

    # 左右のライン(端の角は重複してるので除く)
    for y in range(1, height - 1):
        border_pixels.append(pixels[0, y])
        border_pixels.append(pixels[width - 1, y])

    # RGBの平均を求める
    r_avg = sum([pix[0] for pix in border_pixels]) // len(border_pixels)
    g_avg = sum([pix[1] for pix in border_pixels]) // len(border_pixels)
    b_avg = sum([pix[2] for pix in border_pixels]) // len(border_pixels)

    return (r_avg, g_avg, b_avg)

def make_square_image(image: Image.Image) -> Image.Image:
    """画像を正方形にし、背景をフチ色の平均で塗る"""
    width, height = image.size
    new_size = max(width, height)

    # フチ色平均を背景色として使用
    bg_color = get_border_average_color(image)

    new_image = Image.new("RGB", (new_size, new_size), bg_color)
    left = (new_size - width) // 2
    top = (new_size - height) // 2
    new_image.paste(image, (left, top))

    return new_image

def process_images():
    """input内の画像を処理しoutputに保存"""
    os.makedirs(OUTPUT_DIR, exist_ok=True)

    for filename in os.listdir(INPUT_DIR):
        input_path = os.path.join(INPUT_DIR, filename)
        if os.path.isfile(input_path):
            try:
                with Image.open(input_path) as img:
                    square_img = make_square_image(img.convert("RGB"))
                    output_path = os.path.join(OUTPUT_DIR, filename)
                    square_img.save(output_path)
                    print(f"{filename} を処理しました。")
            except Exception as e:
                print(f"{filename} の処理中にエラーが発生しました: {e}")

if __name__ == "__main__":
    process_images()
python
requirements.txt
1
Pillow
text
マトバオーの通常表情
マトバオー

今回、requirements.txtの変化はなかったね。前回のプログラムで必要だった拡張機能(ライブラリ)で十分ってことだ。

新しくテンプレートを作成する

マトバオーの通常表情
マトバオー

ここが地味に大切なポイントで、プログラムをアップデートするときはその都度、新しくテンプレートを複製して欲しいんだ。そのやり方については、前回の記事を参考にしてね。

猫の困惑表情

なんでにゃ?前のapp.pyとrequirements.txtを上書きすればいいはずにゃ。

マトバオーの通常表情
マトバオー

ChatGPTは完璧じゃないから、間違ったコードを書く時もある。そんなコードを今動いているアプリに上書きしてしまって、壊れてしまうのを防ぐためだね。ちょっとイメージを共有するね。

(推奨) アップデート時のフォルダ管理

(推奨) アップデート時のフォルダ管理

マトバオーのウインク表情
マトバオー

アップデートするときは複数のフォルダで分けてやることで、もし2が動かなくても1に戻りやすくなるよ。

結果の確認

画像正方形化アプリ 前回と背景色をそろえた場合の比較

画像正方形化アプリ 前回と背景色をそろえた場合の比較

猫の笑い表情

良い感じなのにゃ!これならライオンの上司も納得するはずにゃ。

マトバオーの笑い表情
マトバオー

ふっふっふ。興がのってきたね。次は、ちょっと高度な処理をやってみようか。具体的には、背景を削除する感じだね。

猫の困惑表情

え。別にこれでいいのにゃ。

画像正方形化アプリ2

本ツール「画像正方形化ツール 2」は、input/ フォルダに置いた画像を 縦横比を保ったまま正方形キャンバスへリサイズし、output/ に保存する 自動処理アプリです。背景色には、元画像の外縁ピクセルから算出した平均色を採用し、 白埋めよりも自然な見た目に仕上げます。SNS サムネイルや EC 商品画像の統一などに適しています。

ZIP305.06 kB
公開: 2025/06/14

背景を除去する

SAMについて

SAM(Segment Anything Model)とは、Meta社(旧Facebook社)が開発した、画期的な画像セグメンテーションモデルです。

画像セグメンテーションとは、一言でいうと「画像の中から、モノの形を正確に見つけ出して切り分ける技術」のこと。写真の中にある人や猫、車などを、その輪郭に沿ってハサミで切り抜くような処理をAIが自動で行ってくれます。

今回のケースでは、SAMに商品画像を見つけ出してもらいます。難しく見えますが、使うだけなら簡単です。ChatGPTにSAMを使えというだけですから。

マトバオーの通常表情
マトバオー

SAMは当時のセグメンテーションモデルが分割して行っていたことをひとつのモデルに統合することで驚異的な汎化性能を達成したんだ。個人的に学習方法がとても面白いんだよね。これだけ巨大なモデルを学習するのには膨大なデータが必要なんだけど、そのデータを未熟なSAMと人間が一緒に作成しながら進化していったんだ。

猫の困惑表情

オタク怖いのにゃ

ChatGPTへの依頼

app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
実行ディレクトリに、inputフォルダとoutputフォルダがあります。input内のファイルを処理してoutputに出力するPythonプログラムを書いてください。

【条件】
- 必ず単一スクリプト./app.pyで完結させてください。実行コマンドは「python app.py」です。pdf2imageのような外部依存が存在するライブラリの使用も禁止です。
- ライブラリの導入が必要な場合は./requirements.txtの内容も書いてください。このときバージョンの指定は行わないでください。
- ./input、./output、./_app以外を対象とするCRUD含めいかなる操作も禁止です。./inputはRのみ許可します。./outputはCのみ許可します。./_appはCRUDすべて許可します。
- 仕様に忠実かつ必要十分にしてください。明示的に設定項目が必要と指令された場合は、./input/settings.txtを作成したり、Tkinter GUIで都度設定変更できるようにするなどしてください。
- 特に./input、./outputディレクトリは適切な構造化により視認性を保つようにしてください。
- ./_appはユーザーが参照する必要のない一時ファイルやデータベースファイルの作成など自由に使ってください。
- README.txtの内容も示してください。

###

【仕様】
前回作成したプログラムをアップデートしてください。
前回は、元画像のフチの色の平均を背景色に設定して正方形にするということをしていましたが、今回は、「SAM huge」をつかって被写体を認識した後、その背景を削除するアプローチにしてください。このとき、重みはhuggingface_hubからコード上で取得できるようにしてください。


import os
from PIL import Image

# ディレクトリ設定
INPUT_DIR = './input'
OUTPUT_DIR = './output'
APP_DIR = './_app'

def get_border_average_color(image: Image.Image) -> tuple:
    """画像の上下左右フチの平均色を取得する"""
    pixels = image.load()
    width, height = image.size

    border_pixels = []

    # 上下のライン
    for x in range(width):
        border_pixels.append(pixels[x, 0])
        border_pixels.append(pixels[x, height - 1])

    # 左右のライン(端の角は重複してるので除く)
    for y in range(1, height - 1):
        border_pixels.append(pixels[0, y])
        border_pixels.append(pixels[width - 1, y])

    # RGBの平均を求める
    r_avg = sum([pix[0] for pix in border_pixels]) // len(border_pixels)
    g_avg = sum([pix[1] for pix in border_pixels]) // len(border_pixels)
    b_avg = sum([pix[2] for pix in border_pixels]) // len(border_pixels)

    return (r_avg, g_avg, b_avg)

def make_square_image(image: Image.Image) -> Image.Image:
    """画像を正方形にし、背景をフチ色の平均で塗る"""
    width, height = image.size
    new_size = max(width, height)

    # フチ色平均を背景色として使用
    bg_color = get_border_average_color(image)

    new_image = Image.new("RGB", (new_size, new_size), bg_color)
    left = (new_size - width) // 2
    top = (new_size - height) // 2
    new_image.paste(image, (left, top))

    return new_image

def process_images():
    """input内の画像を処理しoutputに保存"""
    os.makedirs(OUTPUT_DIR, exist_ok=True)

    for filename in os.listdir(INPUT_DIR):
        input_path = os.path.join(INPUT_DIR, filename)
        if os.path.isfile(input_path):
            try:
                with Image.open(input_path) as img:
                    square_img = make_square_image(img.convert("RGB"))
                    output_path = os.path.join(OUTPUT_DIR, filename)
                    square_img.save(output_path)
                    print(f"{filename} を処理しました。")
            except Exception as e:
                print(f"{filename} の処理中にエラーが発生しました: {e}")

if __name__ == "__main__":
    process_images()
text

ChatGPTからの返答

app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import os
from PIL import Image

import torch
import torchvision
from huggingface_hub import hf_hub_download
from segment_anything import sam_model_registry, SamAutomaticMaskGenerator

# --- 初期設定 ---
INPUT_DIR = "./input"
OUTPUT_DIR = "./output"
TMP_DIR = "./_app"
CHECKPOINT_NAME = "sam_vit_h_4b8939.pth"

os.makedirs(OUTPUT_DIR, exist_ok=True)
os.makedirs(TMP_DIR, exist_ok=True)

# --- SAMモデル読み込み ---
chkpt_path = hf_hub_download("ybelkada/segment-anything", f"checkpoints/{CHECKPOINT_NAME}")
sam = sam_model_registry["vit_h"](checkpoint=chkpt_path)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
sam.to(device=device)
sam.eval()

mask_generator = SamAutomaticMaskGenerator(sam)

# --- 処理関数 ---
def process_image(path_in, path_out):
    img = Image.open(path_in).convert("RGBA")
    img_rgb = img.convert("RGB")
    np_img = torch.from_numpy((torch.ByteTensor(torch.ByteStorage.from_buffer(img_rgb.tobytes()))).numpy())
    # PIL画像→numpy配列 or torch tensor処理できないため、PILでも扱える処理に変換
    img_arr = torch.tensor(torchvision.transforms.functional.pil_to_tensor(img_rgb)).permute(1,2,0).cpu().numpy()

    masks = mask_generator.generate(img_arr)
    # 面積最大のマスクを選択
    largest = max(masks, key=lambda m: m["area"])
    mask = largest["segmentation"]

    # 背景を透明化
    img_data = img.load()
    for y in range(img.height):
        for x in range(img.width):
            if mask[y, x] == 0:
                img_data[x, y] = (0, 0, 0, 0)

    # 正方形化(中央寄せ)
    size = max(img.width, img.height)
    canvas = Image.new("RGBA", (size, size), (0,0,0,0))
    offset = ((size - img.width)//2, (size - img.height)//2)
    canvas.paste(img, offset)

    canvas.save(path_out)

# --- メイン ---
for fname in os.listdir(INPUT_DIR):
    in_path = os.path.join(INPUT_DIR, fname)
    if not os.path.isfile(in_path):
        continue
    name, ext = os.path.splitext(fname)
    if ext.lower() not in [".jpg", ".jpeg", ".png"]:
        continue
    out_path = os.path.join(OUTPUT_DIR, f"{name}.png")
    process_image(in_path, out_path)
    print(f"Processed {fname} -> {out_path}")
python
requirements.txt
1
2
3
4
5
torch
torchvision
huggingface_hub
segment-anything
Pillow
text
マトバオーの悲しみ表情
マトバオー

実はこのコードが完成するまでに、ChatGPTは実装を5回くらい失敗してるんだよね。そんなときは何度も送りつけて実験という根気が必要になる。それか、エラー内容を送って「直して」と言うかだね。分かる人は手で直してしまってもいいよ。

猫の通常表情

めんどいのにゃ。

マトバオーの悲しみ表情
マトバオー

最近、体感で分かるほどChatGPTは他のChatAIに比べて微妙なんだよね。有料プランにしてo3というモデルを使用するか、ClaudeやGeminiというChatAIを使うとかなり楽になると思う。そこらへんの、ChatAIの比較についてもいつか記事にするね。

結果の確認

画像正方形化アプリ 前回と背景色を除去した場合の比較

画像正方形化アプリ 前回と背景色を除去した場合の比較

猫の驚き表情

良いっ......かと思ったけど、首輪の中に背景の色が残ってるのにゃ。

マトバオーの通常表情
マトバオー

ねずみの鍵の穴のところはちゃんと除去できてるんだけどね。AIは間違えるものだから完ぺきとはいかない。だけど、かなり正確に背景を除去できていると思うよ。

猫の通常表情

ふーん。でも、あっちいし遅いにゃ。パソコンから火が出るかと思ったにゃ。今回は2番目のやつで十分な気がするにゃ。

マトバオーのウインク表情
マトバオー

今回使用したSAMは中でも一番巨大なやつを使ったからね。その分計算量も多い。本当は、GPUを使うことで効率化できるんだけど、そこら辺の話もおいおいしていくね。

画像正方形化アプリ3

このアプリは、`input` フォルダ内の画像から「物体部分だけを切り出し、背景を透明化した正方形画像」を生成して `output` フォルダに保存するツールです。 HuggingFaceの SAM(Segment Anything Model)を利用して、画像の中からもっとも大きな領域(例:商品・人物など)を自動検出し、それ以外の背景を除去します。

ZIP305.06 kB
公開: 2025/06/14

おわりに

本記事では、写真の背景を除去して正方形に加工する作業を完全自動化するプロセスを、2つの異なるアプローチで紹介しました。

フチの色を背景にする方法
元の画像との違和感をなくすため、画像のフチ(外周)の平均色を算出して背景色に設定しました。この方法は、シンプルなコードで実現でき、処理も高速です。手軽に自然な仕上がりを求める場合に適しています。
AI(SAM)で背景を完全に除去する方法
より高度なアプローチとして、Meta社が開発した画像セグメンテーションモデル「SAM」を利用しました。これにより、被写体を高精度で認識し、背景を透過させることが可能になりました。ただし、大規模なモデルを使用するため、処理に時間がかかり、PCへの負荷も大きくなるという側面があります。

AIの動きを実践的に知りたい方へ

つくりながら学ぶ! PyTorchによる発展ディープラーニング
広告 - Amazonアソシエイトつくりながら学ぶ! PyTorchによる発展ディープラーニング
¥1,9142025/6/25時点)
4.3146件のレビュー)

# 期間限定いまなら 50% OFF! ディープラーニングの発展・応用手法を実装しながら学ぼう 本書ではディープラーニングの発展・応用手法を実装しながら学習していきます。ディープラーニングの実装パッケージとしてPyTorchを利用します。扱うタスク内容とディープラーニングモデルは次の通りで「ビジネスの現場でディープラーニングを活用するためにも実装経験を積んでおきたいタスク」という観点で選定しました。 [本書で学習できるタスク] 転移学習、ファインチューニング:少量の画像データからディープラーニングモデルを構築 物体検出(SSD):画像のどこに何が映っているのかを検出 セマンティックセグメンテーション(PSPNet):ピクセルレベルで画像内の物体を検出 姿勢推定(OpenPose):人物を検出し人体の各部位を同定しリンク GAN(DCGAN、Self-Attention GAN):現実に存在するような画像を生成 異常検知(AnoGAN、Efficient GAN):正常画像のみからGANで異常画像を検出 自然言語処理(Transformer、BERT):テキストデータの感情分析を実施 動画分類(3DCNN、ECO):人物動作の動画データをクラス分類 本書は第1章から順番に様々なタスクに対するディープラーニングモデルの実装に取り組むことで高度かつ応用的な手法が徐々に身につく構成となっています。各ディープラーニングモデルは執筆時点でState-of-the-Art(最高性能モデル)の土台となっており、実装できるようになればその後の研究・開発に役立つことでしょう。 ディープラーニングの発展・応用手法を楽しく学んでいただければ幸いです。

マトバオーの通常表情
マトバオー

今回登場した、セグメンテーションモデルについても載ってるよ。かなり見やすく書いてあって、自分の手で実装したものが動作する感動を味わえるよ。

蛇足

マトバオーの通常表情
マトバオー

一度作ったアプリをアップデートする方法のイメージはついたかな?ChatGPTが提案してきた機能が気に入らない場合はこうやってアップデートすることで改善していけるから、ぜひ挑戦して欲しい。ただし、今回の記事で言うと「SAM」みたいな知らないと指示ができないこともある。そういった部分は今後の記事でたくさん紹介していくので期待しててね!

猫の通常表情

それはいいけど、至急パソコンが火を噴かない方法を教えるにゃ。ちょっと怖かったにゃ。

関連キーワード

この記事をシェア