1. DNN모듈이 무엇인가?
2. DNN 모듈로 얼굴을 인식할때 사용할 framework
3. DNN module과 Caffe framework로 face detection 처리
4. DNN module로 동영상 face detection 처리
4. DNN module을 이용한 face recognition 의 결과 분석 및 한계점
1. what's DNN module?
-> 단순한 object detect 모듈인 Haar 모듈 만으로는 퍼포먼스나 얼굴을 인식해내는 측면에서 한계가 분명히 존재한다. 따라서 좀 더 성능을 향상시키기 위해 딥러닝 모듈인 deep neural network module(이하 dnn 모듈)을 도입할 수 있다.
(2017.8월에 나온 모듈) : dnn 모듈이 개발됨으로써 computer vision 분야에서의 굉장히 많은 발전과 함께 opencv 자체의 위상이 달라지는 계기가 될수 있었다.
: opencv dnn 모듈은 directed graph 이고, 이미 만들어진 네트워크에서 순방향 실행을 위한 용도로 설계되었다.
그러므로 딥러닝 학습은 기존의 caffe, tensorflow등의 다른 딥러닝 프레임워크에서 진행하고, 학습된 모델을 불러와서
실행할 때는 dnn 모듈을 사용하는 방식이다. dnn 모듈은 파이썬 환경에서 뿐만 아니라 c/c++ 환경에서도 동작할 수 있기 때문에 프로그램 이식성이 높다는 장점이 존재한다.
2. DNN 모듈 예제를 분석할 때 사용할 framework
- caffe framework module (machine vision library)
: caffe framework는 딥러닝 프레임워크의 일종으로, 표현성, 속도, 모듈성을 염두에 두고 개발되었다고 한다.
주로 컴퓨터 비전 머신러닝, 영상처리에 특화되어 있으며, c/c++기반으로 사용된다. 계산시 GPU 자원을 주로 활용하게 되는데 딥러닝 라이브러리인 DNN을 활용해 성능을 최적화시킬수 있다. (이때 dnn이 사용된다.)
caffe framework은 이미 여러 기여자들이 공유하고 있는 모델을 통해 본인의 코드를 테스트해볼 수 있고, 비슷한 테스트에 대한 수고를 줄일 수 있다는 장점이 존재한다.
그렇지만 computer vision 밖에서의 분야는 타 프레임워크에 비해 범용성이 상대적으로 떨어진다.
+) computer vision이란?
: 인공지능의 한 분야로써 어떤 영상에서 장면이나 특징 들을 이해하는 컴퓨터를 프로그래밍하는게 목적이다.
영상에서 물체의 detection, segmentaion, recognition을 시행할때 , 연속되는 영상에서 물체를 추적할 때,
어떤 장면을 3차원 모델로 매핑하는 기술등의 목표를 갖고 있다.
3. caffe framework와 dnn 모듈을 이용한 face recognition
: 실제로 얼굴이 인식되는 코드를 분석해보면서 어떻게 dnn 모듈을 이용한 얼굴인식이 기능하는지 살펴보도록 하자.
1) 얼굴을 dnn 모듈을 통해 명확히 인식하기 위해선 우선 caffe framework로 해당 이미지를 학습시켜서 자신만의 모델을 만들어야 한다. 그렇게 딥러닝을 통해 학습된 binary 상태의 모델 파일인 caffemodel과 해당 신경망 모델의 레이어를 구성하고 속성을 정의한 prototxt 파일을 로드해준다.
model_name='res10_300*300_ssd_iter_14000.caffemodel'
prototxt_name='deploy.prototxt.txt'
min_confidence=0.5
file_name="marathon_01.jpg"
2) 그 후에 detectAndDisplay() 라는 함수를 하나 정의해주고, 그 안에서 이미지를 읽어들여서 얼굴을 탐지하도록 해줄 것이다.
def detectAndDisplay(frame):
# 해당 모델을 blob 형태로 변환한다
model=cv2.dnn.readNetFromCaffe(prototxt_name,model_name);
blob=cv2.dnn.blobFromImage(cv2.resize(frame,(300,300)),1.0,
(300,300),(104.0,177.0,123.0))
model.setInput(blob)
detections=model.forward()
1. dnn 모듈에서의 readNetFromCaffe 함수를 사용해 caffeframework의 네트워크 모델을 읽어들인다.
위에서 미리 정의한 caffemodel과 prototxt를 인자로 받아와서 하나의 Net 객체를 반환하게 된다.
2. dnn 모듈의 blobFromImage 함수를 사용하여 이미지를 가지고 4차원의 blob 을 만든다.
: caffe framework에서는 원본 이미지가 아니라 이를 binary large object(이하 blob)로 변환하여 정보 덩어리를 다루 게 된다. Blob는 C와 유사한 방식으로 저장된 N차원의 배열이며, Caffe는 blob를 이용하여 데이터를 저장하고 소통한다.
=> 이미지 데이터 1회 처리량에 대한 틀에 적용된 N차원의 blob는 N x K(채널: R,G,B(색)) x H(높이) x W(밑변) 값으 로 return된다.
+) blobFromImage 함수에서는 이미지를 resize하고, crop하고, 색 channel을 바꾸는 기능 또한 존재한다.
따라서 해당 코드에서는 적당한 사이즈로 이미지를 resize해주었다,
3. 그 다음에는 blob를 신경망에 새롭게 넣어주기로 하고, setinput 함수를 사용하여 입력받아줄 수 있다.
그 이후에 forward()함수를 통해 신경망이 학습데이터를 입력받은 후에 forward propagation (순방향 네트워크 실행)을
진행시켜 준다.
3) 이제 신경망에 blob를 input해서 넣고 학습을 시켰으니, 그 output을 실제 이미지에 적용하여 표현해 주어야 한다.
학습된 이미지와 얼마나 비슷한지, 어느 위치에서 얼굴인식이 되는지등의 내용을 학습시킨 이미지에 그리게 된다.
for i in range(0, detections.shape[2]):
confidence = detections[0, 0, i, 2]
min_confidence=0.3;
if confidence > min_confidence:
box = detections[0, 0, i, 3:7] * np.array([width, height, width, height])
(startX, startY, endX, endY) = box.astype("int")
print(confidence, startX, startY, endX, endY)
text = "{:.2f}%".format(confidence * 100)
y = startY - 10 if startY - 10 > 10 else startY + 10
cv2.rectangle(frame, (startX, startY), (endX, endY),
(0, 255, 0), 2)
cv2.putText(frame, text, (startX, y),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1)
cv2.imshow("Face Detection by dnn", frame)
1. detection은 이미지의 속성들을 퍼센티지로 표현한 4차원 배열인데, 이제 이 배열을 차례대로 읽어들이면서 분석을 해보도록 하겠다.
=> 여기서 이 때 각각 detection[0,0,i,2] 는 4차원 배열에서 사람의 얼굴들이라고 인식된 부분, 따라서 이미지에 그려질 box라고 볼 수 있겠다.
<example>
2. 그리고 사람 얼굴을 인식했을때 얼마나 정확도가 높은지, 결과를 신뢰해도 되는지에 대한 변수가 존재하는데, 그게 confidence변수이다. 이게 min_confidence 보다 커야 궁극적으로 "사람의 얼굴"을 인식했다고 볼수 있게 된다.
최소 confidence는 0.3, 즉 30퍼센트로 계산하였다. 이는 각각의 box의 속성을 퍼센티지로 모두 비교해서 인식이 된다. 따라서 min_confidence보다 퍼센티지가 높은 box들만 분석을 하게 된다.
(min_confidence가 낮아질수록 얼굴로 인식하게 되는 box들은 더 많아질 수 있다.)
3. 분석할 box들이 정해졌다면 이제 이 box들의 좌표 속성을 읽어들어와서 분석을 시켜야 한다.
- 3번째 detection[0,0,i,3]는 전체 폭 중 박스 시작점의 x좌표 상대위치 (왼쪽 맨 위 시작점)
- 4번째 detection[0,0,i,4]는 전체 높이 중 박스 시작점의 y좌표 상대위치
- 5번째 detection[0,0,i,5]는 전체 폭 중 박스 끝점의 x좌표 상대위치 (오른쪽 맨 아래 끝점)
- 6번째 detection[0,0,i,6]는 전체 높이 중 박스 끝점의 y좌표 상대위치
이 이후에 각 box들의 속성을 numpy array에 width, height, width, height 배열에 각각 담아준다.
confidence와 함께 출력해주면, 각 각 box들의 신뢰도와 box의 좌표위치를 알 수 있다.
4. box의 속성들까지 모두 분석을 끝마쳤다면, 사용자가 직관적으로 몇 퍼센트 정도 신뢰를 할수 있는지, 얼굴이라고 인식된 부분이 어디 인지 원래 사진에 표현을 해주어야 한다.
1) 우선 confidence 부분은 퍼센티지로 나타내어 주는 것이 알아보기 편하므로 100을 곱해주어 그대로 화면위에
출력해준다. ( box보다 살짝 10정도 위에 text를 출력해줘야 보기 편하다. startY좌표 +10 정도 위치에 출력한다.)
2) 그 이후에, 해당 box를 사람 얼굴 위에 그려주어야 한다. 시작점과 끝점을 startX,startY, endX,endY로 지정해주고, 색깔과 두께까지 지정해주면 box가 사람 얼굴이라고 인식된 부분 위에 print된다.
=> detectanddisplay 함수가 완성되면 사진을 인식하여 얼굴로 인식된 부분에 box와 confidence가 출력되는 것을 확인 할 수 있다.
4) 함수가 다 완성되었으니, 그림을 하나 받아와서 그대로 detectanddisplay 함수에 넣어줘서 얼굴 인식된 부분을 box로 출력해주면 dnn으로 얼굴을 인식하는 코드가 완성된다.
img = cv2.imread('marathon_02.jpg')
cv2.imshow("Original Image", img)
detectAndDisplay(img)
<전체 코드>
import cv2
import numpy as np
model_name='res10_300x300_ssd_iter_140000.caffemodel'
prototxt_name='deploy.prototxt.txt'
def detectAndDisplay(frame):
model=cv2.dnn.readNetFromCaffe(prototxt_name,model_name);
blob=cv2.dnn.blobFromImage(cv2.resize(frame,(300,300)),1.0,
(300,300),(104.0,177.0,123.0))
model.setInput(blob)
detections=model.forward()
for i in range(0, detections.shape[2]):
confidence = detections[0, 0, i, 2]
min_confidence=0.05;
if confidence > min_confidence:
box = detections[0, 0, i, 3:7] * np.array([width, height, width, height])
(startX, startY, endX, endY) = box.astype("int")
print(confidence, startX, startY, endX, endY)
text = "{:.2f}%".format(confidence * 100)
y = startY - 10 if startY - 10 > 10 else startY + 10
cv2.rectangle(frame, (startX, startY), (endX, endY),
(0, 255, 0), 2)
cv2.putText(frame, text, (startX, y),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1)
cv2.imshow("Face Detection by dnn", frame)
img = cv2.imread('marathon_01.jpg')
(height, width) = img.shape[:2]
detectAndDisplay(img)
cv2.waitKey(0)
cv2.destroyAllWindows()
4. DNN module로 face detection 동영상 처리
: 몇개의 코드만 추가하면 동영상 또한 딥러닝을 통해 처리가 가능하다.
detectanddisplay쪽 아래 코드만 바꿔주면 가능하다.
1) opencv의 VideoCapture함수를 이용해 mp4,gif 파일을 읽어들인다.
2) video가 열리지 않거나, frame이 확인되지 않으면 break되고, 정상적으로 동영상이 인식되면 그대로 실행된다. 인물의 움직임에 따라 박스가 따라감을 확인할 수 있다.
img='obama_01.mp4'
cap=cv2.VideoCapture(img)
#-- 2. Read the video stream
if not cap.isOpened:
print('--(!)Error opening video capture')
exit(0)
while True:
ret, frame = cap.read()
if frame is None:
print('--(!) No captured frame -- Break!')
break
detectAndDisplay(frame)
# Hit 'q' on the keyboard to quit!
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cv2.waitKey(0)
cv2.destroyAllWindows()
5. DNN 모듈로 진행한 face recognition result 분석
1) 우선 사람이 한명만 있는 사진은 아주 무리없이 90퍼센트에 가까운 확률로 인식이 잘 된다.
2) 그렇지만 단체 사진으로 갈 수록 인식률이 살짝씩 떨어지게 되는데, 이 인식률은 min_confidence, 즉 최소 신뢰도를 어떻게 조절하느냐에 따라 다르다.
1. min_confidence를 0.5로 했을때, 즉 인식률이 50퍼센트 이상인 부분만 "사람의 얼굴"을 인식했다고 가정했을때,
인식률은 상당히 낮다. 사람 얼굴이라고 인정하는 신뢰도의 하한이 상당히 높기 때문이다.
-> 이의 이유는 여러가지이다. 사람 얼굴쪽 빛이 지나치게 어두울 수도 있고, 모자를 써서 인식이 제대로 안될 수도 있고, 또 머리카락이 얼굴을 가렸거나, 이목구비가 잘 안보이면 인식률이 상당히 낮음을 확인 할 수 있다.
2. min_confidence를 0.3으로 낮추면 좀더 인식률이 높아진다. 30%이상만 사람 얼굴이라고 인식이 되면 box를 print하기 때문이다. 그렇지만 0.3 이하로 더 낮추면 인식률이 더 높아질 수는 있으나, 신뢰도는 상당히 낮다고 볼 수 있다.
3. 마지막으로 min_confidence를 5퍼센트 정도로 아예 낮춰보자.
-> 이처럼 사람 얼굴이 무엇인지 인식조차 못하고 거의 모든 배경에 box를 그려버린다. 이처럼 최소 인식률을 너무 낮춰버리면 face recognition에 대한 신뢰도가 너무 낮아짐을 확인할 수 있다.
따라서 min_confidence를 신뢰할 수 있을 정도로 잘 조정해서 얼굴 인식을 진행해야 할 것 같다.
=> 따라서 종합해보자면 haar 모듈이 인식하지 못하는 얼굴 또한 상당히 잘 인식해 내고, 인식률을 조정할 수 있다는 점에서 상당히 우수한 모듈인건 확실하다. 그렇지만 역시 아직은 고개를 돌리거나, 얼굴을 살짝 가리는 등의 변수가 존재하면 인식을 잘 못하는 점과, 해당 얼굴이 "사람의 얼굴"인지만 인식하는 부분에서만 그치는 등의 약간의 허점이 존재하므로 dnn 모듈보다 더 퍼포먼스가 좋고, 사물까지도 인식이 가능한 yolo 모델과 face_recognition 모듈 또한 적용하고 분석해볼 필요가 있다. 더 발전된 모듈을 통해 인식속도 또한 개선하고, 얼굴을 학습하고, 사진이나 동영상에서 해당 인물을 찾아내는 기술까지 적용 가능할 것으로 보인다.
'Computer Science > 영상처리 + FACE-ID project' 카테고리의 다른 글
Haar module detection (0) | 2020.04.07 |
---|---|
영상처리의 기본~ 이미지 가공 (0) | 2020.03.18 |