OpenCV 是计算机视觉领域最常用的开源库,而 C++ 作为其原生支持语言,具有运行效率高、适合工程化开发的特点。本文基于实战代码,从环境搭建核心数据结构基础图像操作面向对象封装,全面讲解 OpenCV C++ 的入门知识,帮助你快速掌握图像编程的核心技能。

一、环境准备与工程搭建

在开始代码编写前,需完成 OpenCV C++ 环境配置,主要步骤如下:

  1. 安装 OpenCV:从 OpenCV 官网 下载对应系统的安装包,解压并配置环境变量(Windows 需添加 opencv/build/x64/vc15/bin 到 Path)。
  2. IDE 配置:以 Visual Studio 为例,新建 C++ 项目后,在 “属性页” 中配置:
    • 包含目录:添加 opencv/build/include
    • 库目录:添加 opencv/build/x64/vc15/lib
    • 链接器输入:添加 opencv_world4xxd.lib(调试版)和 opencv_world4xx.lib(发布版,xx 为版本号)
  3. 验证环境:编译运行基础图像显示代码,确认无链接错误。

二、核心数据结构:Mat 矩阵

cv::Mat 是 OpenCV 存储图像和矩阵的核心数据结构,相当于 “图像容器”,掌握其特性是入门的关键。

1. Mat 的基本属性

cv::Mat src = cv::imread("ocv01.jpg", cv::IMREAD_COLOR);
int cols = src.cols;      // 图像宽度(列数)
int rows = src.rows;      // 图像高度(行数)
int channels = src.channels();  // 通道数(1=灰度图,3=彩色图)
int type = src.type();     // 数据类型(如 CV_8UC3 表示 8 位无符号 3 通道)
  • 通道数:灰度图为 1 通道(仅亮度信息),彩色图(BGR)为 3 通道(蓝、绿、红)。
  • 数据类型CV_[位数][符号][类型]C[通道数],如 CV_8UC3 表示 8 位无符号字符型 3 通道。

2. Mat 的创建与复制

// 方法1:创建指定尺寸和类型的矩阵(初始化为0)
cv::Mat m1(Size(320, 240), CV_8UC3);  // 320x240 的 3 通道矩阵

// 方法2:用 zeros/ones 初始化
cv::Mat m2 = cv::Mat::zeros(Size(8, 8), CV_8UC1);  // 8x8 全 0 矩阵(黑色)
cv::Mat m3 = cv::Mat::ones(Size(8, 8), CV_32FC1);  // 8x8 全 1 矩阵(32位浮点)

// 方法3:复制已有矩阵(深拷贝)
cv::Mat src_copy1, src_copy2;
src.copyTo(src_copy1);  // 推荐方式
src_copy2 = src.clone(); // 等价于 copyTo
  • 深拷贝 vs 浅拷贝cv::Mat dst = src 是浅拷贝(仅复制引用),修改 dst 会影响 srccopyTo 和 clone 是深拷贝(复制数据),两者独立。

三、基础图像操作

1. 图像读取与显示

图像读取是所有视觉程序的第一步,需注意路径合法性和显示窗口的管理。

// 读取图像(IMREAD_COLOR:忽略透明度,返回 3 通道 BGR 图像)
cv::Mat src = cv::imread("ocv01.jpg", cv::IMREAD_COLOR);

// 检查图像是否读取成功
if (src.empty()) {
    printf("无法打开图像!\n");
    return -1;
}

// 创建窗口(WINDOW_FREERATIO:支持自由缩放)
cv::namedWindow("原图", cv::WINDOW_FREERATIO);
cv::imshow("原图", src);  // 显示图像

cv::waitKey(0);           // 等待按键(0 表示无限等待)
cv::destroyAllWindows();   // 销毁所有窗口
  • 路径注意事项:Windows 系统路径用 // 或 /(如 E:/Project/ocv01.jpg),Linux/macOS 用 /;相对路径基于程序运行目录。

