C++ OpenCV 机器学习与深度学习
OpenCV 不仅支持传统的计算机视觉任务,还提供了丰富的机器学习和深度学习功能,通过这些功能,可以实现图像分类、目标检测、语义分割等复杂任务。
机器学习:OpenCV 提供了多种传统机器学习算法,如 KNN、SVM、决策树等。
深度学习:OpenCV 的 DNN 模块支持加载和运行预训练的深度学习模型(如 TensorFlow、PyTorch、Caffe 等)。
机器学习与深度学习的应用场景
图像分类:
使用机器学习或深度学习模型对图像进行分类。
应用场景:医学影像分类、工业质检等。
目标检测:
使用深度学习模型检测图像中的目标。
应用场景:自动驾驶、安防监控等。
语义分割:
使用深度学习模型对图像中的每个像素进行分类。
应用场景:医学影像分析、遥感图像分析等。
常用机器学习算法
OpenCV 提供了以下常见的机器学习算法:
算法 | 描述 |
---|---|
KNN | K 近邻算法,用于分类和回归。 |
SVM | 支持向量机,用于分类和回归。 |
决策树 | 基于树结构的分类和回归算法。 |
随机森林 | 基于多个决策树的集成学习算法。 |
K-Means | 聚类算法,用于将数据分为多个簇。 |
K 均值聚类(K-Means)
K 均值聚类是一种无监督学习算法,主要用于将数据集划分为K个簇。每个簇由距离其中心点最近的样本组成。
K-Means 算法的核心思想是通过迭代优化簇中心,使得每个样本点到其所属簇中心的距离最小。
实现步骤:
- 初始化:随机选择K个样本作为初始簇中心。
- 分配:将每个样本分配到距离最近的簇中心。
- 更新:重新计算每个簇的中心点。
- 迭代:重复步骤2和3,直到簇中心不再变化或达到最大迭代次数。
OpenCV 中的 K-Means:
实例
#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 的核心思想是找到一个超平面,使得不同类别的样本点之间的间隔最大化。
实现步骤:
- 训练:通过训练数据找到一个最优超平面。
- 预测:使用训练好的模型对新数据进行分类。
OpenCV中的SVM:
实例
#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通过线性变换将原始数据映射到一个新的坐标系中,使得数据在新坐标系中的方差最大化。
实现步骤:
- 计算协方差矩阵:计算数据集的协方差矩阵。
- 特征值分解:对协方差矩阵进行特征值分解,得到特征向量和特征值。
- 选择主成分:选择前K个最大的特征值对应的特征向量作为主成分。
- 数据投影:将原始数据投影到主成分上,得到降维后的数据。
OpenCV中的PCA:
实例
#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/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/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/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
用于绘制检测框。