July 15, 2020

[59호]Locker Locker

59 ict lockerlocker (555)

2019 ICT 융합 프로젝트 공모전 참가상

Locker Locker

글 | 광운대학교 정지은, 최천옥

1. 심사평
칩센 홍채인식 안면 인식을 통한 door open 시스템은 이미 많은 곳에서 적용이 되어 있으므로 기존 시스템 대비하여 어떠한 장점이나 이점이 있는지 확인이 필요할 것으로 보입니다. 또한 스마트폰과 블루투스를 통해 연결을 하게 될 경우 근거리 제어의 제약이 생기게 되므로, 이 부분에 대한 보완도 필요할 것으로 생각됩니다.
뉴티씨 자동도어록 회사에서 이러한 기능을 필요로 할 수 있을 것이라는 생각이 듭니다. 또한, 아파트의 입구문도 이런식으로 인식하여 열리게 하면 좋겠다는 생각을 합니다. 실제로 사용이 될 수 있는 가능성이 높다고 생각되므로 좀 더 보완하여 제품에 들어갈 수 있는 기술이 되도록 하면 좋겠습니다.
위드로봇 실험 결과에 대한 분석이 빠져있습니다.
펌테크 실생활과 접목된 실용성을 지닌 작품으로 생각됩니다. 전체 하드웨어 및 소프트웨어 시스템을 연동하는 과정에 어려움이 있었을 것으로 예상됩니다. 시스템 구성 중 Lattepanda board, opencv를 사용해 영상처리를 과정을 효율적으로 구성하였다고 생각하며 기획의도에 따라 전체 시스템 구성이 최종품 대비 중간단계 이상까지는 진행된 것으로 예상됩니다. 진행된 단계까지의 구체적인 동작 과정이 담긴 영상 자료가 있었다면 평가에 도움이 되었을 텐데 다소 아쉬운 생각이 듭니다. 하지만 전체적인 기획의도, 기술 구현도 측면에서 본다면 우수한 작품으로 생각됩니다.

2. 작품 개요
아동 유괴에 관한 문제는 그 대상이 어린 유아라는 점에서 문제의 심각성이 대두되고 있다. 아동 유괴는 그 발생 장소가 다양하지만, 주거지는 2015년에는 21.9%, 2016년에는 25.6%, 2017년에는 15.8%라는 높은 비율로 일정 부분을 차지하고 있다. 맞벌이가 늘어나는 지금 같은 추세에서는 집에 혼자 있는 이른바 ‘나홀로 아이’를 타깃으로 한 범죄도 늘어나고 있다. ‘나홀로 아이’들이 위험한 이유는 집에 모르는 사람이 와도 문을 열어주어야 하는지에 대한 판단을 하기 힘들다는 것이며, 2017년 통계에 의하면 아동 유괴 범죄자의 32.3%가 피해자와 지인이었다는 점을 고려하면 더더욱 위험한 상황임을 실감할 수 있다. 또한 대부분의 가정이 사용하고 있는 전자 도어락의 허점이 발견되면서 밖에서도 손쉽게 문을 열수 있는 방법이 늘어났다는 것도 위험성의 한 부분이다. 더 이상 도어락 하나로 아이들의 안전을 보장할 수 없게 되었고, 그에 따른 추가적인 잠금 장치에 대한 필요성이 커지고 있다.

3. 작품 설명
영상처리를 통한 얼굴인식 프로그램 제작
opencv와 웹캠을 사용하여, 부모 혹은 보호자의 얼굴을 촬영하고, 보호자의 얼굴 데이터를 사전에 학습시킨다. 외부인이 문 앞에 서면 외부인의 얼굴을 인식하고, 미리 학습시켜 둔 부모의 얼굴과 일치하는 지를 조사함으로써, 아이에게 안전한 방문자 인지를 판단한다.

어플리케이션을 이용한 하드웨어 제어
얼굴인식으로 미리 등록된 사람이 아닌 경우 어플리케이션을 통한 알림을 받고, 현관문에 설치된 잠금 장치의 개폐여부를 결정한다. 모르는 사람에게도 쉽게 현관문을 열어주는 아이를 대신하여 어른인 부모가 문의 개폐여부를 정할 수 있게 한다.

