Opencv4 c++ 自用笔记 03 滑动条、相机与视频操作
1. 相机与视频操作
1.1 打开视频/相机
OpenCV 中 imread()
只能读取静态图像,若要读取视频文件或摄像头流,需要使用 VideoCapture
类:
// 构造函数
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 读取并播放视频
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; // 读取下一帧到 frameif (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) |
示例:
double width = video.get(cv::CAP_PROP_FRAME_WIDTH);
double height = video.get(cv::CAP_PROP_FRAME_HEIGHT);
3. 视频写入与保存
3.1 VideoWriter
类
// 构造函数
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 保存摄像头视频
#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);// 配置 VideoWriterint 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 创建滑动条
createTrackbar(trackbarName, windowName, &value, maxCount, callback, userdata=0);
trackbarName:滑动条名称
windowName:所属窗口名称
value:滑动条的当前值(整型指针)
maxCount:滑动条最大值
callback:回调函数,每次滑动时调用
userdata:用户自定义数据指针(可选)
4.2 示例:图像阈值调整
#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函数对图像的更新。
#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;
}