웹 워커를 사용하여 MediaPipe 감지 작업을 메인 스레드에서 분리하는 방법을 설명해드리겠습니다. 이 방법은 UI의 반응성을 향상시키고 전반적인 성능을 개선할 수 있습니다.
javascript
Copy
import { initializeDetectors } from '@/lib/mediapipe/tasksVision';
let detectors;
self.onmessage = async (event) => {
const { type, data } = event.data;
switch (type) {
case 'INIT':
detectors = await initializeDetectors();
self.postMessage({ type: 'INIT_COMPLETE' });
break;
case 'DETECT':
if (!detectors) {
self.postMessage({ type: 'ERROR', message: 'Detectors not initialized' });
return;
}
const { imageData, width, height, timestamp } = data;
const faceResult = detectors.faceLandmarker.detectForVideo({ data: imageData, width, height }, timestamp);
const handResult = detectors.handLandmarker.detectForVideo({ data: imageData, width, height }, timestamp);
self.postMessage({
type: 'DETECTION_RESULT',
faceResult,
handResult,
});
break;
}
};
javascript
Copy
import { useEffect, useRef, useCallback, useState } from 'react';
import { Camera } from '@mediapipe/camera_utils';
export function useMotionCapture(localVideoRef, setLandmarks) {
const workerRef = useRef(null);
const cameraRef = useRef(null);
useEffect(() => {
workerRef.current = new Worker(new URL('./detection.worker.js', import.meta.url), { type: 'module' });
workerRef.current.onmessage = (event) => {
const { type, faceResult, handResult } = event.data;
if (type === 'DETECTION_RESULT') {
processLandmarks(faceResult, handResult);
}
};
workerRef.current.postMessage({ type: 'INIT' });
return () => {
workerRef.current.terminate();
};
}, []);
const processLandmarks = useCallback((faceResult, handResult) => {
// 랜드마크 처리 로직 (이전과 동일)
setLandmarks(newLandmarks);
}, [setLandmarks]);
const detectFrame = useCallback(() => {
if (!workerRef.current || !localVideoRef.current) return;
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = localVideoRef.current.videoWidth;
canvas.height = localVideoRef.current.videoHeight;
ctx.drawImage(localVideoRef.current, 0, 0);
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
workerRef.current.postMessage({
type: 'DETECT',
data: {
imageData: imageData.data,
width: canvas.width,
height: canvas.height,
timestamp: performance.now(),
}
}, [imageData.data.buffer]);
}, [localVideoRef]);
useEffect(() => {
if (!localVideoRef.current) return;
const initCamera = async () => {
cameraRef.current = new Camera(localVideoRef.current, {
onFrame: detectFrame,
width: 320,
height: 240,
frameRate: 30
});
await cameraRef.current.start();
};
initCamera();
return () => {
if (cameraRef.current) {
cameraRef.current.stop();
cameraRef.current = null;
}
};
}, [localVideoRef, detectFrame]);
return null;
}
postMessage를 사용하여 메인 스레드와 워커 간에 데이터를 주고받습니다.processLandmarks 함수로 처리합니다.이 접근 방식은 MediaPipe 작업을 별도의 스레드로 이동시켜 전반적인 애플리케이션 성능을 향상시킬 수 있습니다. 하지만 구현이 더 복잡해지고 디버깅이 어려워질 수 있으므로, 프로젝트의 요구사항과 복잡성을 고려하여 적용 여부를 결정해야 합니다.