AI 画像鑑識
使用するタイミング
ユーザーが「この画像はAI生成か?加工されているか?他人が使った画像か?」と尋ねた場合、または複数の画像(受領写真、レビュー画像、素材画像)を一括審査する場合に使用します。
コマンド一例
python3 scripts/probe.py 画像パス... # メタデータ層のみ実行
python3 scripts/probe.py --dir ディレクトリ --lib 画像ライブラリパス # 重複チェックを含む
python3 scripts/probe.py --dir ディレクトリ --model <重みディレクトリ> # ピクセル層を含む(オプション)
出力は4段階の結果です。NO-EVIDENCE を「本物の画像」と表現しないでください。
| 結果 | 意味 | できること |
|---|---|---|
AI-SIGNED | AIGC国内規格識別子またはC2PA証明書あり | そのまま信頼できる。生成元の自己証明。 |
AI-LIKELY | 生成器の指紋あり、またはピクセルモデルが高スコア | 手がかりとしてのみ利用。人間による確認が必要。 |
DUPLICATE | 画像ライブラリ内のいずれかの画像とのpHash距離が10以下 | 重複と判定可能。 |
NO-EVIDENCE | 3層すべてで手がかりなし | 「本物」とは言えず、「証拠なし」としか言えない。 |
3層の実際の能力(ローカルテストに基づく。イメージで約束しないこと)
第1層 メタデータ——最も正確で、最も安価(ミリ秒単位、純Python)。
- 国内で準拠して生成された画像には、TC260 AIGC 暗黙的識別子が含まれます:
{"AIGC":{"Label":"1","ContentProducer":...,"ProduceID":...,"ReservedCode1":"...sm3...sm2..."}}。これはPNGのeXIfチャンクのUserComment(0x9286)に格納されることが多く、tEXtにはありません。そのため、テキストブロックのみをスキャンするツールでは見落とされます。 - ただし、一度再保存すると失われます:PillowでJPGやPNGとして保存し直すと、これらのフィールドは消えます。そのため、この層は「元画像とそのまま転送された画像」のみを検出でき、「スクリーンショットや加工済み画像」は検出できません。
- カメラ機器の
Make/Model/DateTimeOriginalが存在する場合、その画像はカメラから直接出力されたものです。すべて空の場合は、ソーシャルプラットフォームで処理されたか、スクリーンショットである可能性が高いです。
第2層 重複チェック——pHash + dHash、20ミリ秒/画像。
- プラットフォームでの圧縮、リサイズ、スクリーンショット:距離0〜2、ほぼ影響なし。
- 7.5%の端を切り抜いた場合:距離8〜24、一部を見逃す可能性あり。
- 異なる画像間の最小距離は24。そのため、しきい値を10に設定するのは安全です。
第3層 ピクセルモデル——低速で不安定。必要な場合のみ使用。
- Community-Forensics ViT-S/384(CVPR 2025):CPUで1画像あたり0.2〜0.6秒。訓練分布内の古い生成器には非常に有効(DALL·E 2の公式テスト画像5枚すべてを識別)。ただし、新しい生成器には全く無効(同一人物が2026年生成の画像7枚をテストした結果、すべてを本物と判定、信頼度は0.0000〜0.0019)。
- そのため、ピクセル層の信頼範囲は「ヒットした場合にのみ意味がある。ヒットしなければ何も意味しない」です。
- 重みはリポジトリに含まれていません。最初に
OwensLab/commfor-model-384(Hugging Face、87MB)をダウンロードし、models/commfor384/に配置する必要があります。
3つのモデルの役割(間違えないこと)
| スクリプト | モデル | 入力として適切なもの | 絶対に入力してはいけないもの |
|---|---|---|---|
scripts/run_commfor.py | ViT-S/16 384(CVPR'25 汎用生成画像識別) | 汎用生成画像、デフォルト --size 384 | 224用の重みを使用しないこと。テストした同一画像群で5枚中3枚しか識別できなかった。 |
scripts/run_raiw.py | RAIW source-classify(10メーカー + unknown) | 「どのメーカーが生成したか」を知りたい場合 | 識別器として使用しないこと。テストした17枚すべてが棄権した。 |
scripts/run_xai.py | EfficientNetV2-B0 5クラス分類(FF++ 顔変換) | 顔画像のみ | 商品画像や受領写真。テストした10枚の本物画像のうち5枚を誤判定した。 |
python3 scripts/run_commfor.py 画像.jpg --size 384 --weights /path/model.safetensors
python3 scripts/run_raiw.py 画像.jpg --weights /path/multi-provider-source-v3.npz
python3 scripts/run_xai.py 顔画像.jpg --weights /path/ff_attribution.ckpt
3つのスクリプトはすべて --weights で重みを指定可能、--out でファイル出力可能(指定しない場合は標準出力のみ)。重みの検索順序は統一して:
--weights > 環境変数 > scripts/../models/<モデル名>/。重みはリポジトリに含まれていません。自分でダウンロードする必要があります:
| モデル | 入手先 | サイズ |
|---|---|---|
| commfor384 | HF OwensLab/commfor-model-384 | 87 MB |
| commfor224 | HF OwensLab/commfor-model-224 | 86 MB |
| RAIW | HF wiltodelta/raiw-source-classify | 2.03 GB |
| XAI-Deepfakes | リポジトリ内 model/checkpoint/ff_attribution.ckpt | 70 MB |
国内からダウンロードする場合はミラー追加:HF_ENDPOINT=https://hf-mirror.com。大容量ファイルは aria2c -x16 -s16 を使用。
ユーザーに手動でダウンロードコマンドを組ませないこと。 既製のスクリプトがあります(デフォルトでhf-mirror、aria2cマルチスレッド、ダウンロード後にファイルサイズとSHA256を検証):
python3 scripts/fetch_weights.py --list # 一覧 + 現在の状態
python3 scripts/fetch_weights.py commfor384 # 87 MB、ピクセル層のみ実行するならこれで十分
python3 scripts/fetch_weights.py --all --jobs 16 # 4つすべてダウンロード、合計2.2 GB
python3 scripts/fetch_weights.py --all --check # 既存ファイルのみ検証
スクリプトはレジューム対応。プロキシによって中断されたファイルは、ファイルサイズ + SHA256 で検出されます(実際に発生:GitHub tarball で70MBのckptが不足し、解凍時に failed finding central directory エラーが発生)。ダウンロード完了後は models/<モデル名>/ に配置され、3つの run_*.py のデフォルト検索パスと一致するため、--weights を指定する必要はありません。
ダウンロードができない場合は、どの手順で停止したかを明確に伝えること。 「理論上は可能」という言葉で実際のテスト結果を代替しないこと。
出力イメージ(この形式で回答すること)
probe.py の実際の出力、3つの段階の各例:
samples/ai/スマホで撮影した宅配便倉庫棚.png -> AI-SIGNED
理由:ファイル内にAIGC準拠識別子あり(Label=1)、生成元の自己証明
メタデータ:aigc_label | 形式 PNG 1024x1536
samples/variants/real01__p75.jpg -> DUPLICATE
理由:real01.jpg との知覚ハッシュ距離 0、しきい値 10
メタデータ:肯定マークなし | 形式 JPEG 1280x853
重複:最近傍 real01.jpg 距離 0 ≤10 で重複と判定
samples/real/real02.jpg -> NO-EVIDENCE
理由:3層とも識別子なし。これは本物の画像を意味しない。業務側で別の証拠を探す必要あり。
メタデータ:肯定マークなし | 形式 JPEG 4500x3000
ユーザーに伝える際は、結果段階は大文字のまま出力すること。「AIの疑い」などの曖昧な表現に翻訳しないこと。理由の行は書き換えず、判定根拠としてそのまま伝えること。NO-EVIDENCE の後には「これは本物の画像を意味しません」と必ず付け加え、誤解を防ぐこと。
しきい値クイックリファレンス
| 判定基準 | しきい値 | 根拠 |
|---|---|---|
| pHash 重複判定 | ≤10 | 異なる画像間の最小距離は24、十分な余裕あり |
| ピクセル p_fake | >0.6 のみ手がかりとして扱う | 0.1〜0.6 の範囲は基本的にノイズ |
| AIGC識別子 | 存在すればヒット | 標準フィールド、しきい値なし |
3つの限界(ユーザーに必ず伝えること)
- 識別子がない ≠ 本物の画像。 一度保存し直すだけで消える。クリップボード、WeChat転送、スクリーンショットですべて消える。
- ピクセルモデル単独で断定してはいけない。 未知の生成器に対しては効果がゼロになり、本物の画像を誤判定することもよくある(テストでは、iPhoneで撮影した段ボール箱の画像を384版モデルが0.896のスコアでAI生成と判定)。
- 追跡可能にするには業務上の手段を取る必要がある: アップロード時に元画像のバイトハッシュを保存、デバイス指紋を記録、同一注文の履歴画像を比較する。これらはどの検出モデルよりも信頼性が高い。
反面教師
image-provenance(クライアントサイドWebツール):見た目は良く、周波数領域分析も完全だが、ソースコードにAIGC/TC260関連のキーワードが一切なく、中国の準拠識別子を完全に無視。また、メタデータ解析はCDN経由でexifrを読み込むため、オフラインではバイトレベルヒューリスティックに退化する。実際に完全なAIGC識別子を持つ画像を解析させたところ、「AIソース証明書を発見できませんでした」と表示した。XAI-Deepfakes:顔変換(FaceForensics++)マルチクラス分類器で、顔のみを認識する。宅配便受領写真を入力すると、10枚の本物画像のうち5枚がFace2Face/DeepFakes/NeuralTexturesと誤判定される。LAID:アーキテクチャは非常に軽量(ShuffleNet 0.34Mパラメータ、CPU 20ms)だが、重みがGoogle Driveにあるため、国内からダウンロードできない。