Skip to content

Commit

Permalink
Merge pull request #20 from DDD-Community/feat/#19
Browse files Browse the repository at this point in the history
Feat/#19
  • Loading branch information
lkhoony authored Aug 18, 2024
2 parents cb00b9f + 25e9137 commit 03d7220
Show file tree
Hide file tree
Showing 14 changed files with 247 additions and 140 deletions.
20 changes: 20 additions & 0 deletions public/icons/more-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions public/icons/posture-craft-side-nav-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions public/icons/side-nav-analysis-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions public/icons/side-nav-crew-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions public/icons/side-nav-monitor-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/posture-guide-2x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
36 changes: 29 additions & 7 deletions src/components/Camera.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import React, { useRef, useEffect } from "react"

type WebcamProps = {
onStreamReady: (video: HTMLVideoElement) => void
interface CameraProps {
detectStart: (video: HTMLVideoElement) => void
canvasRef: React.LegacyRef<HTMLCanvasElement> | undefined
}

const Camera: React.FC<WebcamProps> = ({ onStreamReady }) => {
export default function Camera(props: CameraProps): React.ReactElement {
const { detectStart, canvasRef } = props
const videoRef = useRef<HTMLVideoElement>(null)

const startVideo = (): void => {
Expand All @@ -26,7 +28,7 @@ const Camera: React.FC<WebcamProps> = ({ onStreamReady }) => {
videoRef.current.onloadedmetadata = () => {
if (videoRef.current) {
videoRef.current.play()
onStreamReady(videoRef.current)
detectStart(videoRef.current)
}
}
}
Expand All @@ -41,6 +43,13 @@ const Camera: React.FC<WebcamProps> = ({ onStreamReady }) => {
})

return (
<div
style={{
width: "100%",
height: "100%",
position: "relative",
}}
>
<div style={{ position: "relative", width: "100%", height: "100%" }}>
<video
className="rounded-lg"
Expand All @@ -52,10 +61,23 @@ const Camera: React.FC<WebcamProps> = ({ onStreamReady }) => {
width: "100%",
height: "100%",
objectFit: "fill",
transform: "scaleX(-1)", // 비디오를 좌우 반전시키는 CSS 속성 추가
}}
/>
</div>
<canvas
ref={canvasRef}
width="1280"
height="720"
style={{
position: "absolute",
top: 0,
left: 0,
width: "100%",
height: "100%",
transform: "scaleX(-1)", // 캔버스도 좌우 반전시켜 비디오와 일치시킴
}}
/>
</div>
)
}

export default Camera
}
35 changes: 0 additions & 35 deletions src/components/CameraContianer.tsx

This file was deleted.

94 changes: 22 additions & 72 deletions src/components/PoseDetector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import { detectSlope, detectTextNeck } from "@/utils/detector"
import { drawPose } from "@/utils/drawer"
import { worker } from "@/utils/worker"
import { useCallback, useEffect, useRef, useState } from "react"
import CameraContianer from "./CameraContianer"
import Camera from "./Camera"
import GuidePopup from "./Posture/GuidePopup"

