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

OpenCV调用摄像头生成热力图时索引越界报错问题咨询

问题产生原因

核心问题来自实时摄像头流和本地视频文件的属性差异:

  • 读取本地MP4文件时,cv2.CAP_PROP_FRAME_COUNT可以正确返回视频总帧数,length为有效正整数,循环正常运行后./frames/目录会生成对应帧图片,后续make_video读取目录下第一张图不会触发错误。
  • 调用摄像头(cv2.VideoCapture(0))时,实时流没有预定义的总长度,capture.get(cv2.CAP_PROP_FRAME_COUNT)返回值是0或者-1,直接引发两个连锁问题:
    1. 进度条Bar的max值为0/负数,循环range(0, short)完全不会执行,./frames/目录为空
    2. 后续make_video函数尝试读取空目录下的images[0],自然抛出"index is out of range"索引越界错误。
      另外原代码缺少capture.read()返回值ret的校验,如果摄像头首帧读取失败,frame为None,后续调用frame.shape也会触发崩溃。
修复方案

修改主函数逻辑适配实时流无固定总长度的特性,补全校验逻辑:

  1. 移除依赖总帧数的固定次数循环,改为while True持续读帧,直到按q退出或读帧失败
  2. 补全摄像头打开状态、帧读取结果的校验,避免空值崩溃
  3. 提前创建帧存储目录,调用make_video前判断是否存在有效帧,空目录下不执行视频合成
  4. 调整进度条为动态计数模式,适配实时流场景

修复后的可运行代码:

import os
import numpy as np
import cv2
import copy
from make_video import make_video
from progress.bar import Bar


def main():
    # 提前创建帧存储目录,避免目录不存在报错
    os.makedirs('./frames/', exist_ok=True)
    capture = cv2.VideoCapture(0)
    # 校验摄像头是否正常启动
    if not capture.isOpened():
        print("无法打开摄像头设备")
        return
    
    background_subtractor = cv2.bgsegm.createBackgroundSubtractorMOG()
    first_iteration_indicator = 1
    frame_count = 0
    accum_image = None
    first_frame = None

    print("正在采集摄像头画面,按q键停止采集生成热力图")
    bar = Bar('Processing Frames', suffix='%(index)d frames processed')

    while True:
        ret, frame = capture.read()
        # 读帧失败直接退出循环
        if not ret:
            print("帧读取异常,退出采集")
            break

        # 首帧初始化参数
        if first_iteration_indicator == 1:
            first_frame = copy.deepcopy(frame)
            height, width = frame.shape[:2]
            accum_image = np.zeros((height, width), np.uint8)
            first_iteration_indicator = 0
        else:
            filter = background_subtractor.apply(frame)
            cv2.imwrite('./frame.jpg', frame)
            cv2.imwrite('./diff-bkgnd-frame.jpg', filter)

            threshold = 2
            maxValue = 2
            ret, th1 = cv2.threshold(filter, threshold, maxValue, cv2.THRESH_BINARY)

            accum_image = cv2.add(accum_image, th1)
            cv2.imwrite('./mask.jpg', accum_image)

            color_image_video = cv2.applyColorMap(accum_image, cv2.COLORMAP_HOT)
            video_frame = cv2.addWeighted(frame, 0.7, color_image_video, 0.7, 0)

            frame_count += 1
            name = f"./frames/frame{frame_count}.jpg"
            cv2.imwrite(name, video_frame)

            # 实时显示热力图效果
            cv2.imshow('Real-time Heatmap', video_frame)
            bar.next()

        # 按q键退出采集
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

    bar.finish()
    capture.release()
    cv2.destroyAllWindows()

    # 仅当采集到有效帧时生成结果文件
    if frame_count > 0:
        make_video('./frames/', './output.avi')
        color_image = cv2.applyColorMap(accum_image, cv2.COLORMAP_HOT)
        result_overlay = cv2.addWeighted(first_frame, 0.7, color_image, 0.7, 0)
        cv2.imwrite('diff-overlay.jpg', result_overlay)
        print(f"处理完成,共采集{frame_count}帧,结果已保存至本地")
    else:
        print("未采集到有效帧,未生成结果文件")


if __name__ == '__main__':
    main()
补充说明
  • 如果需要同时兼容本地视频和摄像头两种输入源,可以增加输入源类型判断:读取本地视频时沿用原有固定帧数循环逻辑,调用摄像头时使用上述while循环逻辑即可。
  • 如果运行时提示找不到cv2.bgsegm模块,是因为缺少opencv贡献包,执行pip install opencv-contrib-python安装对应依赖即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 22:54:21