如何使用 JavaScript/ReactJS 在 FastAPI 中上传视频列表并使用 OpenCV 处理它们?

发布于 2025-01-20 08:16:48 字数 3145 浏览 4 评论 0原文

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

前端:reactjs

后端:fastapi

这是后端中的代码的样子:

@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]}

这是我最后从此代码中获得的:

我有一种与视频捕获有关的感觉上传。但是,正如您可以从屏幕截图中看到的那样,视频捕获列表仅具有第一个视频的一个对象。

对可能导致的原因有什么想法吗?

edit :我使用了此问题对于单个视频上传,并以相同的逻辑构建,以通过视频列表进行迭代,但这也不起作用。

I'm trying to switch from uploading a single video to uploading and processing multiple videos. However, it seems that my code saves/reads only the first video. I can't seem to figure out why, as when I print the list of files uploaded, it does include all the subsequent videos that get ignored.

Frontend: ReactJS
enter image description here

Backend: FastAPI

This is what the code looks like in the backend:

@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]}

This is what I last got from this code:
enter image description here

I have a feeling this has to do with video-capture but I thought this was addressed when I switched from looping through the list of videos with a single video capture to a list of video captures for each video uploaded. But as you can see from the screenshot, the list of video captures only has the one object for the first video.

Any idea on what might be causing this?

Edit: I made use of this question for the single video upload and built on the same logic to iterate through the list of videos, but that didn't work either.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

遮云壑 2025-01-27 08:16:48

下面是如何使用 Fetch API< 上传视频列表的示例/a> 在前端, FastAPI 在后端,以及 OpenCV 来处理文件。此示例基于此答案

工作示例

app.py

from fastapi import FastAPI, File, UploadFile, Request, HTTPException
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:
                raise HTTPException(status_code=500, detail='Something went wrong')
            finally:
                file.file.close()
            
            process_video(temp.name)
        except Exception:
            raise HTTPException(status_code=500, detail='Something went wrong when 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})

templates/index.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>

Below is an example on how to upload a list of videos using Fetch API in the frontend and FastAPI in the backend, as well as OpenCV to process the files. This example is based on this answer and this answer.

Working Example

app.py

from fastapi import FastAPI, File, UploadFile, Request, HTTPException
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:
                raise HTTPException(status_code=500, detail='Something went wrong')
            finally:
                file.file.close()
            
            process_video(temp.name)
        except Exception:
            raise HTTPException(status_code=500, detail='Something went wrong when 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})

templates/index.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>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文