使用Django存储视频抽帧到数据库报数组真值歧义错误如何解决
错误原因
- 核心触发点:
cv2.VideoCapture.read()返回的frame是Numpy多维数组格式,而你模型里的imagefile是FileField类型,该字段只能接收文件对象/文件路径,无法直接存储Numpy数组。Django内部在处理字段值做合法性校验时,会对字段值做真值判断,多元素Numpy数组做布尔转换时规则不明确,直接触发了你遇到的ValueError。 - 附带错误1:你把
Image实例的初始化放在了while循环外部,每次循环都是修改同一个实例的属性,调用save()只会更新同一条数据,不会为每个帧生成新的存储记录。 - 附带错误2:模型定义存在两处问题:
- 外键字段的
null="false"写法错误,null参数接收布尔值,正确写法为null=False __str__方法中直接拼接外键对象self.video_id和字符串会触发类型错误,需要先将外键对象转为字符串格式
- 外键字段的
修复方案
1. 先修正models.py的Image模型
from django.db import models class Image(models.Model): # 字段名不要带_id后缀,Django会自动生成_id后缀的数据库字段 video = models.ForeignKey(Video, on_delete=models.CASCADE, null=False) title = models.CharField(max_length=50) imagefile = models.FileField(upload_to='images/', null=True) def __str__(self): return f"{str(self.video)}: {self.title}: {str(self.imagefile)}"
2. 修正视图函数逻辑
需要先将Numpy数组格式的帧编码为图片字节流,再封装为Django可识别的文件对象后再赋值给imagefile字段,同时把实例化逻辑移入循环内:
import os import cv2 from django.core.files.base import ContentFile from .models import Video, Image from moviepy.editor import VideoFileClip def saveFrame(request): video = Video.objects.last() # 本地存储视频直接用path属性,避免自行拼接路径出错 path = video.video.path clip = VideoFileClip(path) clip = clip.subclip(0, 15) clip = clip.cutout(3, 10) # 明确写入临时文件,避免ipython_display生成的临时文件路径异常 clip.write_videofile('__temp__.mp4', codec='libx264') cap = cv2.VideoCapture('__temp__.mp4') i = 0 while cap.isOpened(): ret, frame = cap.read() if not ret: break # 每个帧对应一个新的Image实例 image = Image() image.video = video image.title = f"{video.title}{i}" # 将numpy数组编码为jpg字节流 _, img_byte = cv2.imencode('.jpg', frame) # 封装为Django可识别的文件对象 image_file = ContentFile(img_byte.tobytes(), name=f"{image.title}.jpg") image.imagefile = image_file image.save() print(i) i += 1 cap.release() cv2.destroyAllWindows() # 清理临时文件 if os.path.exists('__temp__.mp4'): os.remove('__temp__.mp4')
内容的提问来源于stack exchange,提问作者Maria Iftikhar
相关产品推荐
相关产品推荐

