라즈베리

라즈베리 파이 Opencv 웹캠에 의한 파이선 Flask Workframe 실시간 웹서버

coding art 2020. 4. 30. 13:21
728x90

파이선 코딩 초보자를 위한 텐서플로우∙OpenCV 머신 러닝 2차 개정판 발행

http://blog.daum.net/ejleep1/1175

 

파이선 코딩 초보자를 위한 텐서플로우∙OpenCV 머신 러닝 2차 개정판 하이퍼링크 목차 pdf 파일

본서는 10월 26일 교보문고 퍼플 POD 출판 신청하였습니다. 일정 기간 검토 후 출판 결정이 될 것이며 11월 초부터 주문 구입이 가능합니다. 참고로 책 목차에 따른 내용별 학습을 위한 코드는 이미

blog.daum.net

-------------------------------------------------------------------------------------------------

 

라즈베리 파이 보드에서 네트워킹 된 외부의 사용자가 특정한 웹 주소의 컨텐츠를 공유할 수 있도록 해 주는 웹서버 구축에 대단히 편리한 Workframe 중의 하나가 Flask 이다.

라즈베리 파이 보드에서 Flask Workframe을 사용하여 웹캠을 사용하는 실시간 웹서버를 파이선 코드를 구성해 보자. 웹서버란 웹의 url 을 통해 request를 보낼 경우 특별하게 지정된 ip 번호인 0.0.0.0:5000 또는 127.0.0.1:500에 출력을 공유하는 시스템이다. 특히 파이선 Flask에서 host=’0.0.0.0’ 으로 설정할 경우 이는 Flask 코드가 실행되며 자체 로컬 ip를 가지는 컴퓨터 웹에서 출력 확인도 가능하지만 아울러 로컬 ip를 끈 상태에서 연결된 네트워킹된 컴퓨터에서 로컬 ip:’ +‘5000’ 으로 request 하여 출력 공유가 가능해진다.

 

라즈베리 파이 보드를 사용하여 비데오 스트리밍 데이터를 네트워킹 된 컴퓨터에서 웹서빙 받기 위해서 사용하는 카메라는 PiCamera 와 웹캠 2종이 있을 수 있다. PiCamera를 사용할 경우에는 지원 라이브러리인 PiCamera PiRGBArray를 사용하여 코드를 작성이 가능하겠지만 반면에 일반 usb 웹캠을 사용할 경우에는 별도의 지원 라이브러리가 없어 곤란해진다. 한편 인텔의 Opencv 라이브러리를 사용하면 PiCameraC270 로지텍 웹캠이든 비데오 영상 스트리밍이 가능해지며 이 기법을 Flask Workframe 에 적용해 보기로 한다.

    Opencv에서 웹캠이나 PiCamera를 공통적으로 사용하기 위해서는 Rasberry Pi Configuration Interface에서 Camera 기능을 Disable 로 처리해 두어야 카메라가 웹캠이든 PiCamera이든 VideoCature(0) 명령에 의해 비데오 카메라로 인식된다. 물론 Opencv 카메라로 인식 될 경우 frame rate 이 일정한 값인 30 으로 고정되는 듯하지만 그다지 문제가 되는 않는다. 아울러 SSH(Secure Shell)Enable 로 설정해야 네트워킹 된 컴퓨터에서 웹서빙을 받을 수 있게 된다. Real VNC 에 네트워크된 디바이스에서의 모니터링 기능도 마찬가지로 웹서버 이상의 기능을 보여 주지만 화면 캡춰가 되지 않아 진정한 공유가 불가능한 단점이 있음에 유의하자.

 

 

Flask_webcam.py 의 코드 구조를 살펴보자. 라이브러리 영역에서 Flask 와 한 세트인 render_template, Response 와 함께 Opencv에 해당하는 cv2import 하자. Opencv를 사용하면 PiCamera 와 같은 특정한 카메라의 특정 라이브러리 사용을 피할 수도 있으나 PiCamera 특유의 기능을 사용하지 못하게 됨에 유의하자.

Flask 코드의 특징 적인 구조는 Flask 선언, root ‘/’에서 index.html을 사용하는 @app.route(‘/’) , root 의 하부 폴더 위치에 해당하는 즉 ‘/video_feed’, 웹의 host 로컬 ip port 설정 영역으로 구성된다. 현재의 코드에서처럼 port 설정이 생략되어 있으면 Default5000 이 된다. port 넘버는 반드시 4자리라야 하며 예를 들어 2자리 수는 안된다. 한편 host 로컬 ip 0.0.0.0 으로설정할 경우 네트워킹된 외부 컴퓨터의 웹에서 현재 Flask 코드 실행 중인 컴퓨터의 로컬 ip + ‘:5000’ 을 웹 url에 입력하여 request를 보낼 수 있으나 로컬 ip127.0.0.1 로 설정하는 경우에는 외부네트워크로부터 request를 받을 수 없음에 유의하자. 아울러 외부로부터 네트워킹을 위해서는 Flask 코드를 실행하는 컴퓨터의 웹을 반드시 꺼야 함에도 유의하자.

 

 

한편 실행코드인 Flask_webcam.py 가 위치한 폴더에 templates폴더가 함께 위치해야 하며 그 안에 index.html 있어야 한다.

 

 

아래의 index.html 코드 구조에는 헤드, CSS title에 이어 Live Streaming 텍스트 문자열과 함께 지정된 url로 대표되는 image source img src=∙∙∙로 정의되는 스트림 영상 주소가 코딩된다.

 

 

코드를 실행하면서 파이선 셸에서 웹 url 과 연결 상태를 모니터링 해 보자. /HTTP/1.1 200 은 제대로 네트워크 연결이 성공적으로 되었다는 의미이며 404 는 에러호서 통신연결 불능 상태이거나 인위적으로 차단했다는 의미이다. 현재 코드에서 host=0.0.0.0 오로 설정했지만 섈에서의 Flask Workframe 의 반응은 자동적으로 127.0.0.1 로 처리 되고 있음을 알 수 있다. 한편 네트워킹 된 외부 컴퓨터의 웹에서 통신 연결을 하려면 라즈베리 파이 보드 터미널에서 ifconfig 명령에 의해 확인 가능한 로컬 ip 번호를 알고 있어야 request를 전송할 수 있다.

 

 

첨부된 코드를 다운받아 Flask 웹서버를 실행해 보자.

#Flask_webserver.py

from flask import Flask, render_template, Response

import cv2

 

app = Flask(__name__)

 

camera = cv2.VideoCapture(0)  # use 0 for web camera

 

def gen_frames():  # generate frame by frame from camera

    while True:

        # Capture frame-by-frame

        success, frame = camera.read()  # read the camera frame

        if (not success):

            break

        else:

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

            frame = buffer.tobytes()

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

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

                   # concat frame one by one and show result

 

 

@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')

 

 

@app.route('/')

def index():

    """Video streaming home page."""

    return render_template('index.html')

 

 

if (__name__ == '__main__'):

 

    app.run(host='0.0.0.0', port=8080)

 

<!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>Live Streaming Demonstration</title>
  </head>
  <body>
  <div class="container">
  <div class="row">
  <div class="col-lg-8 offset-lg-2">
  <h3 class="mt-5">Live Streaming</h3>
  <img src="{{ url_for('video_feed') }}" width="100%">
  </div>
  </div>
  </div>
  </body>
  </html>