p5.js如何捕获摄像头前N帧并循环播放、获取单帧数据
p5.js 摄像头帧捕获循环播放修复方案
问题根源
loadImage()是异步加载方法,直接在draw循环中调用会出现图片未加载完成就进入下一帧的问题,导致无法正常绘制saveFrames()返回的imageData默认MIME类型为application/octet-stream,浏览器无法直接识别为图片资源- 未提前预加载帧资源,重复调用
loadImage()会导致性能极低甚至页面卡顿
修复后完整代码
const FRAME_RATE = 10 const CAPTURE_DURATION = 5 // secs // 总帧数 = 帧率 * 时长 const TOTAL_FRAMES = FRAME_RATE * CAPTURE_DURATION // 存储预加载完成的图片对象,用于绘制 let frameImages = [] // 存储原始base64字符串,后续用于发送到服务端 let frameBase64List = [] let currentFrameIndex = 0 // 加载完成标记,避免未捕获完成时执行绘制逻辑 let isCaptureDone = false function setup() { frameRate(FRAME_RATE) let video = createCapture(VIDEO) video.hide() createCanvas(640, 480) saveFrames('frames', 'png', CAPTURE_DURATION, FRAME_RATE, (frames) => { // 遍历处理所有帧 frames.forEach(frame => { // 替换错误的MIME类型为png格式,保证图片可正常识别 const correctImgData = frame.imageData.replace('data:application/octet-stream', 'data:image/png') // 存base64用于后续上传服务端 frameBase64List.push(correctImgData) // 预加载为p5.Image对象存到绘制数组 frameImages.push(loadImage(correctImgData)) }) isCaptureDone = true }) } function draw() { // 未加载完成不执行绘制 if (!isCaptureDone) return // 绘制当前帧 image(frameImages[currentFrameIndex], 0, 0) // 更新帧索引,到最后一帧自动回到首帧 currentFrameIndex = (currentFrameIndex + 1) % TOTAL_FRAMES }
关键修改说明
- 新增
frameBase64List数组存储处理后的base64字符串,后续发服务端直接遍历这个数组即可获取所有独立帧数据 - 提前在
saveFrames回调中预加载所有帧为p5.Image对象,draw循环中直接使用已经加载完成的资源绘制,无异步问题 - 替换了原始imageData的错误MIME类型,将
application/octet-stream改为image/png,保证浏览器可以正常识别图片资源 - 新增加载完成标记,避免捕获未完成时的空绘制逻辑
- 使用取模运算实现帧索引的循环,逻辑更简洁可靠
内容的提问来源于stack exchange,提问作者user2272048
相关产品推荐
相关产品推荐

