Skip to content

Commit

Permalink
[feat/#46] 꼬리뼈 앉기 탐지 로직 수정, favicon추가
Browse files Browse the repository at this point in the history
  • Loading branch information
lkhoony committed Sep 22, 2024
1 parent e44bec2 commit 3a52507
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 26 deletions.
4 changes: 2 additions & 2 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" as="style" crossorigin href="https://cdn.jsdelivr.net/gh/orioncactus/[email protected]/dist/web/static/pretendard.min.css" />
<!-- <script src="https://unpkg.com/ml5@1/dist/ml5.min.js"></script> -->
<title>자세 공작소</title>
<link rel="icon" href="/src/assets/icons/favicon.svg" />
<title>자세공작소</title>
</head>
<body>
<div id="root"></div>
Expand Down
7 changes: 7 additions & 0 deletions src/assets/icons/favicon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 12 additions & 4 deletions src/components/PoseDetector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import Controls from "./Posture/Controls"
import { useNotificationStore } from "@/store/NotificationStore"
import { duration } from "@/api/notification"
import { useCameraPermission } from "@/hooks/useCameraPermission"
import { useLocation } from "react-router-dom"

const PoseDetector: React.FC = () => {
const [isScriptLoaded, setIsScriptLoaded] = useState<boolean>(false)
Expand Down Expand Up @@ -54,6 +55,8 @@ const PoseDetector: React.FC = () => {

const { requestNotificationPermission } = usePushNotification()
const { hasPermission } = useCameraPermission()

const location = useLocation() // 페이지 이동 감지
// webgl 설정
const initializeBackend = async (): Promise<void> => {
await window.ml5.setBackend("webgl")
Expand Down Expand Up @@ -118,7 +121,9 @@ const PoseDetector: React.FC = () => {
): void => {
if (condition && isSnapSaved) {
if (!timerRef.current) {
console.log(poseType, "start")
timerRef.current = setInterval(() => {
console.log("start")
if (resultRef.current) {
const { keypoints, score } = resultRef.current[0]
const req = { snapshot: { keypoints, score }, type: poseType }
Expand Down Expand Up @@ -273,15 +278,18 @@ const PoseDetector: React.FC = () => {
}
}

// 페이지가 변경될 때마다 타이머를 제거
useEffect(() => {
requestNotificationPermission()
getScript()
clearTimers()
return () => {
worker.postMessage({ type: "terminate", data: {} })
clearTimers()
clearCnt()
worker.postMessage({ type: "terminate", data: {} })
}
}, [location])

useEffect(() => {
requestNotificationPermission()
getScript()
}, [])

useEffect(() => {
Expand Down
4 changes: 2 additions & 2 deletions src/components/Posture/PostureMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ const PostureMessage: React.FC<{
? "브라우저의 카메라 권한을 허용해주세요."
: !isSnapSaved
? "바른 자세를 취한 후, 하단의 버튼을 눌러주세요."
: getIsRight(isShoulderTwist, isTextNeck, isHandOnChin, isTailboneSit)
: getIsRight(isShoulderTwist, isTextNeck, isTailboneSit, isHandOnChin)
? "올바른 자세입니다."
: getMessage(isShoulderTwist, isTextNeck, isHandOnChin, isTailboneSit)}
: getMessage(isShoulderTwist, isTextNeck, isTailboneSit, isHandOnChin)}
</div>
)
}
Expand Down
6 changes: 6 additions & 0 deletions src/utils/calculator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,12 @@ export const getMidPoint = (p1: point, p2: point): point => {
return { x, y }
}

// 두 직선의 기울기를 바탕으로 교각을 구하는 함수
export const getAngleBetweenLines = (slope1: number, slope2: number): number => {
const radian = Math.atan(Math.abs((slope1 - slope2) / (1 + slope1 * slope2)))
return radian * (180 / Math.PI) // 각도를 도(degree)로 변환
}

// /**
// * x=axisX를 기준으로 point를 대칭 이동 시킴
// *
Expand Down
64 changes: 46 additions & 18 deletions src/utils/detector.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getSlopeFromPoints, getMidPoint, getDistance } from "@/utils/calculator"
import { getSlopeFromPoints, getMidPoint, getDistance, getAngleBetweenLines } from "@/utils/calculator"
import type { point } from "@/utils/calculator"

export interface keypoint {
Expand Down Expand Up @@ -283,27 +283,55 @@ export const detectTailboneSit = (refer: pose[], comp: pose[]): boolean | null =
)
return null

// 현재(comp)와 스냅샷(refer) 데이터의 귀 중간 좌표를 계산
const compEarMid = getMidPoint(compLeftEar, compRightEar)
const referEarMid = getMidPoint(referLeftEar, referRightEar)

// 현재(comp)와 스냅샷(refer) 데이터의 어깨 중간 좌표를 계산
const compShoulderMid = getMidPoint(compLeftShoulder, compRightShoulder)
const referShoulderMid = getMidPoint(referLeftShoulder, referRightShoulder)
const referEarDistance = getDistance(referLeftEar, referRightEar)
const compEarDistance = getDistance(compLeftEar, compRightEar)

// 귀와 어깨 사이의 거리 계산
const referShoulderDistance = getDistance(referLeftShoulder, referRightShoulder)
const referEarsDistance = getDistance(referLeftEar, referRightEar)
const compShoulderDistance = getDistance(compLeftShoulder, compRightShoulder)
const compEearsDistance = getDistance(compLeftEar, compRightEar)

// 조건 1: 현재(comp)의 귀 중간 y좌표가 스냅샷(refer)보다 아래에 있고,
// 현재(comp)의 어깨 중간 y좌표도 스냅샷(refer)보다 아래에 있는지 확인
const compY = compEarMid.y - referEarMid.y > 20 && compShoulderMid.y - referShoulderMid.y > 20
// 귀의 중점 계산
const referEarMidpoint = getMidPoint(referLeftEar, referRightEar)
// 귀의 중점 계산
const compEarMidpoint = getMidPoint(compLeftEar, compRightEar)

const referForwardHeadDistance = Math.max(referLeftShoulder.y, referRightShoulder.y) - referEarMidpoint.y
const compForwardHeadDistance = Math.max(compLeftShoulder.y, compRightShoulder.y) - compEarMidpoint.y

const referShoulderSlope = getSlopeFromPoints(referLeftShoulder, referRightShoulder)

// 2. 왼쪽 어깨-왼쪽 귀를 잇는 직선의 기울기
const referLeftShoulderEarSlope = getSlopeFromPoints(referLeftShoulder, referLeftEar)

// 3. 오른쪽 어깨-오른쪽 귀를 잇는 직선의 기울기
const referRightShoulderEarSlope = getSlopeFromPoints(referRightShoulder, referRightEar)

// 조건 2: 현재(comp)의 귀 거리와 어깨 거리가 참조(refer)의 90%보다 짧은지 확인
const compDistance = compEearsDistance < referEarsDistance * 0.9 && compShoulderDistance < referShoulderDistance * 0.9
const compShoulderSlope = getSlopeFromPoints(compLeftShoulder, compRightShoulder)

// 두 조건을 모두 만족하면 true 반환, 그렇지 않으면 false 반환
return compY && compDistance
// 2. 왼쪽 어깨-왼쪽 귀를 잇는 직선의 기울기
const compLeftShoulderEarSlope = getSlopeFromPoints(compLeftShoulder, compLeftEar)

// 3. 오른쪽 어깨-오른쪽 귀를 잇는 직선의 기울기
const compRightShoulderEarSlope = getSlopeFromPoints(compRightShoulder, compRightEar)

const referLeftAngle = getAngleBetweenLines(referShoulderSlope, referLeftShoulderEarSlope)
const referRightAngle = getAngleBetweenLines(referShoulderSlope, referRightShoulderEarSlope)

const compLeftAngle = getAngleBetweenLines(compShoulderSlope, compLeftShoulderEarSlope)
const compRightAngle = getAngleBetweenLines(compShoulderSlope, compRightShoulderEarSlope)

const referAngleRatio = 1 / (referLeftAngle + referRightAngle)
const compAngleRatio = 1 / (compLeftAngle + compRightAngle)
const referCorrectRatio = (0.4 * referForwardHeadDistance) / (1.5 * referEarDistance + 0.3 * referShoulderDistance)
const compCorrectRatio = (0.4 * compForwardHeadDistance) / (1.5 * compEarDistance + 0.3 * compShoulderDistance)

const referRatio = 0.7 * referCorrectRatio + 0.3 * referAngleRatio
const compRatio = 0.7 * compCorrectRatio + 0.3 * compAngleRatio

const RATIO_DIFF_THRESHOLD = 0.88

if (referRatio * RATIO_DIFF_THRESHOLD > compRatio) {
return true
} else {
return false
}
}

0 comments on commit 3a52507

Please sign in to comment.