📷
画像処理100本ノックに挑戦|Bi-linear補間(026/100)
これはなに?
画像処理100本ノックを、TypeScriptとlibvipsで挑戦してみる記事の26本目です。
前回
実装
お題
Bi-linear補間により画像を1.5倍に拡大せよ。
Bi-linear補間とは周辺の4画素に距離に応じた重みをつけることで補完する手法である。 計算量が多いだけ処理時間がかかるが、画質の劣化を抑えることができる。
Coding
import sharp from 'sharp';
export async function bilinearInterpolation(
inputPath: string,
outputPath: string,
scaleX: number = 1.5,
scaleY: number = 1.5
): Promise<void> {
try {
const image = await sharp(inputPath)
.raw()
.toBuffer({ resolveWithObject: true });
const { data, info } = image;
const { width, height, channels } = info;
// 新しいサイズを計算
const newWidth = Math.round(width * scaleX);
const newHeight = Math.round(height * scaleY);
const newData = Buffer.alloc(newWidth * newHeight * channels);
// 各ピクセルについてバイリニア補間を計算
for (let y = 0; y < newHeight; y++) {
for (let x = 0; x < newWidth; x++) {
// 元の座標を計算(浮動小数点)
const srcX = x / scaleX;
const srcY = y / scaleY;
// 四隅の座標を計算
const x1 = Math.floor(srcX);
const y1 = Math.floor(srcY);
const x2 = Math.min(x1 + 1, width - 1);
const y2 = Math.min(y1 + 1, height - 1);
// 距離による重みを計算
const dx = srcX - x1;
const dy = srcY - y1;
// 各チャネルについて補間を実行
for (let c = 0; c < channels; c++) {
// 四隅のピクセル値を取得
const pos11 = (y1 * width + x1) * channels + c;
const pos12 = (y1 * width + x2) * channels + c;
const pos21 = (y2 * width + x1) * channels + c;
const pos22 = (y2 * width + x2) * channels + c;
const f11 = data[pos11];
const f12 = data[pos12];
const f21 = data[pos21];
const f22 = data[pos22];
// バイリニア補間の計算
const value = (1 - dx) * (1 - dy) * f11 +
dx * (1 - dy) * f12 +
(1 - dx) * dy * f21 +
dx * dy * f22;
// 結果を保存
const newPos = (y * newWidth + x) * channels + c;
newData[newPos] = Math.min(255, Math.max(0, Math.round(value)));
}
}
}
await sharp(newData, {
raw: {
width: newWidth,
height: newHeight,
channels
}
})
.toFile(outputPath);
console.log('バイリニア補間による拡大が完了しました');
console.log(`元のサイズ: ${width}x${height}`);
console.log(`拡大後のサイズ: ${newWidth}x${newHeight}`);
} catch (error) {
console.error('画像処理中にエラーが発生しました:', error);
throw error;
}
}
結果
入力 | 出力 |
---|---|
![]() |
![]() |
Discussion