제어 값에 따른 잠금장치 하드웨어 제작
기존의 도어락 위에 서보모터를 이용한 새로운 잠금 장치를 설치한다. 어플리케이션의 제어를 통해 잠금 장치를 열고 닫는 것이 가능하다. 잠금 장치의 개폐여부가 어플리케이션과 집 내부에서의 수동식 조절 밖에 없으므로 문 밖의 외부인의 접근을 막을 수 있다. (이때 어린아이의 손이 닿지 않는 현관문의 위쪽에 잠금 장치를 설치한다.)

3.1. 주요 동작 및 특징

import cv2
import numpy as np

이미지와 영상을 처리하기 위해 cv2(opencv)를 사용한다. numpy는 배열 연산과 데이터의 저장을 위해 사용하는데, 특히 이 코드에서는 데이터(이미지)의 저장을 목적으로 쓴다.

face_classifier = cv2.CascadeClassifier(‘cascades/data/haarcascade_frontalface_alt2.xml’)

CascadeClassifier은 이미 학습된 classifier을 불러오는 함수로, Haarcascade_frontal face는 얼굴 정면이 이미 학습된 xml 파일이다.

cap = cv2.VideoCapture(0)
A = 0

cv2.VideoCapture(0)함수로 웹캠을 사용해 비디오 캡처 객체를 생성한다. 변수 A는 사진의 개수를 세기 위해 설정하였다.

def scissors(img): #얼굴 영역만
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) #흑백처리
scaleFactor=2
minNeighbors=5
faces = face_classifier.detectMultiScale(gray, scaleFactor, minNeighbors)
if faces is (): # 얼굴이 없다면 None
return None
for (x, y, w, h) in faces:
ROI = img[y:y + h, x:x + w] # ROI 설정
return ROI

scissors 함수는 말그대로, 얼굴 부분만 잘라주는 함수이다. 특징이 발견된 곳을 좌표로 추출하는 detectMultiScale을 사용하고, scaleFactor은 축소 비율, minNeighbors는 어떤 곳을 특징으로 선택하기 위해서 주변에 있어야 하는 영역의 수이다. Haarcascade는 밝기로 특징을 추출하기 때문에 흑백처리를 해준다.

