はじめに
Geminiなどの生成AI画像には、右下に半透明の可視ウォーターマークが入ることがあります。この記事では、それを単なる「邪魔なロゴ」としてではなく、画像処理の問題として見たときにどう整理できるかをメモします。
参考にしたのは Allen Kuo さんの次の記事です。
Removing Gemini 3.5 AI Watermarks from Images & Veo Videos: A Deep Dive into Reverse Alpha Blending
自分でもブラウザで触れる形の実験用UIを用意しています。
この記事は技術メモです。自分が権利を持つ画像、または利用許諾のある画像だけを対象にしてください。可視ウォーターマークを消しても、画像に含まれる来歴情報や不可視の透かしまで消えるとは限りません。
問題を「合成の逆問題」として見る
半透明のロゴは、多くの場合 alpha blending で合成されています。1ピクセル単位で見ると、ざっくり次の式です。
C_obs = alpha * C_logo + (1 - alpha) * C_bg
- C_obs: 実際に見えている画素
- C_logo: ロゴ側の画素
- C_bg: 元画像側の画素
- alpha: 透明度
知りたいのは C_bg です。C_logo と alpha が分かっているなら、式を変形できます。
C_bg = (C_obs - alpha * C_logo) / (1 - alpha)
つまり、ウォーターマーク除去は必ずしも「周囲からそれっぽく塗る」だけではなく、合成された式を逆向きに解く問題として扱えます。
JavaScriptで書くとこうなる
実装の核だけを抜き出すと、このくらい単純です。
const clamp8 = (v: number) => Math.max(0, Math.min(255, Math.round(v)));
function reverseAlphaBlend(observed: number, logo: number, alpha: number) {
if (alpha <= 0) return observed;
if (alpha >= 0.98) return observed;
return clamp8((observed - alpha * logo) / (1 - alpha));
}
RGBなら各チャンネルに同じ処理をかけます。
type RGB = { r: number; g: number; b: number };
function restorePixel(obs: RGB, logo: RGB, alpha: number): RGB {
return {
r: reverseAlphaBlend(obs.r, logo.r, alpha),
g: reverseAlphaBlend(obs.g, logo.g, alpha),
b: reverseAlphaBlend(obs.b, logo.b, alpha),
};
}
実際にはここに、ロゴ位置、alpha map、色空間、JPEG圧縮、リサイズ後のズレなどが乗ってきます。式は簡単でも、プロダクトで安定させる部分はそこからです。
alpha mapが少しズレるだけで破綻する
reverse alpha blending の面白いところは、ハマるとかなり正確なのに、前提が少し崩れるとすぐ残像が出ることです。
たとえば次のようなケースです。
- ウォーターマーク位置が数pxずれている
- 画像がSNSやスクショ経由でリサイズされている
- JPEG再圧縮で境界付近の値が変わっている
- ロゴのalpha profileがバージョンごとに違う
この場合、式自体は正しくても、入力している alpha や C_logo が間違っているので、結果として薄い影や反転したような跡が残ります。
ここで単純な全面インペイントをすると、背景の細部までぼけやすくなります。個人的には、まず数学的に戻せる部分を戻し、残ったエッジだけを小さく補正する設計が扱いやすいと感じました。
Web UIに落とすときの設計
Webアプリとして触れる形にすると、CLIツールとは別の制約があります。
- ユーザーは必ずしも対象位置を正確に知らない
- 画像サイズや圧縮状態がかなりバラバラ
- ブラウザ上では処理時間とメモリを抑えたい
- 失敗時に「どこが対象領域だったか」を見せる必要がある
そのため、UIとしては次の流れが分かりやすいです。
- 画像を読み込む
- 自動検出できる場合は候補領域を出す
- うまく検出できない場合はユーザーがブラシや矩形で領域指定する
- reverse alpha blending または inpainting 系の処理を適用する
- 処理前後を比較してダウンロードする
自分のサイトでは、より一般的なケースにも使えるように、領域指定とAI補完寄りのUIにしています。
実装時に気をつけたい点
1. alphaが1に近い画素は不安定
1 - alpha で割るため、alphaが1に近いと値が暴れます。実用上は閾値を置いて、無理に復元せず別処理に回すほうが安全です。
2. sRGBとlinear RGBを混ぜない
どの色空間で合成されたかによって逆算結果が変わります。ブラウザのCanvasで扱うなら、まずはsRGB前提で実装し、結果を見ながら調整するのが現実的でした。
3. 全領域をAIで塗らない
AI補完は便利ですが、背景のディテールも変えてしまいます。alpha mapのエッジや残像が出やすい部分だけにマスクを作り、そこだけ補正するほうが自然です。
4. 失敗時の見せ方も重要
画像処理は100%成功しません。失敗時に「処理対象の範囲」「処理前後の差分」「やり直しやすい操作」を見せるだけで、ユーザーの体験はかなり変わります。
まとめ
Geminiのような半透明ウォーターマークは、画像処理として見ると alpha blending の逆問題として整理できます。
- ロゴ画像とalpha mapが分かるなら、式で逆算できる
- 位置や透明度がズレると残像が出る
- リサイズや再圧縮後は、数学的復元だけでは足りないことがある
- Web UIでは自動検出だけでなく、手動指定と失敗時の再調整が大事
単に「消す」ではなく、どこまでを数式で戻し、どこからを補完で扱うかを分けると、実装の見通しがかなり良くなりました。