---
# System prepended metadata

title: 병실내 실시간 비디오 행동인식 서비스

---

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

![](https://i.imgur.com/8pSMUgF.png)

## 프로젝트 요약
- 병실에 설치된 카메라를 이용해 환자의 행동을 인식하는 인공지능 서비스를 개발하였습니다.
- 걷기, 앉기, 서기, 잠자기, 낙상 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 기반 사람 검출 기능을 추가하여 비디오 데이터와 검출 데이터를 수집하였습니다.

![](https://i.imgur.com/FUqZe29.png =x300)

**데이터 예시**: 8명을 대상으로 1,648개 비디오 샘플 수집
|Class|Example|
|-|-|
| <span style="font-weight:normal">Falling</span> | ![](https://i.imgur.com/1edrG4N.png) |
| Sitting | ![](https://i.imgur.com/LR9yctU.png) |
| Standing | ![](https://i.imgur.com/6Lp44T3.png) |
| Sleeping | ![](https://i.imgur.com/XAdkYET.png) |
| Walking | ![](https://i.imgur.com/97xx8y1.png) |


### 서비스 아키텍처 설계
> 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에 배포하였습니다.

![](https://i.imgur.com/Q20TE1D.png)

### 행동인식 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을 오버레이하여 스트리밍한 결과입니다.

![](https://i.imgur.com/ZyTsBfU.gif =x320)

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


### 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을 실시간으로 확인할 수 있도록 하였습니다.

![](https://i.imgur.com/ydPubGM.png =x320)


### 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}$")
    ```