def CAM(MD):
face = cv2.resize(scissors(frame), (250, 250)) # 크기 = 250*250
face = cv2.cvtColor(face, cv2.COLOR_BGR2GRAY)
file_name = MD + ‘/user’ + str(A) + ‘.jpg’
cv2.imwrite(file_name, face)
cv2.putText(face, str(A)+’/802’, (0, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2)
cv2.imshow(‘Face Crop’, face)
return face

CAM함수는 이미지의 크기를 250*250으로 지정해주며, 흑백으로 바꿔주고 찍힌 사진의 이름을 무엇으로 정할지 정해준다. MD(input) 파일에 ‘user+A(변수-사진찍힌 횟수).jpg’로 저장이 된다. 사진이 찍힐 때, 사용자가 확인할 수 있도록 A(변수-찍힌 횟수)/802(총 횟수)가 뜬다.

while True:
ret, frame = cap.read() # 캡쳐하기
if scissors(frame) is not None:
A += 1
CAM(‘model1’)
else:
print(“얼굴 위치를 조정해주세요”)
pass

위 반복문은 캡처하는 역할이다. frame에 얼굴 정문이 인식될 때 사진이 찍히고, 인식이 되지 않는다면 ‘얼굴 위치를 조정해주세요’라고 나타난다.

if cv2.waitKey(1) == 13 or A == 501:
img2=cv2.imread(‘noname.png’,0)
cv2.imshow(‘frame’, img2)
cv2.waitKey(5000)
cv2.destroyWindow(‘frame’)
pass

if cv2.waitKey(1) ==13 or A==502:

while True:
ret, frame = cap.read() # 캡쳐하기
if scissors(frame) is not None:
A += 1
CAM(‘model2’)
if cv2.waitKey(1) == 13 or A == 802:
break

break

cap.release()
cv2.destroyAllWindows()
print(‘완료되었습니다.’

502장이 찍히거나 enter키를 누르게 되면 중지한다. 그 후에 ‘잠시만 기다려주세요’라고 뜬다. 5초 후에 그 창이 닫히며 다음 사람이 찍을 수 있다. 같은 알고리즘으로 계속된다. 데이터가 많을수록 정확도가 높아지기 때문에 총 802장을 촬영한다. 그 후, ‘완료되었습니다’라고 뜨며 프로그램이 종료된다.

59 ict lockerlocker (1)

라이브러리들 중에서 처음 쓰는 listdir, isfile, join에 대한 설명은 다음과 같다. listdir은 현재 폴더의 파일이 리스트 형식으로 출력되는 라이브러리이다. isfile을 쓰면 파일이 존재하는지 알 수 있고, join으로 해당 OS 형식에 맞도록 입력 받은 경로를 연결할 수 있다.

import cv2
import numpy as np
from os import listdir
from os.path import isfile, join

ser = serial.Serial(‘COM11’, 9600)
data_path = ‘model1/’
onlyfiles = [f for f in listdir(data_path) if isfile(join(data_path,f))] Train_Data, Q = [], [] for i, file in enumerate(onlyfiles):
image_path = data_path + onlyfiles[i] images = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
Train_Data.append(np.asarray(images, dtype=np.uint8))
Q.append(i)
Q = np.asarray(Q, dtype=np.int32)
model = cv2.face.LBPHFaceRecognizer_create()
model.train(np.asarray(Train_Data), np.asarray(Q))
print(“모델1훈련완료되었습니다”)

model1에 있는 파일 리스트를 얻고, 데이터와 매칭될 변수를 지정한다. 그리고 파일 개수만큼 반복한다. 이미지를 불러와서 Train_data에 이미지를 배열로 추가시킨다. 모델을 생성하고 학습시킨다. 완료되면 ‘훈련 완료되었습니다’라고 뜬다.

data_path = ‘model2/’
onlyfiles = [f for f in listdir(data_path) if isfile(join(data_path,f))] Train_Data, Q = [], [] for i, file in enumerate(onlyfiles):
image_path = data_path + onlyfiles[i] images = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
Train_Data.append(np.asarray(images, dtype=np.uint8))
Q.append(i)
Q = np.asarray(Q, dtype=np.int32)
model = cv2.face.LBPHFaceRecognizer_create()
model.train(np.asarray(Train_Data), np.asarray(Q))
print(“모델2훈련완료되었습니다”)

model2에 있는 파일 리스트를 얻은 후 동일한 알고리즘으로 진행된다.

face_classifier = cv2.CascadeClassifier(‘cascades/data/haarcascade_frontalface_alt2.xml’)

def Detector(img, size = 0.5):
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = face_classifier.detectMultiScale(gray,2,5)
if faces is():
return img,[] for(x,y,w,h) in faces:
cv2.rectangle(img, (x,y),(x+w,y+h),(0,255,255),2)
roi = img[y:y+h, x:x+w] roi = cv2.resize(roi, (300,300))
return img,roi

Detector함수는 검출된 영역을 흑백처리를 한 후 0.5사이즈로 만들어 전달하는 함수이다.

cap = cv2.VideoCapture(0)

while True:
ret,frame = cap.read()
image,face = Detector(frame)
try:
face = cv2.cvtColor(face,cv2.COLOR_BGR2GRAY)
result = model.predict(face)
if result[1]<500:
confidence=int(100*(1-(result[1])/300))
display_string=str(confidence)+’% user’
cv2.putText(image,display_string,(100,120),cv2.FONT_HERSHEY_SIMPLEX,1,(250,120,255),2)
if confidence>83:
cv2.imshow(‘LOCKER’,image)
val = 0
ser.write(val)
else:
cv2.imshow(‘LOCKER’,image)
val = 1
ser.write(val)
except:
cv2.imshow(‘LOCKER’,image)
pass

if cv2.waitKey(1)==13:
break

cap.release()
cv2.destroyAllWindows()

웹캠을 연결해서 창에서 얼굴을 검출해 변환하고 예측을 시도한다. 유사도(Confidence)를 계산하여 띄워준다. 만약 83이상이라면 동일 인물로 생각하여 ‘Locker Locker’를 해제 해주고, 작다면 라떼판다에게 변수(val)을 보낸다. 엔터를 누른다면, 반복문에서 탈출하게 되고 종료된다.

어플리케이션 동작부

59 ict lockerlocker (2)

라떼판다와의 블루투스 설정 및 서보모터의 작동여부를 결정한다.

59 ict lockerlocker (3)

부가적인 설정으로 위급한 상황에 대비하여 경찰 혹은 지인에게 전화할 수 있는 기능을 구현하였다.

Serial 통신부

59 ict lockerlocker (4)

작품에 사용되는 사용시스템인 pyCharm과 라떼판다(라떼판다 내부에는 아두이노 레오나르도와 window10이 설치되어 내장되어 있다.) 그리고 어플리케이션의 역할이 각각 다르다. 먼저 pycharm은 외부인에 방문하였을 때 얼굴을 판별하는 기능을 하며, 어플은 외부인의 방문에 대한 알림과 잠금 장치를 사용할 지에 대한 유무를 결정하고, 라떼판다는 잠금 장치를 작동시키는 역할을 한다. 그 때 어플리케이션은 pyCharm에서 외부인의 얼굴 판별 데이터를 받아야 작동이 가능하며, 라떼판다는 어플리케이션의 잠금장치 작동여부 데이터를 전달 받아야 작동이 가능하다. 그렇기에 3가지의 사용시스템 사이의 serial통신으로 데이터 값들을 전달받는 시스템을 구상하였다.

전체적인 틀 설명
얼굴인식 소프트웨어에서 83%의 정확도 이상인 경우에서의 변수의 값과 이하인 경우에서의 변수 값을 다르게 설정하여, 상황에 맞는 변수 값을 serial통신을 통해 라떼판다에 내장된 아두이노 레오나르도로 넘겨준다. 그 바뀐 변수 값을 어플리케이션에서 인식하여, 아이의 보호자가 아닌 외부인의 방문인 경우에는 알람이 울리도록 설정하여 준다. 그 후 아이의 보호자가 문의 개폐여부를 결정하고, 어플리케이션의 버튼을 누르면 그 때 정해지는 새로운 변수 값을 라떼판다로 serial통신을 통해 전달하여 잠금 장치를 작동시킨다.

#include <SoftwareSerial.h> //시리얼통신 라이브러리 호출

각각의 소프트웨어와 하드웨어 간에 통신을 가능하게 하는 라이브러리를 호출한다.

SoftwareSerial mySerial(blueTx, blueRx);
SoftwareSerial appSerial(blueTx_2, blueRx_2);//시리얼 통신을 위한 객체선언

Serial.begin(9600); //시리얼모니터
mySerial.begin(9600);
appSerial.begin(9600);

serial통신은 블루투스 모듈을 사용하였다. 각각의 객체를 선언한 후 9600보드레이트에서 시작함을 알리는 함수를 사용하였다.
Serial 통신으로 통신 받은 값이 존재한다면, .read()함수를 통해 그 새로운 값을 변수에 지정하는 함수를 사용하였다.

if(mySerial.available()>0){
val=mySerial.read();

#include <Servo.h>

void loop(){
if(mySerial.available()>0){
val=mySerial.read();
}
if(appSerial.available()>0){
int app = appSerial.read();
if(app==0){
for(angle=0;angle<90;angle++){
myservo.write(angle);
delay(15);
}}
else if(app==1){
for(angle=90;angle>0;angle–){
myservo.write(angle);
delay(15);
}
}
}
}

서보모터 라이브러리를 호출한다.
어플리케이션을 통한 서보모터 제어 코드로 어플리케이션에서 정한 변수의 값이 ‘0’ 이라면 서보모터를 90도 회전하여 문을 열고, ‘1’이라면 반대쪽으로 90도 회전하여 문을 잠그는 코드이다.

59 ict lockerlocker (1)

문 밖의 외부인이 등록된 보호자가 아닐 경우 어플리케이션으로 문을 잠글 수 있다.

59 ict lockerlocker (5)

어플리케이션으로 open을 누를 경우 잠금 장치를 해제하여 문을 열 수 있다.

59 ict lockerlocker (6)

문 밖 초인종 위치에 웹캠을 설치하여 외부인이 오면 얼굴인식이 가능하도록 한다.

3.2. 전체 시스템 구성

59 ict lockerlocker (7)

3.3. 개발 환경 및 참고문헌

59 ict lockerlocker (8)

· 개발 언어 : 파이썬, c언어
· Tool : 파이참, 아두이노
· 사용 시스템 :  파이썬, 파이참, OpenCv, 앱 인벤터, 라떼판다, 아두이노

3.4. 참고문헌
· https://www.youtube.com/watch?v=PmZ29Vta7Vc
· https://www.youtube.com/watch?v=TGQcDaZ56ao
· https://opencv-python.readthedocs.io/en/latest/doc/01.imageStart/imageStart.html

 

 

Leave A Comment

*