개인 프로젝트: 3차시 Raspberry Pi 로 얼굴인식하기 - Marvic1130/EmbeddedSystem_Class GitHub Wiki

Raspberry Pi 로 얼굴인식하기

Cam Test

캠이 재대로 나오는지 확인하기위해 CamTest.py를 작성한다.

Raspberry pi 캠 설정하기

이번 프로젝트에서 사용할 캠은 라즈베리파이 보드에 연결하는 기본 캠을 사용할 예정이다.

IMG_0444

먼저 아래의 명령어를 입력하여 설정에 들어간다.

sudo raspi-config

스크린샷 2022-12-19 오후 9 14 19

  1. Interface Options 을 선택한다.

스크린샷 2022-12-19 오후 9 15 10

I1 Legacy Camera Enable/disable legacy camera support 를 누른 후 yes(enable) 선택

스크린샷 2022-12-19 오후 9 17 31

스크린샷 2022-12-19 오후 9 19 04

그 다음 Finish 를 누르면 Reboot를 할거냐고 물어보는데 yes 를 선택하여 Reboot 한다.

스크린샷 2022-12-19 오후 9 23 39

Reboot가 완료되었다면 아래 코드를 실행하여 카메라가 실행되는지 확인한다.


import numpy as np
import cv2

if __name__ == '__main__':
    cap = cv2.VideoCapture(0)
    cap.set(3, 640)  # set Width
    cap.set(4, 480)  # set Height

    while (True):
        ret, frame = cap.read()
        # gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

        cv2.imshow('frame', frame)
        # cv2.imshow('gray', gray)

        k = cv2.waitKey(30) & 0xff
        if k == 27:  # press 'ESC' to quit
            break
    cap.release()
    cv2.destroyAllWindows()


코드 내에 주석처리한 부분은 흑백영상을 출력하는 코드이다.

스크린샷 2022-12-19 오후 9 28 17

소켓 통신

소켓 통신을 사용하는 이유

만들려고하는 프로그램은 opencv를 이용하여 얻어온 영상에서 얼굴을 인식한 후, 인식한 얼굴을 머신러닝을 이용하여 누구인지를 판별하는 프로그램인데 라즈베리파이 안에서 얼굴인식과 머신러닝을 사용하기에는 성능이 부족하여 Server에서 얼굴인식과 머신러닝을 수행한 후 결과값을 Client(라즈베리파이)로 넘겨주는 방법을 사용하려한다.

소켓 설치

아래 명령어를 사용하여 apt-get을 update, upgrade한다.

sudo apt-get update

sudo apt-get upgrade

아래 명령어를 입력하여 socket을 설치한다.

sudo apt-get install socket

라즈베리파이 캠 Socket통신으로 스트리밍

Project/FaceDetector_Server/Test/Server.py 코드를 서버컴퓨터에서 실행한다.

Project/FaceDetector_Client/main.py 코드를 라즈베리파이에서 실행한다.

이때 주의해야할 사항은 s.connect 내부 튜플에서 서버컴퓨터의 ip를 입력해야한다.

스크린샷 2022-12-20 오전 1 52 23

서버 컴퓨터의 ip를 알아내는 방법은 아래와 같다.

Windows: ipconfig

Linux, Mac OS: ifconfig

192.168로 시작하는 ip를 찾으면 된다.

아래 사진은 라즈베리파이에서 ifconfig 한 결과

그다음 실행하면 아래와같이 캠이 정상적으로 스트리밍되는것을 볼 수있다.

얼굴인식

얼굴인식 알고리즘

얼굴인식 알고리즘으로 대표적으로 Haar Cascade 라는 머신러닝 기반 알고리즘을 사용하는데 이것의 단점은 마스크를 착용하면 얼굴을 정상적으로 인식할 수 없다는 점이다.

이 프로젝트에서는 OpenCv 얼굴 특징점 추출 알고리즘으로 사람 얼굴에 마스크 이미지를 씌운 후 얼굴로 인식할 수 있도록 학습시킨 모델을 사용하였다.

얼굴인식 실행

Server에서 Project/FaceDetector_Server/Server.py를 실행시킨다.

Client(Raspberry Pi)는 위에서 사용한 코드 를 실행시킨다.

그러면 아래와 같은 결과를 얻을 수 있다.

스크린샷 2022-12-20 오후 3 20 29

코드

Client


# -*- coding: utf8 -*-
import cv2
import socket
import numpy as np
 
## TCP 사용
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
## server ip, port
s.connect(('192.168.100.3', 8808))
 
 
## webcam 이미지 capture
cam = cv2.VideoCapture(0)
 
