人物のセグメンテーションを行い、3D空間に描画するゲーム。
人物画像の3D描画
抽出された人物画像は、PlaneGeometry(平面)にマッピングされ、透明な背景の状態で3D空間に表示
Three.jsの初期化
Three.jsを使って3Dシーンを作成し、カメラとレンダラーを初期化します。BoxGeometryとランダムな色のMeshBasicMaterialを使って、カラフルなキューブをランダムに配置します。
BodyPixでの人物抽出
ローカルの画像を選択すると、BodyPixで人物のセグメンテーションが行われ、背景を透明にした画像がに描画されます。そのcanvasをテクスチャとしてTHREE.Textureに渡し、3D空間に描画します。
人物画像の3D描画
抽出された人物画像は、PlaneGeometry(平面)にマッピングされ、透明な背景の状態で3D空間に表示されます。
アニメーション
animate関数でシーン全体が回転し、キューブと人物が回転する3D空間を作成します。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3D空間に人物画像を描画</title>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs"></script>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/body-pix"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<style>
body {
margin: 0;
overflow: hidden;
}
canvas {
display: block;
}
</style>
</head>
<body>
<input type="file" id="upload" accept="image/*">
<br>
<img id="input-image" style="display:none;">
<canvas id="output-canvas" style="display:none;"></canvas>
<script>
let scene, camera, renderer;
let personTexture;
// Three.jsのシーンを初期化
function initThreeJS() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5;
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// カラフルなキューブを作成
const geometry = new THREE.BoxGeometry(1, 1, 1);
for (let i = 0; i < 50; i++) {
const material = new THREE.MeshBasicMaterial({ color: Math.random() * 0xffffff });
const cube = new THREE.Mesh(geometry, material);
cube.position.set((Math.random() - 0.5) * 10, (Math.random() - 0.5) * 10, (Math.random() - 0.5) * 10);
scene.add(cube);
}
animate();
}
// アニメーションループ
function animate() {
requestAnimationFrame(animate);
scene.rotation.x += 0.01;
scene.rotation.y += 0.01;
renderer.render(scene, camera);
}
// 人物の画像を平面に描画
function addPersonToScene(texture) {
const geometry = new THREE.PlaneGeometry(3, 4);
const material = new THREE.MeshBasicMaterial({ map: texture, transparent: true });
const plane = new THREE.Mesh(geometry, material);
scene.add(plane);
}
// BodyPixのモデルをロード
let net;
async function loadBodyPix() {
net = await bodyPix.load();
console.log('BodyPixモデルがロードされました');
}
loadBodyPix();
// 画像が選択されたときの処理
const upload = document.getElementById('upload');
const inputImage = document.getElementById('input-image');
const outputCanvas = document.getElementById('output-canvas');
const ctx = outputCanvas.getContext('2d');
upload.addEventListener('change', (event) => {
const file = event.target.files[0];
const reader = new FileReader();
reader.onload = (e) => {
inputImage.src = e.target.result;
inputImage.onload = () => {
processImage();
};
};
reader.readAsDataURL(file);
});
// 画像を処理して人物のみを抽出
async function processImage() {
outputCanvas.width = inputImage.width;
outputCanvas.height = inputImage.height;
// セグメンテーションを実行
const segmentation = await net.segmentPerson(inputImage);
// 画像のピクセルデータを取得
ctx.drawImage(inputImage, 0, 0);
const imageData = ctx.getImageData(0, 0, inputImage.width, inputImage.height);
const data = imageData.data;
// セグメンテーション結果に基づいて人物部分のみを描画
for (let i = 0; i < data.length; i += 4) {
const n = i / 4;
if (segmentation.data[n] === 0) {
data[i + 3] = 0; // 背景部分は透明にする
}
}
ctx.putImageData(imageData, 0, 0);
// Three.js用のテクスチャとして設定
personTexture = new THREE.Texture(outputCanvas);
personTexture.needsUpdate = true;
// 人物をシーンに追加
addPersonToScene(personTexture);
}
// Three.jsの初期化
initThreeJS();
</script>
</body>
</html>
Webカメラの映像を取得バージョン。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3D空間に人物画像を描画</title>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs"></script>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/body-pix"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<style>
body {
margin: 0;
overflow: hidden;
}
canvas {
display: block;
}
#video {
display: none; /* カメラの映像は隠しますが、内部で使用します */
}
</style>
</head>
<body>
<video id="video" width="640" height="480" autoplay></video>
<input type="button" id="capture" value="キャプチャ">
<canvas id="output-canvas" style="display:none;"></canvas>
<script>
let scene, camera, renderer;
let personTexture;
let net;
// Three.jsのシーンを初期化
function initThreeJS() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5;
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// カラフルなキューブを作成
const geometry = new THREE.BoxGeometry(1, 1, 1);
for (let i = 0; i < 50; i++) {
const material = new THREE.MeshBasicMaterial({ color: Math.random() * 0xffffff });
const cube = new THREE.Mesh(geometry, material);
cube.position.set((Math.random() - 0.5) * 10, (Math.random() - 0.5) * 10, (Math.random() - 0.5) * 10);
scene.add(cube);
}
animate();
}
// アニメーションループ
function animate() {
requestAnimationFrame(animate);
scene.rotation.x += 0.01;
scene.rotation.y += 0.01;
renderer.render(scene, camera);
}
// 人物の画像を平面に描画
function addPersonToScene(texture) {
const geometry = new THREE.PlaneGeometry(3, 4);
const material = new THREE.MeshBasicMaterial({ map: texture, transparent: true });
const plane = new THREE.Mesh(geometry, material);
scene.add(plane);
}
// BodyPixのモデルをロード
async function loadBodyPix() {
net = await bodyPix.load();
console.log('BodyPixモデルがロードされました');
}
loadBodyPix();
// Webカメラの映像を取得
async function setupCamera() {
const video = document.getElementById('video');
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
video.srcObject = stream;
return new Promise(resolve => {
video.onloadedmetadata = () => {
resolve();
};
});
}
// 画像を処理して人物のみを抽出
async function processImage() {
const video = document.getElementById('video');
const outputCanvas = document.getElementById('output-canvas');
const ctx = outputCanvas.getContext('2d');
outputCanvas.width = video.videoWidth;
outputCanvas.height = video.videoHeight;
ctx.drawImage(video, 0, 0);
// セグメンテーションを実行
const segmentation = await net.segmentPerson(outputCanvas);
// 画像のピクセルデータを取得
const imageData = ctx.getImageData(0, 0, outputCanvas.width, outputCanvas.height);
const data = imageData.data;
// セグメンテーション結果に基づいて人物部分のみを描画
for (let i = 0; i < data.length; i += 4) {
const n = i / 4;
if (segmentation.data[n] === 0) {
data[i + 3] = 0; // 背景部分は透明にする
}
}
ctx.putImageData(imageData, 0, 0);
// Three.js用のテクスチャとして設定
personTexture = new THREE.Texture(outputCanvas);
personTexture.needsUpdate = true;
// 人物をシーンに追加
addPersonToScene(personTexture);
}
// イベントリスナーの設定
document.getElementById('capture').addEventListener('click', processImage);
// Three.jsの初期化とカメラのセットアップ
async function init() {
await setupCamera();
initThreeJS();
}
init();
</script>
</body>
</html>