# 영상 보행분석 프로젝트
> 경북대학교병원 / 2019.05 ~ 2021.01 (1년 9개월)
<img src="https://i.imgur.com/zHJ7WEE.gif" width="100%" style="boarder:1px solid gray">
## 프로젝트 요약
- 경북대학교병원 신경과 전문의와 협업하여 진행한 프로젝트로, 카메라를 활용하여 보행 변수(속도, 보폭 등)을 측정하는 딥러닝 모델을 개발하였습니다.
- 통제되지 않은 보행분석 환경(보행자 이외의 사람이 등장)에서 노이즈를 최소화하기 위한 3D CNN 모델을 개발하였습니다.
- External validation을 통해, 상용 보행분석 장비 [GAITRite](https://www.gaitrite.com/) 시스템과 높은 agreement를 확인 및 검증하였습니다.
- Flask 기반 보행분석 inference API를 구현하였습니다.
- 저널 논문 1편, 컨퍼런스 논문 1편의 학술적 성과를 이루었습니다.
- 저널 논문 (Scientific Reports, 2021) : [링크](https://www.nature.com/articles/s41598-021-90524-9)
- 컨퍼런스 논문 (ICONIP, 2019) : [링크](https://link.springer.com/chapter/10.1007/978-3-030-36808-1_69)
**Code** : [link](https://github.com/youhs4554/gaitanalysis); **Notion** : [link](https://checker-zinnia-239.notion.site/Camera-based-Human-Gait-Analysis-cf86be898416489eb654f3bbdef8386f)
## 개발 목표
- 딥러닝 기반 영상 보행분석 모델 개발
- WEB 기반 병원 정보 시스템에서 보행 분석결과 조회 기능을 위한 Flask 기반 서빙 파이프라인 구현
## 기술 스택
- PyTorch, Skorch
- Numpy, OpenCV
- Pandas, Matplotlib, Seaborn
- Flask, sqlalchemy
- Video Understanding, Vision-based Gait Analysis, 3D CNNs, Yolo v3
## 개발 내용
### 환자 영역 선택
> 환자의 보행에 집중하기 위해, [Yolo v3](https://pjreddie.com/darknet/yolo/)를 활용하여 사람 검출 및 트래킹을 수행하였습니다. 환자 영역은 규칙 기반 방법을 적용하여 선택하였습니다.
- **트래킹 결과** : 인접 프레임간의 IOU를 계산하고 그리디한 방법으로 트래킹을 진행하였습니다.
<table>
<tr>
<td>
<b>IOU 트래커</b>
<img src="https://i.imgur.com/A61mQUA.png">
</td>
<td>
<b>결과물</b>
<img src="https://i.imgur.com/VBIJ7I0.gif">
</td>
</tr>
</table>

<!-- <iframe src="https://drive.google.com/file/d/1D0zcotC6aGFW3PreE9VyhK0rvPX_Nl2G/preview" width="50%" height="240" allow="autoplay"></iframe> -->
- **환자 영역 선택 결과** : 박스의 중심점을 기준으로 x축 대비 y축 변화가 가장 큰 트래킹 ID를 선택하였습니다.
<table>
<tr>
<td>
<b>x,y 변위 그래프 비교</b>
<br>
(환자의 track id : <font color="orange">주황색</font>)
<img src="https://i.imgur.com/oaAXrev.png">
</td>
<td>
<b>결과물</b>
<img src="https://i.imgur.com/rriwG1M.gif">
</td>
</tr>
</table>
>


<!-- <iframe src="https://drive.google.com/file/d/1Gt_y5Dn1S3qnx7LLBbZ1I2jda5CQwpe3/preview" width="50%" height="240" allow="autoplay"></iframe> -->
### Mask Supervision
- 환자 영역을 나타내는 바이너리 **마스크 예측 레이어**를 추가하였습니다.
- 마스크 예측 결과와 CNN feature를 곱해줘서 환자가 아닌 영역의 **CNN activation을 억제**하였습니다.
<br>
<img src="https://i.imgur.com/PVhZDTf.png" height="300px">
<br>
<br>
코드는 다음과 같습니다.
```python=
# i번째 백본 네트워크 레이어에서 output을 얻습니다. (x는 i-1번째 레이어 output)
out = backbone_layer(x)
# seg_layer를 통해 바이너리 마스크를 예측합니다. seg_layer는 1x1x1 conv 레이어 입니다.
seg = torch.sigmoid(seg_layer(out))
# x의 shape를 백본 output과 동일하게 맞춰줍니다.
x = max_pool3d(x, [int(x.size(i)/out.size(i)) for i in range(2, 5)]) # max poolling
x = matching_layer(x) # 1x1x1 conv -> BN -> ReLU; conv를 통해 채널 갯수를 맞춰줍니다.
# 첫째 항 : mask supervision을 적용합니다. i번째 백본 출력 out과 예측된 마스크 seg를 곱해줍니다.
# 둘째 항 : mask noise로 인한 blackout을 방지하기 위해, seg를 inverting하여 (i-1) 번째 output인 x와 곱한 결과를 출력에 반영합니다.
x = out * seg + x * (1-seg)
```
### 모델 아키텍처
> torchvision에서 제공하는 [r2plus1d-18](https://arxiv.org/abs/1711.11248) 모델의 각 레이어마다 mask supervision을 반복적으로 수행하여 전체 모델을 구성하였습니다. 각 레이어 마다 $L^{mask}$를 계산하여 $L^{main}$와 함께 최적화 하였습니다. ($L^{mask}$: BCE, $L^{main}$: SmoothL1Loss)
전체 모델 구조는 다음과 같습니다. (모델의 전체 코드는 [여기](https://github.com/youhs4554/gaitanalysis/blob/afc1bab4fd1f3b68d70d2107234bda3a8d833bd7/src/dev/models/regression_model.py#L566)에서 확인할 수 있습니다.)
<br>
<img src="https://i.imgur.com/PwYudE1.png" height="400px">
### 결과
> Mask supervision의 효과를 CNN activation 시각화를 통해 확인해 보았습니다. 보행자 이외의 사람이 있더라도 **환자 주변에서 activation이 높게 형성**되는 것을 확인하였습니다.

<br>
> Scatter plot을 그려본 결과, mask supervision 적용 후 **scatter의 모양이 더 linear해 지는 것을 확인**하였습니다. (x 축 : ground truth, y축 : predicted)

> 또한, **성능 향상**에도 도움이 되는 것을 확인하였습니다.
<table style="text-align:center">
<tr>
<td rowspan="2">Method</td>
<td colspan="3">Mean Absolute Error (MAE)</td>
<td colspan="3">R-squared</td>
</tr>
<tr>
<td>Temporal</td>
<td>Spatial</td>
<td>Summarized</td>
<td>Temporal</td>
<td>Spatial</td>
<td>Summarized</td>
</tr>
<tr>
<td>baseline</td>
<td>0.046</td>
<td>4.15</td>
<td>5.33</td>
<td>0.53</td>
<td>0.70</td>
<td>0.70</td>
</tr>
<tr>
<td>+mask supervision</td>
<td><b>0.037</b></td>
<td><b>2.74</b></td>
<td><b>3.81</b></td>
<td><b>0.79</b></td>
<td><b>0.82</b></td>
<td><b>0.90</b></td>
</tr>
</table>
### 상용 보행분석 장비 GAITRite 시스템과 agreement 검증
> Scatter plot, Bland-Altman plot, Intraclass correlation 등의 분석을 통해 GAITRite와 **높은 agreement**를 보이는 것을 확인 및 검증하였습니다.
**[:arrow_right: 자세한 분석 결과는 논문에서 확인할 수 있습니다. :arrow_left:](https://www.nature.com/articles/s41598-021-90524-9)**
Correlation 분석 테이블은 다음과 같습니다.
<img src="https://i.imgur.com/4f5oiVL.png" height="300px">
:::success
- 학습 데이터에 포함되지 않았던 특정 질환군(INPH;특발성 정상압수두증)에 대한 external validation 실험을 진행하였습니다.
- [ICC](https://en.wikipedia.org/wiki/Intraclass_correlation) 0.8 이상의 우수한 agreement를 확인하였습니다.
📗 Excellent: ICC > 0.75, Good: 0.40<ICC<0.75, Poor: ICC<0.40 [[출처](https://www.sciencedirect.com/science/article/abs/pii/S0966636216307111?via%3Dihub)]
:::
### 보행분석 모델 서빙
> 웹 페이지를 통해 업로드 된 보행 비디오를 분석하는 Flask 기반 inference API를 구현하였습니다.
- sqlalchemy의 `execute()` 를 사용하여 DB Insert 기능을 구현하였습니다.
- 여러 요청이 동시에 들어왔을 때, 쓰레드 간의 race condition이 일어나지 않도록 `scoped_session()`을 사용하였습니다.
Inference API는 다음과 구현하였습니다. (전체 코드는 [여기](https://github.com/youhs4554/gaitanalysis/blob/master/src/dev/demo/app.py)에서 확인할 수 있습니다.)
```python=
from sqlalchemy.orm import scoped_session, sessionmaker
@app.route('/api')
def api_call():
'''
병원정보 시스템(HIS) 웹 클라이언트에서 '분석' 버튼 클릭시 분석이 시작됩니다. (실시간 분석이 아닌, 업로드된 비디오파일을 분석)
'''
# ... 중략 ...
engine = VariableInterface.db._engine # 엔진으로는 Oracle DB를 사용하였습니다.
session = scoped_session(sessionmaker(
autocommit=False, autoflush=False, bind=engine))
sess = session()
VariableInterface.sess = sess
try:
for n in range(len(VariableInterface.query_res.filepath.values)):
VariableInterface.VIDEO_PATH = f'./demo/static/tmp_{n}.avi' # inference 서버에 업로드 된 비디오 파일입니다.
# fetch video file!
fetch_file(fileseq=n)
# run model!
run_model()
# write result to DB!
write_result()
# callback of success, notifying task is done!
success_callback()
sess.commit()
except BadRequestException:
sess.rollback()
return VariableInterface.BadResponse
finally:
sess.close()
return VariableInterface.GreetingResponse
```
### 보행분석 결과 조회
> Inference API를 통해 분석된 결과가 병원 정보 시스템에서 조회될 수 있도록 하였습니다.
- **테이블 뷰**

- **그래프 뷰**
