猫の手ツール

Algorithm & UI/UX

ブラウザ完結で実現する
高速スキャン風・2値化アルゴリズム

「スマホで撮った写真をスキャナー風に見せる」というシンプルな体験の裏側では、Canvas APIによる画素操作と、ユーザーがストレスを感じないための非同期・軽量化処理が組み合わされています。サーバーを介さないプライバシー重視の設計思想も紹介します。

このツールの入力から出力まで

現行コードの確認日:

入力
書類などの写真を選び、白黒を分けるしきい値を指定します。
処理
画素の明るさを一定のしきい値と比べ、白または黒へ変換します。確認用と保存用で異なる解像度を使います。
出力
出力は JPEG(品質指定 0.95)。

まず確認する点:局所的な影に合わせて基準を変える処理ではありません。影と薄い線が混在する写真では、文字を残すと影も黒くなる場合があります。

実装の確認箇所:src/pages/image/scan-filter/index.astro。以下のコード抜粋と出力条件は、この本番実装に基づいて説明します。

仕組みを読み進めるときは、Canvas APIと画像処理(画像寸法、drawImage、画素と透明度の扱い)、メモリ管理と画像処理(画素バッファ、縮小と容量予算)が参考になります。

1. 輝度に基づくしきい値による2値化アルゴリズム

単に白か黒かに分けるだけではなく、人間が「文字」として認識しやすいコントラストを保つため、まずカラー画像をグレースケール化する際に独自の輝度計算を行っています。RGB各色に対して人間の視覚特性に合わせた係数を適用することで、画像全体を同じ明るさの基準で白黒に分けます。影を自動除去する処理ではありません。

1画素の RGB を白または黒にする例です。しきい値を上げると黒になる範囲が増えます。

function binarize(r, g, b, threshold = 128) {
  const brightness = r * 0.299 + g * 0.587 + b * 0.114;
  return brightness >= threshold ? 255 : 0;
}

この処理により、スライダーを動かすたびにリアルタイムで画像が変化し、最適な「クッキリ感」をユーザーが直感的に調整できるようになっています。

2. 「ダブルキャンバス」によるUXの最適化

スライダー操作に応じて再計算する画素数を減らすため、本ツールでは「プレビュー用」と「書き出し用」の2つのCanvasを使い分けるハックを採用しています。

  • プレビュー用: UI表示に合わせ、幅 800px 以下にリサイズした画像に対して処理を行います。これにより操作中に処理する画素数を減らします。
  • 書き出し用: ユーザーが「保存」を押した瞬間のみ、読み込み時に制限した解像度(長辺最大 2500px)で重い処理を実行します。

出力の仕様と確認する点

しきい値は 1〜254 で、局所的な明るさを見て基準を変える適応的2値化ではありません。紙に濃い影があると、文字を残す設定で影も黒くなる場合があります。均一な明るさで撮った書類に向きます。

プレビューは幅 800px 以下で JPEG 化した画像を使い、保存時には長辺 2500px 以下の処理画像を再計算します。縮小と圧縮の影響で、細い文字の見え方がプレビューと保存画像で異なることがあります。

出力は JPEG(品質指定 0.95)。処理中は白黒2値でも、JPEG 圧縮後の輪郭に中間色が生じます。OCR、傾き・台形補正、検索可能な PDF の作成は行いません。