gazou-compressor.jp

Quality Ladder:PSNR/SSIM/VMAF 指標の実務的な使い分け

Quality Ladder は品質グレード(例: Q90→Q85→Q80...)を並べ主観しきい値を決める手法。 しかし PSNR / SSIM / (MS-)SSIM / VMAF など客観指標を無批判に閾値化すると “文字が滲むが指標OK” という UX崩壊の盲点 を生みます。本稿は Ladder ツール (/quality-ladder) を軸に 指標を 翻訳可能な意思決定単位 に落とすワークフローを提示します。

関連ツール
品質差の視覚化には Color Heatmap、アーチファクト比較には Dither Compare も併用すると局所差検出が加速。

要点(TL;DR)

1. 指標の特性マップ

PSNR は単純で高速、SSIM は構造類似、MS-SSIM は複数スケールでの視覚特性近似、VMAF は動画文脈で重特徴量。 静止画バッチ比較なら PSNR + (MS-)SSIM の2指標で 80% 以上の妥当性が得られるケースが多いです。

import sharp from 'sharp';
import { getSSIM } from 'ssim.js'; // npm i ssim.js

// PSNR を計算 (単純二乗誤差から導出)
async function psnr(a: Buffer, b: Buffer) {
  if (a.length !== b.length) throw new Error('dimension mismatch');
  let mse = 0;
  for (let i = 0; i < a.length; i++) {
    const d = a[i] - b[i];
    mse += d * d;
  }
  mse /= a.length;
  if (mse === 0) return Infinity;
  const PIXEL_MAX = 255;
  return 10 * Math.log10((PIXEL_MAX * PIXEL_MAX) / mse);
}

async function main() {
  const ref = sharp('ref.png').raw().ensureAlpha().toBuffer({ resolveWithObject: true });
  const cand = sharp('q85.png').raw().ensureAlpha().toBuffer({ resolveWithObject: true });
  const [r, c] = await Promise.all([ref, cand]);
  const psnrValue = await psnr(r.data, c.data);
  const { mssim } = getSSIM(
    { data: r.data, width: r.info.width, height: r.info.height },
    { data: c.data, width: c.info.width, height: c.info.height },
    { ssim: 'fast' }
  );
  console.log({ psnrValue, ssim: mssim });
}
main();

簡易 PSNR / SSIM 計測サンプル。実運用ではガンマ補正後(sRGB → linear)に計算し、アルファ分離や領域マスクを適用します。

2. Ladder 取得の標準手順

  1. 代表 8〜12 枚を カテゴリ(写真/UI/イラスト) 別にピック。
  2. 各画像で Q=95→90→85... と書き出しサイズと指標を記録。
  3. 知覚差が初めて“気になる”段の 1つ上 を候補品質に。
  4. UI文字/線画マスクを適用し再測定→差異が再拡大するなら品質1段戻す。

3. 指標レンジの経験値

状況PSNR(dB)SSIM
写真公開許容境界~380.96+
UI文字劣化前40+0.985+
過圧縮兆候≤36<0.94

※ 数値は社内ベンチ一例。自社の表示サイズ/画面PPIで再キャリブレーションを推奨。

4. CI への組込み

差分生成→最小許容PSNR/SSIM下回り or 文字マスク領域で閾値割れ → PR 失敗。可視化ログは /quality-ladder の静的キャプチャをアーティファクト保存。

name: image-quality
on: [pull_request]
jobs:
  ladder:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npm ci
      - name: Compute metrics
        run: node scripts/compute-quality-ladder.mjs --out report.json
      - name: Validate thresholds
        run: node scripts/validate-thresholds.mjs report.json thresholds.json
      - name: Upload artifacts
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: ladder-report
          path: report/*

5. よくある失敗

6. まとめ

Quality Ladder は “指標を鵜呑みする” ためでなく “主観境界を数値で再現” する枠組みです。PSNR+SSIMのペアと領域マスクで再現性を確立し、変更の安全性を CI で自動担保しましょう。

公開日: 2025-09-06編集: gazou-compressor.jp
次の一歩

自社に最適化する際は (1) 代表セット更新頻度を四半期ごとに定義 (2) 閾値変更は PR テンプレで理由必須化 (3) UI 文字領域マスク PNG をリポジトリ管理 の 3点を先に制度化するとブレが激減します。

FAQ

FAQ(よくある質問)

1画像形式の基本方針は?(写真/スクショ/透過)
写真は AVIF / WebP(画質80–85%目安)、UIやスクショはPNG / WebP Lossless、単色ロゴはSVGが基本です。 実装の詳細は srcset/sizes設計ガイド スクショ最適化 を参照してください。
2圧縮しても画質を落とさないコツは?
実表示幅に合わせたリサイズ → 過大ダウンロードを防ぎ、srcset/sizes を 実描画幅に一致させます。画質は写真で 80–85% を起点に、ノイズやエッジを目視確認。 仕上げは /compare で Before/After を見比べるのがおすすめです。
3CLSを悪化させない画像の置き方は?
すべての画像に width/height(または親に aspect-ratio)を与え、広告・埋め込みは 予約サイズを先に確保します。詳しくは CLSゼロ設計ガイド を参照。

gazou-compressor.jp 編集部

画像圧縮・変換・背景除去などの実践テクニックと、Webで“速く・軽く・崩さない”ためのノウハウを発信しています。

関連記事

トピック/更新日の近いコンテンツ