# 병실내 실시간 비디오 행동인식 서비스 > 경북대학교병원 / 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}$") ```