메인
home
소프트웨어
home

[웹 컨트롤러 제작][덕원여고][이은]

웹 AI 모델로 피코 제어하기

<!DOCTYPE html> <html lang="ko"> <head> <meta charset="UTF-8"> <title>손 제스처 + 블루투스</title> <style> body { margin: 0; overflow: hidden; background: #000; } #video, #canvas { position: absolute; top: 0; left: 0; width: 100vw; height: 100vh; object-fit: cover; transform: scaleX(-1); } #gestureNumber { position: absolute; top: 40px; left: 50%; transform: translateX(-50%); color: white; font-size: 6rem; font-weight: bold; text-shadow: 2px 2px 10px #000; z-index: 10; } #connectButton { position: absolute; top: 10px; left: 10px; z-index: 20; padding: 10px 20px; font-size: 16px; } </style> </head> <body> <video id="video" autoplay playsinline muted></video> <canvas id="canvas"></canvas> <div id="gestureNumber">-</div> <button id="connectButton">블루투스 연결</button> <!-- MediaPipe Hands --> <script src="https://cdn.jsdelivr.net/npm/@mediapipe/hands/hands.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/@mediapipe/drawing_utils/drawing_utils.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/@mediapipe/camera_utils/camera_utils.min.js"></script> <script> const video = document.getElementById('video'); const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); const gestureDisplay = document.getElementById('gestureNumber'); const connectButton = document.getElementById('connectButton'); let lastGesture = null; let device, server, writeCharacteristic; let isConnected = false; const NUS_SERVICE_UUID = '6e400001-b5a3-f393-e0a9-e50e24dcca9e'; const NUS_TX_CHAR_UUID = '6e400002-b5a3-f393-e0a9-e50e24dcca9e'; connectButton.addEventListener('click', async () => { try { device = await navigator.bluetooth.requestDevice({ filters: [{ services: [NUS_SERVICE_UUID] }] }); server = await device.gatt.connect(); const service = await server.getPrimaryService(NUS_SERVICE_UUID); writeCharacteristic = await service.getCharacteristic(NUS_TX_CHAR_UUID); isConnected = true; alert('블루투스 연결 완료'); } catch (error) { alert('연결 실패: ' + error); } }); function countFingers(landmarks) { let count = 0; const tips = [8, 12, 16, 20]; for (let tip of tips) { if (landmarks[tip].y < landmarks[tip - 2].y) count++; } if (landmarks[4].x > landmarks[2].x) count++; return count; } function isHandOpen(fingerCount) { return fingerCount >= 4; } function detectGesture(results) { const hands = results.multiHandLandmarks; if (!hands || hands.length === 0) { updateGesture("-"); return; } const states = hands.map(lm => isHandOpen(countFingers(lm))); if (states.length === 1) { if (states[0]) updateGesture("1"); else updateGesture("2"); } else if (states.length === 2) { if (states[0] && states[1]) updateGesture("3"); else if (!states[0] && !states[1]) updateGesture("4"); else updateGesture("-"); } } function updateGesture(gesture) { if (gesture !== lastGesture) { gestureDisplay.textContent = gesture; lastGesture = gesture; if (isConnected && gesture !== "-") { sendData(gesture); } } } async function sendData(data) { const encoded = new TextEncoder().encode(data); try { await writeCharacteristic.writeValue(encoded); console.log("전송됨:", data); } catch (err) { console.error("전송 실패:", err); } } const hands = new Hands({ locateFile: file => `https://cdn.jsdelivr.net/npm/@mediapipe/hands/${file}` }); hands.setOptions({ maxNumHands: 2, modelComplexity: 1, minDetectionConfidence: 0.7, minTrackingConfidence: 0.7 }); hands.onResults(results => { canvas.width = video.videoWidth; canvas.height = video.videoHeight; ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.drawImage(results.image, 0, 0, canvas.width, canvas.height); if (results.multiHandLandmarks) { for (let lm of results.multiHandLandmarks) { drawConnectors(ctx, lm, HAND_CONNECTIONS, { color: '#00FF00', lineWidth: 2 }); drawLandmarks(ctx, lm, { color: '#FF0000', lineWidth: 2 }); } } detectGesture(results); }); async function startCamera() { const stream = await navigator.mediaDevices.getUserMedia({ video: true }); video.srcObject = stream; video.onloadedmetadata = () => { const camera = new Camera(video, { onFrame: async () => await hands.send({ image: video }), width: 640, height: 480 }); camera.start(); }; } startCamera().catch(err => alert("카메라 접근 실패: " + err.message)); </script> </body> </html>
Python
복사

미디어파이프로 웹에서 불러오기

코드펜으로 나만의 웹사이트 제작하기

https://codepen.io/leeun/full/XJbqNgZ
Python
복사
[과제명][학교][이름] 바꿔주세요, 과제태그를 선생님 설명 듣고 넣어주세요.