FastAPIはPythonで簡単にAPIサーバーが立てられるライブラリです。
fastapi.tiangolo.com
今回これを利用して、HTTP POSTで送られた画像になんらかの認識処理をかけて、結果をjsonで返すようなプログラムを書いたのでメモしておきます。
その際、送られてきた画像はOpenCVで処理してます。
1. 必要なライブラリをインストール
FastAPIはuvicornというASGI(Asynchronous Server Gateway Interface)サーバーを使用しています。ASGIが何かはとりあえず知らなくても良いです。
他に、opencvやnumpyなどもインストールします。
$ pip install fastapi
$ pip install "uvicorn[standard]"
$ pip install python-multipart
$ pip install numpy
$ pip install opencv-python
2. FastAPIのコードを書く
ここでは単純に画像を受け取って、ローカルにpng形式で保存し、そのファイル名と画像サイズをjsonで返すプログラムを書きました。
以下のコードをmain.pyというファイルに記載します。
from fastapi import FastAPI, UploadFile, File, Form
from fastapi.responses import HTMLResponse
import cv2
import numpy as np
import os
# FastAPIのインスタンス生成
app = FastAPI()
# Http Postの処理
# 送付されてきた画像をフォーマットを指定して保存
@app.post("/api")
async def save_img(file:UploadFile = File(...), format:str=Form()):
try:
if file:
#画像をメモリ上へ読み込み
data = await file.read()
#バイナリへ変換
array = np.fromstring(data, np.uint8)
#画像へ変換(OpenCV)
img = cv2.imdecode(array, flags=cv2.IMREAD_COLOR)
# ファイル名の拡張子を指定フォーマットのものへ変更
basename, _ = os.path.splitext(file.filename)
savename = basename + "." + format
# 画像を保存(フォーマットはOpenCVが拡張子で判断)
cv2.imwrite(savename, img)
# 応答
response = {"save filename":savename, "image size": str(img.shape)}
return response
except Exception as e:
print(e)
# Top Page (Http Get)
# Formを表示
@app.get("/")
async def main():
content = """
<body>
<form action="/api" enctype="multipart/form-data" method="post">
<input name="file" type="file" />
<br/>
<select name="format">
<option value="jpg">jpg</option>
<option value="png">png</option>
<option value="bmp">bmp</option>
</select>
<input type="submit"/>
</form>
</body>
"""
return HTMLResponse(content=content)
3. サーバーの起動と動作確認
以下のコマンドでサーバーを起動します。
$ uvicorn main:app --reload
main.pyのappというFastAPIオブジェクトが起動されます。
次に
http://localhost:8000
へアクセスすると、以下のようなWebフォームが開きます。
画像ファイル送信フォーム
ここで、ファイルを選択し、保存したいフォーマットを選択して「送信」ボタンを押すと、画像がHTTP Postで送信され、例えば以下のようなjsonを受け取ります。
{"save filename":"query.png","image size":"(1280, 871, 3)"}
FastAPIを起動したディレクトリ上に画像ファイルが指定フォーマットで保存されているのが確認できると思います。