Jetson Nano

Jetson Nano에서 PiCamera에 의한 Flask Opencv 안면인식

coding art 2020. 5. 15. 19:41
728x90

Jetson Nano 보드에서는 라즈베리 파이에서 PiCamera 라이브러리 설치와는 달리 CSI Camera를 설치하여 PiCamera를 사용하는 것이 가능하다. 큰 차이점은 라즈베리 파이에서 Opencv를 사용할 경우 명령 cv2.VideoCaputre(0) 에 의해 Default PiCamera 사용이 가능하지만 CSI Camera에서는 아래와 같이 GStreamer를 사용하며 VideoCapture에서도 GStreamer를 정확하게 지정해 줄 해 줄 필요가 있다. 한편 GStreamer에서는 3280X2464 해상도까지 처리가 가능하며 웹서버용으로 사용을 감안할 경우 640X480 해상도면 충분하다.

 

이와 같은 카메라 처리 코드를 사용하여 Jetson Nano 보드에서 웹서버용 코드를 작성하여 실행시켜 보자. 우선 Jetson Nano에서도 터미널을 열어 sudo apt-get update, sudo apt-get up grade alc sudo apt-get dist-upgrade 명령 실행 후 sudo pip install flask 명령을 실행하여 Flask 시스템을 설치한다. Jetson Nano에서는 Opencv 3.3.1이 이미 설치가 되어 있다.

Jetson Nano에서 Flask 웹서버 예제를 다시 해 보는 이유는 Jetson Nano 보드가 GPU 시스템이기 때문이다. 윈도우즈10 시스템에서 안면 인식을 위한 한 사이클당 실행 시간이 80 밀리 초 이상이였다면 라즈베리파이에서는 그 7~8배에 달하는 600 밀리 초 이상이었다. 즉 실행은 되지만 움직임이 너무 느리다는 문제가 발생한다. 라즈베리 파이 보다 실행 속도가 훨씬 빠르다는 특히 안면 인식 인공지능 계산을 지원 가능한 GPU 를 장착한 Jetson Nano 보드의 성능을 평가해 보도록 한다.

윈도우즈10라즈베리 파이나 Jetson Nano 나 다 동일한 폴더 구조를 준비해야 한다. 즉 실행 코드가 들어 있는 폴더에 templates 폴더가 있어야 하며 index.html 파일이 들어 있어야 한다. 한편 Jetson Nano 에는 PiCamera 가 설치된 상태에서 CSI Camera 라이브러리가 사전 설치되어 있어야 하며 코드 앞부분에 GStreamer 함수를 코딩해 두도록 하자. 한편 Jetson Nano에는 haarcascade 라이브러리도 이미 설치가 되어 있으므로 별도로 설치할 필요 없이 위 코드 사례에서처럼 사용하면 된다.

 

 

실행 결과 한 사이클당 소모 시간이 200 밀리 초 이상이 소요되었다. 즉 라즈베리파이 보다는 3배 빨랐으며 윈도우즈10 데스크 탑 보다는 3배가량 느린 것으로 평가된다. GPU 장착으로 인해 실행 속도가 빨라 웹서버 코드 실행이 가능하다고 볼 수 있다.

 

 

#face_detect_webserver.py

from flask import Flask, render_template, Response

 

import cv2

import numpy as np

import time

import datetime

import sys

 

def gstreamer_pipeline(

    capture_width=3280,

    capture_height=2464,

    #display_width=205,

    display_width=640,

    #display_height=154,

    display_height=480,

    framerate=21,

    flip_method=2,

    

):

    return (

        "nvarguscamerasrc ! "

        "video/x-raw(memory:NVMM), "

        "width=(int)%d, height=(int)%d, "

        "format=(string)NV12, framerate=(fraction)%d/1 ! "

        "nvvidconv flip-method=%d ! "

        "video/x-raw, width=(int)%d, height=(int)%d, format=(string)BGRx ! "

        "videoconvert ! "

        "video/x-raw, format=(string)BGR ! appsink"

        % (

            capture_width,

            capture_height,

            framerate,

            flip_method,

            display_width,

            display_height,

        )

    )

 

face_Cascade = cv2.CascadeClassifier( "/usr/share/OpenCV/haarcascades/haarcascade_frontalface_default.xml")

 

app = Flask(__name__)

 

@app.route('/')

def index():

    """Video streaming home page."""

    now = datetime.datetime.now()

    timeString = now.strftime("%Y-%m-%d %H:%M")

    templateData = {

            'title':'Image Streaming',

            'time': timeString

            }

    return render_template('index.html', **templateData)

 

def gen_frames():

    camera = cv2.VideoCapture(gstreamer_pipeline(), cv2.CAP_GSTREAMER)

    

    time.sleep(0.2)

    lastTime = time.time()*1000.0

 

    while True:

        ret, image = camera.read()

        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

       

        faces = face_Cascade.detectMultiScale(gray,scaleFactor=1.1,minNeighbors=6)

        delt = time.time()*1000.0-lastTime

        s = str(int(delt))

        #print (delt," Found {0} faces!".format(len(faces)) )

        lastTime = time.time()*1000.0

        # Draw a rectangle around the faces

        for (x, y, w, h) in faces:

            cv2.circle(image, (int(x+w/2), int(y+h/2)), int((w+h)/3), (255, 255, 255), 3)

        cv2.putText(image, s, (10, 25),cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)

        now = datetime.datetime.now()

        timeString = now.strftime("%Y-%m-%d %H:%M")

        cv2.putText(image, timeString, (10, 45),cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 0, 0), 2)

        #cv2.imshow("Frame", image)

        key = cv2.waitKey(1) & 0xFF

     # if the `q` key was pressed, break from the loop

        if key == ord("q"):

            break

   

        ret, buffer = cv2.imencode('.jpg', image)

        frame = buffer.tobytes()

        yield (b'--frame\r\n'

               b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')

       

 

@app.route('/video_feed')

 

def video_feed():

    """Video streaming route. Put this in the src attribute of an img tag."""

    return Response(gen_frames(),

                    mimetype='multipart/x-mixed-replace; boundary=frame')

 

if __name__ == '__main__':

    app.run(host='0.0.0.0') 

 

 

#index.html

<!doctype html>
<html lang="en">
<head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"
          integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">

    <title>{{title}}</title>
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-lg-8  offset-lg-2">
            <h3 class="mt-5">{{time}}</h3>
            <img src="{{ url_for('video_feed') }}" width="100%">
        </div>
    </div>
</div>
</body>
</html>