# 병실내 실시간 비디오 행동인식 서비스
> 경북대학교병원 / 2021.02 ~ 2021.06 (5개월)

## 프로젝트 요약
- 병실에 설치된 카메라를 이용해 환자의 행동을 인식하는 인공지능 서비스를 개발하였습니다.
- 걷기, 앉기, 서기, 잠자기, 낙상 5가지 행동을 실시간으로 분류합니다.
- PyQt 기반 실시간 행동 인식 프로토타입을 개발하였습니다.
- Docker Compose를 사용하여 멀티 컨테이너 서비스를 효율적으로 관리하였습니다.
**Code** : [link](https://github.com/youhs4554/cogward_vision_ai_services); **Notion** : [link](https://checker-zinnia-239.notion.site/Human-Activity-Recognition-for-Hospital-Room-Surveillance-2b3397acdf2c4e048c6b0df6b05974eb)
## 개발 목표
- 병실 내 행동 데이터 수집 인프라 구축 및 행동 인식 API 개발
- 실시간 환자 행동 상태 모니터링 서비스를 제공하여 환자 안전관리 향상
## 기술 스택
- PyTorch, TorchServe
- Kafka, gRPC
- OpenCV
- Docker, Docker Compose
- PyQt5
- Video Understanding, Human, Behavior Recognition, Yolo v3
## 개발 내용
### 데이터 수집툴 개발
> 비디오 레코더에 Yolo v3 기반 사람 검출 기능을 추가하여 비디오 데이터와 검출 데이터를 수집하였습니다.

**데이터 예시**: 8명을 대상으로 1,648개 비디오 샘플 수집
|Class|Example|
|-|-|
| <span style="font-weight:normal">Falling</span> |  |
| Sitting |  |
| Standing |  |
| Sleeping |  |
| Walking |  |
### 서비스 아키텍처 설계
> Kafka 브로커 서버에서 비디오 스트림을 받는 클라이언트(`camera-monitor`), 행동 인식(`camera-action`), 사람 검출(`camera-detection`) 모듈을 다음과 같이 구성하여 시스템을 구성하였습니다.
<table>
<tr>
<td><img src="https://i.imgur.com/2ikcC9L.png"></td>
<td><img src="https://i.imgur.com/0ZRoRBQ.png"></td>
</tr>
</table>
> `camera-action`, `camera-detection`, `camera-monitor` 각 모듈을 도커 이미지로 빌드하여 도커 Hub에 배포하였습니다.

### 행동인식 API 개발 (`camera-action`)
**역할**: 걷기, 앉기, 서기, 잠자기, 낙상에 대한 실시간 분류 결과 제공
- **Inference Handler**: TorchServe의 `BaseHandler`를 오버라이딩하여 inference를 위한 커스텀 핸들러를 구현하였습니다. (전체 코드는 [여기](https://github.com/youhs4554/neural_riskistic/blob/backend/backend/handlers/activity_classifier.py)에서 확인할 수 있습니다.)
- `torch-model-archiver`를 통해 PyTorch 모델 파일을 `.mar` 파일로 변환하였습니다.
```bash
torch-model-archiver --model-name STCNet_8f_CesleaFDD6 \
--force \
--version 1.0 \
--serialized-file model_ckpt/STCNet_8f_CesleaFDD6-1/version_2/checkpoints/epoch\=45.ckpt \
--export-path model_store \
--handler handlers/activity_classifier.py \
--extra-files activity_lib.zip,model_ckpt/STCNet_8f_CesleaFDD6-1/version_2/hparams.yaml,handlers/handler_utils.py
```
- **TorchServe CLI를 사용하여 모델 서빙**
```bash
torchserve --start --ncs --model-store model_store --models STCNet_8f_CesleaFDD6.mar --ts-config config.properties # if additional model is developed, append othre .mar files
```
- **프로토타입**
> 행동인식 결과와 Grad-CAM을 오버레이하여 스트리밍한 결과입니다.

### 사람 검출 API 개발 (`camera-detection`)
**역할**: 환자의 위치를 검출하여 행동 인식 모델의 안정적인 동작을 지원
- Yolo v3를 사용하는 [오픈 소스](https://github.com/komorin0521/darknet_server)를 활용하여 환자 검출 API 서버를 구축하였습니다.
- Darknet 설정 후 dockerization 하여 사용했습니다.

### Kafka 브로커에서 비디오 스트림을 받는 클라이언트 (`camera-monitor`)
**역할**: 특정 `ROOM_NUMBER`에 설치된 카메라 id로 명명된 topic을 subscribe하여 스트림을 받고 `camera-action`, `camera-detection` 모듈에 API call 하는 역할을 합니다.
- **비디오 스트림 받기**
```python=
consumer = KafkaConsumer(bootstrap_servers=BROKER)
consumer.subscribe(pattern=f"room_{ROOM_NUMBER}.{CAMERA_ID}$")
for msg in consumer:
image = np.frombuffer(msg.value, dtype=np.uint8)
image = cv2.imdecode(image, cv2.IMREAD_COLOR)
```
- **검출 결과 요청**
```python=
post_data = {"image": base64.b64encode(msg.value).decode("utf-8"),
"get_img_flg": False}
res = requests.post(DETECTION_API,
json=post_data).json()
person_box = list(
filter(lambda x: x.get("obj_name") == TARGET_OBJ, res["resultlist"])) # TARGET_OBJ="person"
```
- **행동인식 결과 요청**
> `infer_image()` 호출 시 모델명을 지정해주면 해당하는 [핸들러](https://github.com/youhs4554/neural_riskistic/blob/48a7bf9610e2f95bed1677214513b4dcafe80c3f/backend/handlers/activity_classifier.py#L12)(=ActivityClassifier)가 호출되어 결과를 리턴합니다.
```python
prediction = infer_image(get_inference_stub(target=ACTION_API),
"model@" + msg.topic, image_for_action, ix)
```
> gRPC stub을 통해 TorchServe에 inference 요청을 보내 결과를 받습니다.
```python
def infer(stub, model_name, input_data):
response = stub.Predictions(
inference_pb2.PredictionsRequest(model_name=model_name, input=input_data))
try:
prediction = response.prediction.decode('utf-8')
except grpc.RpcError as e:
exit(1)
return prediction
```
호출되는 RPC는 다음과 같습니다. (전체 protobuf는 [여기](https://github.com/youhs4554/neural_riskistic/blob/demo/backend/grpc_test/protos/inference.proto)에서 확인할 수 있습니다.)
```protobuf
service InferenceAPIsService {
// ...
// Predictions entry point to get inference using default model version.
rpc Predictions(PredictionsRequest) returns (PredictionResponse) {}
}
```
### PyQT 기반 프로토타입 구현
> 인식된 행동의 confidence level을 실시간으로 확인할 수 있도록 하였습니다.

### Docker Compose 기반 다중 컨테이너 관리
- docker compose를 활용하여 컨테이너 관리를 용이하게 했습니다. (docker-compose.yaml 파일은 [여기](https://github.com/youhs4554/cogward_vision_ai_services/blob/master/docker-compose.yaml)에서 확인할 수 있습니다.)
```bash
# 서비스 실행
ROOM_NUMBER={ROOM_NUMBER} docker-compose up -d
# 서비스 종료
ROOM_NUMBER={ROOM_NUMBER} docker-compose down -d
# 로그 확인
ROOM_NUMBER={ROOM_NUMBER} docker-compose logs -f
```
- 확장성을 위해, 카메라가 설치된 `ROOM_NUMBER`를 지정하면 해당 room의 비디오 스트림을 받아서 행동인식 결과를 확인할 수 있도록 구현하였습니다.
```python
consumer = KafkaConsumer(bootstrap_servers=BROKER)
consumer.subscribe(pattern=f"room_{ROOM_NUMBER}.{CAMERA_ID}$")
```