画像の差分比較手法 - ピクセル単位からセマンティック比較まで
画像差分比較の用途と重要性 - なぜ画像を比較するのか
画像の差分比較は、2 枚の画像間の違いを検出・定量化・可視化する技術です。単純に見えるこの処理は、実際には多くの分野で重要な役割を果たしています。
ビジュアルリグレッションテスト: Web 開発において、コード変更が UI の見た目に意図しない影響を与えていないかを自動検証します。CSS の変更やライブラリのアップデート後に、スクリーンショットを比較して視覚的な回帰を検出します。Chromatic、Percy、BackstopJS などのツールがこの用途に特化しています。
品質管理: 製造業では、製品の外観検査に画像比較が使用されます。基準画像と撮影画像を比較し、傷、汚れ、色ムラなどの欠陥を自動検出します。半導体のウェハー検査や食品の外観検査など、高速かつ高精度な判定が求められる場面で活躍します。
医療画像解析: MRI や CT スキャンの経時変化を追跡し、腫瘍の成長や治療効果を定量的に評価します。過去の画像と現在の画像を正確に位置合わせ (レジストレーション) した上で差分を抽出する高度な技術が使われます。
衛星画像解析: 異なる時期に撮影された衛星画像を比較し、都市の拡大、森林の減少、災害の被害範囲などを検出します。変化検出 (Change Detection) と呼ばれるこの分野は、リモートセンシングの中核技術です。
著作権保護: 画像の無断使用や改変を検出するために、オリジナル画像との類似度を計算します。リサイズ、トリミング、フィルター適用などの加工を経ても同一画像を特定できる堅牢な比較手法が求められます。
ピクセル単位の差分比較 - 最もシンプルなアプローチ
最も基本的な画像比較手法は、対応するピクセル同士の色値を直接比較する方法です。実装が簡単で高速ですが、人間の知覚とは異なる結果を返す場合があります。
絶対差分 (Absolute Difference):
2 枚の画像の各ピクセルについて、RGB 各チャンネルの差の絶対値を計算します。数式で表すと diff(x,y) = |A(x,y) - B(x,y)| です。差分画像を生成すると、変化のあった箇所が明るく表示されます。閾値を設定し、差分が閾値を超えるピクセルを「変化あり」と判定します。
平均二乗誤差 (MSE: Mean Squared Error):
全ピクセルの差分の二乗平均を計算します。画像全体の差異を 1 つの数値で表現できるため、比較結果の定量化に便利です。ただし、MSE が同じでも人間の目には全く異なる印象を与える場合があります。例えば、全体的にわずかに明るくなった画像と、一部に大きなノイズが入った画像は、MSE が同じでも知覚的な差は大きく異なります。
PSNR (Peak Signal-to-Noise Ratio):
MSE を対数スケールに変換した指標で、単位は dB です。PSNR = 10 * log10(MAX^2 / MSE) で計算します。値が大きいほど画像が類似していることを示します。一般的に 30dB 以上であれば人間の目には差が分かりにくく、40dB 以上であればほぼ同一と見なせます。画像圧縮の品質評価で広く使用されていますが、知覚的な品質との相関は完全ではありません。
ピクセル比較の限界:
1 ピクセルのずれ (アンチエイリアシングの差異、サブピクセルレンダリングの違い) でも大きな差分として検出されるため、ビジュアルリグレッションテストでは偽陽性 (false positive) が多発します。この問題を解決するために、後述する構造的・知覚的な比較手法が開発されました。
構造的類似度 (SSIM) - 人間の視覚特性を考慮した比較
SSIM (Structural Similarity Index Measure) は、人間の視覚システムの特性を考慮して設計された画像品質評価指標です。2004 年に Wang らによって提案され、現在最も広く使用される画像品質指標の 1 つです。
SSIM の 3 つの比較要素:
- 輝度 (Luminance): 画像の平均明るさの比較。人間の目は絶対的な明るさよりも相対的な明るさの変化に敏感です。
- コントラスト (Contrast): 画像の標準偏差 (明暗の振幅) の比較。コントラストの変化は画像の印象を大きく左右します。
- 構造 (Structure): 正規化された画像パターンの相関。エッジやテクスチャなど、画像の構造的な情報を比較します。
SSIM の値は -1 から 1 の範囲で、1 が完全一致を示します。一般的に 0.95 以上であれば視覚的にほぼ同一、0.90 以上であれば高品質、0.80 未満であれば明確な劣化が認識されます。
MS-SSIM (Multi-Scale SSIM):
SSIM を複数のスケール (解像度) で計算し、統合する拡張版です。人間の視覚は画像を複数の解像度で同時に処理しているため、MS-SSIM は SSIM よりも知覚的な品質との相関が高いとされています。画像を段階的にダウンサンプリングし、各スケールで SSIM を計算して重み付き積で統合します。
実装例:
Python では scikit-image ライブラリの structural_similarity 関数で簡単に計算できます。from skimage.metrics import structural_similarity as ssim; score, diff = ssim(imageA, imageB, full=True) のように使用し、スコアと差分マップの両方を取得できます。JavaScript では ssim.js ライブラリが利用可能です。
知覚的差分検出 - 人間の目に見える違いだけを検出する
知覚的差分 (Perceptual Diff) は、人間の視覚システムのモデルに基づいて、実際に人間が知覚できる差異のみを検出する手法です。ピクセル単位の比較では大量に発生する偽陽性を大幅に削減できます。
ΔE (Delta E) - 色差の知覚的指標:
CIE Lab 色空間における 2 色間のユークリッド距離です。Lab 色空間は人間の色知覚に基づいて設計されているため、ΔE の値が知覚的な色の違いと良く対応します。一般的に ΔE < 1 は人間には区別できない差、ΔE < 3 は注意深く見ないと分からない差、ΔE > 5 は明確に異なる色として認識されます。
perceptualdiff ツール:
Hector Yee が開発した知覚的差分検出ツールです。人間の視覚システムの空間周波数感度 (CSF: Contrast Sensitivity Function) をモデル化し、視覚的に検出不可能な差異を無視します。アンチエイリアシングの微妙な違いやサブピクセルレンダリングの差異を正しく無視できるため、ビジュアルリグレッションテストでの偽陽性が大幅に減少します。
DSSIM (Structural Dissimilarity):
SSIM の逆数に基づく非類似度指標です。DSSIM = (1 - SSIM) / 2 で計算され、0 が完全一致、値が大きいほど差異が大きいことを示します。SSIM の知覚的な妥当性を活かしつつ、差分の大きさを直感的に表現できます。
LPIPS (Learned Perceptual Image Patch Similarity):
深層学習モデル (VGG、AlexNet) の中間層特徴量を使って画像の知覚的類似度を計算する手法です。2018 年に Zhang らが提案し、従来の指標よりも人間の知覚判断との相関が高いことが示されています。事前学習済みの CNN が抽出する特徴量は、テクスチャ、エッジ、形状などの高次の視覚情報を捉えるため、単純なピクセル比較では検出できない意味的な差異も評価できます。
ビジュアルリグレッションテストでの実践 - ツールと戦略
Web 開発における画像差分比較の最も一般的な用途は、ビジュアルリグレッションテストです。UI の意図しない変更を自動検出し、品質を維持するための実践的なアプローチを解説します。
主要ツールの比較:
- Chromatic: Storybook と統合されたビジュアルテストサービス。コンポーネント単位でスクリーンショットを比較し、変更を検出します。クラウドベースで並列実行が可能で、大規模プロジェクトに適しています。
- Percy (BrowserStack): CI/CD パイプラインに統合しやすいビジュアルテストプラットフォーム。複数ブラウザ・解像度での比較をサポートし、レスポンシブデザインの検証に強みがあります。
- BackstopJS: オープンソースのビジュアルリグレッションテストツール。Puppeteer または Playwright でスクリーンショットを撮影し、
resemblejsで比較します。セルフホスト可能でコストを抑えられます。 - reg-suit: 日本発のオープンソースツール。S3 や GCS にスクリーンショットを保存し、PR ごとに差分レポートを生成します。GitHub Actions との連携が容易です。
偽陽性の削減戦略:
ビジュアルリグレッションテストの最大の課題は偽陽性です。以下の戦略で偽陽性を削減します。アンチエイリアシング差異を無視する閾値設定 (ピクセル差分が 1-2 以下なら無視)。動的コンテンツ (日時表示、ランダム要素) のマスキング。フォントレンダリングの差異を吸収するための許容範囲設定。テスト環境の固定 (Docker コンテナ内で一貫したレンダリング環境を確保)。
効果的なテスト戦略:
全ページのフルスクリーンショットではなく、コンポーネント単位での比較が推奨されます。変更の影響範囲が明確になり、差分の原因特定が容易になります。また、ビューポートサイズを固定し、レスポンシブブレークポイントごとにテストケースを分けることで、再現性の高いテストが実現できます。
画像差分比較の実装テクニック - コードで実現する比較処理
画像差分比較を自分のプロジェクトに組み込む際の実装テクニックを、具体的なコード例とともに解説します。
Node.js での実装 (pixelmatch):
pixelmatch は高速で軽量なピクセル比較ライブラリです。アンチエイリアシング検出機能を内蔵しており、ビジュアルリグレッションテストに適しています。const numDiffPixels = pixelmatch(img1, img2, diff, width, height, { threshold: 0.1 }) のように使用し、差分ピクセル数と差分画像を同時に取得できます。threshold パラメータで色差の許容範囲を調整します。
Python での実装 (OpenCV):
OpenCV を使えば、単純なピクセル比較から高度な構造的比較まで幅広い手法を実装できます。cv2.absdiff(img1, img2) で絶対差分を計算し、cv2.threshold で二値化して変化領域を抽出します。さらに cv2.findContours で変化領域の輪郭を検出し、バウンディングボックスで囲むことで、差分箇所を視覚的にハイライトできます。
ブラウザでの実装 (Canvas API):
Canvas API を使えば、ブラウザ上でリアルタイムに画像比較が可能です。2 枚の画像を Canvas に描画し、getImageData() でピクセルデータを取得して比較します。差分結果を別の Canvas に描画すれば、ユーザーに視覚的なフィードバックを提供できます。Web Worker で比較処理を実行すれば、UI のブロッキングを防止できます。
差分の可視化手法:
- ヒートマップ: 差分の大きさを色の濃淡で表現。赤が大きな差分、青が小さな差分を示します。
- オーバーレイ: 2 枚の画像を半透明で重ね合わせ、差異のある箇所がちらつくように表示します。
- スライダー (Before/After): 左右にスライダーを動かして 2 枚の画像を切り替える UI。ユーザーが直感的に差分を確認できます。
- ブリンク比較: 2 枚の画像を高速に切り替えて表示。人間の目は変化に敏感なため、微細な差分も検出しやすくなります。