Algorithm & UI/UX
輝度を熱分布に変換する「疑似カラーマッピング」の技術的背景
本ツールは、実際の熱センサーを使用する代わりに、画像の「明るさ(輝度)」を温度に見立て、独自のカラーパレットへ再マッピングすることでサーモカメラのような視覚効果を得ています。ここでは、その計算ロジックと描画パフォーマンスの最適化について解説します。
1. 輝度ベースの疑似カラー変換とコントラスト調整
サーモグラフィ特有の「熱い部分は赤く、冷たい部分は青い」という表現は、画像処理における「疑似カラー変換」の一種です。まず各ピクセルのRGB値を人間が感じる明るさ(輝度)へ変換し、それを温度のインデックスとして扱います。
この際、単純なグレースケール変換だけでなく、スライダーによる「コントラスト(熱の強弱)」と「オフセット(全体的な温度感)」の補正を数式に組み込んでいます。これにより、暗い写真でも熱分布がはっきり見えるような調整が可能になります。
// ピクセルごとの熱分布シミュレーション
function calculateThermalIndex(r, g, b, config) {
// 輝度の計算(NTSC係数を用いた重み付け)
let luminance = // ここにRGBから輝度を算出する標準的な計算が入ります;
// コントラスト調整:128(中間値)を基準にスケーリング
const contrast = config.contrastVal / // 基準定数;
luminance = ((luminance / 255.0 - 0.5) * contrast + 0.5) * 255.0;
// 温度感(オフセット)の追加
luminance += (config.tempOffset * 255.0);
// 0〜255の範囲にクランプし、パレットのインデックスとして返す
return Math.max(0, Math.min(255, Math.floor(luminance)));
} 2. 256色の動的サーモパレット生成(Jet風グラデーション)
静的な画像ファイルとしてパレットを持つ代わりに、実行時に256色のRGB配列をプログラムで生成しています。この手法のメリットは、リソースの軽量化だけでなく、パレットの境界値を微調整することで「より熱そうに見える配色」を柔軟に定義できる点にあります。
計算は 濃青 -> 青 -> シアン -> 緑 -> 黄 -> 赤 -> 白 の順に色が遷移するように、特定の閾値ごとにRGB各チャンネルを線形補間しています。
function generateThermalPalette() {
const palette = [];
for (let i = 0; i < 256; i++) {
let t = i / 255.0; // 0.0 (低温) to 1.0 (高温)
let r=0, g=0, b=0;
// 閾値に基づいた段階的な色遷移計算
if (t < // 低温域の閾値) {
// ここに濃青から青への補間処理が入ります
} else if (t < // 中温域の閾値) {
// ここにシアンから緑への補間処理が入ります
} else {
// ここに赤から白(最高温)への補間処理が入ります
}
palette.push([Math.round(r), Math.round(g), Math.round(b)]);
}
return palette;
} 3. Canvas 2D APIによる高速ピクセル処理のハック
高解像度の画像をリアルタイムで加工するため、Canvasの ImageData を直接操作しています。数百万ピクセルに及ぶループ処理をブラウザのメインスレッドで完結させるため、いくつかの最適化を施しています。
一つは willReadFrequently: true フラグの使用です。これはブラウザに対し、頻繁にピクセルデータの読み取りが発生することを伝え、メモリ配置を最適化させるためのものです。また、リサイズ処理を前段に挟むことで、処理対象のデータ量を一定以下に抑え、操作時の「ヌルヌル感」を維持しています。
function renderThermalEffect(ctx, img, cw, ch) {
// 描画最適化フラグを有効にしてコンテキスト取得
const context = canvas.getContext('2d', { willReadFrequently: true });
// Canvasからピクセル配列を一括取得
const imageData = context.getImageData(0, 0, cw, ch);
const data = imageData.data;
// TypedArray(Uint8ClampedArray)に対する高速なループ
for (let i = 0; i < data.length; i += 4) {
const index = calculateThermalIndex(data[i], data[i+1], data[i+2], config);
const [pr, pg, pb] = cachedPalette[index];
data[i] = pr; // Red
data[i+1] = pg; // Green
data[i+2] = pb; // Blue
// Alphaは変更しないことで透明度を維持
}
// 処理結果をCanvasへ書き戻し
context.putImageData(imageData, 0, 0);
} Developer's Note
「サーモグラフィ風」というネタ要素の強いツールですが、技術的には非常にクラシックかつ奥の深い画像処理を詰め込んでいます。
特にこだわったのは、パレットの「白飛び」の表現です。本物のサーモカメラでは、温度が飽和すると白く発光するように見えます。これを再現するため、パレットの最高温域(インデックス255付近)に向かってRGBすべてを255へ急激に近づける調整を行いました。
また、SNSでのシェアを前提としているため、プライバシー保護は最優先事項です。Canvasでの処理をすべてクライアントサイド(ブラウザ内)で完結させることで、ユーザーがどんなに「アツい」写真をアップロードしても、そのデータが私たちのサーバーに届くことは絶対にありません。安心してお楽しみください!