質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

アップロード

アップロードは特定のファイルをウェブサーバに送るプロセスのことを指します。

API

APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

Q&A

解決済

1回答

2031閲覧

Windows上でpythonプログラムでaxios.jsのWebAPIで画像をアップロードしてレスポンスする方法

dendenmushi

総合スコア98

OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

アップロード

アップロードは特定のファイルをウェブサーバに送るプロセスのことを指します。

API

APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

0グッド

0クリップ

投稿2020/05/06 09:26

編集2020/05/06 14:09

前提・実現したいこと

pythonプログラムでaxios.jsのWebAPIで画像をアップロードしてレスポンスしたい。
参考URL:https://qiita.com/s-yoshiki/items/d4a460b2ab56e72220b9

環境

作業PC:windows10 64bit
サーバー:Windows10上、できればさくらVPS(Linux)上でも試したい。
python:3.7(Anaconda仮想環境)

ディレクトリ構成

index.html

html

1./ 2├── face_detect.py # 顔検出の処理 3├── index.py # リクエスト処理 4├── templates # html(テンプレート) 5│ └── index.html 6└── tmp # アップロードされた画像格納ディレクトリ 7 └── sample.jpg

該当のソースコード

html

1<html> 2 <head> 3 <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.js"></script> 4 </head> 5 <body> 6 <div class="container"> 7 <canvas id="canvas"></canvas> 8 <hr> 9 <label> 10 画像 11 <input type="file" class="form-control" id="image"> 12 </label> 13 <button id="run"> 14 submit 15 </button> 16 </div> 17 <script src="index.js"> 18 </script> 19 </body> 20</html>

index.js

js

1(function(){ 2 3 document.getElementById("run").addEventListener("click", function(){ 4 var params = new FormData(); 5 var file = document.getElementById("image").files[0] 6 7 params.append('image', file) 8 axios.post('/api', params).then(function(response) { 9 response.data.forEach((e) => { 10 var v = e.face 11 drawRect(v.x, v.y, v.w, v.h) 12 e.eyes.forEach((eye) => { 13 eye.x += v.x 14 eye.y += v.y 15 drawRect(eye.x, eye.y, eye.w, eye.h) 16 }) 17 }) 18 }).catch(function(error) { 19 alert("error") 20 }); 21 }) 22 23 document.getElementById("image").addEventListener("change", function(e) { 24 var file = e.target.files; 25 var reader = new FileReader(); 26 reader.readAsDataURL(file[0]); 27 reader.onload = function() { 28 var source = reader.result; 29 drawImage(reader.result) 30 } 31 }, false); 32 33 function drawImage(src) { 34 var canvas = document.getElementById("canvas") 35 var context = canvas.getContext('2d') 36 var image = new Image() 37 image.src = src; 38 image.onload = function() { 39 canvas.width = image.width 40 canvas.height = image.height 41 context.drawImage(image, 0, 0) 42 } 43 } 44 45 function drawRect(x, y, w, h) { 46 var canvas = document.getElementById("canvas") 47 var context = canvas.getContext('2d') 48 context.rect(x, y, w, h); 49 context.stroke(); 50 } 51})()

index.py

python

1import os,sys 2from flask import Flask, render_template, request, jsonify 3from jinja2 import FileSystemLoader 4import base64 5 6from face_detect import get_facepos 7 8app = Flask(__name__) 9 10app.config['MAX_CONTENT_LENGTH'] = 1 * 1024 * 1024 11app.config['UPLOAD_FOLDER'] = './tmp' 12 13@app.route("/", methods=['GET']) 14def get_index(): 15 return render_template('index.html') 16 17@app.route("/api", methods=['POST']) 18def face_detect(): 19 img = request.files['image'] 20 name = img.filename 21 path = os.path.join(app.config['UPLOAD_FOLDER'], name) 22 img.save(path) 23 face_pos = get_facepos(path) 24 return jsonify(face_pos)

face_detect.py

python

1import numpy as np 2import cv2 3 4def get_facepos(img_path): 5 face_cascade = cv2.CascadeClassifier('/path/to/haarcascade_frontalface_default.xml') 6 eye_cascade = cv2.CascadeClassifier('/path/to/haarcascades/haarcascade_eye_tree_eyeglasses.xml') 7 8 img = cv2.imread(img_path) 9 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) 10 faces = face_cascade.detectMultiScale(gray, 1.3, 5) 11 12 result = [] 13 for (x,y,w,h) in faces: 14 face_dst = { 15 "x": np.asscalar(x), 16 "y": np.asscalar(y), 17 "w": np.asscalar(w), 18 "h": np.asscalar(h) 19 } 20 eyes_dst = [] 21 roi_gray = gray[y:y+h, x:x+w] 22 eyes = eye_cascade.detectMultiScale(roi_gray) 23 for (ex,ey,ew,eh) in eyes: 24 eye_pos = { 25 "x": np.asscalar(ex), 26 "y": np.asscalar(ey), 27 "w": np.asscalar(ew), 28 "h": np.asscalar(eh) 29 } 30 eyes_dst.append(eye_pos) 31 result.append({ 32 "face": face_dst, 33 "eyes": eyes_dst 34 }) 35 return result