2. 颜色空间转换

OpenCV 支持多种颜色空间转换,其中 BGR↔灰度图 和 BGR↔HSV 最常用。

void Test::colorSpace(cv::Mat& image) {
    cv::Mat gray, hsv;
    // BGR 转灰度图(3 通道→1 通道,用于边缘检测、阈值处理)
    cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY);
    // BGR 转 HSV(适合颜色分割,抗光照变化)
    cv::cvtColor(image, hsv, cv::COLOR_BGR2HSV);
    
    cv::imshow("灰度图", gray);
    cv::imshow("HSV图", hsv);
    cv::waitKey(0);
    cv::destroyAllWindows();
}
  • HSV 优势:H(色调)、S(饱和度)、V(明度)分离,比 BGR 更适合颜色过滤(如检测红色物体只需指定 H 范围)。
  • 转换码cvtColor 第三个参数为转换码,完整列表见 OpenCV 文档

3. 像素级访问与操作

直接操作像素是图像处理的基础(如反色、亮度调整),OpenCV 提供两种高效方式:

方式 1:at<> 函数(简单直观,适合小规模操作)
// 遍历像素并反色(灰度图)
for (int row = 0; row < image.rows; row++) {
    for (int col = 0; col < image.cols; col++) {
        // 读取像素值(uchar 适用于 8 位图像)
        uchar pv = image.at<uchar>(row, col);
        // 反色操作(255 - 原像素值)
        image.at<uchar>(row, col) = 255 - pv;
    }
}
方式 2:指针访问(效率高,适合大图像)
// 遍历像素并反色(彩色图,BGR 通道)
for (int row = 0; row < image.rows; row++) {
    // 获取当前行首地址
    uchar* current_row = image.ptr<uchar>(row);
    for (int col = 0; col < image.cols; col++) {
        // 操作 B 通道(注意顺序:B→G→R)
        *current_row++ = 255 - *current_row;
        // 操作 G 通道
        *current_row++ = 255 - *current_row;
        // 操作 R 通道
        *current_row++ = 255 - *current_row;
    }
}
  • 效率对比:指针访问比 at<> 快 10 倍以上,推荐在处理视频帧或大图像时使用。
  • 通道顺序:OpenCV 彩色图默认是 BGR 顺序(而非 RGB),操作时需注意顺序。

4. 图像算术运算

通过算术运算可调整图像亮度、对比度,OpenCV 提供安全的运算函数(自动处理像素溢出)。

void Test::operate(cv::Mat& image) {
    cv::Mat dst;
    // 创建与原图同尺寸的矩阵,所有像素值为 (2,2,2)
    cv::Mat scale = cv::Mat::ones(image.size(), image.type()) * 2;
    // 像素乘法:每个通道值 × 2(整体提亮)
    cv::multiply(image, scale, dst);  // 自动截断超过 255 的值
    
    cv::imshow("亮度提升", dst);
    cv::waitKey(0);
}
  • 常用函数
    • cv::add(src1, src2, dst):像素加法(亮度提升)
    • cv::subtract(src1, src2, dst):像素减法(亮度降低)
    • cv::multiply(src1, src2, dst):像素乘法(对比度提升)
    • cv::addWeighted(src1, alpha, src2, beta, gamma, dst):加权融合(图像叠加)

四、交互工具:轨迹栏(Trackbar)

轨迹栏可实时调整参数(如阈值、亮度),是调试视觉算法的重要工具,需配合回调函数使用。

// 轨迹栏回调函数(必须为全局或静态函数)
static void on_trackbar(int val, void* userdata) {
    std::cout << "当前值:" << val << std::endl;
    // 可通过 userdata 传递图像等数据,实现实时更新
    cv::Mat* img = (cv::Mat*)userdata;
    cv::Mat dst = *img * val / 100.0;  // 用轨迹栏值调整亮度
    cv::imshow("轨迹栏演示", dst);
}

