716 字
4 分钟
Python cv2读取视频文件内存溢出
2022-08-14

前言#

这两天在做毕设,尝试使用 Python 的 cv2 库读取一个视频文件并对图像进行处理,但我读取完视频文件后发现内存占用达到了 4.9GB,可实际上视频文件之后 10.8MB 多一点:

原因#

由于我的电脑只有可怜的 8GB 内存,所以这个问题需要进行及时处理,否则视频文件一大内存肯定会溢出。

首先我尝试读取一段视频,并读取单帧图片,然后 sys.getsizeof() 查询图片的实际存储大小,发现单帧图片的大小大概在 2.63MB 左右,这个大小还行,但实际再算上视频的 1389 帧的数量,内存占用就达到了 3662MB。

然后查看了一下图片的存储格式,numpy.ndarray,每个像素点也是,但每个通道的数据是uint8。

恍然大悟,720 * 1280 * 3 = 2764800 Byte,算上数组的指针等开销,确实差不多。

但视频的压缩率是真的高,也不知道怎么实现的。

import sys
import cv2
# Test1: 查看整个视频文件读取后的大小 3662MB
video = cv2.VideoCapture("data/TrafficVideo.mp4")
print(sys.getsizeof(video)) # 32 Byte
val, img = video.read()
print(sys.getsizeof(val)) # 28 Byte
print(sys.getsizeof(img)) # 2764928 Byte
print(video.get(cv2.CAP_PROP_FRAME_COUNT)) # 1389
video.release()
# Test2: 查看存储格式 uint8 1Byte
video = cv2.VideoCapture("data/TrafficVideo.mp4")
val, img = video.read()
print(type(img)) # <class 'numpy.ndarray'>
print(img.shape) # (720, 1280, 3) = 2764800 单个像素 1Byte
print(type(img[0][0][0])) # <class 'numpy.uint8'>
video.release()

解决方案#

方法1: 缩放图像#

这里我尝试将图像缩放到原有的 1/4 大小(高和宽对半),内存占用直接砍 3/4 ,立竿见影:

import sys
import cv2
import time
# Test3: 尝试将图片压缩到原始的1/4 915MB
video = cv2.VideoCapture("data/TrafficVideo.mp4")
val, img = video.read()
height, width, channel = img.shape
img = cv2.resize(img, (int(height/2), int(width/2)))
print(sys.getsizeof(img)) # 691328 Byte
video.release()
# Test4: 看看压缩后再放大的图片效果
video = cv2.VideoCapture("data/TrafficVideo.mp4")
val, img = video.read()
cv2.imshow("Origin", img)
height, width, channel = img.shape
img = cv2.resize(img, (int(width/2), int(height/2)))
img = cv2.resize(img, (int(width), int(height)))
cv2.imshow("Resize", img)
cv2.waitKey(0)
video.release()

比比时间看看,如果不算提前读取的时间,从硬盘取比从内存区慢了近10倍,原来抑制播放速度的最大原因是读取速度啊…

# Test5:
time1 = time.time()
video = cv2.VideoCapture("data/TrafficVideo.mp4")
val, img = video.read()
cv2.imshow("Origin", img)
time2 = time.time()
print(time2 - time1)
height, width, channel = img.shape
img = cv2.resize(img, (int(width/2), int(height/2)))
time1 = time.time()
img = cv2.resize(img, (int(width), int(height)))
cv2.imshow("Resize", img)
time2 = time.time()
print(time2 - time1)
video.release()

碰到个bug,尝试 安装对应包之后,安装opencv-contrib-python不是opencv-python 我之前试过cv2和pyqt的包冲突,opencv-contrib-python-headless

Terminal window
sudo apt install libgtk2.0-dev
sudo apt install pkg-config
pip install opencv-contrib-python

方法1:删除 cv2 中的 libqxcb

找到 ~/.local/lib/python3.8/site-packages/cv2/qt/plugins 调用的相同库 libqxcb.so ,并删除该文件,但在其他只调用 cv2 的项目中无法再使用窗口

方法2:安装 opencv-contrib-python-headless

Terminal window
pip uninstall opencv-python
pip install opencv-contrib-python-headless
cv2.error: OpenCV(4.5.5) /io/opencv/modules/highgui/src/window.cpp:1268: error: (-2:Unspecified error) The function is not implemented.
Rebuild the library with Windows, GTK+ 2.x or Cocoa support.
If you are on Ubuntu or Debian, install libgtk2.0-dev and pkg-config, then re-run cmake or configure script in function 'cvShowImage'
Python cv2读取视频文件内存溢出
https://fuwari.vercel.app/posts/编程/python/python-cv2读取视频文件内存溢出/
作者
Asuwee
发布于
2022-08-14
许可协议
CC BY-NC-SA 4.0