解决 OpenCV 'NoneType' 报错

Introduction

在使用 python + opencv 的过程中,我们经常会遇到 NoneType 的报错。有很多原因都会导致这个错误,结合本人经历以及网上找到的一些案例,大概可以把 NoneType 报错原因分为两类:

  • cv2.imread 调用无效的图片地址。

  • cv2.VideoCapture 加载视频流或者视频文件时读取到错误的帧。

What is a NoneType error?

当你运行 python 程序,出现如下错误时:

1
AttributeError: 'NoneType' object has no attribute 'something'

这里的 something 可以代指任意属性。

当我们看到上面的错误时,通常都会认为自己使用了特定的类或者对象的实例,调用错误。但实际上,这是 python 的内置类型 None 造成的。

顾名思义,None 代表 value 的缺省,例如函数返回了一个 unexpected 结果 或者返回失败。

举一个会产生 NoneType 报错的例子:

1
2
3
4
5
6
7
>>> a = None
>>> a.bar = True
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'bar'
>>>

上述代码中,我声明了一个变量 a 并把它设为 None

然后,我希望将 abar 属性设为 True,但是因为 a 是一个 NoneType 的对象,所以 python 不允许这样赋值,于是报错。

Two reasons of OpenCV NoneType errors

下面主要解释下两种引起 NoneType 报错的情况:

图片读写 cv2.imread

如果你的代码中调用了 cv2.imread 函数,然后收到 NoneType 的报错,那么最有可能的原因就是 cv2.imread 收到了无效的文件路径。

对于 cv2.imread 函数,它不会因为你传入一个无效的文件路径而报错,它只会返回 None

当你通过 cv2.imread 去访问你硬盘中的一张属性为 None 的图片时,就会收到 NoneType 的报错。

视频读写 cv2.VideoCapture

当你需要获取视频流的时候,你会用到 cv2.VideoCapture 函数。它接受两种参数:

  1. A string representing the path to a video file on disk.(字符串时表示视频文件路径)。

  2. An integer representing the index of a webcam on your computer.(数字时表示摄像头id,当只有一个摄像头时,传入0,OpenCV 会打开该摄像头)。

虽然相对于通过 cv2.imread 加载图片来说,利用 OpenCV 来处理视频流和视频文件要复杂得多,但是适用相同的规则。

当你使用 cv2.VideoCapture 来加载视频流或者视频文件时出现 NoneType 报错或者 AssertionError 时,可能的原因如下:

  1. 视频文件路径错误。

  2. 缺少视频解码器。(用本地视频播放器打开该视频文件,测试是否可以播放)。

  3. 摄像头对 OpenCV 不可用。(这个问题可能由很多原因导致。例如:缺少驱动,摄像头id错误,摄像头损坏等)

处理视频时遇到的问题太过复杂,需要系统地逐个排除。

首先,确保可以使用其他程序打开摄像头;

其次,能够用本地播放程序打开视频文件;

如果上述都没问题,可能是因为 OpenCV 安装的错误。