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'
问题根源
- 你用
vars(ap.parse_args())把参数解析结果转换成了字典,所以访问参数必须用字典索引语法(比如args["width"]),而不是点语法(args.width)。 - 你的参数解析器里完全没有添加
--width、--height、--scale、--mean、--rgb这些参数,代码里直接访问会导致键不存在的错误。
修复步骤
- 先在参数解析部分补充缺失的参数:
# 添加模型输入相关的可选参数 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.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
相关产品推荐
相关产品推荐

