ウェブカメラの映像にリアルタイムでモザイクをかけ、スライダーでモザイクの大きさを調整することができます。
モザイク処理とは、画像の一部をぼかしたり、小さなブロックに分割してその平均色で置き換える処理です。
スライダーでブロックサイズ(モザイクの解像度)を調整できます。
コードをメモ帳などのテキストエディタに貼り付け、ファイルを「index.html」などの拡張子が.htmlのファイルとして保存します。その後、保存したファイルをブラウザで開けば、コードが実行されます。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Webcam Mosaic Effect</title>
<style>
canvas {
display: block;
margin: auto;
border: 1px solid black;
}
#slider {
width: 300px;
margin: auto;
display: block;
}
</style>
</head>
<body>
<h1>Webcam Mosaic Effect</h1>
<video id="video" autoplay></video>
<canvas id="canvas"></canvas>
<input type="range" id="slider" min="1" max="50" value="10">
<label for="slider">モザイクサイズの調整</label>
<script>
const video = document.getElementById('video');
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const slider = document.getElementById('slider');
// ウェブカメラのストリーミング
async function setupCamera() {
const stream = await navigator.mediaDevices.getUserMedia({
video: true,
});
video.srcObject = stream;
return new Promise((resolve) => {
video.onloadedmetadata = () => {
resolve(video);
};
});
}
// モザイク処理を行う関数
function applyMosaic(imageData, blockSize) {
const width = imageData.width;
const height = imageData.height;
// 画像データを操作
for (let y = 0; y < height; y += blockSize) {
for (let x = 0; x < width; x += blockSize) {
// ブロック内の平均色を計算
const redValues = [];
const greenValues = [];
const blueValues = [];
// ブロック内のピクセルを走査
for (let dy = 0; dy < blockSize; dy++) {
for (let dx = 0; dx < blockSize; dx++) {
const pixelX = x + dx;
const pixelY = y + dy;
if (pixelX < width && pixelY < height) {
const index = (pixelY * width + pixelX) * 4;
redValues.push(imageData.data[index]);
greenValues.push(imageData.data[index + 1]);
blueValues.push(imageData.data[index + 2]);
}
}
}
// ブロック内の平均色を計算
const avgRed = redValues.reduce((a, b) => a + b, 0) / redValues.length;
const avgGreen = greenValues.reduce((a, b) => a + b, 0) / greenValues.length;
const avgBlue = blueValues.reduce((a, b) => a + b, 0) / blueValues.length;
// ブロック内のすべてのピクセルに平均色を適用
for (let dy = 0; dy < blockSize; dy++) {
for (let dx = 0; dx < blockSize; dx++) {
const pixelX = x + dx;
const pixelY = y + dy;
if (pixelX < width && pixelY < height) {
const index = (pixelY * width + pixelX) * 4;
imageData.data[index] = avgRed;
imageData.data[index + 1] = avgGreen;
imageData.data[index + 2] = avgBlue;
imageData.data[index + 3] = 255; // アルファ値(不透明度)
}
}
}
}
}
return imageData;
}
// メインループ
async function main() {
await setupCamera();
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
const processFrame = () => {
ctx.drawImage(video, 0, 0);
let imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const blockSize = parseInt(slider.value);
// モザイクを適用
imageData = applyMosaic(imageData, blockSize);
ctx.putImageData(imageData, 0, 0);
requestAnimationFrame(processFrame);
};
processFrame();
}
main();
</script>
</body>
</html>