const PoseDetector: React.FC = () => {
const [isScriptLoaded, setIsScriptLoaded] = useState<boolean>(false)
Expand All @@ -14,6 +15,7 @@ const PoseDetector: React.FC = () => {
const [isModelLoaded, setIsModelLoaded] = useState<boolean>(false)
const [mode] = useState<string>("snapshot")
const [isSnapSaved, setIsSnapSaved] = useState<boolean>(false)
const [isPopupVisible, setIsPopupVisible] = useState<boolean>(false)
const modelRef = useRef<any>(null)
const snapRef = useRef<pose[] | null>(null)
const resultRef = useRef<pose[] | null>(null)
Expand Down Expand Up @@ -142,27 +144,40 @@ const PoseDetector: React.FC = () => {
// setIsSnapSaved(false)
// }

// 팝업 열기
const handleShowPopup = () => {
setIsPopupVisible(true)
}

// 팝업 닫기
const handleClosePopup = () => {
setIsPopupVisible(false)
}

return (
<>
{isScriptError ? (
"스크립트 불러오기 실패"
"자세를 트래킹 하기 위한 모델을 불러오는 것에 실패 했습니다. 잠시 후 다시 시도해 주시기 바랍니다."
) : !isScriptLoaded ? (
"스크립트 불러오는 중"
) : (
<div className="relative flex h-full w-full flex-col items-center justify-center">
<CameraContianer detectStart={detectStart} canvasRef={canvasRef} isModelLoaded={isModelLoaded} />
<Camera detectStart={detectStart} canvasRef={canvasRef} />
{isModelLoaded && (
<>
<div className="absolute top-0 flex w-[100%] items-center justify-center rounded-t-lg bg-[#1A1B1D] bg-opacity-75 p-[20px] text-white">
<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(slope, isTextNeck)
? "올바른 자세입니다."
: "올바르지 않은 자세입니다."}
</div>
{!isSnapSaved && (
<div className="absolute bottom-0 flex w-[100%] items-center justify-center gap-[20px] p-[50px] text-white">
<button className="rounded rounded-full bg-[#FFFFFF] bg-opacity-80 p-[20px] text-black">
<div className="absolute bottom-0 flex w-full items-center justify-center gap-[20px] p-[50px] text-white">
<button
className="rounded rounded-full bg-white bg-opacity-80 p-[20px] text-black"
onClick={handleShowPopup}
>
가이드 다시 볼게요!
</button>
<button
Expand All @@ -175,72 +190,7 @@ const PoseDetector: React.FC = () => {
)}
</>
)}
{/* {isModelLoaded && (
<div
style={{
display: "flex",
}}
>
<div className="text-center">
<div className="font-bold text-red-500">본 화면은 좌우가 반대로 보이고 있으니 주의하세요!</div>
<div>
<select className="rounded border border-gray-400 bg-white p-2" onChange={onChangeMode}>
<option value={"snapshot"}>스냅샷 모드 (올바른 자세 촬영 후, 해당 자세 기준으로 측정)</option>
<option value={"skeleton"}>자동 모드 (올바른 자세 기준으로 측정)</option>
</select>
</div>
{mode === "snapshot" && (
<div
style={{
paddingTop: "5px",
}}
>
{isSnapSaved ? (
<button
className="rounded bg-blue-500 px-4 py-2 font-bold text-white"
onClick={initializePoseMonitoring}
>
스냅샷 다시 찍기
</button>
) : (
<button className="rounded bg-blue-500 px-4 py-2 font-bold text-white" onClick={getInitSnap}>
올바른 자세를 촬영한 후 자세 측정 시작!
</button>
)}
</div>
)}
{mode === "skeleton" && (
<>
<div className="p-1 font-bold">자동 모드입니다. 자동으로 부적절한 자세를 추적합니다.</div>
<div className="flex gap-10">
<button
className="rounded bg-blue-500 px-4 py-2 font-bold text-white disabled:bg-gray-400"
onClick={getInitSnap}
// disabled={snapShoptPose.length > 0}
>
자세 모니터링 시작!
</button>
<button
className="rounded bg-red-500 px-4 py-2 font-bold text-white disabled:bg-gray-400"
onClick={onCancelAutoPoseMonitoring}
// disabled={snapShoptPose.length === 0}
>
자세 모니터링 취소
</button>
</div>
</>
)}
</div>
<div
style={{
paddingLeft: "20px",
paddingTop: "20px",
}}
>
<TrackingResult isTextNeck={isTextNeck} slope={slope} />
</div>
</div>
)} */}
{isPopupVisible && <GuidePopup onClose={handleClosePopup} />} {/* 팝업 표시 */}
</div>
)}
</>
Expand Down
27 changes: 27 additions & 0 deletions src/components/Posture/GuidePopup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import GuideImage from "public/images/posture-guide-2x.png"

const GuidePopup = ({ onClose }: { onClose: () => void }) => {
return (
<div className="absolute inset-0 flex items-center justify-center backdrop-blur-lg">
{/* blur 처리 */}
<div className="pointer-events-auto relative w-[600px] rounded-lg bg-white p-8 shadow-lg">
{/* 이미지로 대체된 가이드 부분 */}
<div className="mb-8 flex justify-center">
<img
src={GuideImage} // 이미지 경로를 실제 경로로 수정하세요
alt="바른자세 가이드"
className="h-auto w-full" // 이미지 사이즈 조정
/>
</div>

<div className="mt-6 flex justify-center">
<button className="rounded-full bg-blue-500 px-4 py-2 text-white" onClick={onClose}>
모니터링 시작하기
</button>
</div>
</div>
</div>
)
}

export default GuidePopup
Loading

0 comments on commit 03d7220

Please sign in to comment.