Skip to content

Commit

Permalink
Merge pull request #38 from DDD-Community/feat/#32
Browse files Browse the repository at this point in the history
[feat/#32] 턱괴기 기능 추가, 그룹 리스트에 그룹에 참가한 유저들 목록이 보이도록 수정
  • Loading branch information
G-hoon authored Aug 28, 2024
2 parents 6b46d77 + e033c11 commit 109fd0c
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 9 deletions.
20 changes: 14 additions & 6 deletions src/components/PoseDetector.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import usePushNotification from "@/hooks/usePushNotification"
import type { pose } from "@/utils/detector"
import { detectSlope, detectTextNeck } from "@/utils/detector"
import { detectHandOnChin, detectSlope, detectTextNeck } from "@/utils/detector"
import { drawPose } from "@/utils/drawer"
import { worker } from "@/utils/worker"
import { useCallback, useEffect, useRef, useState } from "react"
Expand All @@ -19,6 +19,7 @@ const PoseDetector: React.FC = () => {
const [isScriptError, setIsScriptError] = useState<boolean>(false)
const [isTextNeck, setIsTextNeck] = useState<boolean | null>(null)
const [isShoulderTwist, setIsShoulderTwist] = useState<boolean | null>(null)
const [isHandOnChin, setIsHandOnChin] = useState<boolean | null>(null)
const [isModelLoaded, setIsModelLoaded] = useState<boolean>(false)
const [isSnapSaved, setIsSnapSaved] = useState<boolean>(false)
const [isPopupVisible, setIsPopupVisible] = useState<boolean>(false)
Expand All @@ -28,7 +29,7 @@ const PoseDetector: React.FC = () => {

const turtleNeckTimer = useRef<any>(null)
const shoulderTwistTimer = useRef<any>(null)
// const chinUtpTimer = useRef<any>(null)
const chinUtpTimer = useRef<any>(null)
// const tailboneSit = useRef<any>(null)

const canvasRef = useRef<HTMLCanvasElement>(null)
Expand Down Expand Up @@ -89,12 +90,14 @@ const PoseDetector: React.FC = () => {
if (snapRef.current) {
const _isShoulderTwist = detectSlope(snapRef.current, results, false)
const _isTextNeck = detectTextNeck(snapRef.current, results, true)
const _isHandOnChin = detectHandOnChin(results)

if (_isShoulderTwist !== null) setIsShoulderTwist(_isShoulderTwist)
if (_isTextNeck !== null) setIsTextNeck(_isTextNeck)
if (_isHandOnChin !== null) setIsHandOnChin(_isHandOnChin)
}
},
[setIsShoulderTwist, setIsTextNeck, showNotification]
[setIsShoulderTwist, setIsTextNeck, setIsHandOnChin, showNotification]
)

const detectStart = useCallback(
Expand Down Expand Up @@ -139,8 +142,12 @@ const PoseDetector: React.FC = () => {
}
}

const getIsRight = (_isShoulderTwist: boolean | null, _isTextNeck: boolean | null): boolean => {
if (!_isShoulderTwist && !_isTextNeck) return true
const getIsRight = (
_isShoulderTwist: boolean | null,
_isTextNeck: boolean | null,
_isHandOnChin: boolean | null
): boolean => {
if (!_isShoulderTwist && !_isTextNeck && !_isHandOnChin) return true
return false
}

Expand All @@ -166,6 +173,7 @@ const PoseDetector: React.FC = () => {

usePoseTimer(isTextNeck, "TURTLE_NECK", turtleNeckTimer)
usePoseTimer(isShoulderTwist, "SHOULDER_TWIST", shoulderTwistTimer)
usePoseTimer(isHandOnChin, "CHIN_UTP", chinUtpTimer)

useEffect(() => {
requestNotificationPermission()
Expand Down Expand Up @@ -209,7 +217,7 @@ const PoseDetector: React.FC = () => {
<div className="absolute top-0 flex w-full items-center justify-center rounded-t-lg bg-[#1A1B1D] bg-opacity-75 p-[20px] text-white">
{!isSnapSaved
? "바른 자세를 취한 후, 하단의 버튼을 눌러주세요."
: getIsRight(isShoulderTwist, isTextNeck)
: getIsRight(isShoulderTwist, isTextNeck, isHandOnChin)
? "올바른 자세입니다."
: "올바르지 않은 자세입니다."}
</div>
Expand Down
6 changes: 3 additions & 3 deletions src/components/Posture/PostrueCrew.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import PostureGuide from "@assets/icons/posture-guide-button-icon.svg?react"
import RankingGuideToolTip from "@assets/images/ranking-guide.png"
import { useEffect, useState } from "react"
import SelectBox from "@components/SelectBox"
import { useAuthStore } from "@/store"

interface IPostureCrew {
groupUserId: number
Expand All @@ -19,15 +20,14 @@ interface PostureCrewProps {

export default function PostrueCrew(props: PostureCrewProps) {
const { toggleSidebar } = props
const accessToken = useAuthStore((state) => state.accessToken)
const [crews, setCrews] = useState<IPostureCrew[]>([])
const [isConnected, setIsConnected] = useState<"loading" | "success" | "disconnected">("loading")
const [isEnabled, setIsEnabled] = useState(true)
const [notiAlarmTime, setNotiAlarmTime] = useState("틀어진 즉시")

useEffect(() => {
const token =
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJoZXJvLWFsaWdubGFiLWFwaSIsImF1ZCI6Imhlcm8tYWxpZ25sYWItYXBpIiwiaWQiOjIwMDAwMSwidHlwZSI6ImFjY2Vzc1Rva2VuIiwiZXhwIjoxNzM1Mzk4MDAwfQ.pIl87yrMX4EVoLlBOG0A2X5AMRRUXalwMKnfH6cSDE8"
const socket = new WebSocket(`wss://api.alignlab.site/ws/v1/groups/1/users?X-HERO-AUTH-TOKEN=${token}`)
const socket = new WebSocket(`wss://api.alignlab.site/ws/v1/groups/1/users?X-HERO-AUTH-TOKEN=${accessToken}`)

socket.onopen = () => {
console.log("WebSocket connected")
Expand Down
44 changes: 44 additions & 0 deletions src/utils/detector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,3 +184,47 @@ export const detectSlope = (refer: pose[], comp: pose[], isSnapShotMode = true):
return true
}
}

/**
* 손을 턱에 괴고 있는 자세를 감지하는 함수
* @param poses 현재 포즈 데이터 배열
* @returns 손을 턱에 대고 있으면 true, 아니면 false, 판단할 수 없으면 null
*/
export const detectHandOnChin = (poses: pose[]): boolean | null => {
if (!poses || poses.length === 0) return null

// 필요한 키포인트 추출
const nose = getXYfromPose(poses, "nose")
const leftEar = getXYfromPose(poses, "left_ear")
const rightEar = getXYfromPose(poses, "right_ear")
const leftWrist = getXYfromPose(poses, "left_wrist")
const rightWrist = getXYfromPose(poses, "right_wrist")
const leftShoulder = getXYfromPose(poses, "left_shoulder")
const rightShoulder = getXYfromPose(poses, "right_shoulder")

// 키포인트가 없으면 null 반환
if (!nose || !leftEar || !rightEar || !leftWrist || !rightWrist || !leftShoulder || !rightShoulder) return null

// 턱의 위치를 추정 (코와 귀 중간점의 중간점)
const earMidpoint = getMidPoint(leftEar, rightEar)
const estimatedChin = getMidPoint(nose, earMidpoint)

// 어깨 너비 계산
const shoulderWidth = getDistance(leftShoulder, rightShoulder)

// 턱 부근을 판단하기 위한 거리를 어깨 너비의 비율로 설정
// 이 비율은 실제 테스트를 통해 조정이 필요할 수 있습니다.
const CHIN_PROXIMITY_RATIO = 0.5 // 어깨 너비의 25%
const chinProximityThreshold = shoulderWidth * CHIN_PROXIMITY_RATIO

// 손목과 추정된 턱 위치 사이의 거리 계산
const leftWristToChinDistance = getDistance(leftWrist, estimatedChin)
const rightWristToChinDistance = getDistance(rightWrist, estimatedChin)

// 왼손이나 오른손 중 하나라도 턱 근처에 있으면 true 반환
if (leftWristToChinDistance < chinProximityThreshold || rightWristToChinDistance < chinProximityThreshold) {
return true
}

return false
}

0 comments on commit 109fd0c

Please sign in to comment.