スペースキーを押すと、現在のマウス位置を中心に画像をアップサンプリングします。
コードをメモ帳などのテキストエディタに貼り付け、ファイルを「index.html」などの拡張子が.htmlのファイルとして保存します。その後、保存したファイルをブラウザで開けば、コードが実行されます。
バイキュービック補間(Bicubic Interpolation)は、画像処理で用いられる技術で、画像の拡大や縮小時にピクセル値を滑らかに補完します。バイキュービック補間は、周囲の16ピクセル(4x4のピクセルブロック)を使用して新しいピクセルの値を計算します。
バイキュービック補間は、距離に応じて各点に重みを付け、その重み付きの平均値を計算する手法です。そして、この重みの変化は、三次多項式によって滑らかに変化するように設計されています。
具体的には、補間する対象点に対して、最も近い4つのデータポイント(1次元の場合)や16個のデータポイント(2次元の場合)を選び、それぞれの点の距離に基づいた重みを三次多項式で計算します。これにより、隣接するデータ点が補間結果にどれだけ影響を与えるかが決まります。
この三次多項式の特徴は、滑らかに値を補完することで、近傍のデータ点に依存しつつも、全体の変化が急激にならないようにします。
まとめると:
重みは対象点と隣接点の距離に応じて計算され、
三次多項式を用いることで、補間が滑らかかつ自然な形で行われる
ということになります。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>バイキュービック補間によるアップサンプリング</title>
<style>
#canvas {
border: 1px solid black; /* キャンバスの枠線 */
cursor: crosshair; /* マウスカーソルを十字に設定 */
}
</style>
</head>
<body>
<h1>画像アップサンプリングデモ</h1>
<input type="file" id="upload" accept="image/*" /> <!-- 画像ファイルを選択するための入力 -->
<canvas id="canvas"></canvas> <!-- 画像を表示するためのキャンバス -->
<script>
const upload = document.getElementById('upload'); // アップロード用のファイル入力
const canvas = document.getElementById('canvas'); // キャンバス要素
const ctx = canvas.getContext('2d'); // 2Dコンテキストを取得
let originalImage = null; // アップロードされたオリジナル画像
let mouseX = 0; // マウスのX座標
let mouseY = 0; // マウスのY座標
// 画像をアップロードするイベントリスナー
upload.addEventListener('change', (event) => {
const file = event.target.files[0]; // 選択されたファイルを取得
if (file) {
const reader = new FileReader(); // FileReaderオブジェクトを作成
reader.onload = (e) => {
const img = new Image(); // 画像オブジェクトを作成
img.onload = () => {
originalImage = img; // 画像が読み込まれたらオリジナル画像に設定
canvas.width = img.width; // キャンバスの幅を画像の幅に設定
canvas.height = img.height; // キャンバスの高さを画像の高さに設定
ctx.drawImage(img, 0, 0); // オリジナル画像をキャンバスに描画
};
img.src = e.target.result; // 読み込んだデータを画像ソースに設定
};
reader.readAsDataURL(file); // ファイルをデータURLとして読み込む
}
});
// マウスの動きに応じて座標を更新するイベントリスナー
canvas.addEventListener('mousemove', (event) => {
const rect = canvas.getBoundingClientRect(); // キャンバスの位置とサイズを取得
mouseX = event.clientX - rect.left; // マウスのX座標をキャンバスの左端からの距離に変換
mouseY = event.clientY - rect.top; // マウスのY座標をキャンバスの上端からの距離に変換
// マウスカーソルの座標を表示
ctx.clearRect(0, 0, canvas.width, canvas.height); // キャンバスをクリア
if (originalImage) {
ctx.drawImage(originalImage, 0, 0); // オリジナル画像を再描画
}
ctx.fillStyle = 'rgba(255, 0, 0, 0.5)'; // 赤い色を半透明で設定
ctx.fillRect(mouseX - 5, mouseY - 5, 10, 10); // マウスカーソル位置を示す四角を描画
});
// スペースキーを押したときにアップサンプリングを実行
document.addEventListener('keydown', (event) => {
if (event.code === 'Space' && originalImage) { // スペースキーが押された場合
upsample(mouseX, mouseY); // 現在のマウス位置を中心にアップサンプリングを実行
}
});
// アップサンプリング処理を行う関数
function upsample(centerX, centerY) {
const scale = 2; // アップサンプリングのスケール
const newWidth = originalImage.width * scale; // 新しい幅(元の画像の幅 × スケール)
const newHeight = originalImage.height * scale; // 新しい高さ(元の画像の高さ × スケール)
// 一時的なキャンバスを作成
const tempCanvas = document.createElement('canvas'); // 一時キャンバスを作成
const tempCtx = tempCanvas.getContext('2d'); // 一時キャンバスの2Dコンテキストを取得
tempCanvas.width = newWidth; // 一時キャンバスの幅を設定
tempCanvas.height = newHeight; // 一時キャンバスの高さを設定
// バイキュービック補間で拡大
tempCtx.imageSmoothingEnabled = true; // 画像スムージングを有効化
tempCtx.imageSmoothingQuality = 'high'; // 高品質スムージングを設定
tempCtx.drawImage(originalImage, 0, 0, originalImage.width, originalImage.height,
0, 0, newWidth, newHeight); // オリジナル画像を拡大して一時キャンバスに描画
// 中心座標に合わせてアップサンプリングされた部分を描画
const displaySize = 400; // 表示する領域のサイズ
const startX = Math.max(0, (centerX * scale) - displaySize / 2); // 描画開始X座標
const startY = Math.max(0, (centerY * scale) - displaySize / 2); // 描画開始Y座標
// 拡大された画像をメインキャンバスに描画
ctx.clearRect(0, 0, canvas.width, canvas.height); // メインキャンバスをクリア
ctx.drawImage(originalImage, 0, 0); // 元の画像を再描画
ctx.drawImage(tempCanvas, startX, startY, displaySize, displaySize,
centerX - displaySize / 2, centerY - displaySize / 2,
displaySize, displaySize); // アップサンプリングされた部分を描画
}
</script>
</body>
</html>