はじめに
Webカメラで撮った画像をHTTPの通信を介して顔検出モデル等が動いている別のサーバーに送信するようなコードを何度か書いたので忘れないようにメモする。
サンプルコードでは、送信側でWebカメラから撮った画像を一定間隔でサーバに送信し、受信側で顔を検出してボックスを描画した上でローカルに画像ファイルを保存している。
送信側
sender.py
import numpy as np
import cv2
import time
import json
import base64
import requests
def send_image(img):
# 画像を送信可能な形式に変換してJSONに格納
_, encimg = cv2.imencode(".png", img)
img_str = encimg.tostring()
img_byte = base64.b64encode(img_str).decode("utf-8")
img_json = json.dumps({'image': img_byte}).encode('utf-8')
# HTTPリクエストを送信
response = requests.post("http://localhost:8080/save", data=img_json)
print('{0} {1}'.format(response.status_code, json.loads(response.text)["message"]))
if __name__ == '__main__':
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FPS, 30)
i = 0
while True:
_, img = cap.read()
if i % 5 == 0:
send_image(img)
i += 1
受信側
receiver.py
import os
import json
import cv2
import base64
import numpy as np
from datetime import datetime
from flask import Flask, request, Response
app = Flask(__name__)
count = 0
# 画像を保存するフォルダの作成
image_dir = "./images"
if not os.path.isdir(image_dir):
os.mkdir(image_dir)
def detect_face(img):
# 顔検出モデル('haarcascade_frontalface_default.xml')は下記リンクからダウンロードできる
# https://github.com/opencv/opencv/tree/master/data/haarcascades
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
faces = face_cascade.detectMultiScale(img, 1.3, 5)
return faces
@app.route('/save', methods=['POST'])
def save_image():
# データの変換処理
data = request.data.decode('utf-8')
data_json = json.loads(data)
image = data_json['image']
image_dec = base64.b64decode(image)
data_np = np.fromstring(image_dec, dtype='uint8')
decimg = cv2.imdecode(data_np, 1)
# 顔検出してボックスを描画
gray_img = cv2.cvtColor(decimg, cv2.COLOR_BGR2GRAY)
faces = detect_face(gray_img)
for (x,y,w,h) in faces:
decimg = cv2.rectangle(decimg,(x,y),(x+w,y+h),(255,0,0),2)
# 画像ファイルを保存
global count
filename = "./images/image{}.png".format(count)
cv2.imwrite(filename, decimg)
count += 1
# HTTPレスポンスを送信
return Response(response=json.dumps({"message": "{} was saved".format(filename)}), status=200)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)
参考
http://edosha.hatenablog.jp/entry/2017/09/05/174453
https://ysss.hateblo.jp/entry/2018/07/31/053507