손가락 펴짐 확인
// 두 벡터 사이의 각도 계산 함수
function calculateAngle(a: any, b: any, c: any): number {
const ab = { x: b.x - a.x, y: b.y - a.y, z: b.z - a.z };
const bc = { x: c.x - b.x, y: c.y - b.y, z: c.z - b.z };
const dotProduct = ab.x * bc.x + ab.y * bc.y + ab.z * bc.z;
const magnitudeAB = Math.sqrt(ab.x * ab.x + ab.y * ab.y + ab.z * ab.z);
const magnitudeBC = Math.sqrt(bc.x * bc.x + bc.y * bc.y + bc.z * bc.z);
const angleInRadians = Math.acos(dotProduct / (magnitudeAB * magnitudeBC));
const angleInDegrees = angleInRadians * (180 / Math.PI); // 라디안을 도로 변환
return angleInDegrees;
}
// 손가락 펴짐 확인 함수 (5개 랜드마크 사용) ----------------------------
function isFingerStraight(landmarks: any[], fingerIndex: number): boolean {
const baseIndex = fingerIndex * 4 + 1; // 손가락 시작 인덱스 계산
const wrist = landmarks[0];
const cmc = landmarks[baseIndex];
const mcp = landmarks[baseIndex + 1];
const dip = landmarks[baseIndex + 2];
const tip = landmarks[baseIndex + 3];
// 손가락 관절 사이의 각도 계산
const angle1 = calculateAngle(wrist, cmc, mcp);
const angle2 = calculateAngle(cmc, mcp, dip);
const angle3 = calculateAngle(mcp, dip, tip);
// 각도 임계값 설정 (직선에 가까울수록 작은 값)
const firstAngle = 60;
const secondAngle = 15;
const thirdAngle = 15;
// 모든 각도가 임계값보다 작으면 손가락이 펴져있다고 판단
// 첫번째 기울기는 손목에서 부터 시작하는 것이기 때문에 어느정도 구부림 허용
return angle1 < firstAngle && angle2 < secondAngle && angle3 < thirdAngle;
}
// 엄지와 다른 손가락 사이의 거리 확인 함수
function isThumbAwayFromOtherFingers(landmarks: any[]): boolean {
const thumbTip = landmarks[4];
const tapDistance = 0.075;
// 다른 손가락 끝점들과의 거리 계산
const distances = [8, 12, 16, 20].map(index => {
const fingerTip = landmarks[index];
return Math.hypot(
thumbTip.x - fingerTip.x,
thumbTip.y - fingerTip.y,
thumbTip.z - fingerTip.z
);
});
// 모든 거리가 임계값보다 크면 true 반환
return distances.every(distance => distance > tapDistance);
}
// 엄지 손가락 펴짐 확인 함수 (5개 랜드마크 사용) ----------------------------
function thumbFingerStraight(landmarks: any[]): boolean {
const wrist = landmarks[0];
const cmc = landmarks[1];
const mcp = landmarks[2];
const dip = landmarks[3];
const tip = landmarks[4];
// 손가락 관절 사이의 각도 계산
const angle1 = calculateAngle(wrist, cmc, mcp);
const angle2 = calculateAngle(cmc, mcp, dip);
const angle3 = calculateAngle(mcp, dip, tip);
// 각도 임계값 설정 (직선에 가까울수록 작은 값)
const firstAngle = 40;
const secondAngle = 25;
const thirdAngle = 30;
// 엄지와 검지 끝 사이의 거리 계산
const thumbTip = landmarks[4];
const thumbDip = landmarks[3];
// 엄지와 다른 손가락 사이의 거리 충분 여부 확인
const isThumbAway = isThumbAwayFromOtherFingers(landmarks);
// 모든 각도 조건을 만족하고, 엄지와 검지 사이의 거리가 임계값보다 크면 true 반환
return angle1 < firstAngle &&
angle2 < secondAngle &&
angle3 < thirdAngle &&
isThumbAway;
}
// 손바닥 펴짐 확인 함수 (수정된 손가락 펴짐 함수 사용) ---------------------------
function isHandOpen(landmarks: any[]): boolean {
const thumbIsStraight = thumbFingerStraight(landmarks); // 엄지
const indexIsStraight = isFingerStraight(landmarks, 1); // 검지
const middleIsStraight = isFingerStraight(landmarks, 2); // 중지
const ringIsStraight = isFingerStraight(landmarks, 3); // 약지
const pinkyIsStraight = isFingerStraight(landmarks, 4); // 새끼
return thumbIsStraight && indexIsStraight && middleIsStraight && ringIsStraight && pinkyIsStraight;
}
function printAngle(landmarks:any[], num:number){
let f = 4*num ;
//첫번째 마디
console.log("첫번째 마디 : "+calculateAngle(landmarks[0],landmarks[f+1],landmarks[f+2]))
//두번재 마디
console.log("두번째 마디 : "+calculateAngle(landmarks[f+1],landmarks[f+2],landmarks[f+3]))
//세번째 마디
console.log("세번째 마디 : "+calculateAngle(landmarks[f+2],landmarks[f+3],landmarks[f+4]))
console.log("===========================");
}