2、视频数据基础:视频的数字化表示与实战读取
大家好,我是你们这门课的老朋友。今天咱们来聊聊视频数据的基础。说实话,我刚开始做行为识别那会儿,也踩过不少坑——比如读进来的视频全是花屏,或者帧率对不上导致模型训练直接崩掉。所以这一章,咱们把视频的“底裤”扒干净,看看它到底是怎么存的、怎么读的。
2.1 视频的数字化表示
视频说白了,就是一连串快速播放的图片。但计算机里存视频,可不会傻乎乎地存几千张独立图片——那样一个10秒的视频就能撑爆你的硬盘。所以,视频的数字化表示涉及几个核心概念。
2.1.1 帧(Frame)
帧就是视频里的每一张静态画面。比如一个30fps的视频,每秒就有30帧。人眼有个视觉暂留效应,只要帧率超过24fps,看起来就是流畅的。
我个人习惯:做行为识别时,通常不会把每一帧都送进模型。比如一个1分钟的视频有1800帧,全处理太慢了。我一般会隔几帧取一帧,或者只取关键帧。
2.1.2 码率(Bitrate)
码率就是视频每秒占用的数据量,单位是bps(比特每秒)。码率越高,画质越好,文件也越大。举个例子:
- 低码率(500kbps):适合网络传输,但画面会有马赛克
- 高码率(10Mbps):画质清晰,适合做精细分析
2.1.3 分辨率(Resolution)
分辨率就是视频的宽×高,比如1920×1080(1080p)。分辨率越高,细节越丰富,但计算量也越大。
| 分辨率 | 常见场景 | 我推荐用于行为识别吗? |
|---|---|---|
| 640×480 | 老式监控 | 不推荐,太糊了 |
| 1280×720 | 普通摄像头 | 可以,但注意细节 |
| 1920×1080 | 高清视频 | 推荐,平衡了清晰度和速度 |
| 3840×2160 | 4K视频 | 慎用,除非你有GPU集群 |
你想想看,如果做“挥手”识别,640×480可能还能用;但如果是“偷窃”这种需要看清手指动作的,至少得720p起步。
2.2 常见视频格式
视频格式说白了就是“容器+编码”。容器决定文件后缀,编码决定压缩方式。
2.2.1 MP4(最常用)
MP4是目前最通用的格式。它用H.264或H.265编码,压缩率高,画质损失小。我90%的项目都用MP4。
- 优点:兼容性好,OpenCV直接支持
- 缺点:编码复杂,解码稍慢
2.2.2 AVI(老牌格式)
AVI是微软的老格式,现在用得少了。它通常不压缩或采用低压缩率,所以文件巨大。一个10秒的AVI可能比MP4大10倍。
2.2.3 其他格式
- MOV:苹果生态常用,OpenCV也能读
- FLV:直播流常用,但行为识别很少用
- MKV:多轨道格式,适合存多个音频/字幕
2.3 视频读取与帧提取实战(OpenCV基础)
好了,理论说完了,咱们直接上代码。OpenCV是视频处理最常用的库,没有之一。
2.3.1 安装OpenCV
如果你还没装,先跑这行命令:
pip install opencv-python
2.3.2 读取视频并获取基本信息
咱们先写个脚本,看看视频的“身份证”:
import cv2
# 打开视频文件
cap = cv2.VideoCapture('test.mp4')
# 获取基本信息
fps = cap.get(cv2.CAP_PROP_FPS) # 帧率
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) # 宽度
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) # 高度
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) # 总帧数
print(f"帧率: {fps} FPS")
print(f"分辨率: {width} x {height}")
print(f"总帧数: {total_frames}")
# 记得释放资源
cap.release()
嗯,这里要注意:cap.get()返回的是浮点数,记得转成int。我刚开始写的时候忘了转,结果后面做循环时索引报错,排查了半天。
2.3.3 逐帧提取并保存
接下来,咱们把视频的每一帧都提取出来,存成图片。这在做数据集准备时特别有用。
import cv2
import os
cap = cv2.VideoCapture('test.mp4')
output_dir = 'frames'
os.makedirs(output_dir, exist_ok=True)
frame_count = 0
while True:
ret, frame = cap.read()
if not ret:
break # 视频读完了
# 保存每一帧
filename = os.path.join(output_dir, f'frame_{frame_count:04d}.jpg')
cv2.imwrite(filename, frame)
frame_count += 1
cap.release()
print(f"共提取 {frame_count} 帧")
cap.read()返回两个值——ret(是否成功)和frame(图像数据)。如果ret为False,说明视频结束了或者出错了。一定要检查ret,否则会死循环。
2.3.4 按间隔提取帧(实战常用)
说实话,全量提取太浪费了。我一般每隔5帧或10帧取一帧,既能保留动作信息,又不会数据爆炸。
import cv2
cap = cv2.VideoCapture('test.mp4')
interval = 5 # 每5帧取一帧
frame_count = 0
saved_count = 0
while True:
ret, frame = cap.read()
if not ret:
break
if frame_count % interval == 0:
cv2.imwrite(f'frame_{saved_count:04d}.jpg', frame)
saved_count += 1
frame_count += 1
cap.release()
print(f"原始帧数: {frame_count}, 保存帧数: {saved_count}")
2.3.5 实时显示视频(调试用)
有时候你想看看视频内容对不对,可以用imshow实时显示:
import cv2
cap = cv2.VideoCapture('test.mp4')
while True:
ret, frame = cap.read()
if not ret:
break
cv2.imshow('Video', frame)
# 按'q'键退出
if cv2.waitKey(25) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
为什么会用waitKey(25)?因为25毫秒约等于40fps,和常见视频帧率匹配。如果视频是30fps,你可以改成33毫秒。
2.4 本章小结
这一章咱们把视频的“底”摸清了:帧、码率、分辨率是三个核心参数;MP4是主流格式;OpenCV的VideoCapture是读取视频的利器。下一章,咱们会深入视频的时空特征,开始真正的行为识别之旅。
记住:视频处理的第一步永远是“读对视频”。我见过太多人因为视频格式不对、帧率不匹配,导致后面模型训练全白费。所以,先把基础打牢,后面才能飞得稳。
公众号:蓝海资料掘金营,微信deep3321