【问题标题】:How to upload list of videos in FastAPI using JavaScript/ReactJS and process them with OpenCV?如何使用 JavaScript/ReactJS 在 FastAPI 中上传视频列表并使用 OpenCV 处理它们?
【发布时间】:2023-02-01 15:22:57
【问题描述】:

我正在尝试从上传单个视频切换到上传和处理多个视频;但是,我的代码似乎只保存/读取第一个视频。我似乎无法弄清楚为什么,因为当我打印上传的文件列表时,它确实包括所有被忽略的后续视频。

前端: 反应

后端: 快速API

这是代码在后端的样子:

@app.post("/upload")
def upload_video(fileList: Optional[List[UploadFile]] = File(None)):

    videofiles = []

    for file in fileList:
        print("Uploading:", file.filename)
        print(".................................")

        extension = file.filename.split(".")[-1] in ("mp4", "avi")
        if not extension:
            return "Video must be in mp4 or avi format!"
    try:
        try:
            contents = file.file.read()
            with temp as f:
                print("what's happening: ")
                f.write(contents)
                videofiles.append(cv2.VideoCapture(temp.name))

                print('list of videos uploaded :')
                for vidcap in videofiles:
                    print("video:", vidcap)

                    # Check if camera opened successfully
                    if (vidcap.isOpened() == False):
                        print("Error opening video file")

                    # get height, width and frame count of the video
                    width, height = (
                        int(vidcap.get(cv2.CAP_PROP_FRAME_WIDTH)),
                        int(vidcap.get(cv2.CAP_PROP_FRAME_HEIGHT))
                    )

                    print(f"width: {width}")
                    print(f"height: {height}")

                    # count the number of frames
                    frames = vidcap.get(cv2.CAP_PROP_FRAME_COUNT)
                    fps = vidcap.get(cv2.CAP_PROP_FPS)

                    # calculate duration of the video
                    seconds = round(frames / fps)
                    video_time = datetime.timedelta(seconds=seconds)
                    print(f"duration in seconds: {seconds}")
                    print(f"video time: {video_time}")

        except Exception:
            return {"message": "There was an error uploading the file"}
        finally:
            file.file.close()
    except Exception:
        return {"message": "There was an error processing the file"}
    finally:
        os.remove(temp.name)

    count = 0;
    for vid in videofiles:
        count += 1
    print("number of video capture objects uploaded:", count)


return {"uploadStatus": "Complete", "filenames": [f.filename for f in fileList]}

这是我最后从这段代码中得到的:

我觉得这与视频捕获有关,但我认为当我从循环播放单个视频捕获的视频列表切换到每个上传视频的视频捕获列表时,这个问题得到了解决。但正如您从屏幕截图中看到的那样,视频捕获列表只有第一个视频的一个对象。

知道是什么原因造成的吗?

编辑:我将这个question 用于单个视频上传,并基于相同的逻辑构建以遍历视频列表,但这也不起作用。

【问题讨论】:

  • @Chris 嗨,不,不幸的是。我使用相同的逻辑遍历我正在传递的视频列表,但它似乎不是那样工作的。我将 try-except 放在 for 循环中,但视频捕获列表仍然只包含第一个视频的捕获。顺便说一句,谢谢你指出来! :)

标签: reactjs opencv fastapi video-capture multiple-file-upload


【解决方案1】:

下面是一个关于如何在前端使用Fetch API和在后端使用FastAPI以及处理文件的OpenCV上传视频列表的示例。此示例基于this answer 和this answer。

工作示例

应用程序.py

from fastapi import FastAPI, File, UploadFile, Request
from tempfile import NamedTemporaryFile
from typing import List, Optional
from fastapi.templating import Jinja2Templates
import cv2
import os

app = FastAPI()
templates = Jinja2Templates(directory='templates')

def process_video(filename):
    print('Processing ' + filename)
    cap = cv2.VideoCapture(filename)
    while cap.isOpened():
        ret, frame = cap.read()
        if not ret:
            break
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        cv2.imshow('frame', gray)
        if cv2.waitKey(1) == ord('q'):
            break
    cap.release()
    cv2.destroyAllWindows()


@app.post('/submit')
def upload(files: Optional[List[UploadFile]] = File(None)):
    for file in files:
        temp = NamedTemporaryFile(delete=False)
        try:
            try:
                contents = file.file.read()
                with temp as f:
                    f.write(contents);
            except Exception:
                return {'message': 'There was an error uploading the file'}
            finally:
                file.file.close()
            
            process_video(temp.name)
        except Exception:
            return {'message': 'There was an error processing the file'}
        finally:
            #temp.close()  # the `with` statement above takes care of closing the file
            os.remove(temp.name)
        
    return {'Files Uploaded': [f.filename for f in files]}
    

@app.get('/')
def index(request: Request):
    return templates.TemplateResponse('index.html', {'request': request})

模板/索引.html

<!DOCTYPE html>
<html>
   <body>
      <input type="file" id="fileInput" name="file" multiple><br>
      <input type="button" value="Upload video files" onclick="submit()">
      <script>
         function submit() {
             var fileInput = document.getElementById('fileInput');
             if (fileInput.files[0]) {
                var formData = new FormData();
                for (const file of fileInput.files)
                    formData.append('files', file);
                    
                 fetch('/submit', {
                       method: 'POST',
                       body: formData,
                     })
                     .then(res => res.text())
                     .then(data => {
                       console.log(data);
                     })
                     .catch(error => {
                       console.error(error);
                     });
             }
         }
      </script>
   </body>
</html>

【讨论】:

  • 你好,非常感谢。我仍在尝试弄清楚为什么您的答案有效而我的答案无效,但这解决了我的问题!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-07-17
  • 1970-01-01
  • 2015-08-28
  • 1970-01-01
  • 2022-08-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多