# ChatGPT・GPT Imageの背景透過が市松模様に：見分け方と直し方

> 色付きの背景に重ねても残る市松模様は、透過ではなく画像に描かれた模様です。APIはbackgroundの指定、ChatGPTは保存したファイルの確認で防げます。

- URL: https://blog.laozhang.ai/ja/posts/gpt-image-transparent-background-checkerboard
- Published: 2026-10-02
- Updated: 2026-10-02
- Author: LaoZhang AI Team (https://blog.laozhang.ai/ja/about)
- Category: 画像生成AI
- Tags: GPT Image 2.5, ChatGPT, 背景透過, 透過PNG, 市松模様, 画像生成API

---
ChatGPTやGPT ImageのAPIに背景透過を頼んで、白とグレーの市松模様が付いた画像が返ってきたとき、それが透過かどうかは見た目では決まりません。保存したファイルを赤や青など色の付いた背景に重ねて、下の色が見えれば本物の透過、市松模様がそのまま残れば、模様が絵として描き込まれた不透明な画像です。

本物の透過を得る方法は、作った入口で変わります。APIなら`background`に`transparent`を指定し、出力形式をPNGかWebPにします。ChatGPTの画面には透過の切り替えスイッチがなく、言葉で頼むしかないので、保存したファイルを毎回確かめる必要があります。すでに市松模様が描き込まれてしまった画像は、被写体の色がはっきりしていて輪郭が硬い素材なら後半のスクリプトで模様を消せますが、白っぽい被写体や髪の毛のような柔らかい輪郭では元の画像からやり直すほうが確実です。

以下に載せるスクリプト2本と数値は、Pillowで描いた合成画像をローカルで処理した結果です（Python 3.12.1、Pillow 12.0.0、macOS、2026年10月2日）。ChatGPTでの生成と有料のAPI呼び出しは行っていないため、ChatGPTやAPIの挙動についての記述は、OpenAIの公式ドキュメントとユーザーの報告に基づいています。APIのリクエスト例も、公式リファレンスの仕様に沿って書いたもので、実際のキーでは実行していません。

## 市松模様は2種類：透過の表示と、画像に描き込まれた模様

透過を意味する市松模様は片方だけです。もう片方は、透過に見えるように描かれた絵です。

1つ目は、画像編集ソフトやビューアーが透明な部分の後ろに敷いて見せる市松模様です。ファイルの中には存在せず、表示のための目印にすぎません。この画像を別の画像に重ねると、模様は消えて下の画像が見えます。

2つ目は、白とグレーの四角が画素として描かれている市松模様です。こちらはリンゴや文字と同じ「絵の一部」なので、どこに重ねても模様ごと載ります。「透明風」「偽物の透過」と呼ばれているのはこの状態です。

違いを決めているのはアルファチャンネルです。アルファチャンネルは、各画素が色とは別に持つ「透明度」の値で、0なら完全に透明、255なら完全に不透明です。本物の透過PNGは背景の画素のアルファが0になっています。描き込まれた市松模様の画像は、アルファチャンネルがないか、あっても全画素が255です。

モデルが市松模様を描いてしまう理由について、OpenAIは説明を公開していません。「学習した画像の中で、透過が市松模様として写っていたから」という説明がよく挙げられますが、これは利用者側の推測です。確かなのは、OpenAIのプロンプトガイドが「描かれた市松模様は透過ではない」と明記し、ファイルにアルファチャンネルがあるかを確認するよう求めていることです（[Image prompting guide](https://developers.openai.com/api/docs/guides/image-prompting)）。

## 本物か偽物かの見分け方：保存したファイルを色の上に重ねる

保存した元のファイルを、赤・青・緑など色の付いた背景の上に置きます。PowerPointやKeynoteのスライド、Canva、Figma、画像編集ソフトのレイヤーなど、背景色を変えられる場所ならどこでもかまいません。

| 重ねたときの見え方 | ファイルの状態 | 判定 |
| --- | --- | --- |
| 下の色が被写体のまわりに見える | 背景の画素が透明 | 本物の透過 |
| 白とグレーの市松模様が残る | 模様が画素として描かれている | 偽物。透過していない |
| 白や単色の四角い背景が残る | 背景が不透明な単色、または保存・変換の途中で透明度が失われた | 透過していない |

判定に使えないものが3つあります。

- **チャット画面やプレビューの見た目。** ChatGPTのプレビューが透過部分をどう表示するかは、公式ヘルプに記載がありません。画面上の市松模様が表示なのか絵なのかは、画面だけでは区別できません。
- **スクリーンショット。** スクリーンショットは画面に映った結果を新しい不透明な画像として保存します。本物の透過画像を撮っても、撮った画像には透過が残りません。
- **拡張子。** PNGやWebPは透明度を保存できる形式ですが、全画素が不透明なPNGも普通に存在します。`.png`で終わっていても透過の証拠にはなりません。

重ねて下の色が見えたら、次は輪郭を見ます。暗い色と明るい色の両方に重ね、白いふちや背景色の残りがないかを、髪、ガラス、影のまわりで確かめます。OpenAIのガイドも、アルファチャンネルの確認箇所として髪、ガラス、影、輪郭を挙げています。

## Pythonで判定する：アルファチャンネルを数えるスクリプト

枚数が多いときや、目で見て迷うときは、アルファチャンネルを直接数えれば結果が一つに決まります。次のスクリプトは、ファイルの実際の形式（拡張子ではなく中身）を読み、透明・半透明・不透明の画素の割合を出し、不透明なら外周が市松模様かどうかまで調べます。

```python
"""本物の透過と、描き込まれた市松模様を見分ける。

使い方: python check_transparency.py image.png [ほかのファイル...]
Pillowが必要です (pip install pillow)。
"""
import sys
from collections import Counter
from pathlib import Path

from PIL import Image


def border_pixels(rgb, ring=0.04):
    """画像の外周の細い枠にある画素。背景はたいていここにある。"""
    w, h = rgb.size
    t = max(2, int(min(w, h) * ring))
    px = rgb.load()
    for y in range(h):
        for x in range(w):
            if x < t or x >= w - t or y < t or y >= h - t:
                yield px[x, y]


def painted_checkerboard(rgb):
    """外周が、交互に並ぶ明るい無彩色2色でできていればTrue。"""
    w, h = rgb.size
    small = rgb.resize((min(w, 256), min(h, 256)), Image.NEAREST)
    tones = Counter()
    total = 0
    for r, g, b in border_pixels(small):
        total += 1
        if max(r, g, b) - min(r, g, b) <= 12 and min(r, g, b) >= 150:
            tones[round((r + g + b) / 3 / 8)] += 1  # 灰色を8刻みでまとめる
    if total == 0 or sum(tones.values()) / total < 0.85:
        return False  # 外周の大半が明るい灰色・白ではない
    buckets = sorted(tones)
    light = [b for b in buckets if tones[b] / total >= 0.15]
    if len(light) < 2 or (max(light) - min(light)) * 8 < 10:
        return False  # 1色だけ: ただの白背景か灰色背景
    # 2色が大きな塊ではなく、上端の行で交互に並んでいること。
    mid = (max(light) + min(light)) * 8 / 2
    row = [sum(small.getpixel((x, 1))) / 3 > mid for x in range(small.width)]
    flips = sum(1 for a, b in zip(row, row[1:]) if a != b)
    return flips >= 4


def check(path):
    with Image.open(path) as im:
        real_format, mode = im.format, im.mode
        rgba = im.convert("RGBA")  # パレット透過も本物のアルファチャンネルになる
    print(f"{path.name}: {real_format}, mode {mode}, {rgba.width}x{rgba.height}")
    if real_format not in ("PNG", "WEBP"):
        print(f"  透過なし: 中身は{real_format}で、透明度を保存できない形式です。")
        return "wrong-format"

    hist = rgba.getchannel("A").histogram()
    total = rgba.width * rgba.height
    clear, solid = hist[0], hist[255]
    partial = total - clear - solid
    print(f"  アルファ: 透明 {clear / total:.1%}、半透明 {partial / total:.1%}、不透明 {solid / total:.1%}")

    if clear == total:
        print("  空: すべての画素が透明です。")
        return "empty"
    if clear + partial == 0:
        if painted_checkerboard(rgba.convert("RGB")):
            print("  偽物: 透明な画素がなく、外周は2色の灰色の格子です。市松模様は描き込まれています。")
            return "painted-checkerboard"
        print("  不透明: 透明な画素がありません。背景は絵の一部です。")
        return "opaque"
    if clear == 0 and len([v for v in hist if v]) == 1:
        print("  全体が半透明: アルファ値が1種類だけです。不透明度が下がっただけで、切り抜かれていません。")
        return "faded"
    print("  本物: 透明な画素があります。次に、暗い背景と色付きの背景で輪郭を確認してください。")
    return "real"


if __name__ == "__main__":
    if len(sys.argv) < 2:
        sys.exit(__doc__)
    for name in sys.argv[1:]:
        check(Path(name))
```

`check_transparency.py`という名前で保存し、`pip install pillow`のあと`python check_transparency.py sticker.png`のように実行します。ファイルは複数並べて渡せます。描き込まれた市松模様の画像では、次のように出ます。

```text
painted-checkerboard.png: PNG, mode RGB, 512x512
  アルファ: 透明 0.0%、半透明 0.0%、不透明 100.0%
  偽物: 透明な画素がなく、外周は2色の灰色の格子です。市松模様は描き込まれています。
```

出力の3行目の先頭が判定です。

| 表示 | 意味 | 次にすること |
| --- | --- | --- |
| 本物 | 透明な画素がある | 暗い背景と色付きの背景で輪郭を確認する |
| 偽物 | 全画素が不透明で、外周が2色の明るい灰色の格子 | 作り直すか、後半の修復スクリプトを検討する |
| 不透明 | 全画素が不透明。白背景などの単色、または検出できない模様 | 透過していないので作り直す |
| 透過なし | 中身がJPEGなど、透明度を保存できない形式 | 保存・変換の経路を見直す |
| 全体が半透明 | 全画素が同じアルファ値。切り抜きではなく全体が薄くなっただけ | 作り直す |
| 空 | 全画素が透明 | 被写体まで消えている。作り直す |

### 合成画像10種での判定結果

Pillowで描いた512×512の合成画像10種（赤い円形の被写体に白いラベルを載せた図）にこのスクリプトをかけた結果、10種すべてが想定どおりに判定されました。

| 合成画像 | 判定 |
| --- | --- |
| アルファ付きPNG | 本物 |
| アルファ付きWebP | 本物 |
| パレット透過のPNG | 本物 |
| 市松模様を描いたPNG、RGB | 偽物 |
| 市松模様を描いたPNG、RGBAだが全画素が不透明 | 偽物 |
| 市松模様にぼかし・ノイズ・JPEG圧縮を加えてPNGに保存し直したもの | 偽物 |
| 白背景のPNG | 不透明 |
| 中身がJPEGで拡張子だけ`.png` | 透過なし |
| 全体を一律に半透明にしたPNG | 全体が半透明 |
| 全画素が透明のPNG | 空 |

この結果が示すのは、スクリプトの判定ロジックが合成画像に対して意図どおり動くことまでです。モデルが実際に描く市松模様は、マスの大きさが不揃いだったり、遠近や陰影が付いていたり、灰色が濃かったりすることがあり、その場合は「偽物」ではなく「不透明」と表示される可能性があります。どちらの表示でも「このファイルは透過していない」という結論は変わりません。

## 市松模様が出た原因を、作った入口ごとに切り分ける

原因は、生成、APIリクエスト、経由したサービス、保存・共有の4か所のどこかにあります。判定の結果と、画像を作った入口の組み合わせで、見るべき場所が決まります。

| 判定と状況 | 作った入口 | 疑う場所 | 次の手 |
| --- | --- | --- | --- |
| 市松模様が残る | ChatGPTの画面 | 生成。モデルが背景に模様を描いた | 元の画像か新しいチャットから、書き方を変えて頼み直す |
| 市松模様や白背景が残る | OpenAIのAPIを直接 | リクエスト。`background`を送っていない、または出力形式がJPEG | レスポンスの`background`と`output_format`を見る |
| 市松模様や白背景が残る | 中継APIやノーコードツール | 経路。パラメータが上流に渡っていない | 提供元のドキュメントで、そのモデル名が透過に対応しているか確認する |
| 作った直後は透過だったのに、あとで白背景になった | どれでも | 保存・共有。JPGへの変換、スクリーンショット、再圧縮 | 生成直後のファイルに戻り、PNGかWebPのまま渡す |
| 透過しているが、輪郭に白いふちが残る | どれでも | 輪郭の半透明部分 | 暗い背景で確認し、作り直すか編集ソフトで輪郭を整える |

![市松模様の原因を入口別に切り分ける図。ChatGPTの画面は生成、OpenAIのAPIはリクエスト、中継APIやノーコードツールは経路、あとで白背景になった場合は保存と共有を疑い、それぞれの次の手を示す](https://blog.laozhang.ai/posts/ja/gpt-image-transparent-background-checkerboard/img/checkerboard-cause-by-entry.webp)

以下、入口ごとの手順です。

## ChatGPTで背景透過を頼むときの書き方と、確認が要る理由

ChatGPTでは、指示の文章だけが手段です。OpenAIのヘルプは、ChatGPT Imagesが指示に従って「背景を透明にする」ことができると説明していますが、透過を切り替える設定や、保存されるファイル形式については記載がありません（[Images in ChatGPT](https://help.openai.com/en/articles/11084440-images-in-chatgpt)、2026年10月2日時点）。パラメータで固定できない以上、結果は毎回ファイルで確かめることになります。

OpenAIのプロンプトガイドがAPI向けに示している考え方は、ChatGPTでの書き方にもそのまま使えます。要点は3つです。被写体を単体で切り出すと書くこと、背景に描いてほしくないものを具体的に並べること、続けて編集するたびに透過の維持を書き直すことです。

```text
添付したキャラクターだけを切り出した、背景が透明なPNG素材を作ってください。
- 被写体は1体だけ、中央に、周囲に余白を取る
- 背景の画素は実際に透明にする（アルファチャンネル付き）
- 市松模様、白やグレーの単色背景、風景、床、落ち影、枠、文字は描かない
- キャラクターの顔、色、線は元の画像から変えない
```

「透過していることが分かるように」「透明部分を市松模様で」といった言い方は避けます。模様を描く方向の指示として読まれるおそれがあるからです。

うまくいかなかったという報告は実際にあります。OpenAI Developer Communityのスレッド（2026年5〜6月、GPT Image 2の時期）では、ChatGPTが返した画像について「市松模様が画像に焼き込まれていて、本物のアルファチャンネルの透過ではなかった」という投稿があり、同じスレッドには本物の透過や部分的な透過が得られたという投稿もあります（[スレッド](https://community.openai.com/t/having-trouble-getting-transparent-backgrounds-in-chatgpt-images/1380143)）。日本語のnoteやXにも「消えない市松模様」「市松模様の背景にして騙してきた」といった体験談があります。これらは失敗が起こりうることを示す報告で、ChatGPT Images 2.5で現在どのくらいの割合で起きるかを示すデータは公開されていません。

失敗した画像に「市松模様を消して」と頼むのは勧められません。それはもう一度の生成的な編集で、被写体ごと描き直されることがあります。OpenAIのガイドも、編集を繰り返すと残したかった細部が変わりうると注意しています。頼み直すなら、市松模様が付く前の元画像に戻るか、新しいチャットで最初から頼みます。ChatGPTのどこで画像を作成・編集するかは「[ChatGPT Images 2.5の使い方：SunburstとFlareはどこで選べる？](https://blog.laozhang.ai/ja/posts/chatgpt-images-2-5)」にまとめています。

## APIではbackgroundをtransparentに、出力形式はPNGかWebPに

APIでは、透過はプロンプトではなくパラメータで指定します。OpenAIの[APIリファレンス](https://developers.openai.com/api/reference/resources/images/methods/generate)（2026年10月2日時点）によると、`background`は`transparent`、`opaque`、`auto`のいずれかで、既定値は`auto`です。`auto`では背景をどうするかをモデルが決めます。プロンプトに「背景透過」と書いても、`background`を送っていなければ`auto`のままで、パラメータを設定したことにはなりません。

対応状況は次のとおりです。

| モデル | 透明背景 |
| --- | --- |
| `gpt-image-2.5-sunburst`、`gpt-image-2.5-flare`（2026-09-08のスナップショットを含む） | 対応 |
| `gpt-image-2`、`gpt-image-2-2026-04-21` | プレビューとして対応 |

`transparent`を使うときは、出力形式を`png`か`webp`にする必要があります。`jpeg`は透明度を保存できません。リファレンスは、透過を特定のサイズや品質設定と結びつけてはいません。編集のエンドポイント（`/images/edits`）でも同じ指定が使えます。

リクエストの形は次のようになります。公式リファレンスの仕様に沿って書いた例で、実際のキーでは実行していません。GPT Imageのモデルは、利用前にAPIの組織認証（Organization Verification）が必要な場合があります。

```bash
curl -s https://api.openai.com/v1/images/generations \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-image-2.5-flare",
    "prompt": "赤いマグカップ1個だけを切り出した商品素材。背景は透明。市松模様、単色背景、風景、影は描かない。",
    "background": "transparent",
    "output_format": "png"
  }' > response.json

# 画像を開く前に、実際に使われた設定を確認する
jq '{background, output_format}' response.json

# Base64の画像をファイルに戻して、アルファチャンネルを確認する
jq -r '.data[0].b64_json' response.json | base64 --decode > mug.png
python check_transparency.py mug.png
```

確認の順番は2段階です。

1. **レスポンスのフィールド。** リファレンスによると、レスポンスには生成に使われた`background`（`transparent`か`opaque`）と`output_format`（`png`、`webp`、`jpeg`）が入ります。ここが`opaque`や`jpeg`なら、画像を開くまでもなく透過ではありません。リクエストのどこかで指定が落ちています。
2. **保存したファイルのアルファチャンネル。** フィールドが`transparent`でも、OpenAIのガイドはデコードした画像のアルファチャンネルを確認するよう求めています。前の節のスクリプトで「本物」と出ることを確かめます。

GPT Imageのモデルは画像を常にBase64で返します。デコードして保存するときに、途中でJPEGに変換するライブラリや設定を挟まないようにします。PNGでは`output_compression`を指定しません。このパラメータはJPEGとWebPだけのものです。

パラメータと合わせて、プロンプトにも被写体を単体で切り出すことと、市松模様・単色背景・風景・影を描かないことを書きます。編集を続ける場合は、リクエストのたびに`background`を指定し直し、プロンプトにも透過の維持を書きます。

「GPT Imageは背景透過に非対応」と書いている記事があるのは、時期の違いです。2026年8月より前、OpenAIのドキュメントは`gpt-image-2`が透明背景に対応していないとしていました。その後`gpt-image-2`がプレビューとして対応し、2026年9月のGPT Image 2.5では2モデルともプレビューの但し書きなしで対応しています。2モデルの選び方は「[GPT Image 2.5 FlareとSunburstの違い](https://blog.laozhang.ai/ja/posts/gpt-image-2-5-sunburst-vs-flare)」を参照してください。

## 中継API経由でbackgroundが効かないときは経路を確認する

同じモデル名でも、リクエストがどの経路を通るかで`background`の扱いが変わります。ここでいう中継APIは、OpenAIのAPIを直接呼ぶ代わりに、別の事業者のエンドポイントを経由して同じモデルを使うサービスのことで、ゲートウェイ、プロキシ、APIアグリゲーターとも呼ばれます。ノーコードツールのノードも、パラメータを通すかどうかという点では同じ問題を持ちます。

経路で差が出る具体例として、LaoZhang APIの[GPT Image 2.5のドキュメント](https://docs.laozhang.ai/en/api-capabilities/gpt-image-2-5)（2026年9月24日時点の公開価格）は、3種類の経路を分けて書いています。

| 経路とモデル名 | 透過出力の扱い | 課金 |
| --- | --- | --- |
| `gpt-image-2.5-flare-vip`、`gpt-image-2.5-sunburst-vip` | `"background": "transparent"`と`"output_format": "png"`で透過PNGを出力できると記載 | 1回$0.03 |
| `gpt-image-2.5-flare`、`gpt-image-2.5-sunburst`（公式転送） | OpenAIのパラメータに従う | OpenAIの単価でトークン課金 |
| `gpt-image-2.5-web` | 対応パラメータは保証されず、`-vip`の指定が使えると想定しないよう記載 | 1回の定額 |

つまり、リクエストに`background`を書いていても、それを保証していない経路では白背景や描かれた市松模様が返る余地があります。これはどの事業者でも同じで、次の3点を確認します。

- 使っているモデル名について、提供元のドキュメントが`background`への対応を明記しているか
- レスポンスに`background`と`output_format`が含まれているか。中継サービスがこの2つのフィールドをそのまま返すかどうかは事業者によって異なり、含まれていなければファイルで判断する
- 保存したファイルが判定スクリプトで「本物」になるか

1回ごとの定額で透過出力を使いたい場合、上の`-vip`の2モデルは選択肢になります。ただし有料の呼び出しによる確認はしていないので、最初の1枚で必ずファイルを判定してください。同じドキュメントによると、この2モデルはマスクによる部分編集には対応しておらず、2026年9月16日から22日まで利用できない期間がありました。費用の比較は「[GPT Image 2.5 Sunburstの料金：公式単価と1回$0.03のAPIを比較](https://blog.laozhang.ai/ja/posts/gpt-image-2-5-api-pricing)」にあります。

n8nでは、標準のOpenAIノードから`background`を送れないため、HTTP Requestノードで直接リクエストを組み立てます。手順は「[n8nでGPT Image 2.5：ノードとHTTPの使い分け](https://blog.laozhang.ai/ja/posts/gpt-image-2-5-n8n)」を参照してください。

## 保存や共有で透過が消える：JPG変換・スクショ・再圧縮

生成直後のファイルが本物の透過でも、そのあとの扱いで透過は失われます。作った直後は透けていたのに、渡した先で白背景になっている場合は、次のどれかを疑います。

- **JPGへの変換。** JPEGにはアルファチャンネルがなく、変換すると透明な部分は単色で塗りつぶされます。「容量を減らすためにJPGで書き出す」設定や、自動で変換するアプリに注意します。
- **スクリーンショットやコピー。** 画面を撮った画像は不透明な新しい画像です。透過素材は、保存ボタンでダウンロードしたファイルそのものを使います。
- **アップロード先での再圧縮。** チャットアプリやSNS、サイトの投稿画面は、アップロードされた画像を再圧縮したりJPEGに変換したりすることがあります。サービスごとの挙動は異なるので、相手が受け取ったファイルを判定してもらうか、ファイル転送やクラウドストレージのように中身を変えない方法で渡します。

渡す直前にもう一度判定スクリプトをかけるか、色付きの背景に重ねて確かめておくと、どの段階で消えたかが分かります。グッズや印刷の入稿データは、入稿先が指定する形式と解像度に従ってください。渡すファイル形式の選び方は「[透過PNGの作り方：素材で選ぶ方法と保存後の確認](https://blog.laozhang.ai/ja/posts/transparent-image-maker)」で扱っています。

なお、透過を目的としていない画像の表面に細かい格子が浮く現象は、ここで扱っている問題とは別のものです。そちらは「[GPT Image 2.5のざらつき・市松模様の対処法](https://blog.laozhang.ai/ja/posts/gpt-image-2-5-noise-grainy)」を参照してください。

## 焼き込まれた市松模様を消すスクリプトと、救えない画像

描き込まれた市松模様は、条件が合えばあとから本物の透過に変えられます。条件は、被写体の色がはっきりしていること、輪郭が硬いこと、市松模様が白と明るい灰色であることです。次のスクリプトは、画像の外周から明るい無彩色の画素をたどって透明にしていきます。外周とつながっている部分にしか届かないので、被写体に囲まれた白（目、歯、ラベルなど）は残ります。

```python
"""描き込まれた明るい灰色・白の市松模様を、本物の透過に変える。

使い方: python remove_painted_checkerboard.py fake.png fixed.png
Pillowが必要です (pip install pillow)。

画像の外周から、明るい無彩色の画素をたどって塗りつぶす。
外周とつながっている背景にしか届かないので、被写体に囲まれた白
（目、歯、ラベル）は残る。白や明るい灰色の被写体の輪郭は格子と
区別できず、ぼけた輪郭には明るい縁が細く残る。
"""
import sys
from collections import deque

from PIL import Image

src, dst = sys.argv[1], sys.argv[2]
im = Image.open(src).convert("RGBA")
w, h = im.size
px = im.load()


def is_grid(p):
    r, g, b, _ = p
    return max(r, g, b) - min(r, g, b) <= 14 and min(r, g, b) >= 170


seen = bytearray(w * h)
queue = deque()
for x in range(w):
    queue.append((x, 0))
    queue.append((x, h - 1))
for y in range(h):
    queue.append((0, y))
    queue.append((w - 1, y))

removed = 0
while queue:
    x, y = queue.popleft()
    i = y * w + x
    if seen[i]:
        continue
    seen[i] = 1
    if not is_grid(px[x, y]):
        continue
    px[x, y] = (0, 0, 0, 0)
    removed += 1
    if x > 0:
        queue.append((x - 1, y))
    if x < w - 1:
        queue.append((x + 1, y))
    if y > 0:
        queue.append((x, y - 1))
    if y < h - 1:
        queue.append((x, y + 1))

im.save(dst)
print(f"画素の{removed / (w * h):.1%}を透明にしました -> {dst}")
```

`python remove_painted_checkerboard.py fake.png fixed.png`のように、元のファイルと出力先を渡します。元のファイルは上書きされません。

### 合成画像での修復結果と、被写体が消える境界

合成画像での結果は次のとおりです。被写体は赤い円形で、中に白いラベルがあります。

| 合成画像 | 背景のうち透明になった割合 | 被写体の欠損 | 囲まれた白いラベル | 修復後の判定 |
| --- | --- | --- | --- | --- |
| きれいな市松模様 | 100.0% | 0% | 100%残った | 本物 |
| ぼかし・ノイズ・JPEG圧縮を加えた市松模様 | 99.63% | 0% | 100%残った | 本物 |
| 白に近い被写体が市松模様に接している | — | 100%が消えた | — | — |

![合成画像での修復結果の比較図。きれいな市松模様とぼかしやノイズを加えた市松模様では赤い被写体と白いラベルが残り、白に近い被写体は修復後にすべて消える](https://blog.laozhang.ai/posts/ja/gpt-image-transparent-background-checkerboard/img/checkerboard-repair-boundary.webp)

3行目が失敗の境界です。被写体が白や明るい灰色で、市松模様と直接つながっていると、スクリプトは被写体を背景と区別できず、被写体ごと透明にします。白い服、白い動物、白い商品、銀色の金属などが当てはまります。

もう一つの限界は輪郭です。修復後の画像には半透明の画素がありません（0%）。画素は透明か不透明かの二択になるので、輪郭は硬くなり、髪の毛、毛並み、ガラス、ぼけた影のような柔らかい境界は再現できません。ぼけた輪郭には明るい縁が細く残ることもあります。

この結果も合成画像でのものです。モデルが描いた市松模様で灰色が濃い場合や、模様に陰影が付いている場合は、しきい値に入らない画素が残ります。修復後は必ず暗い背景に重ねて、残った画素と輪郭を目で確認してください。

どの手段を選ぶかは、素材で決まります。

| 素材 | 向いている手段 |
| --- | --- |
| ベタ塗りのロゴ、アイコン、輪郭のはっきりしたステッカーで、被写体に白や明るい灰色の外周がない | 上のスクリプトで修復 |
| 白っぽい被写体、髪や毛、ガラス、半透明、影を残したい素材 | 市松模様が付く前の元画像に戻り、透過を指定して作り直す |
| 元画像がなく、被写体を1画素も変えたくない | 選択範囲で背景を消すツールを使う。生成的な編集は被写体が変わることがある |

手元の写真やロゴを画像編集ソフトやオンラインツールで背景透過にする方法は、「[透過PNGの作り方：素材で選ぶ方法と保存後の確認](https://blog.laozhang.ai/ja/posts/transparent-image-maker)」にまとめています。

## ChatGPTの背景透過と市松模様のQ&A

### ChatGPTで画像の背景を透過するにはどうすればいいですか？

画像を添付するか生成したうえで、被写体だけを切り出すこと、背景の画素を実際に透明にすること、市松模様や単色背景や影を描かないことを文章で指示します。ChatGPTには透過を固定する設定がないため、保存したファイルを色付きの背景に重ねて、下の色が見えるかを確かめてください。市松模様が残ったら、その画像に修正を重ねず、元の画像から頼み直します。

### ChatGPTの画面に市松模様が見えれば透過PNGですか？

画面の見た目だけでは判断できません。透明部分の表示としての市松模様と、絵として描かれた市松模様は、画面上では同じに見えます。ChatGPTのプレビューが透過をどう表示するかも公式ヘルプには書かれていません。保存したファイルを色付きの背景に重ねるか、判定スクリプトでアルファチャンネルを確認してください。

### APIでtransparentを指定しても白背景になるのはなぜですか？

白背景でも市松模様でも、まずレスポンスの`background`と`output_format`を見ます。`opaque`や`jpeg`になっていれば、指定がモデルまで届いていません。中継APIやノーコードツールを経由している場合は、そのモデル名や経路が`background`に対応しているかを提供元のドキュメントで確認します。フィールドが`transparent`なのにファイルが不透明な場合は、デコードや保存の途中でJPEGに変換していないかを調べます。

### 透過PNGを送ったら、相手の画面では白背景になっていたのはなぜですか？

送る途中でファイルが変わった可能性があります。チャットアプリやSNSは画像を再圧縮したりJPEGに変換したりすることがあり、JPEGは透明度を保存できません。スクリーンショットで渡した場合も同じです。生成直後のファイルを、中身を変えない方法で渡してください。
