LoginSignup
4
6

More than 3 years have passed since last update.

[python] Webカメラからキャプチャした画像をサーバに送信して保存する

Last updated at Posted at 2020-10-16

概要

以下を実装します。
・ブラウザでWebカメラを起動
・カメラ画面の画像をキャプチャ
・キャプチャ画像をサーバに送信して保存

フォルダ構成

/home/capture_img
|--run.py
|--app
|  |--api.py
|  |--service.py
|  |--static
|  |  |--main.js
|  |--templates
|  |  |--index.html
|--images #キャプチャした画像の保存先

ソースコード

run.py

run.py
from app.api import api

if __name__ == '__main__':
    api.run(host='0.0.0.0', port=8000)

app/api.py

app/api.py
from flask import Flask, request, make_response, render_template, url_for

from . import service

api = Flask(__name__)

@api.route('/', methods=['GET'])
def index():
    return render_template('index.html')

@api.route('/capture_img', methods=['POST'])
def capture_img():
    msg = service.save_img(request.form["img"])
    return make_response(msg)

app/service.py

app/service.py
import base64
import numpy as np
import cv2

def save_img(img_base64):
    #binary <- string base64
    img_binary = base64.b64decode(img_base64)
    #jpg <- binary
    img_jpg=np.frombuffer(img_binary, dtype=np.uint8)
    #raw image <- jpg
    img = cv2.imdecode(img_jpg, cv2.IMREAD_COLOR)
    #デコードされた画像の保存先パス
    image_file="/home/capture_img/images/img0000.jpg"
    #画像を保存
    cv2.imwrite(image_file, img)
    return "SUCCESS"

templates/index.html

templates/index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>get_capture</title>
</head>
<body>
    <h3>スペースキー押下でキャプチャ取得</h3>
    <video id="video" width="640" height="480" autoplay></video>
    <canvas id="canvas" class="canvas-wrapper"></canvas>
</body>

<script src="{{url_for('static', filename='main.js')}}"></script>

<style>
    /* canvasは非表示にする */
    #canvas {
        display: none !important;
    }
</style>
</html>

static/main.js

static/main.js
var video = document.getElementById('video');
// getUserMedia()でカメラ映像の取得
var media = navigator.mediaDevices.getUserMedia({ video: true });
//リアルタイム再生(ストリーミング)を行うためにビデオタグに流し込む
media.then((stream) => {
    video.srcObject = stream;
});

var canvas = document.getElementById('canvas');
canvas.setAttribute('width', video.width);
canvas.setAttribute('height', video.height);

video.addEventListener(
    'timeupdate',
    function () {
        var context = canvas.getContext('2d');
        context.drawImage(video, 0, 0, video.width, video.height);
    },
    true
);

// スペースキー押下時にキャプチャ取得を実行するリスナーを設定
document.addEventListener('keydown', (event) => {
    var keyName = event.key;
    if (keyName === ' ') {
        console.log(`keydown: SpaceKey`);
        context = canvas.getContext('2d');
        // 取得したbase64データのヘッドを取り除く
        var img_base64 = canvas.toDataURL('image/jpeg').replace(/^.*,/, '')
        captureImg(img_base64);
    }
});

var xhr = new XMLHttpRequest();

// キャプチャ画像データ(base64)をPOST
function captureImg(img_base64) {
    const body = new FormData();
    body.append('img', img_base64);
    xhr.open('POST', 'http://localhost:8000/capture_img', true);
    xhr.onload = () => {
        console.log(xhr.responseText)
    };
    xhr.send(body);
}

必要なモジュールのインストール

root@ed9f7bedad16:/# pip install opencv-python flask

実行

root@ed9f7bedad16:/# python /home/capture_img/run.py
 * Serving Flask app "app.api" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://0.0.0.0:8000/ (Press CTRL+C to quit)

動作確認

http://localhost:8000にアクセス & スペースキー押下

スクリーンショット 2020-10-16 23.50.02.png

root@ed9f7bedad16:/# ls /home/capture_img/images/
img0000.jpg

キャプチャ画像が保存されました。
img0000.jpg

以上です。

4
6
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
4
6