赞
踩
在使用python的streamlit库处理上传的文件时碰到一个问题,文件上传后是以字节数组的形式存在内存中,我在后续需要使用cv2库逐帧操作上传的视频,这里就产生一个问题,cv2怎么读取到内存中字节形式的视频?
经过多次查找,发现可以使用ffmpeg从内存中将字节流解码,然后再由cv2处理。
代码如下:
import streamlit as st
# streamlit中上传文件的函数
@st.cache(allow_output_mutation=True,show_spinner=False)
def load_local_video(uploaded_video):
bytes_data = uploaded_video.getvalue()
print(uploaded_video.name)
return bytes_data
uploaded_video = st.sidebar.file_uploader(" ")
video = load_local_video(uploaded_video)
处理逻辑就是使用ffprobe获取字节流中内存相关信息,然后使用ffmpeg解码。随后从字节流中逐帧获取视频。
import numpy as np import cv2 import io import subprocess as sp import threading import json from functools import partial import shlex # Write to stdin in chunks of 1024 bytes. def writer(stream,process): for chunk in iter(partial(stream.read, 1024),b''): process.stdin.write(chunk) try: process.stdin.close() except (BrokenPipeError): pass # For unknown reason there is a Broken Pipe Error when executing FFprobe. def do(video): bytes_stream = io.BytesIO(video) #执行子进程并定到输入输出的接口,这里使用ffprobe检测视频的信息 # 注意,这里的路径是我本地的路径,运行代码的时候需要更改路径,并且确保你的电脑装上了ffmpeg process = sp.Popen(shlex.split('E:/ffmpeg-4.3.1-2020-11-19-essentials_build/bin/ffprobe -v error -i pipe: -select_streams v -print_format json -show_streams'), stdin=sp.PIPE, stdout=sp.PIPE, bufsize=10**8) pthread = threading.Thread(target=writer,args=(bytes_stream,process)) pthread.start() pthread.join() #从标准输入输出流中获取视频信息 in_bytes = process.stdout.read() process.wait() p = json.loads(in_bytes) #得到视频的分辨率 width = (p['streams'][0])['width'] height = (p['streams'][0])['height'] bytes_stream.seek(0) process = sp.Popen(shlex.split('E:/ffmpeg-4.3.1-2020-11-19-essentials_build/bin/ffmpeg -i pipe: -f rawvideo -pix_fmt bgr24 -an -sn pipe:'), stdin=sp.PIPE, stdout=sp.PIPE, bufsize=10**8) thread = threading.Thread(target=writer,args=(bytes_stream,process)) thread.start() #将视频解码完毕 all_bytes = process.stdout.read()#将视频字节从内存中读取出来 counter = len(all_bytes)/(width * height * 3) #print(str(counter)+' 帧') l = 0 my_bar = st.progress(0) with st.spinner(text="视频检测中"): while l < counter: in_bytes = all_bytes[:width * height * 3] all_bytes = all_bytes[width * height * 3:] if not in_bytes: break # Break loop if no more bytes. # Transform the byte read into a NumPy array in_frame = (np.frombuffer(in_bytes, np.uint8).reshape([height, width, 3])) #完成视频逐帧获取,可以使用cv2操作in_frame图像 # TODO l = l+1
我需要逐帧解析视频并完成相对应的操作,以上操作就可以做到了。但是需要注意,此处代码并没有针对帧率处理。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。