OpenCV - Flask

songmin jeon·2024년 1월 9일
0

1. Flask

  • 플라스크(Flask)는 파이썬으로 작성된 마이크로 웹 프레임워크의 하나
    • 특별한 도구나 라이브러리가 필요 없음
    • 웹 화면에 카메라 영상 출력
    • 웹 출력 영상을 Gray 이미지로 출력
# flask 설치
!pip install flask

1.1. flask 서버 실행하기

  • 명령어

app = Flask(__name__)
#Flask 객체를 app 변수에 할당

@app.route("/")
#Flask에게 어떤 URL이 해당 함수를 실행하는지 알려줌

app.run(host='127.0.0.1', port=5000)
#서버 IP, 포트 등을 설정하고 서버를 실행
#브라우저에서 IP와 포트로 서버 접속


1.2. URL를 함수로 연결하기

  • 명령어

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


1.3. URL을 변수로 사용하기

  • 명령어

@app.route("/hello/값")
# URL에 값을 설정
# 브라우저에서 IP와 포트로 서버 접속하고 URL로 100을 넘김

from flask import Flask

# 값이 하나인 경우
app = Flask(__name__)
@app.route('/hello/<value1>')
def hello(value1):
    return 'Hello World'+value1
# 만약 객체명이 __main__이라면
if __name__ == '__main__':
    # 서버 ip를 설정하고 포트번호 지정해서 서버를 실행시켜라
    app.run(host='127.0.0.1',port=5000)
from flask import Flask

# 값이 두개인 경우
app = Flask(__name__)
@app.route('/hello/<value1>/<value2>')
def hello(value1, value2):
    return 'Hello World'+value1+":"+value2
# 만약 객체명이 __main__이라면
if __name__ == '__main__':
    # 서버 ip를 설정하고 포트번호 지정해서 서버를 실행시켜라
    app.run(host='127.0.0.1',port=5000)

2.HTML 문서 반환

2.1. html 문서를 반환하기

  • 적용방법

render_template("hello.html")

# hello.html 문서를 반환
# hello.html 파일을 작성하고 templates 폴더를 생성하고 저장
# 브라우저에서 IP와 포트로 서버 접속
  • html 기본 형식(젤 윗줄의 형식만 참조)
%%writefile ./templates/hello.html
<html>
<body>
<h1>Hello World !! </h1>
</body>
</html>
from flask import Flask, render_template

app = Flask(__name__)
@app.route('/')
def hello():
    return render_template('hello.html')
# 만약 객체명이 __main__이라면
if __name__ == '__main__':
    # 서버 ip를 설정하고 포트번호 지정해서 서버를 실행시켜라
    app.run(host='127.0.0.1',port=5000)


3. 이미지 포함된 문서 반환

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

  • static 폴더 : 자원을 담아 놓는 폴더
  • static 폴더에 이미지 폴더를 만들고 출력할 이미지를 저장
%%writefile ./templates/imgdisp.html
<html>
<body>
<img src="{{url_for('static', filename='./images/butterfly.png')}}" width="50%">
</body>
</html>
from flask import Flask, render_template

app = Flask(__name__)
@app.route('/')
def hello():
	# 나비 이미지 리턴
    return render_template('imgdisp.html')
# 만약 객체명이 __main__이라면
if __name__ == '__main__':
    # 서버 ip를 설정하고 포트번호 지정해서 서버를 실행시켜라
    app.run(host='127.0.0.1',port=5000)


4. 데이터 스트리밍 구현

4.1. 구현방법

  • 명령어

Response(stream_with_context(test()))
# 텍스트 스트리밍 함수 test()를 실행
  • Helloitem 으로 출력됨.

4.2. return으로 값을 반환하는 경우

# return으로 값을 반환하는 경우
import time 
def return_abc() :
    alphabets = []
    
    for ch in 'ABC':
        time.sleep(1)
        alphabets.append(ch)
    
    return alphabets

for ch in return_abc() :
    print(ch)
    
# return_abc() 함수를 다 실행한 후에 값을 반환 받아서 for문을 돌림
# time.sleep(1)으로 인해 3번 돌면서 3초후에 A, B, C가 한번에 출력

