1. 引言
大家都来写OpenCV😊,学的好开心!
2. 视频基础与OpenCV简介
2.1 视频的定义
视频(Video)是由一系列静态图像(帧)以一定速率连续播放形成的动态影像。其本质是利用人眼的视觉暂留效应,将静止的画面转化为连续的动态内容。视频通常包含画面、音频轨道,有时还包括字幕、特效等信息。
视频的主要应用领域
- 影视娱乐
- 教育培训
- 安防监控
- 通信与直播
- 自动驾驶与智能交通
2.2 OpenCV简介
OpenCV(Open Source Computer Vision Library)是一个跨平台的计算机视觉和机器学习软件库,支持C++、Python等多种语言。它为视频处理、图像分析、机器学习等任务提供了高效的算法和接口。
3. 视频读写
3.1 视频的基本操作
图片转视频
将多张图片按顺序和时间间隔组合,添加转场、音乐、字幕等,生成视频。例如旅游纪念视频、照片合成动画等。
视频转图片
从视频中提取特定帧作为图片,用于精彩瞬间捕捉、视频封面、画面分析等。例如电影剧照、运动分析等。
3.2 OpenCV读取视频详解
OpenCV通过
cv::VideoCapture
类实现视频文件或摄像头流的读取。
代码示例
cpp
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
//1 指定视频文件路径创建VideoCapture
VideoCapture cap("C:/Users/Administrator/Desktop/video/cat.mp4");
//2 判断是否成功打开视频
if (!cap.isOpened())
{
cout << "视频打开失败!" << endl;
return -1;
}
//3 获取视频基本信息
double width = cap.get(CAP_PROP_FRAME_WIDTH);
double height = cap.get(CAP_PROP_FRAME_HEIGHT);
double count = cap.get(CAP_PROP_FRAME_COUNT);
double fps = cap.get(CAP_PROP_FPS);
cout << "视频的宽=" << width << endl;
cout << "视频的高=" << height << endl;
cout << "视频的总帧数=" << count << endl;
cout << "视频的fps=" << fps << endl;
//4 逐帧读取视频并展示
Mat frame;
width = width * 0.2;
height = height * 0.2;
while (true)
{
cap >> frame;
if (frame.empty())
{
break;
}
Mat dst;
resize(frame, dst, Size(width,height));
Mat gray;
cvtColor(dst, gray, COLOR_BGR2GRAY);
imshow("video", dst);
imshow("gray video", gray);
if (waitKey(1000/fps) == 27)
{
break;
}
}
//5 释放资源
cap.release();
destroyAllWindows();
return 0;
}
视频属性表
属性名 说明 类型 示例值 CAP_PROP_FRAME_WIDTH 视频帧宽度(像素) double 1920 CAP_PROP_FRAME_HEIGHT 视频帧高度(像素) double 1080 CAP_PROP_FPS 视频帧率(帧/秒) double 30.0 CAP_PROP_FRAME_COUNT 视频总帧数 double 2500 CAP_PROP_POS_FRAMES 当前帧索引(从0开始) double 100 CAP_PROP_POS_MSEC 当前时间戳(毫秒) double 3500.0 CAP_PROP_FOURCC 编解码器FourCC代码 double 1196444237 CAP_PROP_BRIGHTNESS 摄像头亮度(仅摄像头有效) double 0.5 CAP_PROP_CONTRAST 摄像头对比度 double 0.3 CAP_PROP_SATURATION 摄像头饱和度 double 0.8 CAP_PROP_EXPOSURE 摄像头曝光值 double -4.0 CAP_PROP_AUTOFOCUS 自动对焦是否开启 double 1.0
3.3 视频保存与编码格式
OpenCV通过
cv::VideoWriter
类实现视频录制与保存。FourCC编码格式
'MJPG'
:Motion-JPEG,常用于.avi文件'XVID'
:XVID编码,适用于.avi文件'H264'
:H.264编码,适用于.mp4文件(需安装OpenH264库)
视频保存代码示例
cpp
void writeVideo(VideoCapture& cap)
{
cv::String fileName = "C:/Users/Administrator/Desktop/video/temp.avi";
int fourcc = VideoWriter::fourcc('M', 'J', 'P', 'G');
double width = cap.get(CAP_PROP_FRAME_WIDTH);
double height = cap.get(CAP_PROP_FRAME_HEIGHT);
double fps = cap.get(CAP_PROP_FPS);
VideoWriter writer(fileName,fourcc,fps,Size(width,height),false);
if (!writer.isOpened())
{
cout << "视频文件打开失败!" << endl;
return;
}
Mat src;
while (true)
{
cap >> src;
if (src.empty())
{
break;
}
Mat gray;
cvtColor(src, gray, COLOR_BGR2GRAY);
writer.write(gray);
if (waitKey(30) == 27)
{
break;
}
}
cout << "已经成功保存视频" << endl;
writer.release();
}
视频保存流程
- 创建VideoWriter对象,指定文件名、编码格式、帧率、分辨率、是否彩色
- 判断文件是否成功打开
- 逐帧写入视频
- 释放资源
4. 视频追踪
4.1 视频追踪定义与应用
视频追踪(Video Tracking)是指在连续的视频帧中定位并跟踪特定目标(如人脸、车辆)的运动轨迹。广泛应用于:
- 安防监控
- 自动驾驶
- 人机交互
- 运动分析
视频追踪流程
- 目标检测:识别并定位目标
- 特征提取:提取目标特征(颜色、形状、纹理等)
- 模型更新:适应目标外观变化
- 位置预测与校正:预测目标位置并校正
4.2 Meanshift算法原理与实现
Meanshift算法定义
Meanshift是一种基于密度估计的非参数化聚类算法,广泛用于目标追踪。其核心思想是通过迭代将搜索窗口向目标区域的颜色直方图分布中心移动,实现目标定位。
直方图反向投影
直方图反向投影是指将目标区域的颜色分布映射到整幅图像,得到每个像素属于目标的概率图。
反向投影流程
- 选定目标区域,计算HSV直方图
- 对每一帧计算直方图
- 对比直方图,得到相似度
- 生成概率图,作为Meanshift输入
Meanshift代码解析
cpp
void meanshiftTest(VideoCapture& cap)
{
Mat frame;
cap >> frame;
if (frame.empty())
{
cout << "无法读取视频帧" << endl;
return;
}
Rect roi = selectROI("请选择追踪目标",frame,false);
if (roi.width <= 0 || roi.height <= 0)
{
cout << "已取消选择roi区域" << endl;
return;
}
Mat target = frame(roi).clone();
imshow("target", target);
Mat hsv_target;
cvtColor(target, hsv_target, COLOR_BGR2HSV);
Mat mask;
inRange(hsv_target, Scalar(0, 30, 0), Scalar(180, 255, 255), mask);
int histSize = 180;
float range[] = { 0,180 };
const float* histRange = { range };
Mat hist_target;
int channels[] = { 0 };
calcHist(&hsv_target, 1, channels, mask, hist_target, 1, &histSize, &histRange);
normalize(hist_target, hist_target, 0,255, NORM_MINMAX);
TermCriteria criteria(TermCriteria::EPS | TermCriteria::COUNT, 10, 1);
while (true)
{
cap >> frame;
if (frame.empty())
{
break;
}
Mat hsvFrame;
cvtColor(frame, hsvFrame, COLOR_BGR2HSV);
Mat back;
calcBackProject(&hsvFrame, 1, channels, hist_target, back,&histRange);
meanShift(back, roi, criteria);
rectangle(frame, roi, Scalar(0, 255, 0));
imshow("视频追踪", frame);
if (waitKey(30) == 27)
{
break;
}
}
}
关键函数说明
selectROI
:手动选择目标区域calcHist
:计算目标区域颜色直方图normalize
:归一化直方图calcBackProject
:计算反向投影概率图meanShift
:执行Meanshift迭代,更新目标位置
TermCriteria参数说明
参数类型 说明 TermCriteria::EPS 收敛到指定精度时终止 TermCriteria::COUNT 达到最大迭代次数时终止 10 最大迭代次数 1 精度阈值(像素)
4.3 Camshift算法原理与实现
Camshift算法定义
Camshift(Continuously Adaptive Mean Shift)是Meanshift的改进版,能自适应调整搜索窗口的大小和方向,适合目标尺度和方向变化明显的场景。
Camshift实现流程
- 初始化目标模型,计算颜色直方图
- 定义搜索窗口
- 执行Meanshift迭代
- 根据目标分布调整窗口大小和方向
- 更新窗口位置,输出最佳拟合椭圆
Camshift代码解析
cpp
void camshiftTest(VideoCapture& cap)
{
Mat frame;
cap >> frame;
if (frame.empty())
{
cout << "无法读取视频帧" << endl;
return;
}
Rect roi = selectROI("请选择追踪目标", frame, false);
if (roi.width <= 0 || roi.height <= 0)
{
cout << "已取消选择roi区域" << endl;
return;
}
Mat target = frame(roi).clone();
imshow("target", target);
Mat hsv_target;
cvtColor(target, hsv_target, COLOR_BGR2HSV);
Mat mask;
inRange(hsv_target, Scalar(0, 60, 32), Scalar(180, 255, 255), mask);
int histSize = 180;
float range[] = { 0,180 };
const float* histRange = { range };
Mat hist_target;
int channels[] = { 0 };
calcHist(&hsv_target, 1, channels, mask, hist_target, 1, &histSize, &histRange);
normalize(hist_target, hist_target, 0, 255, NORM_MINMAX);
TermCriteria criteria(TermCriteria::EPS | TermCriteria::COUNT, 10, 1);
while (true)
{
cap >> frame;
if (frame.empty())
{
break;
}
Mat hsvFrame;
cvtColor(frame, hsvFrame, COLOR_BGR2HSV);
Mat back;
calcBackProject(&hsvFrame, 1, channels, hist_target, back, &histRange);
RotatedRect trackBox = CamShift(back, roi, criteria);
rectangle(frame, roi, Scalar(0, 255, 0));
//ellipse(frame, trackBox, Scalar(0, 0, 255), 2);
imshow("视频追踪", frame);
if (waitKey(30) == 27)
{
break;
}
}
}
Camshift返回值说明
RotatedRect
:最佳拟合椭圆,包含中心位置、大小、旋转角度
4.4 Meanshift与Camshift对比分析
算法 窗口大小 适应目标变化 适用场景 实时性 输出信息 Meanshift 固定 不适应 目标大小不变 极高 位置 Camshift 自适应 适应 目标尺度/方向变化 较高 位置+大小+方向
选择建议
- 优先Meanshift:目标大小和方向基本不变,对实时性要求极高
- 优先Camshift:目标尺度或方向变化明显,需要输出目标朝向信息
5. 摄像头实时处理
5.1 实时处理定义与应用
摄像头实时处理是指通过摄像头捕获视频流,对每一帧图像进行即时处理和分析,并实时显示或反馈结果。应用包括:
- 实时人脸检测
- 运动物体追踪
- 增强现实(AR)效果
5.2 摄像头实时捕获与处理流程
- 打开摄像头(
cv::VideoCapture
)- 逐帧读取视频流
- 对每一帧进行处理(如灰度化、边缘检测等)
- 实时显示处理结果(
cv::imshow
)- 释放资源
摄像头实时处理代码解析
cpp
void cameraTest()
{
VideoCapture cap(0);
cap.set(CAP_PROP_FRAME_WIDTH,680);
cap.set(CAP_PROP_FRAME_HEIGHT, 480);
Mat frame;
while (true)
{
cap >> frame;
if (frame.empty())
{
cout << "无法读取摄像头帧" << endl;
break;
}
Mat gray;
cvtColor(frame, gray, COLOR_BGR2GRAY);
imshow("实时帧", frame);
imshow("灰度帧", gray);
if (waitKey(30) == 27)
{
break;
}
}
cap.release();
destroyAllWindows();
}
5.3 实时视频处理应用举例
5.3.1 实时跟踪
利用Meanshift或Camshift算法对摄像头捕获内容进行实时目标跟踪。
cpp
void camShiftCameraTest()
{
VideoCapture cap(0);
Mat frame;
cap >> frame;
if (frame.empty())
{
cout << "无法读取视频帧" << endl;
return;
}
Rect roi = selectROI("请选择追踪目标", frame, false);
if (roi.width <= 0 || roi.height <= 0)
{
cout << "已取消选择roi区域" << endl;
return;
}
Mat target = frame(roi).clone();
imshow("target", target);
Mat hsv_target;
cvtColor(target, hsv_target, COLOR_BGR2HSV);
Mat mask;
inRange(hsv_target, Scalar(0, 60, 32), Scalar(180, 255, 255), mask);
int histSize = 180;
float range[] = { 0,180 };
const float* histRange = { range };
Mat hist_target;
int channels[] = { 0 };
calcHist(&hsv_target, 1, channels, mask, hist_target, 1, &histSize, &histRange);
normalize(hist_target, hist_target, 0, 255, NORM_MINMAX);
TermCriteria criteria(TermCriteria::EPS | TermCriteria::COUNT, 10, 1);
while (true)
{
cap >> frame;
if (frame.empty())
{
break;
}
Mat hsvFrame;
cvtColor(frame, hsvFrame, COLOR_BGR2HSV);
Mat back;
calcBackProject(&hsvFrame, 1, channels, hist_target, back, &histRange);
RotatedRect trackBox = CamShift(back, roi, criteria);
rectangle(frame, roi, Scalar(0, 255, 0));
//ellipse(frame, trackBox, Scalar(0, 0, 255), 2);
imshow("视频追踪", frame);
if (waitKey(30) == 27)
{
break;
}
}
destroyAllWindows();
}
5.3.2 实时边缘检测
通过摄像头实时捕获视频,使用Canny算法提取图像边缘。
cpp
void cameraCannyTest()
{
VideoCapture cap(0);
cap.set(CAP_PROP_FRAME_WIDTH, 680);
cap.set(CAP_PROP_FRAME_HEIGHT, 480);
Mat frame;
while (true)
{
cap >> frame;
if (frame.empty())
{
cout << "无法读取摄像头帧" << endl;
break;
}
Mat gray;
cvtColor(frame, gray, COLOR_BGR2GRAY);
Mat blur;
GaussianBlur(gray, blur, Size(3, 3),1.5);
Mat dst;
Canny(blur, dst, 50, 150);
imshow("实时帧", frame);
imshow("边缘检测", dst);
if (waitKey(30) == 27)
{
break;
}
}
cap.release();
destroyAllWindows();
}
5.3.3 其他应用
摄像头实时捕获内容不仅能做跟踪和边缘检测,还可用于:
- 实时人脸识别
- 实时手势识别
- 实时目标分割
- 实时AR效果叠加
6. 总结与展望
好学,爱学,还得学!