1. 相机与视频操作
1.1 打开视频/相机
OpenCV 中 imread()
只能读取静态图像,若要读取视频文件或摄像头流,需要使用 VideoCapture
类:
cpp
// 构造函数
cv::VideoCapture::VideoCapture();
cv::VideoCapture::VideoCapture(const std::string& filename, int apiPreference = cv::CAP_ANY); // 打开视频文件,apiPreference为设置属性
cv::VideoCapture::VideoCapture(int index, int apiPreference = cv::CAP_ANY); // 打开摄像头,index 为设备 ID
// 或者先默认构造,再调用 open()
VideoCapture cap;
cap.open("example.avi");
cap.open(0);
1.2 读取并播放视频
cpp
VideoCapture video("example.avi");
if (!video.isOpened()) {
std::cerr << "Error: 无法打开视频文件!" << std::endl;
return -1;
}
double fps = video.get(cv::CAP_PROP_FPS); // 读取帧率
int delay = static_cast<int>(1000.0 / fps); // 每帧显示时长(毫秒)
while (true) {
cv::Mat frame;
video >> frame; // 读取下一帧到 frame
if (frame.empty()) break; // 视频结束或读取失败则退出
cv::imshow("Video Playback", frame);
if (cv::waitKey(delay) == 'q') break;
}
video.release();
cv::destroyAllWindows();
2. 视频属性查询
使用 VideoCapture::get(propId)
可以获取视频或摄像头流的各种参数:
Property | 参数 ID |
---|---|
当前播放位置(毫秒) | CAP_PROP_POS_MSEC (0) |
视频宽度 | CAP_PROP_FRAME_WIDTH (3) |
视频高度 | CAP_PROP_FRAME_HEIGHT (4) |
帧率 | CAP_PROP_FPS (5) |
编解码器 | CAP_PROP_FOURCC (6) |
总帧数 | CAP_PROP_FRAME_COUNT (7) |
返回图像格式 | CAP_PROP_FORMAT (8) |
摄像头专属属性 | |
亮度 | CAP_PROP_BRIGHTNESS (10) |
对比度 | CAP_PROP_CONTRAST (11) |
饱和度 | CAP_PROP_SATURATION (12) |
色调 | CAP_PROP_HUE (13) |
增益 | CAP_PROP_GAIN (14) |
示例:
cpp
double width = video.get(cv::CAP_PROP_FRAME_WIDTH);
double height = video.get(cv::CAP_PROP_FRAME_HEIGHT);
3. 视频写入与保存
3.1 VideoWriter
类
cpp
// 构造函数
cv::VideoWriter::VideoWriter();
cv::VideoWriter::VideoWriter(const std::string& filename,
int fourcc,
double fps,
cv::Size frameSize,
bool isColor = true);
filename :输出文件路径及名称(带后缀)
fourcc :编码格式,使用 VideoWriter::fourcc('M','J','P','G')
等,-1为自动采用合适的编解码器
fps :输出帧率
frameSize :视频分辨率(宽, 高)
isColor :是否彩色(true
/false
)
3.2 保存摄像头视频
cpp
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main() {
VideoCapture cap(0);
if (!cap.isOpened()) {
cerr << "Error: 无法打开摄像头!" << endl;
return -1;
}
// 读取第一帧以获取格式
Mat frame;
cap.read(frame);
bool isColor = (frame.type() == CV_8UC3);
// 配置 VideoWriter
int codec = VideoWriter::fourcc('M','J','P','G');
double fps = 30.0;
Size size(640, 480);
VideoWriter writer("output.avi", codec, fps, size, isColor);
if (!writer.isOpened()) {
cerr << "Error: 无法创建视频写入器!" << endl;
return -1;
}
// 循环读取并写入
while (1) {
if (!cap.read(frame) || frame.empty()) {
cerr << "Error: 无法读取帧或帧为空!" << endl;
break;
}
writer.write(frame);
imshow("Capture & Save", frame);
if (waitKey(30) == 'q') {
cout << "退出程序" << endl;
break;
}
}
cap.release();
writer.release();
destroyAllWindows();
return 0;
}
4. 窗口交互与滑动条
4.1 创建滑动条
cpp
createTrackbar(trackbarName, windowName, &value, maxCount, callback, userdata=0);
trackbarName :滑动条名称
windowName :所属窗口名称
value :滑动条的当前值(整型指针)
maxCount :滑动条最大值
callback :回调函数,每次滑动时调用
userdata:用户自定义数据指针(可选)
4.2 示例:图像阈值调整
cpp
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int maxValue = 127;
Mat gray, binary;
void callback(int, void*) {
adaptiveThreshold(gray, binary, maxValue,
ADAPTIVE_THRESH_MEAN_C,
THRESH_BINARY, 11, 2);
imshow("Thresh", binary);
}
int main() {
string inputPath = "/home/user/test.jpg";
string outputPath = "/home/user/outputs.jpg";
gray = imread(inputPath, IMREAD_GRAYSCALE);
if (gray.empty()) {
cerr << "Error: 无法读取输入图像!" << endl;
return -1;
}
namedWindow("Thresh");
createTrackbar("MaxValue", "Thresh", &maxValue, 255, onTrackbar);
// 初始显示
onTrackbar(0, nullptr);
while (true) {
char key = (char)waitKey(10);
if (key == 'q') {
imwrite(outputPath, binary);
cout << "结果已保存到: " << outputPath << endl;
break;
}
}
destroyAllWindows();
return 0;
}
回调函数签名 :void callback(int pos, void* userdata);
每次滑动时,pos
为当前滑动位置,可用全局变量或 getTrackbarPos()
获取最新值。
5. 相机图像处理示例
上述代码中实现了利用滑动条调整二值化图像中的阈值,核心在于callback函数对图像的更新。
cpp
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int maxValue = 127;
Mat gray, binary;
void callback(int, void*) {
adaptiveThreshold(gray, binary, maxValue,
ADAPTIVE_THRESH_MEAN_C,
THRESH_BINARY, 11, 2);
imshow("Binary", binary);
}
int main() {
VideoCapture cap(0);
if (!cap.isOpened()) {
cerr << "Error: 无法打开摄像头!" << endl;
return -1;
}
namedWindow("Binary");
createTrackbar("Threshold", "Binary", &maxValue, 255, onTrackbar);
while (1) {
Mat frame;
cap >> frame;
if (frame.empty()) {
cerr << "Error: 捕获帧为空!" << endl;
break;
}
// 转灰度并二值化
cvtColor(frame, gray, COLOR_BGR2GRAY);
onTrackbar(0, nullptr); // 初始更新一次
imshow("Binary", binary);
if (waitKey(30) == 'q') {
destroyWindow("Binary");
break;
}
}
cap.release();
return 0;
}