본문 바로가기

IT/Cloud

[AWS] 라즈베리파이를 통해 인원수 추출(AWS Rekognition 이용)

GICT 2020에서 내가 맡았던 기능에 대한 어떻게 구현했는지를 쓰려고 한다.

 

내가 맡은 기능은 인원수 추출하여 다시 라즈베리파이가 Request 하면 Response로 인원수를 보내주는 역할을 맡았다.

 

맡은 기능은 이전에 내가 만들어 본 적 있는 기능이라 나름 간편하게 구현할 수 있었다.

 

언어→python

클라우드 환경→Rekognition, S3, IAM, Lambda

라즈베리파이 4B+카메라 모듈

 

1) 카메라에서 사진을 캡처하여 S3로 보내는 역할을 수행하기 위한 IAM 발급

IAM의 정책은 S3 fullAccessadmin정도만 주면 된다.

(+Rekognition은 그냥 넣어둠😘)

 

2) 라즈베리파이에서 OpenCv을 설치하고 카메라에서 사진을 캡처해서 S3로 보내는 코드 작성.

 

라즈베리파이 설정

맨날 맨날 라즈베리파이 설정을 까먹어서...

www.notion.so

위에 Notion에 언급한 라즈베리파이 설정을 완료하고(GUI 설정은 안 해도 상관없다 버전 업과 OpenCv 정도만 필요하다.)

 

import cv2
from datetime import datetime
import threading
import time
import boto3

cam = cv2.VideoCapture(0,cv2.CAP_V4L)
cam.set(3, 640) # set video widht
cam.set(4, 480) # set video height
#config
s3=boto3.client('s3',
   aws_access_key_id='본인 access key',
   aws_secret_access_key='본인 secret aceess key')

def print_real():
    ret, img =cam.read()
    now =datetime.now()
    realti=str(now.year)+str(now.month)+str(now.day)+str(now.hour)+str(now.minu$
    filename1='image/'+realti+'.jpg'
		filename2=realti+'.jpg'
    cv2.imwrite("image/"+realti+".jpg",img)

    bucket_name='본인 bucket이름'
    s3.upload_file(filename1,bucket_name,filename2)
    threading.Timer(0.5,print_real).start()

print_real()

위와 같이 코드를 짜고 실행하면 사진이 저장된다.

 

S3

업로드된 파일명은 연월일시간분초. jpg로 저장했다.(중복이 없게 하기 위해서ㅎ)

 

3) S3에서 사진이 들어오면 Lambda의 트리거를 이용해 인원수를 추출한다.

Lambda에서 역할을 설정할 때 rekognition과 cloudwatch , S3 기능은 꼭 포함하도록 한다.

(생각해보니까 1번째거 권한을 같이 주면 두 개 안 해도 되는데 예전의 나 반성해라 리소스 낭비임ㅋㅋㅋㅋ)

IAM 권한

AWS Lambda 부분

아래 코드는 Lambda에서 작동하는 코드로 S3 버킷 안에 이벤트가 발생하면(이미지가 들어오면) 실행되는 코드로 들어온 이미지에서 Rekognition의 Object Detection 함수를 이용해서 Response을 받고 사람의 boundbox의 개수를 세서 사람 수를 측정한다.

import json
import boto3
import time
import io
from datetime import datetime
import threading

s3= boto3.client('s3')


def detect_labels(bucket,photo):
	rekognition = boto3.client("rekognition")
	response = rekognition.detect_labels(Image={'S3Object':{'Bucket':bucket,'Name':photo}},MaxLabels=10)

	return response['Labels']

def lambda_handler(event, context):
    now=datetime.now()

    numberpeople=""

    try:
        for record in event['Records']:
            filename = record['s3']['object']['key']
            bucket = record['s3']['bucket']['name']
            source= detect_labels(bucket,filename)
            
            for i in source:
                if 'Person' in str(i):
                    numberpeople+=str(len(i['Instances']))
                    print(len(i['Instances']))
                    break
            else:
                numberpeople=str(0)

        realti=str(now.year)+str(now.month)+str(now.day)+str(now.hour)+str(now.minute)+str(now.second)    
        realtitxt=realti+".txt"
        with open('/tmp/'+realtitxt,'w') as f:
            f.write(numberpeople)
            
        s3.upload_file('/tmp/'+realtitxt,'버킷이름',realtitxt)
        print("업로드 완료")
    except Exception as e:
        print(e)
    
    return "complete"

 

이 코드에서 이벤트가 일어나면 이러한 Response가 발생한다

4) 추출한 인원수를 다시 S3에 txt 파일로 저장한다.

 

위에 언급한 코드에 이 부분으로 인해 버킷(하트)에 인원수가 저장된다.

 

실행 화면

이렇게 한 명이 있을 시에는 1명이라는 숫자가 0명일 경우에는 0이 txt 파일에 저장됨.

 

5) 위에 과정을 거쳐 나온 인원수를 다시 라즈베리파이에서 S3 Request 통해 가져온다.

import boto3


s3=boto3.client('s3',
   aws_access_key_id='',
   aws_secret_access_key='')

arr=[]
myfile=[]

for object in s3.list_objects(Bucket='버킷이름')['Contents']:
    s3.download_file('버킷이름', object['Key'], object['Key'])
    arr.append(object['Key'])
    myfile.append("")

for i in range(len(arr)):
    myfile[i]=open(arr[i],'r',encoding='utf-8')
    mystring=myfile[i].read()
    print(mystrㆍing)

위에 코드를 라즈베리파이에서 실행시키면

이런 식으로 인원수가 일정 시간마다 추출된다.

+) 생각해보니 S3 버킷을 Public 설정해줘야 한다.

 

============================================================================

문제점

클라우드 서비스의 문제인지 내가 짠 코드의 문제인지 delay가 꽤 길다->줄여야 한다.