Skip to content

About

아마추어 테니스 선수가 자기 경기 영상을 올리면 이동 경로·이동거리·코트 히트맵으로 분석해 주고, 예정된 대회 일정도 모아 보여주는 웹 서비스

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

CourtVision

테니스 경기 영상을 올리면 선수를 추적해 이동 경로 · 이동거리 · 속도 · 코트 히트맵을 보여주고, 흩어진 국내 아마추어 대회 일정을 한곳에 모아 보여주는 웹 서비스입니다.

컴퓨터 비전, 크롤링, 웹 서비스 개발, 모델 경량화를 하나의 프로젝트로 묶어 처음부터 끝까지 만들어 본 개인 프로젝트입니다. 구현은 AI(Claude)와 협업했고, 요구사항 정의 · 결과 검토 · 검증 질문 · 실험 설계 판단은 제가 맡았습니다.

핵심 역량

역량 이 프로젝트에서 한 일
컴퓨터 비전 YOLO11n 검출 + BoT-SORT 추적을 Homography로 실제 코트 좌표(m)에 연결해 이동거리·속도·히트맵 산출
모델 학습·평가 공 검출 모델을 v1~v3a까지 파인튜닝하고 같은 영상 기준으로 적중률·오검출률 비교, 악화된 가설까지 검증해 기록
모델 경량화 NNCF + OpenVINO INT8 양자화로 모델 크기 68%↓(10.9→3.5MB), CPU 추론 약 1.7배 빠름, 서비스 지표 변화까지 확인
크롤링 · 데이터 KATO·KTA 일정 수집, SQLite 저장, upsert() 변경 감지와 이력 관리, 무작위 시각 일 1회 수집
백엔드 · 프론트 FastAPI 로그인·세션·분석 기록 API, 프레임워크 없는 단일 페이지 UI(다크/라이트·모바일)
배포 환경 Dockerfile·compose 작성, 컨테이너 안에서 서비스·크롤러 동작 확인 (로컬 한정)
실험 태도 측정 조건 불일치로 1차 결과를 스스로 폐기·재측정, 한계와 못 한 것을 문서에 명시

홈 화면

한눈에 보기

문제 아마추어는 경기 영상을 찍어도 분석할 방법이 없고, 대회 정보는 협회 사이트마다 흩어져 있다
해결 영상 → 선수 추적 → 실제 코트 좌표(m)로 변환 → 통계·히트맵. 대회 일정은 자동 수집해 DB에 저장
스택 FastAPI · SQLite · YOLO11n · BoT-SORT · OpenCV · OpenVINO · Docker
상태 로컬 동작, Docker 컨테이너 실행 확인. 외부 서버 배포는 아직

주요 기능

영상 분석 — 영상을 올리고 코트 4점을 클릭하면 선수의 이동거리, 평균/최고 속도, 궤적, 히트맵을 만듭니다. 4단계 스텝 위저드로 한 번에 한 단계만 보이게 설계했습니다.

영상 분석 화면

대회 일정 — KATO, KTA의 공개 일정을 수집해 출처·부별·접수중 필터로 보여줍니다. 매일 하루 한 번, 매번 다른 무작위 시각에 수집하며, 접수상태 등이 바뀌면 변경 이력을 남깁니다.

대회 일정 화면

로그인 · 마이페이지 — 분석 결과를 촬영일별로 저장하고 다시 볼 수 있습니다. 다크/라이트 테마, 모바일 화면을 지원합니다.

영상 분석 파이프라인

영상 업로드 → 코트 4점 클릭 → YOLO11n 선수 검출 → BoT-SORT 추적
           → Homography로 화면 좌표를 코트 좌표(m)로 변환
           → 이동거리 · 속도 · 궤적 · 히트맵

실험과 결과

수치와 한계는 모두 문서로 남겼습니다. 아래 값은 해당 문서에 있는 그대로입니다.

1. 공 검출 모델 파인튜닝 — results/v2_ball_experiment.md

video9 기준, 20px 이내 적중률 / 공이 없는 프레임의 오검출률 (conf 0.35)

모델 적중률 오검출률 비고
v1 92.9% 37.6%
v2 (채택) 95.3% 15.6% 공 없는 배경 이미지 571장 추가
v3 92.9% 21.8% 공개 데이터 추가 → 오히려 악화
v3a 99.4% 31.6% 배경 보정 가설 → 기각

