10
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

画像をjsonでPOSTしてflaskで受け取る

Last updated at Posted at 2020-03-05

やりたいこと

画像をjsonとしてPOSTして、flaskで受け取りたい。
ただ、bytes型のデータをjsonの値とすることはできないためひと工夫が必要。

ローカルでサーバーを立てて試してみた。

base64って?

前述の通り、バイナリデータをjsonの要素とすることができない。テキストデータならOK。

それならばバイナリデータをある規則で一旦テキストデータに変換して伝送して、受け取った先で元のバイナリデータに変換すればよい。

バイナリデータをテキストデータに変換する規則の一つがbase64である。

#こうした
結構丁寧に解説。

まずクライアント側。
データの変遷は以下の通り。

画像をPillowImageとして読み込む
⇒ bytesに変換する
⇒ base64でエンコードする(まだbytes)
⇒ bytesだったデータをstrに変換する
⇒ json.dumpsしてjsonにする
⇒ 無事jsonでPOSTできる

client.py
import requests
from PIL import Image
import json
import base64
from io import BytesIO

img = Image.open("iruka.jpeg")

# PillowImageをbytesに変換してさらにbase64に変換
buffered = BytesIO()
img.save(buffered, format="JPEG")
img_byte = buffered.getvalue() # bytes
img_base64 = base64.b64encode(img_byte) # base64でエンコードされたbytes ※strではない

# まだbytesなのでjson.dumpsするためにstrに変換(jsonの要素はbytes型に対応していないため)
img_str = img_base64.decode('utf-8') # str

files = {
    "text":"hogehoge",
    "img":img_str
    }

r = requests.post("http://127.0.0.1:5000", json=json.dumps(files)) # jsonとしてサーバーにPOSTする

print(r.json())


>>>{'img_shape': [750, 500], 'text': 'hogehogefuga'}

次いで、サーバーサイド。
データの変遷は以下の通り。

jsonで受け取る
⇒ jsonからお目当てのデータ(base64でエンコードされたテキストデータ)を取り出す
⇒ base64でエンコードされたテキストデータをデコードしてbytesに変換する
⇒ Pillowで扱えるように_io.BytesIOに変換する
⇒ 無事に元のPillowImageを取得できる

server.py
from flask import Flask, jsonify, request
from PIL import Image
import json
import base64
from io import BytesIO
import matplotlib.pyplot as plt

app = Flask(__name__)

@app.route("/", methods=["GET", "POST"])
def index():
    json_data = request.get_json() # POSTされたjsonを取得
    dict_data = json.loads(json_data) # jsonを辞書に変換

    img = dict_data["img"] # base64を取り出す # str
    img = base64.b64decode(img) # base64に変換された画像データを元のバイナリデータに変換 # bytes
    img = BytesIO(img) # _io.BytesIO pillowで扱えるように変換
    img = Image.open(img) 
    img_shape = img.size # 取得した画像で適当に処理
    
    text = dict_data["text"] + "fuga" #取得したテキストで適当に処理

    # 処理結果をクライアントに返す
    response = {
        "text":text,
        "img_shape":img_shape        
        }

    return jsonify(response)

if __name__ == "__main__":
    app.debug = True
    app.run()

サーバーのレスポンスからも正しく画像を処理されたことが確認できた。

ちなみに
base64.b64encode()は入力がbytesで出力もbytes。
base64.b64decode()は入力はbytesでもstrでもよいが、出力はbytes。

参考

python - コマンド - POSTからbase64をデコードしてPILで使用する

How to convert PIL Image.image object to base64 string? [duplicate]

10
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?