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

OpenCV实时目标检测视频输入报错求助:shape与AttributeError问题

解决OpenCV视频目标检测的两个报错问题

我来帮你排查并解决这两个报错,咱们一步步拆解问题:

第一个报错:AttributeError: 'cv2.VideoCapture' object has no attribute 'shape'

问题根源

你在循环里犯了一个基础错误:每次都重新初始化cv2.VideoCapture视频捕获对象,而不是读取视频里的帧数据:

frame = cv2.VideoCapture(args["video"])

cv2.VideoCapture是用来控制视频流的对象,不是单帧图像,自然没有shape属性。正确的做法是用你已经创建好的vs对象调用read()方法获取每一帧。

修复代码

把循环里的错误行替换成:

ret, frame = vs.read()
# 视频播放结束时,ret会返回False,直接跳出循环
if not ret:
    break

第二个报错:AttributeError: 'dict' object has no attribute 'width'

问题根源

  1. 你用vars(ap.parse_args())把参数解析结果转换成了字典,所以访问参数必须用字典索引语法(比如args["width"]),而不是点语法(args.width)。
  2. 你的参数解析器里完全没有添加--width、--height、--scale、--mean、--rgb这些参数,代码里直接访问会导致键不存在的错误。

修复步骤

  1. 先在参数解析部分补充缺失的参数:
# 添加模型输入相关的可选参数
ap.add_argument("-w", "--width", type=int, help="input width for the model")
ap.add_argument("-he", "--height", type=int, help="input height for the model")
ap.add_argument("-s", "--scale", type=float, default=0.007843, help="scale factor for blob")
ap.add_argument("-me", "--mean", type=int, default=127.5, help="mean subtraction value")
ap.add_argument("-r", "--rgb", type=bool, default=False, help="swap BGR to RGB")
  1. 修改代码里的参数访问方式,把所有args.width改成args["width"],同理args.height→args["height"]、args.scale→args["scale"]等。

代码里的其他隐藏问题

除了这两个报错,你的代码还有几个需要修复的细节才能正常运行:

  • detections变量未定义:MobileNetSSD的输出不需要调用getOutputsNames,直接用net.forward()获取即可。
  • w和h变量未定义:应该用之前获取的frameWidth和frameHeight。
  • vs.stop()不适用:vs是cv2.VideoCapture对象,应该用vs.release()释放资源。
  • 不必要的灰度转换:MobileNetSSD需要彩色输入,注释掉灰度转换相关代码。

修复后的完整可运行代码

from imutils.video import VideoStream
from imutils.video import FPS
import numpy as np
import argparse
import imutils
import time
import cv2

ap = argparse.ArgumentParser()
ap.add_argument("-p", "--prototxt", required=True, help="path to Caffe 'deploy' prototxt file")
ap.add_argument("-m", "--model", required=True, help="path to Caffe pre-trained model")
ap.add_argument("-c", "--confidence", type=float, default=0.2, help="minimum probability to filter weak detections")
ap.add_argument("-v", "--video", required=True, help="path to input video file")
# 补充缺失的模型输入参数
ap.add_argument("-w", "--width", type=int, help="input width for the model")
ap.add_argument("-he", "--height", type=int, help="input height for the model")
ap.add_argument("-s", "--scale", type=float, default=0.007843, help="scale factor for blob")
ap.add_argument("-me", "--mean", type=int, default=127.5, help="mean subtraction value")
ap.add_argument("-r", "--rgb", type=bool, default=False, help="swap BGR to RGB")

args = vars(ap.parse_args())

CLASSES = ["background", "aeroplane", "bicycle", "bird", "boat", "bottle", "bus", "car", "cat", "chair", "cow", "diningtable", "dog", "horse", "motorbike", "person", "pottedplant", "sheep", "sofa", "train", "tvmonitor"]
COLORS = np.random.uniform(0, 255, size=(len(CLASSES), 3))

print("[INFO] loading model...")
net = cv2.dnn.readNetFromCaffe(args["prototxt"], args["model"])

print("[INFO] starting video stream...")
vs = cv2.VideoCapture(args["video"])
# 检查视频文件是否成功打开
if not vs.isOpened():
    print("[ERROR] could not open video file")
    exit()

time.sleep(2.0)
fps = FPS().start()

while True:
    # 读取单帧视频
    ret, frame = vs.read()
    if not ret:
        break  # 视频播放结束
    
    frame = imutils.resize(frame, width=450)
    # 注释掉灰度转换,MobileNetSSD需要彩色输入
    # frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    # frame = np.dstack([frame, frame, frame])
    
    frameHeight = frame.shape[0]
    frameWidth = frame.shape[1]
    
    inpWidth = args["width"] if args["width"] else frameWidth
    inpHeight = args["height"] if args["height"] else frameHeight
    
    blob = cv2.dnn.blobFromImage(frame, args["scale"], (inpWidth, inpHeight), args["mean"], args["rgb"], crop=False)
    net.setInput(blob)
    
    # 获取MobileNetSSD的检测结果
    detections = net.forward()
    
    for i in np.arange(0, detections.shape[2]):
        confidence = detections[0, 0, i, 2]
        if confidence > args["confidence"]:
            idx = int(detections[0, 0, i, 1])
            box = detections[0, 0, i, 3:7] * np.array([frameWidth, frameHeight, frameWidth, frameHeight])
            (startX, startY, endX, endY) = box.astype("int")
            
            label = "{}: {:.2f}%".format(CLASSES[idx], confidence * 100)
            cv2.rectangle(frame, (startX, startY), (endX, endY), COLORS[idx], 2)
            y = startY - 15 if startY - 15 > 15 else startY + 15
            cv2.putText(frame, label, (startX, y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, COLORS[idx], 2)
    
    cv2.imshow("Frame", frame)
    key = cv2.waitKey(1) & 0xFF
    if key == ord("q"):
        break
    
    fps.update()

fps.stop()
print("[INFO] elapsed time: {:.2f}".format(fps.elapsed()))
print("[INFO] approx. FPS: {:.2f}".format(fps.fps()))

cv2.destroyAllWindows()
vs.release()  # 释放视频捕获资源

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:31:28