試したこと

①haarcascade_eye_tree_eyeglasses.xmlら2つのpathは自身の環境のcv2の中のどこに存在しているかチェックし記載しなおしました。

index.py

python

1if __name__ == "__main__": 2 app.run(port=8888)

上記をindex.pyの下部に追記して、
$ python index.py を実行しhttp://localhost:8888をブラウザ実行しました。

cmd

1 * Serving Flask app "index" (lazy loading) 2 * Environment: production 3 WARNING: This is a development server. Do not use it in a production deployment. 4 Use a production WSGI server instead. 5 * Debug mode: off 6 * Running on http://127.0.0.1:8888/ (Press CTRL+C to quit)

しかし、画面は出るものの、画像をアップロードすることができませんでした。

イメージ説明

イメージ説明

③この他、jsの場所をjsフォルダに変えることも行いましたが、結果は同じでした。

どのポイントを調べれば原因がわかりますでしょうか。どのようにしたら実現できるか教えて頂けないでしょうか。
また、さくらVPSなどのLinuxに配置する場合、このディレクトリ構造ではなく、/var/www/html/にindex.htmlを配置することにあるかと思うのですが、その際のディレクトリはどういった形態になるものなのでしょうか。
よろしくお願い致します。

2020/05/06 21:58追記

ローカル実行についてその後アドバイス頂いたstaticフォルダの中にindex.jsを置いて

js

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

に変更し以下コマンドを実行したところ、

cmd

1D:\work\unittest\face>python index.py

以下結果に変わりました。

ブラウザはEdge。
F12キーを使用し要求と応答ヘッダーやコンソールを確認しました。

イメージ説明
イメージ説明

2020/05/06 22:39

申し訳ありません。face_detect.pyを少し変えてしまった結果を追記してしまいました。正しくは以下になります。
イメージ説明
500エラーはないのですが、errorとサイトからメッセージダイアログが出ている状態になります。

2020/05/06 追記

ローカルでの実行では解決できました。原因が以下でした。
①上記指摘頂いたjsの置き場やhtmlのコード
②face_detect.pyにreturnがなかったこと

face_detect.pyの最後の行に以下を追加。

python

1return result

イメージ説明

あとはLinuxでの実行方法は別質問にさせて一度完了とします。
ありがとうございました。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

アップロード迄は確認出来ました。windows10 python3.7 です。

index.js が読み込まれていなかったので以下のように変更しました。

./ ├── face_detect.py # 顔検出の処理 ├── index.py # リクエスト処理 ├── static # ***追記*** 静的リソース (JS, CSS ファイル等) │ └── index.js ├── templates # html(テンプレート) │ └── index.html └── tmp # アップロードされた画像格納ディレクトリ └── sample.jpg

index.html のテンプレート

diff

1- <script src="index.js"> 2+ <script src="{{url_for('static', filename = 'index.js')}}">

ここは設定で、staticフォルダの探索場所の変更も可能ですが、
他のファイルもサーバー経由でアクセス可能になってしまうので注意が必要な点。

テンプレートを展開する為に、Flask 経由でアクセスする必要があります。

Flask を介さない場合は、index.html, index.js が同じディレクトリでも読み込めますが、
axios.postのアドレスを変えないと、同じサーバーの同ポートに送れなくなるはずです。


しかし、画面は出るものの、

ここが疑問点なのですが、

画像表示のコードは index.js 内にありますが、
index.js が読み込まれていない状態で画像が表示されますか?

画像の「ネットワーク」タブ内では、index.js の読込は 404 (File not found)になっています。

さくらVPS(Linux)上でも試したい。

使ったことないので環境はわかりませんが、
さくらVPS上でどのように Flask サーバーを実行してますか?

通常の HTTPサーバー経由で index.html, index.js にアクセスした状態では、
アップロードされたファイルを受け取るサーバー (index.py) が稼働していない状態なので、
画像は表示されるが、アップロードできない状態になると思います。

投稿2020/05/06 10:53

編集2020/05/06 10:56
teamikl

総合スコア8760

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dendenmushi

2020/05/06 11:35

ありがとうございます。js読み込みこのようにやるのですね…。 まずさくらVPSの前にローカルで実行して試してみようと考えていました。 >画像表示のコードは index.js 内にありますが、 >index.js が読み込まれていない状態で画像が表示されますか? index.pyの一番下に以下のように8888としたところ(よくわからないまま) if __name__ == "__main__": app.run(port=8888) 画像は表示はされましたが、ご指摘のとおりアップロードができないようでした。 port=8080にすると、 「OSError: [WinError 10013] アクセス許可で禁じられた方法でソケットにアクセスしようとしました。」と怒られてしまいました。 これはindex.py側は、仮想か何かで以下のように立ち上げておくべきということでしょうか。 fuser -k 8080/tcp(8080ポート準備) python3 -m venv venv(仮想構築) source venv/bin/activate (仮想実行) nohup python server.py &(×で閉じても常時ついているように) 別cmd立ち上げてからindex.htmlを始めるためのコードをrunでしょうか。混乱してきました…
dendenmushi

