现在位置: 首页 > OpenCV 教程 > 正文

C++ OpenCV 机器学习与深度学习

OpenCV 不仅支持传统的计算机视觉任务,还提供了丰富的机器学习和深度学习功能,通过这些功能,可以实现图像分类、目标检测、语义分割等复杂任务。

  • 机器学习:OpenCV 提供了多种传统机器学习算法,如 KNN、SVM、决策树等。

  • 深度学习:OpenCV 的 DNN 模块支持加载和运行预训练的深度学习模型(如 TensorFlow、PyTorch、Caffe 等)。

机器学习与深度学习的应用场景

图像分类:

  • 使用机器学习或深度学习模型对图像进行分类。

  • 应用场景:医学影像分类、工业质检等。

目标检测:

  • 使用深度学习模型检测图像中的目标。

  • 应用场景:自动驾驶、安防监控等。

语义分割:

  • 使用深度学习模型对图像中的每个像素进行分类。

  • 应用场景:医学影像分析、遥感图像分析等。

常用机器学习算法

OpenCV 提供了以下常见的机器学习算法:

算法描述
KNNK 近邻算法,用于分类和回归。
SVM支持向量机,用于分类和回归。
决策树基于树结构的分类和回归算法。
随机森林基于多个决策树的集成学习算法。
K-Means聚类算法,用于将数据分为多个簇。

K 均值聚类(K-Means)

K 均值聚类是一种无监督学习算法,主要用于将数据集划分为K个簇。每个簇由距离其中心点最近的样本组成。

K-Means 算法的核心思想是通过迭代优化簇中心,使得每个样本点到其所属簇中心的距离最小。

实现步骤:

  1. 初始化:随机选择K个样本作为初始簇中心。
  2. 分配:将每个样本分配到距离最近的簇中心。
  3. 更新:重新计算每个簇的中心点。
  4. 迭代:重复步骤2和3,直到簇中心不再变化或达到最大迭代次数。

OpenCV 中的 K-Means:

实例

#include <opencv2/opencv.hpp>
#include <iostream>

int main() {
    // 生成一些随机数据
    cv::Mat data(100, 2, CV_32F);
    cv::randu(data, cv::Scalar(0, 0), cv::Scalar(100, 100));

    // 设置K值和迭代条件
    int K = 3;
    cv::Mat labels, centers;
    cv::kmeans(data, K, labels, cv::TermCriteria(cv::TermCriteria::EPS + cv::TermCriteria::MAX_ITER, 10, 1.0), 3, cv::KMEANS_PP_CENTERS, centers);

    // 输出结果
    std::cout << "Labels: " << labels << std::endl;
    std::cout << "Centers: " << centers << std::endl;

    return 0;
}

以上代码中,我们生成了100个二维数据点,并使用K-Means算法将其分为3个簇。cv::kmeans函数的参数包括数据、簇数、标签、终止条件等。

支持向量机(SVM)

支持向量机(SVM)是一种有监督学习算法,主要用于分类和回归任务。

SVM 的核心思想是找到一个超平面,使得不同类别的样本点之间的间隔最大化。

实现步骤:

  1. 训练:通过训练数据找到一个最优超平面。
  2. 预测:使用训练好的模型对新数据进行分类。

OpenCV中的SVM:

实例

#include <opencv2/opencv.hpp>
#include <iostream>

int main() {
    // 生成一些训练数据
    cv::Mat trainData = (cv::Mat_<float>(4, 2) << 1, 1, 1, 2, 2, 1, 2, 2);
    cv::Mat labels = (cv::Mat_<int>(4, 1) << 1, 1, -1, -1);

    // 创建SVM模型
    cv::Ptr<cv::ml::SVM> svm = cv::ml::SVM::create();
    svm->setKernel(cv::ml::SVM::LINEAR);
    svm->setType(cv::ml::SVM::C_SVC);
    svm->setC(1);

    // 训练模型
    svm->train(trainData, cv::ml::ROW_SAMPLE, labels);

    // 预测新数据
    cv::Mat testData = (cv::Mat_<float>(1, 2) << 1.5, 1.5);
    float response = svm->predict(testData);
    std::cout << "Predicted label: " << response << std::endl;

    return 0;
}

以上代码中,我们使用 SVM 对二维数据进行分类。

cv::ml::SVM::create() 用于创建 SVM 模型,train 方法用于训练模型,predict方法用于预测新数据的类别。

主成分分析(PCA)

主成分分析(PCA)是一种降维技术,主要用于减少数据集的维度,同时保留数据的主要特征。

PCA通过线性变换将原始数据映射到一个新的坐标系中,使得数据在新坐标系中的方差最大化。

实现步骤:

  1. 计算协方差矩阵:计算数据集的协方差矩阵。
  2. 特征值分解:对协方差矩阵进行特征值分解,得到特征向量和特征值。
  3. 选择主成分:选择前K个最大的特征值对应的特征向量作为主成分。
  4. 数据投影:将原始数据投影到主成分上,得到降维后的数据。

OpenCV中的PCA:

实例

#include <opencv2/opencv.hpp>
#include <iostream>

int main() {
    // 生成一些数据
    cv::Mat data = (cv::Mat_<float>(4, 2) << 1, 2, 2, 3, 3, 4, 4, 5);

    // 创建PCA对象
    cv::PCA pca(data, cv::Mat(), cv::PCA::DATA_AS_ROW, 1);

    // 投影数据
    cv::Mat projected = pca.project(data);
    std::cout << "Projected data: " << projected << std::endl;

    return 0;
}

