Django上传视频,并使用OpenCV提取缩略图

前言

Django上传视频跟Java类似,将在后台将视频文件以二进制储存即可,需要注意的是前端上传文件需要将表单设置属性为enctype="multipart/form-data"。本例使用Django作为后台,实现了将前端视频文件保存至本地,并使用OpenCV对视频的第一帧截取保存至另一目录。

代码

前端

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<form class="form-horizontal" action="{% url 'upload' %}" method="post"
    enctype="multipart/form-data" onsubmit="return false;">
    {% csrf_token %}
    <div class="form-group">
    <div class="col-xs-12">
        <input type="file" id="example-file-input" name="file">
    </div>
    </div>
    <div class="form-group">
    <div class="col-md-9 col-md-offset-3">
        <button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
        <button type="submit" class="btn btn-primary">点击上传</button>
    </div>
    </div>
</form>

urls.py

1
2
3
4
5
6
7
from django.urls import path
from . import views
urlpatterns = [
    path('', views.main),
    path('main', views.main, name='main'),
    path('upload', views.upload, name='upload'),
]

views.py

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
from django.shortcuts import redirect, render
from django.http import HttpResponse
from django.conf import settings
from django.urls import reverse
import cv2
import random
import datetime
import os
import json
def upload(request):
    if request.method == 'POST':
        base_dir = settings.BASE_DIR
        file = request.FILES.get("file")
        # 视频保存目录
        video_path = os.path.join(base_dir, "main/static/main/videos".replace('/', os.path.sep))
        video_name = datetime.datetime.now().strftime("%Y%m%d%H%M%S") + str(random.randint(1, 99)) + file.name.split('.')[0]
        video_abs_path = os.path.join(video_path, video_name + '.' + file.name.split('.')[-1])
        try:
            with open(video_abs_path, 'wb+') as f:
                f.write(file.read())
        except Exception:
            result = {"code": '500', 'information': '文件写入错误!'}
            return HttpResponse(json.dumps(result, ensure_ascii=False))
        # 视频截取
        vc = cv2.VideoCapture(video_abs_path)
        if vc.isOpened():  # 判断是否正常打开
            _, frame = vc.read()
            thumbnail_abs_path = os.path.join(video_path, "thumbnail", video_name) + ".jpg"
            print(thumbnail_abs_path)
            cv2.imwrite(thumbnail_abs_path, frame)  # 存储为图像
            cv2.imencode('.jpg', frame)[1].tofile(thumbnail_abs_path)
            cv2.waitKey(1)
            vc.release()
            return redirect(reverse('crack_detection'))
        else:
            result = {"code": '500', 'information': '视频无法正常打开!'}
            return HttpResponse(json.dumps(result, ensure_ascii=False))
    else:
        result = {"code": '500', 'information': '请求方式错误'}
        return HttpResponse(json.dumps(result, ensure_ascii=False))

效果

https://cdn.jsdelivr.net/gh/wefantasy/FileCloud/img/20210404165629.png
前端
https://cdn.jsdelivr.net/gh/wefantasy/FileCloud/img/20210404170215.png
后台