배운 점: 데이터를 더 넣는다고 좋아지지 않았고, 원인을 가설로 세워 다시 검증해 기각까지 확인했습니다.

2. INT8 경량화 (선수 검출) — results/int8_experiment.md

CPU(Xeon W-2223), 입력 544×960, 300프레임

PyTorch FP32 OpenVINO FP32 OpenVINO INT8
프레임당 시간 72.2 ms 85.7 ms 50.0 ms
모델 크기 5.6 MB 10.9 MB 3.5 MB

서비스 지표까지 비교한 결과(video9 전체, 코트 4점은 근사값을 양쪽에 동일 적용):

FP32 INT8
총 이동거리 33.83 m 33.99 m (+0.5%)
평균 속도 3.41 m/s 3.40 m/s
최고 속도 14.60 m/s 13.43 m/s (-8%)

핵심 지표(이동거리·평균 속도)는 경량화 후에도 거의 그대로였고, 순간값인 최고 속도만 크게 흔들렸습니다.

실패에서 배운 것: 1차 측정은 입력 크기가 달라(정사각형 960×960 vs 직사각형 960×544) 같은 가중치인데 결과가 달랐습니다. 이상해서 원인을 찾아 조건을 맞춰 다시 쟀고, 1차 결과는 폐기하되 로그를 남겼습니다.

설계 결정

  • 크롤링 도구: 대상 페이지(KATO, KTA)가 서버 렌더링이라 응답 HTML에 표가 그대로 있는 것을 확인하고 requests + BeautifulSoup을 선택했습니다. Selenium은 필요하지 않아 쓰지 않았습니다.
  • 정중한 크롤링: User-Agent에 프로젝트 정보 명시, 요청 간 지연, 하루 1회 수집.
  • 변경 감지: upsert()가 신규/변경/동일을 구분해 반환하고, 변경은 이력 테이블에 남깁니다.
  • 외부 텍스트는 textContent로만 삽입(XSS 방지), https 링크만 허용.
  • 프론트는 프레임워크 없이 단일 HTML/JS: 서비스 규모에 맞춰 단순하게 유지했습니다.

지금 안 되는 것

  • 공은 검출까지만 했고, 프레임 간 추적(궤적)은 하지 않았습니다. 서비스에도 연결돼 있지 않습니다.
  • 이동거리·속도는 참고용 추정값입니다. 실측값과 비교 검증하지 않았습니다.
  • 코트 보정은 4점을 직접 클릭해야 합니다 (자동 인식 아님).
  • INT8 모델은 실험만 했고 서비스에는 연결하지 않았습니다.
  • Docker는 로컬 컨테이너 실행까지만 확인했고, 외부에서 접속 가능한 서버 배포는 아직입니다.
  • 실험은 대부분 영상 1개, 측정 1회 기준이라 일반화하기 어렵습니다.

실행 방법

로컬

cd webapp/backend
pip install -r requirements.txt
uvicorn main:app --port 8000

http://localhost:8000 접속. 첫 실행 시 YOLO11n 가중치를 자동으로 내려받습니다. 세션이 메모리에 있어 워커는 1개로 실행합니다.

Docker

docker compose up --build

환경변수(선택): COURTVISION_DB, UPLOAD_DIR, RESULTS_DIR, YOLO_IMGSZ, COOKIE_SECURE(HTTPS 배포 시 1)

폴더 구조

webapp/backend/   FastAPI 서버, 파이프라인, 크롤러, DB
webapp/frontend/  단일 HTML/JS 프론트
src/              실험·검증 스크립트 (공 학습/평가, INT8 등)
results/          실험 기록
docs/             스크린샷, 발표 자료

데이터 출처

대회 정보는 한국테니스발전협의회(KATO)와 대한테니스협회(KTA)가 공개한 일정을 요약한 것이며, 정확한 내용은 각 대회의 원본 링크에서 확인해야 합니다. 화면의 사진은 분위기를 위한 AI 생성 이미지입니다.

About

아마추어 테니스 선수가 자기 경기 영상을 올리면 이동 경로·이동거리·코트 히트맵으로 분석해 주고, 예정된 대회 일정도 모아 보여주는 웹 서비스

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages