作者:小初
时间: 2021-05-08
AttributeError: ‘NoneType’ object has no attribute 'shape’解决方案&OpenCV视频末帧处理不当导致的错误
使用cv读取视频末尾帧时,程序会一直停留在最后一帧,capture.isOpened()一直为true,但是frame数组矩阵已经为空,此时自然无法检测其shape。利用异常处理机制或者if判断可以有效解决此问题。
在pycharm中对车道线视频的检测完毕之后,在不人为终止程序运行的情况下,系统总是提示如下错误:
AttributeError: 'NoneType' object has no attribute 'shape'
#处理过程
if __name__ == '__main__':
# 打开视频
capture = cv2.VideoCapture('video1.mp4')
fourcc = cv2.VideoWriter_fourcc(*'MJPG')
outfile = cv2.VideoWriter('output.avi', fourcc, 25., (1280, 368))
# 循环处理每一帧
while capture.isOpened():
_, frame = capture.read()
origin = np.copy(frame)
frame = process_an_image(frame)
output = np.concatenate((origin, frame), axis=1)
outfile.write(output)
cv2.imshow('video1_out', output)
# 处理退出
if cv2.waitKey(1) == ord('q'):
cv2.destroyAllWindows()
break
从报错的字面意思看是找不到 对象的shape属性,上网查询了相关经验帖,说是路径不对,一一试过之后发现问题并没有解决。询问了老师之后,老师建议抛出异常,检查frame。我就简单修改了下代码,观察frame。
while capture.isOpened():
testM = capture.isOpened()
_, frame = capture.read()
origin = np.copy(frame)
try:
frame = process_an_image(frame)
output = np.concatenate((origin, frame), axis=1)
outfile.write(output)
cv2.imshow('video1_out', output)
except:
print(frame)
# exit(0)
if cv2.waitKey(1) == ord('q'):
cv2.destroyAllWindows()
break
此时发现系统一直在输出 None
此时似乎明白了一些,当程序运行到最后的时候frame数组矩阵全是空的,此时shape属性自然不存在。
为了进一步验证我的观点,我采用debug单步调试,调出frame矩阵数组,逐帧观察frame里面的数据,在车道线视频处理结束之前,数据一切都很正常,frame中保存着图像信息
而当视频处理完毕之后,frame中的数据则立即被清空
这下算是证实了我上面的想法。当程序运行到最后,frame数组矩阵为空,此时shape属性自然不存在,此时程序自然会发生异常。
解决代码代码如下:
while capture.isOpened():
# testM = capture.isOpened()
_, frame = capture.read()
origin = np.copy(frame)
try:
frame = process_an_image(frame)
output = np.concatenate((origin, frame), axis=1)
outfile.write(output)
cv2.imshow('video1_out', output)
except:
# print(frame)
exit(0)
if cv2.waitKey(1) == ord('q'):
cv2.destroyAllWindows()
break
运行结束完美解决问题!
但是此时我还在想一个问题,为什么视频都已经处理完毕了,while循环还能继续执行导致异常,capture.isOpened()的bool值在程序运行中究竟是怎样变化的?
因此我决定继续debug单步执行,同时将capture.isOpened()存储起来到testM便于观察,调出frame窗口、图像输出窗口、testM窗口,逐帧观察
testM = capture.isOpened() #插入到while 执行语句中
此时可以看到,即使视频已经处理完毕,但是capture. isOpened()的值仍为true,而此时的frame已然为None,这才是系统报错的真正原因,视频处理完毕直接结束程序即可。
问题的关键在于isOpened函数会一直检测视频的载入与否,当使用VideoCapture()捕获视频时,并不会因为视频结束而停止此操作,而是会一直停留在视频的最后一帧,因此在不加外界干预的情况下,capture.isOpened()在程序运行期间都会是 true。而如果从外界输入 ‘ q ’ 来手动停止时,可以保证在程序的运行期间,frame都是正常存储数据的,因此手动停止时,系统并不会报错。这个才是整个问题的关键。此博客也有相关解释https://blog.csdn.net/archer_wu2/article/details/85628536
可以在图像处理前对 _(也就是常用的ret) 值进行判断
if _ == True:
......
else:
break
问题解决!
除了上面给出的一种更改方法,增加一条对 frame 的判断也可以解决此问题。
while capture.isOpened():
testM = capture.isOpened()
_, frame = capture.read()
origin = np.copy(frame)
if frame is not None:
try:
frame = process_an_image(frame)
output = np.concatenate((origin, frame), axis=1)
outfile.write(output)
cv2.imshow('video1_out', output)
except:
print(frame)
# exit(0)
else :
exit(0)
# 处理退出
if cv2.waitKey(1) == ord('q'):
cv2.destroyAllWindows()
break
问题解决!!!
问题的关键在于读取视频末尾帧时发生错误,上述三种方法均可以解决此类问题。
第一次写博客,如有错误,欢迎各位大佬批评指正。