使用 C++/OpenCV 裁剪 MP4 视频 🎬
裁剪视频是视频处理中的一项常见任务,其目的是从原始视频画面中提取一个特定的矩形区域,生成一个新的视频。使用 C++ 和 OpenCV,我们可以逐帧处理视频,实现精确的裁剪。
其核心思路是将视频看作是连续的图片序列。我们只需读取视频的每一帧,对该帧图片进行裁剪,然后将裁剪后的图片写入一个新的视频文件即可。
主要步骤
- 打开视频文件 :使用
cv::VideoCapture
对象读取输入的 MP4 文件。 - 获取视频属性:从原视频中获取帧率 (FPS)、帧尺寸、编码格式等信息,用于配置输出视频。
- 创建视频写入器 :使用
cv::VideoWriter
对象,并根据上一步获取的属性(但使用新的、裁剪后的帧尺寸)来创建一个新的 MP4 文件。 - 定义裁剪区域 :创建一个
cv::Rect
对象,定义需要裁剪的区域。 - 逐帧处理 :循环读取原视频的每一帧,使用
cv::Rect
对当前帧进行裁剪,然后将裁剪后的小尺寸帧写入新的视频文件。 - 释放资源:处理完成后,释放视频读取和写入对象。
C++ 完整代码示例
下面的代码演示了如何加载一个 MP4 文件,对其进行中心区域裁剪,并保存为新文件。
cpp
#include <iostream>
#include <opencv2/opencv.hpp>
int main() {
// 1. 打开视频文件
std::string inputPath = "input.mp4"; // 替换成你的视频路径
cv::VideoCapture cap(inputPath);
if (!cap.isOpened()) {
std::cout << "错误: 无法打开视频文件 " << inputPath << std::endl;
return -1;
}
// 2. 获取原视频属性
int frame_width = static_cast<int>(cap.get(cv::CAP_PROP_FRAME_WIDTH));
int frame_height = static_cast<int>(cap.get(cv::CAP_PROP_FRAME_HEIGHT));
double fps = cap.get(cv::CAP_PROP_FPS);
int fourcc = static_cast<int>(cap.get(cv::CAP_PROP_FOURCC)); // 获取编码格式
std::cout << "原视频 - 尺寸: " << frame_width << "x" << frame_height << ", FPS: " << fps << std::endl;
// 3. 定义裁剪区域 (例如,裁剪出一个 640x480 的区域)
int crop_width = 640;
int crop_height = 480;
// 计算左上角坐标,使其居中裁剪
int x = (frame_width - crop_width) / 2;
int y = (frame_height - crop_height) / 2;
cv::Rect crop_region(x, y, crop_width, crop_height);
// 确保裁剪区域有效
if (x < 0 || y < 0 || x + crop_width > frame_width || y + crop_height > frame_height) {
std::cout << "错误: 裁剪区域超出了原视频范围。" << std::endl;
return -1;
}
// 4. 创建视频写入器
std::string outputPath = "output_cropped.mp4";
cv::VideoWriter writer(outputPath, fourcc, fps, cv::Size(crop_width, crop_height));
if (!writer.isOpened()) {
std::cout << "错误: 无法创建视频写入器 " << outputPath << std::endl;
return -1;
}
std::cout << "开始处理视频..." << std::endl;
// 5. 逐帧处理
cv::Mat frame;
while (cap.read(frame)) {
// 如果帧为空,则跳出循环
if (frame.empty()) {
break;
}
// 对当前帧进行裁剪
cv::Mat cropped_frame = frame(crop_region);
// 将裁剪后的帧写入新视频
writer.write(cropped_frame);
}
std::cout << "视频处理完成,已保存至 " << outputPath << std::endl;
// 6. 释放资源
cap.release();
writer.release();
return 0;
}
代码解析
-
cv::VideoCapture cap(inputPath);
创建一个视频捕获对象,并尝试打开指定的视频文件。
isOpened()
方法可以检查是否成功打开。 -
cap.get(...)
此方法用于获取视频的各种属性,如
CAP_PROP_FRAME_WIDTH
(宽度)、CAP_PROP_FPS
(帧率)等。我们必须获取这些信息以正确配置输出视频,否则可能导致播放速度异常或文件损坏。 -
cv::VideoWriter writer(...)
这是创建视频写入器的关键。它需要几个核心参数:
- 输出文件名 :
outputPath
。 - 编码格式 (FourCC) :
fourcc
。我们直接使用从原视频中读取的编码格式。FourCC 是一个4字节的代码,用于唯一标识视频编解码器。 - 帧率 (FPS) :
fps
。保持与原视频一致。 - 帧尺寸 :
cv::Size(crop_width, crop_height)
。注意 :这里必须使用裁剪后的尺寸,而不是原视频的尺寸。
- 输出文件名 :
-
while (cap.read(frame))
这是一个标准的循环,用于逐一读取视频的每一帧。
cap.read(frame)
会读取下一帧并将其存入frame
这个Mat
对象中。当视频读取完毕,该函数会返回false
。 -
cv::Mat cropped_frame = frame(crop_region);
这行代码与裁剪单张图片完全相同。它使用
cv::Rect
对象crop_region
从当前帧frame
中提取感兴趣的区域。 -
writer.write(cropped_frame);
将裁剪后的帧
cropped_frame
写入到我们创建的输出视频文件中。 -
cap.release(); writer.release();
在程序结束时,务必调用
release()
方法来关闭文件并释放相关资源,这是一个良好的编程习惯。
总结
通过 VideoCapture
读取视频、VideoWriter
写入视频以及在循环中对每一帧应用 cv::Rect
裁剪,我们可以用 OpenCV 轻松地实现对 MP4 视频的裁剪。这个流程清晰地展示了视频处理的本质------即对一系列连续图像进行批处理。