2020/05/06 11:59 編集

ローカル実行とは別のさくらVPS実行時の話になってしまいますが実行方法は以下でした。 /var/www/html/index.htmlがすぐに起動する仕組みのようで、全てのファイルをそこに置いてしまっています。 /var/www/html/>python index.pyを実行しているのみでした。
teamikl

2020/05/06 12:33

※ローカル環境とさくらVPS環境での内容が混ざらないように注意してください。 fuser ~ nohup は linux でのコマンドだと思いますが、 一連のコマンドは、内容が飛んでいるので、このまま実行しても意味がありません、 venv は今回の問題には直接影響ありません。 venv を使う場合は、venv に作った環境内に flask 等をインストールするような使い方をします。 (レンタルサーバー上で、ユーザ権限でライブラリをインストールするのに使うのだと思います) >これはindex.py側は、仮想か何かで以下のように立ち上げておくべきということでしょうか。 これは VSPでの話だと思いますが、 CGIとしてwebサーバー側が実行する方法もありますが、(httpサーバーで wsgi 関連の設定が必要) 単独でサーバーとして起動しておく場合は、他にポート解放の設定等が必要になることも有ります。 ここは環境がわからないので何とも言えませんが、一般的なケースではこの2通りです。 良くわからない場合は、ファイルのアップロードの前に (問題の切り分け) レンタルサーバー上では Flask アプリ自体の実行が出来るかどうか確認、 ローカルの場合は、まずは index.js の読込問題の解消を試してください。
dendenmushi

2020/05/06 13:25

>※ローカル環境とさくらVPS環境での内容が混ざらないように注意してください。 はい。わかりました。気を付けます。まずはローカルで実行してみようと思っています。 言われたstaticフォルダにindex.jsを入れてhtmlも書き換えてみました。するとjs読み込みできないというエラーはなくなったようです。POST送信で500エラーが返ってきました。調べたところ主にCGI系のスクリプトで例外エラーが発生した場合に返されるとのことでした。もう少し調査を続けてみます。
dendenmushi

2020/05/06 13:38

ごめんなさい。間違えました。face_detect.pyを少しいじってしまっていて元に戻してからpython index.pyを実行してlocalhost:8888/を確認したものを追記致します。
dendenmushi

2020/05/06 14:07

ローカル上では解決できました。ありがとうございました。質問本文でも追記更新しましたが、原因はご指摘頂いたhtmlとjsの置き方。face_detect.pyのreturn resultが記載されていなかったためでした。ありがとうございました。Linuxに関しては別質問にしてこちらベストアンサーとさせて下さい。ありがとうございました。
teamikl

2020/05/06 21:24 編集

最後まで実行はしてなかったのですが、 手元にコピーしていたコードでは `return result` はあったので、 いろいろ改変し試していた中での修正だったのでしょうか。 とりあえずローカルでは解消したようで良かったです。 > /var/www/html/>python index.pyを実行しているのみでした。 一点だけ、公開を想定されている場合、Flaskの設定によっては、 外部から任意のコードが実行されてしまう ような問題につながることも有るので注意を。 linux環境での実行で気になっていた点は、(アップロードに関しては) デバッグ版でも良いので、とにかくサーバが動いているかどうかだったのですが、 もし公開予定を意図してレンタルサーバ上で動かす場合、 本運用環境の構築では「WSGIサーバ」を使います。 「WSGI」はPythonのWebアプリにとっての「CGI」規格のようなもので、 主要なのはここのサーバの項目に挙がっている3つがあります。 https://python-guideja.readthedocs.io/ja/latest/scenarios/web.html - 環境構築 (venv 環境に必要ライブラリ群をインストール) - ***WSGIサーバ経由での*** Flask アプリの実行 (チュートリアルのHello, world! 表示など) - アップロードの確認 - cv2 を使った挙動の確認 という手順で、段階的にどこで躓いているかを 確認していくといいと思います。 ※ Flask アプリの公開方法はいろいろあります、 (多様な情報があるので混乱しやすいポイント) https://flask.palletsprojects.com/en/1.1.x/deploying/ レンタルサーバの権限等の制限で出来ないことも有りますが まずは、WSGIサーバにある方法をお試し下さい。 (追記: 個人規模での利用なら > python index.py で実行でも支障ありませんが、 ローカル: デバッグ版、さくらVPS: 本運用環境とするのが一般的な構成)
dendenmushi

2020/05/07 02:06

非常に助かりました。そうなのですね。吟味しますが、今のところvenvでcv2を入れてwaitressを利用して頑張ってみようと思います。今日夜にでもチャレンジしてみます。ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問