## 이미지 속성 변경 3 = width, 4 = height
cam.set(3, 1280);
cam.set(4, 720);
 
## 0~100에서 90의 이미지 품질로 설정 (default = 95)
encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), 90]
 
while True:
    # 비디오의 한 프레임씩 읽는다.
    # 제대로 읽으면 ret = True, 실패면 ret = False, frame에는 읽은 프레임
    ret, frame = cam.read()
    # cv2. imencode(ext, img [, params])
    # encode_param의 형식으로 frame을 jpg로 이미지를 인코딩한다.
    result, frame = cv2.imencode('.jpg', frame, encode_param)
    # frame을 String 형태로 변환
    data = np.array(frame)
    stringData = data.tostring()
 
    #서버에 데이터 전송
    #(str(len(stringData))).encode().ljust(16)
    s.sendall((str(len(stringData))).encode().ljust(16) + stringData)
 
cam.release()

Server


import socket
import cv2
import numpy as np
import os
import random
import cv2


# socket에서 수신한 버퍼를 반환하는 함수
def recvall(sock, count):
    # 바이트 문자열
    buf = b''
    while count:
        newbuf = sock.recv(count)
        if not newbuf: return None
        buf += newbuf
        count -= len(newbuf)
    return buf


def rename_file(dist_lable: str):
    count = 0
    file_list = os.listdir("croppedData")
    for i in range(file_list.__len__()):
        if file_list[i].endswith(".jpg"):

            src = "croppedData/" + file_list[i]
            dst = "croppedData/" + dist_lable + count.__str__() + ".jpg"
            os.rename(src, dst)
            print(src + " rename to " + dst)
            count += 1


if __name__ == '__main__':
    facenet = cv2.dnn.readNet('models/model.prototxt', 'models/model.caffemodel')

    HOST = '0.0.0.0'
    PORT = 8808

    # TCP 사용
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    print('Socket created')

    # 서버의 아이피와 포트번호 지정
    s.bind((HOST, PORT))
    print('Socket bind complete')
    # 클라이언트의 접속을 기다린다. (클라이언트 연결을 10개까지 받는다)
    s.listen(10)
    print('Socket now listening')

    # 연결, conn에는 소켓 객체, addr은 소켓에 바인드 된 주소
    conn, addr = s.accept()

    while True:
        # client에서 받은 stringData의 크기 (==(str(len(stringData))).encode().ljust(16))
        length = recvall(conn, 16)
        stringData = recvall(conn, int(length))
        data = np.fromstring(stringData, dtype='uint8')

        # data를 디코딩한다.
        frame = cv2.imdecode(data, cv2.IMREAD_COLOR)
        h, w = frame.shape[:2]

        blob = cv2.dnn.blobFromImage(frame, scalefactor=1., size=(405, 405), mean=(104., 177., 123.))
        facenet.setInput(blob)
        dets = facenet.forward()

        for i in range(dets.shape[2]):
            confidence = dets[0, 0, i, 2]
            if confidence < 0.5:
                continue

            x1 = int(dets[0, 0, i, 3] * w)
            y1 = int(dets[0, 0, i, 4] * h)
            x2 = int(dets[0, 0, i, 5] * w)
            y2 = int(dets[0, 0, i, 6] * h)

            face = frame[y1:y2, x1:x2]
            face = face / 256

            if (x2 >= w or y2 >= h):
                continue
            if (x1 <= 0 or y1 <= 0):
                continue

            face_input = cv2.resize(face, (200, 200))
            face_input = np.expand_dims(face_input, axis=0)
            face_input = np.array(face_input)

            color = (255, 255, 255)

            file_list = os.listdir("croppedData")

            cropped_data_path = "croppedData/temp" + random.randrange(0, 999999).__str__() + ".jpg"
            height_dist = (y2 - y1) // 2
            crop = frame[y1: y2 - height_dist, x1: x2]
            try:
                cv2.imwrite(cropped_data_path, crop)
            except Exception as e:
                print(e)

            cv2.rectangle(frame, pt1=(x1, y1), pt2=(x2, y2), thickness=2, color=color, lineType=cv2.LINE_AA)

        cv2.imshow('masktest', frame)

        key = cv2.waitKey(1)
        if key == 27:
            break

    rename_file('crop')



이전: 개인 프로젝트: 2차시 Raspberry Pi 에 OpenCv 설치하기

다음: 개인 프로젝트: 4차시 Raspberry Pi 로 사람 판별하기