You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PsychoPy录制30秒摄像头视频时长异常(实际43秒)求助

问题诊断与解决方案

你的问题核心在于循环的时间控制和视频帧率不匹配:你用core.Clock()来控制30秒的循环时长,但cap.read()和out.write()的实际耗时、摄像头的真实捕获帧率,和你设定的20.0fps不一致,导致最终写入的总帧数超过了20*30=600帧——而播放器是按你设定的20fps来解析视频,所以总时长=总帧数/20,自然就变长了(比如你实际写了860帧,860/20=43秒,正好对应你的情况)。

下面给你两种可行的解决思路:

方案1:固定捕获的帧数(最可靠)

既然你要的是30秒20fps的视频,直接捕获20*30=600帧即可,这样不管单帧捕获耗时多久,最终总帧数固定,播放时长就是精确的30秒。修改后的代码如下:

from psychopy import locale_setup, visual, core, event, data, gui, microphone
import cv2

# 初始化摄像头
cap = cv2.VideoCapture(0 + cv2.CAP_DSHOW)
# 强制设置摄像头帧率为20fps(部分摄像头可能不支持,可先读取真实帧率再调整)
cap.set(cv2.CAP_PROP_FPS, 20.0)
# 获取摄像头真实帧率(可选,用于验证)
actual_fps = cap.get(cv2.CAP_PROP_FPS)
print(f"摄像头实际帧率: {actual_fps}")

# 初始化视频写入器
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('{}.avi'.format(video_path), fourcc, 20.0, (640,480))

# 计算需要捕获的总帧数:目标帧率 × 目标时长
total_frames = int(20.0 * 30)
for _ in range(total_frames):
    ret, frame = cap.read()
    if ret:  # 确保成功捕获到帧再写入
        out.write(frame)
    else:
        print("警告:捕获帧失败,提前终止录制")
        break

# 清理资源
cap.release()
out.release()
cv2.destroyAllWindows()

方案2:基于时间控制,强制帧间隔匹配目标帧率

如果你坚持用时间循环来控制,可以在每帧捕获后计算耗时,用core.wait()补全剩余时间,确保每帧的间隔接近1/20=0.05秒,这样循环总时长会更接近30秒,写入的帧数也会刚好是600左右:

from psychopy import locale_setup, visual, core, event, data, gui, microphone
import cv2

# 设定目标帧率和时长
target_fps = 20.0
target_duration = 30
frame_interval = 1 / target_fps  # 每帧应该占用的时间

# 初始化计时器
trialTimer = core.Clock()

# 初始化摄像头和写入器
cap = cv2.VideoCapture(0 + cv2.CAP_DSHOW)
cap.set(cv2.CAP_PROP_FPS, target_fps)
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('{}.avi'.format(video_path), fourcc, target_fps, (640,480))

trialTimer.reset()
while trialTimer.getTime() < target_duration:
    frame_start_time = trialTimer.getTime()
    # 捕获并写入帧
    ret, frame = cap.read()
    if ret:
        out.write(frame)
    # 计算当前帧耗时,等待剩余时间以匹配目标帧率
    elapsed_time = trialTimer.getTime() - frame_start_time
    if elapsed_time < frame_interval:
        core.wait(frame_interval - elapsed_time)

# 清理资源
cap.release()
out.release()
cv2.destroyAllWindows()

额外建议

  • 先通过cap.get(cv2.CAP_PROP_FPS)查看摄像头的真实支持帧率,如果你的摄像头不支持20fps,修改目标帧率为摄像头支持的数值,这样录制会更稳定。
  • 避免在录制循环中添加其他耗时操作(比如PsychoPy的窗口绘制、事件检测),这些都会增加单帧耗时,导致循环超时。

内容的提问来源于stack exchange,提问作者djl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 16:27:31