5. 웹 브라우저에 카메라 영상 출력

  • 명령어

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 이미지임을 표시

# index.html를 작성하고 templates 폴더에 저장
# video_feed : 실행할 함수명
# Jinja template : HTML문서에서 파이썬 명령어를 구현하도록 지원하는 도구
# %%writefile : 아래쪽에 있는 내용을 해당 파일에 저장, 위쪽에는 어떤 내용도 있으면 안됨

5.1. 웹 브라우저에 카메라 영상 출력 해보기

import cv2
    
camera = cv2.VideoCapture(0)
    
def get_frames() :
    while True : 
        sussess, frame = camera.read()
        cv2.waitkey(33) # 30 프레임
            
        if not success : 
            yield 100, 200
            continue
        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'
    cap.release()  
%%writefile ./templates/index.html
<html>
<body>
<h3>Live Streaming</h3>
<img src="{{ url_for('video_feed') }}" width="50%"><br>
</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으로 구분)
from flask import Flask, render_template, Response

# Flask 초기화
app = Flask(__name__)

@app.route('/')

def index() :
    # templates 폴더 내부의 index.html을 호출한 클라이언트로 넘겨줌
    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='127.0.0.1', port=5000)

5.2. 스트리밍 데이터에 추가적인 값을 보내고자 하는 경우

import cv2

camera = cv2.VideoCapture(0)

def get_frames():  
    while True:
        success, frame = camera.read()  
        
        cv2.waitKey(33)
        
        if not success:
            continue
        else:
            ret, buffer = cv2.imencode('.jpg', frame)
            frame = buffer.tobytes()
            
            # 문자열를 사용해야함            
            val = "100"
            
            # 이미지프레임과 변수 값을 반환
            yield (b'--frame\r\n' 
                   b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n' +
                   b'Content-Type: text/plain\r\n\r\n' + val.encode() + b'\r\n')

    cap.release() 
%%writefile ./templates/index2.html    
<!DOCTYPE html>
<html>
<body>
    <h3>Live Stream</h3>
    <img src="{{ url_for('video_feed') }}" width="50%"><br>
    <h2>Value: {{ val }}</h2>
</body>
</html>
from flask import Flask, render_template, Response

# Flask app 초기화
app = Flask(__name__)

@app.route('/')
def index():
    # templates 폴더의 index.html 파일을 호출한 클라이언트로 넘김
    return render_template('index2.html')

@app.route('/video_feed')
def video_feed():
    return Response(get_frames(), 
                    mimetype='multipart/x-mixed-replace; boundary=frame')
      
if __name__ == "__main__":
    # 서버 IP를 설정
    app.run(host='127.0.0.1', port=9335)

5.3. 웹 출력 영상을 Gray 이미지로 출력하기

import cv2

cap = cv2.VideoCapture("./images/video.mp4")
def get_frames() :
    while cap.isOpened() :
        ret, frame = cap.read()
        
        cv2.waitKey(33)
        
        if not ret :
            print("프레임 읽기 실패")
            continue
        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')
        
    cap.release()

cap2 = cv2.VideoCapture("./images/video.mp4")
def get_frames_gray() :
    while cap2.isOpened() :
        ret, frame = cap2.read()
        
        cv2.waitKey(33)
        
        # 흑백이미지로 변환
        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        
        if not ret :
            print("읽기 실패")
            continue
        else :
            _, 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')
            
    cap2.release()            
%%writefile ./templates/index_gray.html
<html><body>
<h3>웹켐 테스트</h3>
<img src="{{ url_for('video_feed') }}" width="50%">
<img src="{{ url_for('video_feed_gray') }}" width="50%">
</body></html>
from flask import Flask, render_template, Response

app=Flask(__name__)

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

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

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

if __name__ == "__main__" :
    app.run(host='127.0.0.1', port = 5001)

6. 학습요약

○ 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()) : 데이터 스트리밍을 반환하기

profile
제가 한 번 해보겠습니다.

0개의 댓글