Opencv4 c++ 自用笔记 03 滑动条、相机与视频操作

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;
}
相关推荐
快乐zbc5 小时前
【C++ 基础】:给定一个指针 p,你能判断它是否指向合法的对象吗?
c++
sulikey6 小时前
C++类和对象(下):初始化列表、static、友元、内部类等核心特性详解
c++·static·初始化列表·友元·匿名对象·内部类·编译器优化
遇到困难睡大觉哈哈7 小时前
Harmony os——ArkTS 语言笔记(四):类、对象、接口和抽象类
java·笔记·spring·harmonyos·鸿蒙
oioihoii7 小时前
C++网络编程:从Socket混乱到优雅Reactor的蜕变之路
开发语言·网络·c++
程序员东岸7 小时前
《数据结构——排序(中)》选择与交换的艺术:从直接选择到堆排序的性能跃迁
数据结构·笔记·算法·leetcode·排序算法
笨鸟要努力7 小时前
Qt C++ windows 设置系统时间
c++·windows·qt
神仙别闹7 小时前
基于C++实现(控制台)应用递推法完成经典型算法的应用
开发语言·c++·算法
Ccjf酷儿7 小时前
操作系统 蒋炎岩 4.数学视角的操作系统
笔记
yinchao1638 小时前
EMC设计经验-笔记
笔记
黑客思维者8 小时前
LLM底层原理学习笔记:Adam优化器为何能征服巨型模型成为深度学习的“速度与稳定之王”
笔记·深度学习·学习·llm·adam优化器