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;
}
相关推荐
小黄人软件3 小时前
粘贴助手C++版 支持 Windows 7 / 10 / 11 不会出现缺少api-ms-win-core-path-11-1-0.dll
开发语言·c++·windows
有毒的教程3 小时前
Dev-C++ 避免爆栈(Stack Overflow)完整方案
c++·算法·深度优先
程序员老陆3 小时前
从汇编层面理解 C++ 多线程
开发语言·c++·程序设计
IOT-Power3 小时前
模板方法 + 策略模式
开发语言·c++
深圳老胡4 小时前
STM32F4 OTA升级:单App与双App方案优缺点对比
笔记·stm32·单片机·代码规范
fpcc12 小时前
c++编程实践—堆和栈越界调试
c++
yi01112 小时前
LeetCode 219:存在重复元素 II——哈希表记录“最近一次出现的位置”
数据结构·人工智能·笔记·python·算法·leetcode·哈希表
志尊宝13 小时前
Vue3 零基础每日笔记(073):keep-alive 页面缓存实战——列表页返回不丢状态
vue.js·笔记·缓存·#vue #前端 #前端开发·#javascript·#vue.js
weiabc14 小时前
MSYS2 UCRT64 + g++ C++ 中文输出乱码 完整全过程
c++
灯澜忆梦15 小时前
【面向对象编程C++】| 基础语法
java·c++·算法