⌦ Teachable Machine 를 이용한 운동 횟수 세는 페이지
☑︎ Teachable Machine
https://teachablemachine.withgoogle.com/
Teachable Machine
Train a computer to recognize your own images, sounds, & poses. A fast, easy way to create machine learning models for your sites, apps, and more – no expertise or coding required.
teachablemachine.withgoogle.com
이 프로젝트를 기획하게 된 계기가 Teachable Machine 이다. Teachable Machine은 구글에서 만든 웹기반 노코드 인공지능 학습 툴이다. 이미지, 사운드, 자세를 인식하도록 컴퓨터를 학습시켜서 사이트, 앱 등에 사용할 수 있는 머신러닝 모델을 쉽고 빠르게 만들 수 있다.
머신러닝에 대해 잘 몰랐고 써본 경험도 없지만 머신러닝 입문용으로 사용할 만한 것 같았고, 잘 활용하면 재밌는 웹 서비스를 만들 수 있을 것 같다는 생각이 들어서 사용법을 찾아가며 써 보았다.
이 프로젝트는 운동 개수를 세는 것이기 때문에 포즈 프로젝트를 사용했다.
들어가면 이런 화면이 나오는데, 이제 사진을 찍거나 업로드하여 학습시키면 된다. 이 프로젝트에서는 스쿼트, 런지, 팔굽혀펴기 세가지의 운동 종류를 학습시켰는데, 방법은 세가지 모두 유사하다.
스쿼트를 예로 들면 Class 1 에는 정자세로 서 있는 사진을 웹캠으로 찍어서 학습시켰다. 사용자가 어떤 자세로 시작할 것인지 모르기 때문에 서 있는 것도 여러 방향으로 촬영했다. 밝은 곳 어두운 곳도 구분하여 촬영했다!! 그래서 1000장 정도 찍었던 것 같다.
Class 2 에는 우리가 알고있는 스쿼트 자세로 사진을 찍어 학습시켰다. 마찬가지로 여러 방향으로 촬영했고, 1000장 정도 찍었다.
사진 촬영이 끝나면 모델 학습시키기를 누른다. 생각보다 짧은 시간에 학습이 끝난다. 학습이 끝나면 모델을 미리보기 할 수 있다.
정자세로 서 있을 때는 Class 1 이 100% 로 출력되고, 스쿼트 자세를 했을 때는 Class 2 가 100% 로 출력된다. 100% 정확하진 않고, 엄청 섬세하진 않지만 이렇게만 해도 원하는 방향으로 서비스를 개발할 수 있을 것 같다.
미리보기에서 모델이 잘 학습되었으면 모델을 내보내야 하는데, 내보내는 방법은 업로드와 다운로드가 있다. 나는 업로드를 사용했다. 모델 업로드를 누르고 조금만 기다리면 밑 javascript 코드에 상수 URL이 생긴다. 그거 확인하고 코드 전체를 복사하여 프로젝트에 사용하면 된다.
- JavaScript
Teachable Machine 에서 만들어 준 코드를 그대로 사용해도 문제는 없지만, 내가 원하는 기능을 추가하기 위해 대략적인 코드 내용을 알아야 했다. 이리저리 바꿔보고 또 추가해보고 에러 300번 실패 200번 내면서 만들었다.
① prediction[0] 에는 stand 자세가 학습되어있는 Class 1 정보가 들어있다. prediction[1] 에는 squat 자세가 학습되어있는 Class 2 정보가 들어있다. 그래서 각각 상수의 이름을 stand, squat 로 바꿔주었다. toFixed(2) 는 소숫점자리수를 2개로 제한한다는 뜻이다.
② 스쿼트의 count 가 올라가려면 stand ➡️ squat ➡️ stand 세 과정이 완료되어야 count 가 1이 올라간다. 처음엔 stand ➡️ squat 두 과정 만으로 count 를 올리는 게 아닌가 생각했는데 실험 해보니까 당연히 다시 stand 하는 과정 까지가 "1" 이겠다고 생각했다.
운동 start 버튼을 누르고 카메라를 켠 뒤, 운동을 시작할 때의 상태는 stand 이다. 그 다음 parseInt(squat) 가 1 (100%) 이면 predict 함수 밖에 선언해 준 변수 status 의 값이 "stand" 에서 "squat" 로 바뀌게 된다.
그리고 다시 stand 가 0.98(98%) 초과인 상황에서 status 가 "squat" 인 상태라면 stand ➡️ squat ➡️ stand 의 과정이 이루어졌다는 소리가 된다. ( ( stand > 0.98 ) 이라는 조건을 준 이유는 stand 자세가 학습된 모델과 100% 일치했을 때만 운동 개수를 세어주는 것 보다, 98% 정도만 일치해도 개수를 세어주게 하는 것이 낫겠다는 생각이 들어서다. 2% 차이지만 분명한 차이가 있었다! 진짜다. ) 그렇기 때문에 count++ 를 해준다. 그와 동시에 우측에 만들어 둔 원형 progress bar 도 움직여야 한다. 이 모든 과정이 끝났을 때의 사용자의 자세는 stand 이므로 status 를 "stand" 로 다시 바꾼다.
③ 원형 progress bar 는 count 가 올라감과 동시에 변할 수 있도록 위치한다.
- Controller
@RequestMapping(value = "squat",
method = RequestMethod.GET)
public ModelAndView getSquat(@SessionAttribute(value = "user", required = false) UserEntity user) {
ModelAndView modelAndView;
if (user == null) {
modelAndView = new ModelAndView("redirect:/dios/login");
} else {
modelAndView = new ModelAndView("records/squat");
int goal = this.recordService.readCount(user);
modelAndView.addObject("goal", goal);
}
return modelAndView;
}
squat 페이지도 session에 user가 null 이라면 당장 로그인 화면으로 돌아가게했다.
목표 개수를 user email 을 기준으로 select 하여 받아와서 modelAndView 에 "goal" 이 키인 값으로 넣어준다.
- Service
public int readCount(UserEntity user) {
UserEntity existingUser = this.memberMapper.selectUserByEmail(user.getEmail());
return existingUser.getGoalCount();
}
- Mapper(interface), xml
UserEntity selectUserByEmail(@Param(value = "email") String email);
<select id="selectUserByEmail"
resultType="com.blackgreen.dios.entities.member.UserEntity">
SELECT `email` AS `email`,
`goal_count` AS `goalCount`
FROM `dios_member`.`users`
WHERE BINARY `email` = #{email}
LIMIT 1
</select>
목표 개수를 modelAndView 에 넣어뒀으니 HTML에서 타임리프를 사용하여 th:value="${goal}" 의 형태로 받아올 수 있다. 이것을 javascript의 변수 value 로 받아와서 squat 페이지에 출력한다. 현재 개수는 변수 count 를 사용하여 계속 올라가는 것을 출력하면 된다. 그러면 진행 정도(%)는 Math.round((count / value) * 100) 로 표현할 수 있다.
④ count(현재 개수)와 goal(목표 개수)이 같아지면 측정을 멈춰야 한다.
predict 함수는 loop 함수 안에서 실행되는데 loop 함수는 밖에서 선언해주었던 변수 breakLoop 가 false 일 때만 실행된다. 그러므로 count === goal 일 때 breakLoop 를 true 로 바꿔준다면, 운동 측정 화면이 멈추게 된다.
✔️ requestAnimationFrame 은 재귀함수의 흐름과 같다. 한 번 실행한 함수 안에서 자신을 다시 불러 실행하고, 그게 반복된다.
'웹개발 > DIOS' 카테고리의 다른 글
[웹개발 - DIOS] 주문 페이지 (0) | 2023.02.25 |
---|---|
[웹개발 - DIOS] 장바구니 페이지 (2) (0) | 2023.02.25 |
[웹개발 - DIOS] 장바구니 페이지 (1) (0) | 2023.02.24 |
[웹개발 - DIOS] 기록장 페이지 (0) | 2023.02.23 |
[웹개발 - DIOS] 운동 목표 개수 설정 페이지 (0) | 2023.02.22 |