猫の手ツール

Algorithm & UI/UX

アナログの不完全さを計算で描く:
VHSグリッチのピクセル操作術

デジタルな写真を、あえて「壊す」ことで生まれる情緒。Canvas APIのImageDataをピクセル単位で書き換え、チャンネル分離とトラッキングエラーをシミュレートする実装の裏側を公開します。

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

現行コードの確認日:

入力
写真を選び、ノイズ・色ずれ・走査線を指定します。
処理
赤と青の参照位置を左右へずらし、特定の行を暗くし、乱数で一部の行の参照を変えます。
出力
入力は長辺 1500px 以下に縮小し、1000×1000px の JPEG(品質指定 0.85)を保存します。

まず確認する点:再描画でノイズの模様が変わります。色ずれを強くすると画像端の色が伸びるため、端と細い文字を見ます。

仕上がりの例

写真に走査線や色ずれを加え、VHSビデオ風にした例です。

加工前・加工後
左は緑のかぶりものを着けた愛猫の写真。右は横線と赤・青の色ずれを加えた猫の画像。

加工前・加工後

左は緑のかぶりものを着けた愛猫の写真。右は横線と赤・青の色ずれを加えた猫の画像。

掲載画像はサイトにある既存の公開作例です。保存済みの資料では運営者の愛猫の写真を使用しています。今回の確認日が、この作例を実行した日を表すわけではありません。

保存済み検証記録の条件を見る

資料の種類は「ツールの出力画像を保存した記録」です。公開作例と保存済み記録で素材や色などが異なる場合があるため、下の数値は保存済み検証記録の条件として読んでください。

記録の入力画像
800×1066px (JPEG)
記録の出力画像
1000×1000px (JPEG)
保存済み記録の主な操作・出力条件
画面の項目記録の値現行コードの初期値・範囲
ノイズの強さ30初期値 30 / 範囲 0〜100
色ズレ(色収差)10初期値 10 / 範囲 0〜50
横縞(走査線)40初期値 40 / 範囲 0〜100
写真のズーム100初期値 100 / 範囲 50〜300

記録では「レトロ画像を生成!」から完成表示へ進んでいます。初期値と記録値を比べてから、効果を1項目ずつ変えると作用を確認しやすくなります。

資料ファイルの作成日は実行日として扱っていません。個別端末の処理速度や、ほかの写真に対する検出・加工の精度を測定した資料でもありません。

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

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

1. チャンネル分離(RGB Shift)による色収差の再現

VHS特有の、赤や青が左右に滲む「色収差」は、物理的なテープの磁気転送エラーやレンズの特性を模したものです。デジタルでこれを再現するため、元のピクセルデータをメモリ上にクローンし、R(赤)とB(青)のチャンネルだけを参照する際のX座標を意図的にずらして合成しています。

単純に画像全体をずらすのではなく、ループ内でピクセルインデックスを再計算することで、後述する行単位のノイズともシームレスに連携できる設計にしています。

走査線の暗さを求める例です。3行に1行だけ減光し、設定 100 でも倍率は 0.6 です。

function scanlineFactor(y, amount) {
  return y % 3 === 0 ? 1 - amount / 100 * 0.4 : 1;
}

2. 行単位のランダム・トラッキングエラー

古いビデオデッキでテープの回転が不安定になった際に起こる「横方向の激しいブレ」を再現するため、特定の確率で行(Row)ごとにランダムな水平オフセットを付与するアルゴリズムを導入しています。

全行を一律にずらすのではなく、Math.random() による確率判定を Y 軸ループの直下で行うことで、VHSらしい突発的で予測不可能な映像の乱れを演出しています。

3. 走査線(Scanline)の数学的シミュレート

ブラウン管テレビ特有の横縞は、画像の輝度を周期的に減衰させることで表現しています。画像を重ねるのではなく、ピクセルループ内で y % 3 === 0 のような剰余演算を用い、特定の行に対して減衰係数を乗算しています。

この手法のメリットは、追加の描画コスト(drawImage等)をかけずに、既存のピクセルループのついでに処理を完結できるため、走査線専用の別画像を用意せずに済む点にあります。フレームレートの実測結果や速度の保証ではありません。

出力の仕様と確認する点

入力は長辺 1500px 以下に縮小し、1000×1000px の JPEG(品質指定 0.85)を保存します。VHS 動画を生成する機能ではありません。ノイズは再描画ごとに乱数で作るため模様が変わります。

色ずれは 0〜50px。赤は右側、青は左側の元画素を参照し、緑は元の位置を使います。ノイズ値 / 1000 の確率で行の参照位置をさらにずらしますが、緑まで同じ方向へ移動する処理ではありません。

ノイズ・色ずれ・走査線はそれぞれ 0 にできます。画像端の参照座標は端の画素に固定されるため、強いずれでは端の色が横に伸びます。実際の磁気テープや撮影機器の故障を解析・再現するものではありません。