2
4

ウェブカメラの映像にリアルタイムでモザイクをかけて重要な情報を保護するゲーム。

Last updated at Posted at 2024-10-01

image.png

スクリーンショット 2024-10-02 044107.png

ウェブカメラの映像にリアルタイムでモザイクをかけ、スライダーでモザイクの大きさを調整することができます。

モザイク処理とは、画像の一部をぼかしたり、小さなブロックに分割してその平均色で置き換える処理です。
スライダーでブロックサイズ(モザイクの解像度)を調整できます。

コードをメモ帳などのテキストエディタに貼り付け、ファイルを「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>

2
4
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4