Elsaの技術日記(徒然なるままに)

主に自分で作ったアプリとかの報告・日記を記載

MENU

Flask 動画アップロード方法

前回、Flaskでの動画再生アプリや、
elsammit-beginnerblg.hatenablog.com

Yoloで物体検知が行える動画再生アプリを作成しました。
elsammit-beginnerblg.hatenablog.com

今回はFlaskでの動画アップロード機能を追加して、自分の持っている動画をWeb上で物体検知させて遊んでみたいと思います。



■前提

今回は前回の
"Yoloによる物体検知と動画再生Webアプリを組み合わせてみる"
elsammit-beginnerblg.hatenablog.com

からアップロード機能を実装していきたいと思います。
もし環境やFlaskによる動画再生アプリ作成方法を確認したい場合にはこちらをご覧ください。

■アップロード機能追加(フロントエンド)

ではまずはフロントエンドについてまとめておきたいと思います。
と言ってもフロントエンドはformを用いてpost送信を行うためのコードを書くだけ。
htmlファイルを変更するだけでOKです。
追加するコードはこちら。

<form method = post enctype = multipart/form-data action = "/upload">
      <p><input type=file name = file>
      <input type = submit value = Upload>
</form>

formタグにて送信方法をpostにセットし、ファイル選択用のinputタグとサーバへの送信用のタグを記載しているのみ。
とても簡単!!

今回は実施していませんが、レイアウトにこだわる場合にはcssファイルも変更してみてください。

■サーバサイド

ではメインであるサーバサイド(Flask)を変更していきたいと思います。
まずはコードを載せます。

ALLOWED_EXTENSIONS = set(['mp4', 'wmv', 'avi', 'gif'])
UPLOAD_FOLDER = './uploads'
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER

def allwed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

#動画取得
@app.route('/upload', methods=["POST"])
def get_test():
    if 'file' not in request.files: # ファイルがなかった場合
        print('ファイルがありません')
        return redirect('/')
    file = request.files['file']    # データの取り出し
    if file.filename == '':         # ファイル名がなかった場合
        print('ファイルがありません')
        return redirect("/")
    if file and allwed_file(file.filename):
        filename = secure_filename(file.filename)   # 危険な文字を削除(サニタイズ処理)
        # ファイルの保存し保存したファイルから動画読み出し.
        file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
        Camera.cap = cv2.VideoCapture(UPLOAD_FOLDER+"/"+filename)
        return redirect("/")                        # アップロード後のページに転送
    else:
        print("not movie file")
        return redirect("/")

まず、

@app.route('/upload', methods=["POST"])

ですが、、、ここは今までと同じなので割愛。

request変数にフロントより動画データファイルが渡されるので、

    if 'file' not in request.files: # ファイルがなかった場合
        print('ファイルがありません')
        return redirect('/')
    file = request.files['file']    # データの取り出し

のコードでファイルの有無をチェックしつつ、データを取り出します。

次に、

 if file and allwed_file(file.filename):
        filename = secure_filename(file.filename)   # 危険な文字を削除(サニタイズ処理)

ですが、ファイルが許可されたファイル拡張子であるか?
そして、許可されたファイル拡張子であってもファイル名が悪意のある名前でないか?
をチェックしています。
allwed_file関数ですが、

def allwed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

としました。

悪意のあるファイル名かをチェックする、secure_filename関数ですが、
Flask公式もアップロード機能を追加する際には載せておくことを推奨しているようです。
Uploading Files — Flask Documentation (2.0.x)

下記のような記載があり、ユーザ入力を信じるな。
悪意のあるユーザを想定してどんなファイルでもアップロードさせるのは危険。
と記載されていますね。
気を付けます。
Now the problem is that there is that principle called “never trust user input”. This is also true for the filename of an uploaded file.
All submitted form data can be forged, and filenames can be dangerous. For the moment just remember: always use that function to secure a filename before storing it directly on the filesystem.

最後に、

file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
        Camera.cap = cv2.VideoCapture(UPLOAD_FOLDER+"/"+filename)
        return redirect("/")                        # アップロード後のページに転送

にてサーバの所定位置にアップロードされた動画を格納し、
そこから動画をVideoCaptureしていきます。

■動かしてみる

動かすといっても以前動かした内容に動画アップロード機能が追加されただけなので、
キャプチャのみ載せます。
今回のコードを追加して実行するとこちらのように動画の上にファイルアップロード用のボタンがセットされます。
f:id:Elsammit:20210603225439p:plain

■最後に

今回は様々な動画に対して物体検知が行えるように動画アップロード機能を追加してみました。
全体のコードですが、こちらに格納していますのでよろしければ見ていってください!!
https://github.com/Elsammit/Flask-VideoApplication.git

動画は結果が目で見て分かるのでやっていて楽しいですね!!
もう少し色々な処理を試してみたいな。