본문 바로가기
Study/Python

[Python] OpenCV - 4 Flask

by YoungD 2023. 10. 24.
 
 

Flask 설치 및 서버 실행하기

  • 플라스크(Flask)는 파이썬으로 작성된 마이크로 웹 프레임워크의 하나
    • 특별한 도구나 라이브러리가 필요 없음

flask 설치하기

In [1]:
# Flask 설치
!pip install flask
Requirement already satisfied: flask in c:\users\gjaischool\anaconda3\lib\site-packages (2.2.2)
Requirement already satisfied: Werkzeug>=2.2.2 in c:\users\gjaischool\anaconda3\lib\site-packages (from flask) (2.2.2)
Requirement already satisfied: Jinja2>=3.0 in c:\users\gjaischool\anaconda3\lib\site-packages (from flask) (3.1.2)
Requirement already satisfied: click>=8.0 in c:\users\gjaischool\anaconda3\lib\site-packages (from flask) (8.0.4)
Requirement already satisfied: itsdangerous>=2.0 in c:\users\gjaischool\anaconda3\lib\site-packages (from flask) (2.0.1)
Requirement already satisfied: colorama in c:\users\gjaischool\anaconda3\lib\site-packages (from click>=8.0->flask) (0.4.6)
Requirement already satisfied: MarkupSafe>=2.0 in c:\users\gjaischool\anaconda3\lib\site-packages (from Jinja2>=3.0->flask) (2.1.1)

 

flask 서버 실행하기

  • app = Flask(\_\_name\_\_) : Flask 객체를 app 변수에 할당
  • @app.route("/") : Flask에게 어떤 URL이 해당 함수를 실행하는지 알려줌
  • app.run(host='127.0.0.1', port=5000)
    • 서버 IP, 포트 등을 설정하고 서버를 실행
    • 브라우저에서 IP와 포트로 서버 접속
In [2]:
from flask import Flask

# 초기화
app = Flask (__name__)

# 경로 설정
@app.route("/")
def hello() :
    return "Hello World!"

# 메인 함수라면, py 파일을 단독으로 실행했다면
if __name__ == "__main__" :
    # 서버 시작
    app.run(host="192.168.0.17", port=9000)
 * Serving Flask app '__main__'
 * Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://192.168.0.17:9000
Press CTRL+C to quit

 

URL를 함수로 연결하기

  • @app.route("/hello")
    • URL에 함수명을 설정
    • 브라우저에서 IP와 포트로 서버 접속하고 URL로 함수명을 넘김
In [3]:
# 실습

 

URL을 변수로 사용하기

  • @app.route("/hello/")
    • URL에 value 값을 설정
    • 브라우저에서 IP와 포트로 서버 접속하고 URL로 100을 넘김
In [4]:
# 실습

 

html 문서를 반환하기

  • render_template("hello.html")
    • hello.html 문서를 반환
  • hello.html 파일을 작성하고 templates 폴더를 생성하고 저장
  • 브라우저에서 IP와 포트로 서버 접속
In [5]:
# 실습
In [6]:
# 실습

 

이미지가 포함된 문서 반환하기

  • static 폴더 : 자원을 담아 놓는 폴더
  • static 폴더에 이미지 폴더를 만들고 출력할 이미지를 저장
In [7]:
# 실습
In [8]:
# 실습

 

데이터 스트리밍 구현

구현 방법

  • Response(stream_with_context(test()))
    • 텍스트 스트리밍 함수 test()를 실행
 
 
# 실습
  • yield() 함수 배우기
 
 
# 실습

웹 브라우저에 카메라 영상 출력하기

  • ret, buffer = cv2.imencode('.jpg', frame) : frame 이미지를 jpg로 인코딩
  • frame = buffer.tobytes() : 전송을 위해 인코딩된 이미지를 byte 형식으로 변환
  • yield (b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
    • b : byte 형식임을 의미
    • --frame : 프레임을 표시
    • Content-Type: image/jpeg : 문서가 jpg 이미지임을 표시
  • 카메라로부터 프레임 이미지를 읽어서 반환하는 함수
In [9]:
import cv2

cap = cv2.VideoCapture(0)

def get_frames() :
    while True :
        ret, frame = cap.read()
        
        frame = cv2.flip(frame, 1)
        
        cv2.waitKey(33)
        
        if not ret :
            continue
        # 이미지 프레임을 읽었다면 반환
        else :
            # 배열을 JPG로 변환해서 바이트 단위로 전송
            ret, buff = cv2.imencode(".jpg", frame)
            frame = buff.tobytes()
            
            # 이미지를 반환
            yield (b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
            
        cap.release()
  • index.html를 작성하고 templates 폴더에 저장
    • video_feed : 실행할 함수명
  • %%writefile : 아래에 있는 내용을 설정된 파일에 저장
    • 무조건 첫 줄에 써야됨
  • {{ url_for('video_feed') }} : Jinja 템플릿
    • HTML 문서에 파이썬 코드를 작성하게 해주는 것
In [10]:
%%writefile ./templates/index.html
<html>
<body>
<h1>웹캠 테스트</h1>
<img src="{{ url_for('video_feed') }}" width=50%>
</body>
</html>
  • Response(get_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')
    • get_frames() : 호출할 함수명
    • mimetype : 클라이언트에게 전송된 문서의 타입을 알려주기 위한 파라미터 (type/subtype)
    • multipart : 복합문서 타입 (파일, 영상 등)을 의미
    • x-mixed-replace : x (추가적인 확장 형식), mixed (복합문서), repalce (subtype을 다음 메시지로 대체)
    • boundary : 복합문서 내의 각 문서들을 구분하는 분리자 (동영상이므로 frame으로 구분)
In [11]:
# render_template : Jinja 템플릿이 포함된 HTML을 전송
# Response : 클라이언트의 request에 대해서 응답을 해주는 기능
from flask import Flask, render_template, Response

app = Flask(__name__)

@app.route("/")
def index() :
    return render_template("index.html")

@app.route("/video_feed")
def video_feed() :
    return Response(get_frames(),
             mimetype='multipart/x-mixed-replace; boundary=frame')

if __name__ == "__main__" :
    app.run(host="192.168.0.17", port=9005)
 
요약
 ret, buffer = cv2.imencode() : 영상 인코딩 함수
○ yield() : 반복 실행 중에 중간 과정을 반환할 때 사용

○ Flask : 파이썬으로 제작된 웹 프레임워크 (DJango의 축소 버전)
 app = Flask(__name__) : Flask 객체를 app 변수에 할당
 @app.route("/") : Flask에게 어떤 URL이 해당 함수를 실행하는지 알려줌
 @app.route("/hello") : 서버 주소에 추가적인 URL을 설정
 @app.route("/hello/") : URL에 value 값을 설정
 app.run(host='127.0.0.1', port=5000) : 서버 IP, 포트 등을 설정하고 서버를 실행

 render_template("hello.html") : html 문서를 반환하기
 Response(stream_with_context()) : 데이터 스트리밍을 반환하기