void Test::createTrackbar() {
    cv::Mat img = cv::imread("ocv01.jpg");
    cv::namedWindow("轨迹栏演示", cv::WINDOW_FREERATIO);
    
    // 创建轨迹栏:参数(名称,窗口名,初始值,最大值,回调函数,用户数据)
    cv::createTrackbar("亮度", "轨迹栏演示", 100, 200, on_trackbar, &img);
    
    cv::imshow("轨迹栏演示", img);
    cv::waitKey(0);
    cv::destroyAllWindows();
}
  • 回调函数:必须符合 void(*)(int, void*) 格式,第一个参数为当前轨迹栏值,第二个参数为用户自定义数据(如图像指针)。
  • 常见用途:实时调整 Canny 边缘检测阈值、HSV 颜色分割范围、滤波核大小等。

五、面向对象封装:Test 类设计

将功能封装到类中是工程化开发的核心思想,可提升代码复用性和可维护性。

1. 类结构设计(Test.h)

#pragma once
#include <opencv2/opencv.hpp>
using namespace cv;

class Test {
public:
    void colorSpace(Mat& image);   // 颜色空间转换
    void createMat(Mat& image);    // 矩阵创建与复制
    void getPixel(Mat& image);     // 像素操作
    void operate(Mat& image);      // 算术运算
    void createTrackbar();         // 轨迹栏交互
};

2. 封装优势

  • 模块化:每个函数负责单一功能(如 colorSpace 仅处理颜色转换),逻辑清晰。
  • 可扩展:新增功能(如边缘检测)只需添加成员函数,不影响现有代码。
  • 易维护:集中管理所有图像操作,便于调试和修改。

六、实战技巧与常见问题

1. 效率优化

  • 大图像处理前先缩小(cv::pyrDown),减少计算量。
  • 循环中用指针访问像素,避免 at<> 函数的性能损耗。
  • 尽量使用 OpenCV 内置函数(如 cv::filter2D),底层已优化。

2. 常见错误

  • 图像路径错误imread 失败返回空矩阵,需用 empty() 检查。
  • 通道数不匹配:对彩色图用灰度图的处理逻辑(如 at<uchar>)会导致崩溃。
  • 像素溢出:手动运算(如 pixel * 2)需确保结果 ≤ 255,推荐用 cv::multiply

3. 调试技巧

  • 用 imshow 显示中间结果,观察每一步处理是否正确。
  • 打印矩阵属性(rowscolschannels),确认图像尺寸符合预期。
  • 对轨迹栏回调函数,用 cout 输出参数值,验证交互逻辑。

七、总结与进阶方向

本文通过实战代码讲解了 OpenCV C++ 的核心基础:Mat 数据结构、图像读写、颜色空间转换、像素操作、算术运算和轨迹栏交互,以及面向对象封装思想。这些知识是计算机视觉开发的基石,后续可向以下方向进阶:

  1. 图像处理:学习滤波(高斯滤波、中值滤波)、边缘检测(Canny、Sobel)、形态学操作(腐蚀、膨胀)。
  2. 目标检测:掌握轮廓提取(findContours)、特征匹配(matchShapes)、Haar 级联分类器。
  3. 视频处理:使用 cv::VideoCapture 读取视频,对帧进行实时处理。
  4. 性能优化:学习多线程、GPU 加速(cv::cuda 模块),提升处理速度。

通过持续实践,可逐步掌握 OpenCV 在工业检测、机器人视觉、医学影像等领域的应用。

Logo

昇腾计算产业是基于昇腾系列(HUAWEI Ascend)处理器和基础软件构建的全栈 AI计算基础设施、行业应用及服务,https://devpress.csdn.net/organization/setting/general/146749包括昇腾系列处理器、系列硬件、CANN、AI计算框架、应用使能、开发工具链、管理运维工具、行业应用及服务等全产业链

更多推荐