以上代码中,我们使用PCA对二维数据进行降维。cv::PCA类的构造函数接受输入数据、均值向量、数据排列方式和保留的主成分数。project方法用于将数据投影到主成分上。


OpenCV 与深度学习

随着深度学习在计算机视觉领域的广泛应用,OpenCV 也提供了对深度学习的支持。

通过 OpenCV 的 DNN 模块,开发者可以加载预训练的深度学习模型,并进行图像分类、目标检测、语义分割等任务。

加载预训练的深度学习模型(DNN 模块)

OpenCV 的 DNN 模块支持加载多种深度学习框架(如TensorFlow、Caffe、PyTorch等)的预训练模型。

通过 DNN 模块,开发者可以轻松地将深度学习模型集成到 C++ 应用程序中。

加载模型:

实例

#include <opencv2/opencv.hpp>
#include <opencv2/dnn.hpp>
#include <iostream>

int main() {
    // 加载预训练的Caffe模型
    cv::dnn::Net net = cv::dnn::readNetFromCaffe("deploy.prototxt", "model.caffemodel");

    // 检查模型是否加载成功
    if (net.empty()) {
        std::cerr << "Failed to load model!" << std::endl;
        return -1;
    }

    std::cout << "Model loaded successfully!" << std::endl;

    return 0;
}

以上代码中,我们使用cv::dnn::readNetFromCaffe 函数加载了一个 Caffe 模型。deploy.prototxt 是模型的配置文件,model.caffemodel是 模型的权重文件。

图像分类、目标检测、语义分割

OpenCV的DNN模块支持多种深度学习任务,包括图像分类、目标检测和语义分割。以下是一个简单的图像分类示例:

图像分类:

实例

#include <opencv2/opencv.hpp>
#include <opencv2/dnn.hpp>
#include <iostream>

int main() {
    // 加载预训练的Caffe模型
    cv::dnn::Net net = cv::dnn::readNetFromCaffe("deploy.prototxt", "model.caffemodel");

    // 加载图像
    cv::Mat image = cv::imread("image.jpg");
    if (image.empty()) {
        std::cerr << "Failed to load image!" << std::endl;
        return -1;
    }

    // 预处理图像
    cv::Mat blob = cv::dnn::blobFromImage(image, 1.0, cv::Size(224, 224), cv::Scalar(104, 117, 123));

    // 设置输入
    net.setInput(blob);

    // 前向传播
    cv::Mat prob = net.forward();

    // 获取分类结果
    cv::Point classIdPoint;
    double confidence;
    cv::minMaxLoc(prob.reshape(1, 1), 0, &confidence, 0, &classIdPoint);
    int classId = classIdPoint.x;

    std::cout << "Class ID: " << classId << ", Confidence: " << confidence << std::endl;

    return 0;
}

以上代码中,我们加载了一个 Caffe 模型,并对输入图像进行分类。cv::dnn::blobFromImage 函数用于将图像转换为模型输入格式,net.forward() 用于执行前向传播,cv::minMaxLoc 用于获取分类结果。

使用 OpenCV 运行 YOLO、SSD 等模型

OpenCV 的 DNN 模块还支持运行 YOLO(You Only Look Once)和SSD(Single Shot MultiBox Detector)等目标检测模型。

以下是一个使用 YOLO 模型进行目标检测的示例:

YOLO目标检测:

实例

#include <opencv2/opencv.hpp>
#include <opencv2/dnn.hpp>
#include <iostream>

int main() {
    // 加载YOLO模型
    cv::dnn::Net net = cv::dnn::readNetFromDarknet("yolov3.cfg", "yolov3.weights");

    // 加载图像
    cv::Mat image = cv::imread("image.jpg");
    if (image.empty()) {
        std::cerr << "Failed to load image!" << std::endl;
        return -1;
    }

    // 预处理图像
    cv::Mat blob = cv::dnn::blobFromImage(image, 1/255.0, cv::Size(416, 416), cv::Scalar(0, 0, 0), true, false);

    // 设置输入
    net.setInput(blob);

    // 前向传播
    std::vector<cv::Mat> outs;
    net.forward(outs, net.getUnconnectedOutLayersNames());

    // 解析检测结果
    for (size_t i = 0; i < outs.size(); ++i) {
        float* data = (float*)outs[i].data;
        for (int j = 0; j < outs[i].rows; ++j, data += outs[i].cols) {
            cv::Mat scores = outs[i].row(j).colRange(5, outs[i].cols);
            cv::Point classIdPoint;
            double confidence;
            cv::minMaxLoc(scores, 0, &confidence, 0, &classIdPoint);
            if (confidence > 0.5) {
                int centerX = (int)(data[0] * image.cols);
                int centerY = (int)(data[1] * image.rows);
                int width = (int)(data[2] * image.cols);
                int height = (int)(data[3] * image.rows);
                int left = centerX - width / 2;
                int top = centerY - height / 2;

                cv::rectangle(image, cv::Point(left, top), cv::Point(left + width, top + height), cv::Scalar(0, 255, 0), 2);
            }
        }
    }

    // 显示结果
    cv::imshow("Detection", image);
    cv::waitKey(0);

    return 0;
}

以上代码中,我们加载了一个YOLO模型,并对输入图像进行目标检测。cv::dnn::readNetFromDarknet函数用于加载YOLO模型,net.forward用于执行前向传播,cv::rectangle用于绘制检测框。