如何用 Python 捕获、播放和保存摄像头视频
那我就按平时跟同事解释的方式来聊一遍,别紧张,这个主题其实没你想得那么复杂:就是拿 Python 把摄像头画面抓出来,在屏幕上放一下,再顺手存成一个视频文件。
先说个前提:我们主要用 OpenCV
绝大多数人用 Python 玩摄像头,都是用 opencv-python 这个库,安装就一行:
pip install opencv-python
装完就可以 import cv2 了。如果你是虚拟环境,记得先激活环境再装,不然容易搞混。
第一步:打开摄像头,把画面“抓出来”
你可以先写一个最小可运行的 demo,确认你的摄像头能正常被 Python 访问。比如下面这段代码,我一般也是先跑它:
import cv2
defpreview_camera(camera_index=0):
# 1. 打开摄像头,0 通常是默认摄像头,笔记本就是内置摄像头
cap = cv2.VideoCapture(camera_index)
ifnot cap.isOpened():
print("摄像头打开失败,检查一下摄像头是否被占用,或者 camera_index 写错了")
return
whileTrue:
# 2. 读取一帧图像
ret, frame = cap.read()
ifnot ret:
print("读取摄像头画面失败,可能是摄像头断开了")
break
# 3. 在窗口中显示这一帧
cv2.imshow("Camera Preview - 按 q 退出", frame)
# 4. 等待键盘事件,参数是等待毫秒数
# 如果 1ms 内按下 q,就退出循环
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 5. 释放摄像头资源,关闭窗口
cap.release()
cv2.destroyAllWindows()
if __name__ == "__main__":
preview_camera()
大概的逻辑你可以理解成:
VideoCapture负责“管子”:从摄像头源头往外输视频帧;read()每次从这个“管子”里捞一帧出来;imshow()就是把这一帧画在一个窗体上;waitKey()不光负责等个几毫秒,还顺便监听键盘按键;最后记得 release()和destroyAllWindows(),不然总感觉资源没收拾干净。
如果你电脑插了好几个摄像头,camera_index 可以试 0、1、2 去找。
第二步:一边预览,一边录制保存成视频
能预览之后,离“录屏”就差一步:把每一帧写进一个视频文件。OpenCV 里用 VideoWriter 干这个事。
可以这样写个小工具函数,把摄像头画面录下来:
import cv2
from datetime import datetime
defrecord_camera(
camera_index=0,
output_file=None,
fps=20.0,
frame_size=None
):
cap = cv2.VideoCapture(camera_index)
ifnot cap.isOpened():
print("摄像头打开失败")
return
# 如果没指定输出文件名,就用时间戳来生成一个
if output_file isNone:
output_file = datetime.now().strftime("camera_%Y%m%d_%H%M%S.mp4")
# 获取摄像头的宽高
if frame_size isNone:
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
frame_size = (width, height)
# fourcc 指定视频编码格式,不同系统可能要试几个
# 'mp4v' 生成 mp4,一般还算通用
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter(output_file, fourcc, fps, frame_size)
ifnot out.isOpened():
print("视频文件创建失败,检查路径和编码格式")
cap.release()
return
print(f"开始录制,保存到:{output_file},按 q 停止")
whileTrue:
ret, frame = cap.read()
ifnot ret:
print("读取摄像头失败,中断录制")
break
# 如果摄像头分辨率和 frame_size 不一致,调整一下大小
if (frame.shape[1], frame.shape[0]) != frame_size:
frame = cv2.resize(frame, frame_size)
# 写入这一帧到视频文件
out.write(frame)
# 一边录一边预览
cv2.imshow("Recording - 按 q 停止", frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
out.release()
cv2.destroyAllWindows()
print("录制结束")
if __name__ == "__main__":
record_camera()
这里有几个小点别忽略:
编码器 fourcc:不同系统、不同 OpenCV 版本,支持的编码器不太一样。
fourcc = cv2.VideoWriter_fourcc(*'XVID')
output_file = "output.avi"Windows 上常见 'XVID'、'MJPG'、'mp4v';Linux 上配合 ffmpeg 也能用 X264等等; 录不出来多半就是编码器或后缀名不对,可以换几个组合试试,例如:fps(帧率):设置得高,文件更大,对性能也更挑;一般 20~30fps 就足够了。
frame_size 一定要和写入帧的尺寸一致,不然
VideoWriter会悄悄失败,最后生成个打不开的空文件。
第三步:再来一个“回放”功能,看看录好的视频
录完了你肯定想看一眼是不是正常,这个其实又回到了第一步:VideoCapture 不一定要接摄像头,也可以接一个视频文件路径。
比如:
import cv2
defplay_video(file_path):
cap = cv2.VideoCapture(file_path)
ifnot cap.isOpened():
print("无法打开视频文件:", file_path)
return
whileTrue:
ret, frame = cap.read()
ifnot ret:
print("播放结束")
break
cv2.imshow("Video Playback - 按 q 退出", frame)
# 这里可以稍微大一点的延时,模拟接近原始 fps
if cv2.waitKey(30) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
if __name__ == "__main__":
play_video("camera_20240101_120000.mp4") # 换成你实际录出来的文件名
这个函数其实跟摄像头预览几乎一模一样,区别就是:
VideoCapture传的是文件路径;ret == False代表“读到头了”,不是摄像头坏了。
如果你想用键盘控制“暂停/继续”,也可以在循环里多判断几个按键,比如空格暂停,p 继续,这些都是在 waitKey 上做文章。
第四步:顺手再做点小处理,比如灰度、翻转、加时间戳
既然每一帧都拿到了,不处理一下就关掉有点可惜。OpenCV 的好玩之处也在这儿:你在保存前可以对画面“顺便加工”。
比如在录制时,把画面变成灰度再显示,但保存成彩色,或者干脆保存灰度版。随便举一个加时间戳再录制的版本:
import cv2
from datetime import datetime
defrecord_with_timestamp(camera_index=0, output_file="record_with_ts.mp4"):
cap = cv2.VideoCapture(camera_index)
ifnot cap.isOpened():
print("摄像头打开失败")
return
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
frame_size = (width, height)
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter(output_file, fourcc, 20.0, frame_size)
print("开始录制(带时间戳),按 q 停止")
whileTrue:
ret, frame = cap.read()
ifnot ret:
print("读取失败")
break
# 在左上角画一个时间戳
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
cv2.putText(
frame, # 要画字的图像
now, # 文本
(10, 30), # 坐标(x, y)
cv2.FONT_HERSHEY_SIMPLEX, # 字体
0.8, # 字号
(0, 255, 0), # 颜色 (B, G, R)
2# 线宽
)
out.write(frame)
cv2.imshow("Recording with timestamp - 按 q 停止", frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
out.release()
cv2.destroyAllWindows()
print("录制结束")
if __name__ == "__main__":
record_with_timestamp()
你想做实时美颜、加水印、打马赛克,都是在 frame 上先处理,然后再 out.write(frame) 就行了。
第五步:稍微封装一下,做成一个小工具类
如果你不想每次都复制一坨 while 循环,可以简单封装个类,用起来会舒服一点,比如:
import cv2
from datetime import datetime
from typing import Tuple, Optional
classCameraRecorder:
def__init__(
self,
camera_index: int = 0,
output_file: Optional[str] = None,
fps: float = 20.0,
codec: str = "mp4v",
frame_size: Optional[Tuple[int, int]] = None
):
self.camera_index = camera_index
self.output_file = output_file or datetime.now().strftime("camera_%Y%m%d_%H%M%S.mp4")
self.fps = fps
self.codec = codec
self.frame_size = frame_size
self.cap = None
self.out = None
defopen(self):
self.cap = cv2.VideoCapture(self.camera_index)
ifnot self.cap.isOpened():
raise RuntimeError("摄像头打开失败")
if self.frame_size isNone:
width = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
self.frame_size = (width, height)
fourcc = cv2.VideoWriter_fourcc(*self.codec)
self.out = cv2.VideoWriter(self.output_file, fourcc, self.fps, self.frame_size)
ifnot self.out.isOpened():
self.cap.release()
raise RuntimeError("视频文件创建失败")
defrun(self):
print(f"开始录制,输出文件:{self.output_file},按 q 停止")
whileTrue:
ret, frame = self.cap.read()
ifnot ret:
print("读取摄像头失败")
break
# 可以在这里对 frame 做一些统一处理,比如翻转
# frame = cv2.flip(frame, 1) # 1 为左右镜像
if (frame.shape[1], frame.shape[0]) != self.frame_size:
frame = cv2.resize(frame, self.frame_size)
self.out.write(frame)
cv2.imshow("CameraRecorder - 按 q 停止", frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
defclose(self):
if self.cap isnotNone:
self.cap.release()
if self.out isnotNone:
self.out.release()
cv2.destroyAllWindows()
if __name__ == "__main__":
recorder = CameraRecorder()
try:
recorder.open()
recorder.run()
finally:
recorder.close()
以后你要改录制参数、改分辨率、改编码器,就改构造函数参数;要拓展成“录一段 N 秒然后自动停”,也只要在 run 里加个时间判断。
最后说几个常见小坑,免得你踩
我随口列几个,基本都是大家第一次玩摄像头必踩的:
代码没报错,但窗口一片黑:
很可能是摄像头被别的程序占用了(比如系统自带相机、浏览器); 或者 camera_index写错,试试 1、2。生成的视频文件为 0KB 或打不开:
要么编码器不兼容,要么 frame_size对不上,再要么你没正常走到 release(),进程被你强行停掉了。waitKey写成了 0 导致窗口“卡住”:waitKey(0)是“无限等键盘”,通常是在显示图片时用,实时视频预览就别这么写了,用个小延时,比如 1 或 10。
整体思路就是三句话:
用 VideoCapture从摄像头“接水”;用 imshow把水龙头打开看一眼;想要存起来,就再接个 VideoWriter把每一帧写进文件。
搞清这三块,捕获、播放、保存摄像头视频就算拿下了。剩下的就是看你想在每一帧上做多少骚操作了 😄
-END-
我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html
虎哥作为一名老码农,整理了全网最全《python高级架构师资料合集》,总量高达650GB