はじめに
近年、IoTデバイスの普及に伴い、リアルタイムでのビデオストリーミングが様々な用途で利用されるようになりました。本記事では、Python製のWebフレームワークであるFastAPIを使って、Webカメラからの映像を複数の端末にブロードキャストするAPIの作成方法を解説します。
こちらの記事もおすすめ
必要な環境
- Python 3.7以上
- FastAPI
- OpenCV
- Uvicorn
APIの実装
ステップ1: 必要なモジュールのインポート
まず、必要なモジュールをインポートします。FastAPIとOpenCVを使用するため、以下のようにインポートします。
from fastapi import FastAPI, Response
import cv2
import numpy as np
from fastapi.responses import StreamingResponse
import asyncio
ステップ2: FastAPIアプリケーションの作成
FastAPIアプリケーションを作成します。
app = FastAPI()
ステップ3: カメラの設定
使用するWebカメラの設定を行います。カメラのID、解像度、フォーマットを指定します。
camera_id = 0
cap = cv2.VideoCapture(camera_id)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc('M','J','P','G'))
ステップ4: 最新のフレームを保持する変数の定義
最新のフレームを保持するグローバル変数を定義します。
latest_frame = None
ステップ5: カメラからフレームを取得する非同期関数の定義
カメラから連続的にフレームを取得する非同期関数を定義します。取得したフレームはJPEG形式にエンコードされ、latest_frame
変数に格納されます。
async def fetch_camera_frame():
global latest_frame
while True:
ret, frame = cap.read()
if ret:
_, img_encoded = cv2.imencode(".jpg", frame, [int(cv2.IMWRITE_JPEG_QUALITY), 70])
latest_frame = img_encoded.tobytes()
await asyncio.sleep(0.01) # カメラからのフレーム取得間隔
ステップ6: フレームをクライアントに送信する非同期ジェネレータ関数の定義
latest_frame
変数に格納されたフレームをクライアントに送信する非同期ジェネレータ関数を定義します。この関数はマルチパートレスポンスを生成し、フレームをJPEG形式で送信します。
async def gen_frames():
while True:
if latest_frame is not None:
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + latest_frame + b'\r\n')
await asyncio.sleep(0.01) # クライアントへの送信間隔
ステップ7: アプリケーション起動時のイベントハンドラの定義
アプリケーション起動時に、fetch_camera_frame
関数をバックグラウンドで実行するためのイベントハンドラを定義します。
@app.on_event("startup")
async def startup_event():
asyncio.create_task(fetch_camera_frame())
ステップ8: カメラストリームを提供するエンドポイントの定義
/camera
エンドポイントを定義し、gen_frames
関数を使用してカメラストリームを提供します。
@app.get("/camera")
async def get_camera_stream():
return StreamingResponse(gen_frames(), media_type="multipart/x-mixed-replace;boundary=frame")
ステップ9: アプリケーション終了時のイベントハンドラの定義
アプリケーション終了時に、カメラリソースを解放するためのイベントハンドラを定義します。
@app.on_event("shutdown")
async def shutdown_event():
cap.release()
ステップ10: アプリケーションの実行
Uvicornを使用してアプリケーションを実行します。
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8001)
サーバー全体
from fastapi import FastAPI, Response
import cv2
import numpy as np
from fastapi.responses import StreamingResponse
import asyncio
app = FastAPI()
# カメラ設定
camera_id = 0
cap = cv2.VideoCapture(camera_id)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc('M','J','P','G'))
# 最新のフレームを保持する変数
latest_frame = None
async def fetch_camera_frame():
global latest_frame
while True:
ret, frame = cap.read()
if ret:
_, img_encoded = cv2.imencode(".jpg", frame, [int(cv2.IMWRITE_JPEG_QUALITY), 70])
latest_frame = img_encoded.tobytes()
await asyncio.sleep(0.01) # カメラからのフレーム取得間隔
async def gen_frames():
while True:
if latest_frame is not None:
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + latest_frame + b'\r\n')
await asyncio.sleep(0.01) # クライアントへの送信間隔
@app.on_event("startup")
async def startup_event():
# カメラフレームのフェッチをバックグラウンドで開始
asyncio.create_task(fetch_camera_frame())
@app.get("/camera")
async def get_camera_stream():
return StreamingResponse(gen_frames(), media_type="multipart/x-mixed-replace;boundary=frame")
@app.on_event("shutdown")
async def shutdown_event():
cap.release()
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8002)
クライアントの実装
APIを使用してWebカメラ映像を受信し、表示するクライアントの実装例を以下に示します。
import cv2
import requests
import numpy as np
def stream_video(url):
response = requests.get(url, stream=True)
byte_buffer = bytes()
for chunk in response.iter_content(chunk_size=1024):
byte_buffer += chunk
a = byte_buffer.find(b'\xff\xd8')
b = byte_buffer.find(b'\xff\xd9')
if a != -1 and b != -1:
jpg = byte_buffer[a:b+2]
byte_buffer = byte_buffer[b+2:]
frame = cv2.imdecode(np.frombuffer(jpg, dtype=np.uint8), cv2.IMREAD_COLOR)
cv2.imshow('Video Stream', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
stream_url = 'http://localhost:8001/camera'
stream_video(stream_url)
このクライアントは、指定されたURLからビデオストリームを受信し、OpenCVを使用して表示します。
まとめ
本記事では、FastAPIを使ってWebカメラ映像をストリーミング配信するAPIの作成方法を解説しました。このAPIを使用することで、複数の端末にリアルタイムでWebカメラ映像をブロードキャストすることができます。IoTデバイスやリモートモニタリングシステムの開発に役立つでしょう。
コメント