코드 분석

openCV로 카메라 연동해서 로컬 서버를 만드는 코드입니다.

from flask import Flask, Response, redirect, url_for
import cv2

app = Flask(__name__)

def generate():
    cap = cv2.VideoCapture(0)  
    cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
    cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)

    if not cap.isOpened():
        print("Error: Could not open video device.")
        return

    while True:
        ret, frame = cap.read()
        if not ret:
            print("Error: Failed to capture image.")
            break
        _, jpeg = cv2.imencode('.jpg', frame)
        frame = jpeg.tobytes()
        yield (b'--frame\r\n'
               b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n')

    cap.release()

@app.route('/')
def index():
    # 루트 경로에서 /video_feed로 리디렉션
    return redirect(url_for('video_feed'))

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

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

 

generate 함수

cap = cv2.VideoCapture(0)
  • 카메라 장치를 video0 으로 설정합니다.
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
  • 카메라 해상도를 설정합니다.
 while True:
        ret, frame = cap.read()
        if not ret:
            print("Error: Failed to capture image.")
            break
  • 무한 루프를 실행하여 계속해서 프레임을 캡처하고 전송합니다.
  • ret, frame = cap.read(): 카메라에서 한 프레임을 읽어옵니다.
    • ret은 영상 프레임을 읽었는지 성공 여부를 나타내는 Bool 값입니다.
    • frame은 실제 영상 데이터(프레임)을 나타냅니다.
        _, jpeg = cv2.imencode('.jpg', frame)
        frame = jpeg.tobytes()
  • _, jpeg = cv2.imencode('.jpg', frame): frame을 JPEG 형식의 이미지로 인코딩합니다. _는 첫 번째 반환값(성공 여부)을 무시하는 것입니다.
  • frame = jpeg.tobyptes(): 인코딩된 JPEG 이미지를 바이트 형식으로 변환하여 네트워크 전송에 적합하게 합니다.
        yield (b'--frame\r\n'
               b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n')
  • yield: 제너레이터 함수에서 값을 반환하고, 다음 호출 때 다시 실행을 재개합니다. 여기서는 MJPEG 형식의 HTTP 응답을 실시간 스트리밍 형식으로 제공합니다.
  • b'--frame\r\n': 각 프레임의 시작을 나타내는 MJPEG 경계(boundary)로, 클라이언트가 이미지의 시작과 끝을 인식할 수 있게 합니다.
  • b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n': HTTP 헤더와 함께 JPEG 이미지 데이터를 전송합니다. 
    cap.release()
  • 카메라를 해제하여 다른 프로세스가 접근할 수 있도록 합니다.

URL 도메인 설정하기

@app.route('/')
def index():
    # 루트 경로에서 /video_feed로 리디렉션
    return redirect(url_for('video_feed'))
  • @app.route('/'): Flask 애플리케이션의 루트 경로(http://<IP 주소>:5000/)에서 이 함수를 실행하도록 설정합니다.
  • def index(): 루트 경로에 대한 핸들러 함수입니다.
  • return redirect(url_for('video_feed')): video_feed 엔드포인트로 리디렉션하여 실시간 스트림이 표시되도록 합니다.
@app.route('/video_feed')
def video_feed():
    return Response(generate(),
                    mimetype='multipart/x-mixed-replace; boundary=frame')
  • @app.route('/video_feed'): /video_feed 경로에서 이 함수를 실행하도록 설정합니다.def video_feed(): /video_feed 경로에 대한 핸들러 함수입니다.
  • return Response(generate(), mimetype='multipart/x-mixed-replace; boundary=frame'): generate 함수를 호출하여 반환된 스트림을 HTTP 응답으로 보냅니다.
  • mimetype='multipart/x-mixed-replace; boundary=frame'은 MJPEG 스트리밍을 위해 필요한 MIME 타입으로, 클라이언트가 여러 이미지를 스트리밍 형식으로 처리할 수 있게 합니다.

 

ytw_developer