【opencv】示例-points_classifier.cpp 使用不同机器学习算法在二维空间中对点集进行分类...

94d0054ae0ba0d7ff35aadbf072116ea.png

4db1625a5a1856eaa4e9fdee0c7e235d.png

bdd39b4a84bdd382b384c669847bc528.png

#include "opencv2/core.hpp" // 包含OpenCV核心功能的文件
#include "opencv2/imgproc.hpp" // 包含OpenCV图像处理功能的文件
#include "opencv2/ml.hpp" // 包含OpenCV机器学习模块的文件
#include "opencv2/highgui.hpp" // 包含OpenCV用户界面组件的文件#include <stdio.h>using namespace std; // 使用标准命名空间
using namespace cv; // 使用OpenCV命名空间
using namespace cv::ml; // 使用OpenCV机器学习命名空间const Scalar WHITE_COLOR = Scalar(255,255,255); // 定义一个常量表示白色
const string winName = "points"; // 窗口名
const int testStep = 5; // 测试步长Mat img, imgDst; // 定义两个图像矩阵,img为原图,imgDst为显示结果用
RNG rng; // 随机数生成器vector<Point> trainedPoints; // 存储训练用的点
vector<int> trainedPointsMarkers; // 存储训练点所属的分类标记
const int MAX_CLASSES = 2; // 最大分类数
vector<Vec3b> classColors(MAX_CLASSES); // 存储每个分类的颜色
int currentClass = 0; // 当前选择的分类
vector<int> classCounters(MAX_CLASSES); // 存储每个分类的计数器// 定义一些预处理器标志以确定哪些分类器将会被使用
#define _NBC_ 1 // 正态贝叶斯分类器
#define _KNN_ 1 // K最近邻分类器
#define _SVM_ 1 // 支持向量机
#define _DT_  1 // 决策树
#define _BT_  1 // ADA提升
#define _GBT_ 0 // 梯度提升树
#define _RF_  1 // 随机森林
#define _ANN_ 1 // 人工神经网络
#define _EM_  1 // 期望最大化// 鼠标事件回调函数
static void on_mouse( int event, int x, int y, int /*flags*/, void* )
{if( img.empty() )return;int updateFlag = 0; // 更新标志if( event == EVENT_LBUTTONUP ) // 当鼠标左键松开时{trainedPoints.push_back( Point(x,y) ); // 添加一个点到训练集中trainedPointsMarkers.push_back( currentClass ); // 为这个点标记当前的类别classCounters[currentClass]++; // 相应类别的计数器加一updateFlag = true; // 设置更新标志为真}// 绘制if( updateFlag ){img = Scalar::all(0); // 将图像设置为黑色// 绘制点for( size_t i = 0; i < trainedPoints.size(); i++ ){Vec3b c = classColors[trainedPointsMarkers[i]]; // 获取点的颜色circle( img, trainedPoints[i], 5, Scalar(c), -1 ); // 在图像上用这个颜色绘制一个圆}imshow( winName, img ); // 显示图像}
}// 准备训练样本的辅助函数
static Mat prepare_train_samples(const vector<Point>& pts)
{Mat samples;Mat(pts).reshape(1, (int)pts.size()).convertTo(samples, CV_32F); // 将Point集合转换为Mat格式并改变数据类型return samples;
}// 准备训练数据的辅助函数
static Ptr<TrainData> prepare_train_data()
{Mat samples = prepare_train_samples(trainedPoints); // 准备样本return TrainData::create(samples, ROW_SAMPLE, Mat(trainedPointsMarkers)); // 创建训练数据对象
}// 使用模型进行预测并绘制结果的辅助函数
static void predict_and_paint(const Ptr<StatModel>& model, Mat& dst)
{Mat testSample( 1, 2, CV_32FC1 ); // 创建一个包含两个float类型数值的测试样本for( int y = 0; y < img.rows; y += testStep ) // 按步长遍历图像所有的y坐标{for( int x = 0; x < img.cols; x += testStep ) // 按步长遍历图像所有的x坐标{testSample.at<float>(0) = (float)x; // 设置样本x值testSample.at<float>(1) = (float)y; // 设置样本y值int response = (int)model->predict( testSample ); // 使用模型进行预测dst.at<Vec3b>(y, x) = classColors[response]; // 根据预测结果上色}}
}// 下面的一系列#if预处理器指令是为了在最终的程序中包含或者排除某些分类器的相关代码#if _NBC_
// 使用正态贝叶斯分类器找出决策边界
static void find_decision_boundary_NBC()
{// 学习分类器Ptr<NormalBayesClassifier> normalBayesClassifier = StatModel::train<NormalBayesClassifier>(prepare_train_data());// 预测并绘制决策边界predict_and_paint(normalBayesClassifier, imgDst);
}
#endif#if _KNN_
// 使用K最近邻分类器找出决策边界,并设置K值
static void find_decision_boundary_KNN( int K )
{// 创建KNN对象Ptr<KNearest> knn = KNearest::create();// 设置K值knn->setDefaultK(K);// 设置为分类模式knn->setIsClassifier(true);// 训练模型knn->train(prepare_train_data());// 预测并绘制决策边界predict_and_paint(knn, imgDst);
}
#endif#if _SVM_
// 使用支持向量机找出决策边界,并设置错误惩罚参数C
static void find_decision_boundary_SVM( double C )
{// 创建SVM对象Ptr<SVM> svm = SVM::create();// 设置SVM类型为C-SVCsvm->setType(SVM::C_SVC);// 设置核函数为多项式核svm->setKernel(SVM::POLY); // 也可以选用线性核SVM::LINEAR;// 设置多项式核参数degreesvm->setDegree(0.5);// 设置核函数参数gammasvm->setGamma(1);// 设置核函数参数coef0svm->setCoef0(1);// 设置SVM参数Nusvm->setNu(0.5);// 设置SVM参数Psvm->setP(0);// 设置训练算法的终止条件svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS, 1000, 0.01));// 设置错误惩罚参数Csvm->setC(C);// 训练模型svm->train(prepare_train_data());// 预测并绘制决策边界predict_and_paint(svm, imgDst);// 绘制支持向量Mat sv = svm->getSupportVectors();for( int i = 0; i < sv.rows; i++ ){const float* supportVector = sv.ptr<float>(i);circle( imgDst, Point(saturate_cast<int>(supportVector[0]),saturate_cast<int>(supportVector[1])), 5, Scalar(255,255,255), -1 );}
}
#endif#if _DT_
// 使用决策树找出决策边界
static void find_decision_boundary_DT()
{// 创建决策树对象Ptr<DTrees> dtree = DTrees::create();// 设置决策树最大深度dtree->setMaxDepth(8);// 设置节点最小样本数dtree->setMinSampleCount(2);// 设置是否使用代理分割dtree->setUseSurrogates(false);// 设置交叉验证折数dtree->setCVFolds(0); // 0表示不进行交叉验证// 设置是否使用1SE规则dtree->setUse1SERule(false);// 设置是否修剪被减枝的决策树dtree->setTruncatePrunedTree(false);// 训练模型dtree->train(prepare_train_data());// 预测并绘制决策边界predict_and_paint(dtree, imgDst);
}
#endif#if _BT_
// 使用提升树算法找出决策边界
static void find_decision_boundary_BT()
{// 创建提升树对象Ptr<Boost> boost = Boost::create();// 设置提升类型boost->setBoostType(Boost::DISCRETE);// 设置弱分类器数量boost->setWeakCount(100);// 设置权重修剪率boost->setWeightTrimRate(0.95);// 设置最大深度boost->setMaxDepth(2);// 设置是否使用代理分割boost->setUseSurrogates(false);// 设置类别先验概率boost->setPriors(Mat());// 训练模型boost->train(prepare_train_data());// 预测并绘制决策边界predict_and_paint(boost, imgDst);
}
#endif#if _GBT_
// 使用梯度提升树算法找出决策边界
static void find_decision_boundary_GBT()
{// 设置GBT模型参数GBTrees::Params params( GBTrees::DEVIANCE_LOSS, // 损失函数类型100, // 弱分类器数量0.1f, // 收缩率1.0f, // 子采样比例2, // 最大深度false // 是否使用代理分割);// 创建梯度提升树对象Ptr<GBTrees> gbtrees = StatModel::train<GBTrees>(prepare_train_data(), params);// 预测并绘制决策边界predict_and_paint(gbtrees, imgDst);
}
#endif#if _RF_
// 使用随机森林算法找出决策边界
static void find_decision_boundary_RF()
{// 创建随机森林对象Ptr<RTrees> rtrees = RTrees::create();// 设置最大深度rtrees->setMaxDepth(4);// 设置节点最小样本数rtrees->setMinSampleCount(2);// 设置回归精度rtrees->setRegressionAccuracy(0.f);// 设置是否使用代理分割rtrees->setUseSurrogates(false);// 设置类别数量rtrees->setMaxCategories(16);// 设置类别先验概率rtrees->setPriors(Mat());// 设置是否计算变量重要性rtrees->setCalculateVarImportance(false);// 设置活跃变量数量rtrees->setActiveVarCount(1);// 设置训练算法的终止条件rtrees->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 5, 0));// 训练模型rtrees->train(prepare_train_data());// 预测并绘制决策边界predict_and_paint(rtrees, imgDst);
}
#endif#if _ANN_
// 使用人工神经网络找出决策边界
static void find_decision_boundary_ANN( const Mat& layer_sizes )
{// 创建类别标签矩阵Mat trainClasses = Mat::zeros( (int)trainedPoints.size(), (int)classColors.size(), CV_32FC1 );for( int i = 0; i < trainClasses.rows; i++ ){trainClasses.at<float>(i, trainedPointsMarkers[i]) = 1.f; // 对应类别置为1}// 准备训练样本Mat samples = prepare_train_samples(trainedPoints);// 创建训练数据对象Ptr<TrainData> tdata = TrainData::create(samples, ROW_SAMPLE, trainClasses);// 创建人工神经网络对象Ptr<ANN_MLP> ann = ANN_MLP::create();// 设置网络层大小ann->setLayerSizes(layer_sizes);// 设置激活函数ann->setActivationFunction(ANN_MLP::SIGMOID_SYM, 1, 1);// 设置训练算法的终止条件ann->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS, 300, FLT_EPSILON));// 设置训练方法,这里使用反向传播算法ann->setTrainMethod(ANN_MLP::BACKPROP, 0.001);// 训练模型ann->train(tdata);// 预测并绘制决策边界predict_and_paint(ann, imgDst);
}
#endif#if _EM_
// 使用期望最大化算法找出决策边界
static void find_decision_boundary_EM()
{img.copyTo(imgDst); // 将当前图像复制给目标图像Mat samples = prepare_train_samples(trainedPoints); // 准备训练样本int i, j, nmodels = (int)classColors.size(); // 分类数量vector<Ptr<EM>> em_models(nmodels); // 存储每个类别对应的EM模型Mat modelSamples;// 遍历所有分类来训练EM模型for (i = 0; i < nmodels; i++){const int componentCount = 3; // 每个模型的分量数modelSamples.release(); // 释放模型样本空间// 提取当前类别的所有样本for (j = 0; j < samples.rows; j++){if (trainedPointsMarkers[j] == i)modelSamples.push_back(samples.row(j));}// 训练模型if (!modelSamples.empty()) // 如果当前类别有样本{Ptr<EM> em = EM::create(); // 创建EM模型em->setClustersNumber(componentCount); // 设置聚类数量em->setCovarianceMatrixType(EM::COV_MAT_DIAGONAL); // 设置协方差类型为对角线em->trainEM(modelSamples, noArray(), noArray(), noArray()); // 训练EM模型em_models[i] = em; // 存储训练好的模型}}// 使用贝叶斯分类器对坐标平面的点进行分类// y(x) = arg max_i=1_modelsCount likelihoods_i(x)Mat testSample(1, 2, CV_32FC1); // 测试样本Mat logLikelihoods(1, nmodels, CV_64FC1, Scalar(-DBL_MAX)); // 存储每个样本的概率// 遍历图像上的每个点for (int y = 0; y < img.rows; y += testStep) {for (int x = 0; x < img.cols; x += testStep){testSample.at<float>(0) = (float)x;testSample.at<float>(1) = (float)y;for (i = 0; i < nmodels; i++){if (!em_models[i].empty()) // 如果EM模型有效// 计算测试样本的对数似然概率logLikelihoods.at<double>(i) = em_models[i]->predict2(testSample, noArray())[0];}Point maxLoc;// 找到概率最大的类别minMaxLoc(logLikelihoods, 0, 0, 0, &maxLoc);// 将图像对应位置染成最大概率类别的颜色imgDst.at<Vec3b>(y, x) = classColors[maxLoc.x];}}
}
#endifint main()
{cout << "Use:" << endl<< "  key '0' .. '1' - switch to class #n" << endl<< "  left mouse button - to add new point;" << endl<< "  key 'r' - to run the ML model;" << endl<< "  key 'i' - to init (clear) the data." << endl << endl;cv::namedWindow("points", 1); // 创建一个名为"points"的窗口img.create(480, 640, CV_8UC3); // 创建一个大小为480x640的图像imgDst.create(480, 640, CV_8UC3); // 创建一个用于显示结果的图像imshow("points", img); // 显示原始图像setMouseCallback("points", on_mouse); // 设置鼠标回调函数,response to mouse events// 初始化两个分类的颜色,第一个分类颜色为绿色,第二个分类颜色为红色classColors[0] = Vec3b(0, 255, 0);classColors[1] = Vec3b(0, 0, 255);// 主循环for (;;){char key = (char)waitKey(); // 等待按键if (key == 27) break; // 如果按键是ESC,退出程序if (key == 'i') // 初始化{img = Scalar::all(0); // 清除图像trainedPoints.clear(); // 清除训练点trainedPointsMarkers.clear(); // 清除训练点标记classCounters.assign(MAX_CLASSES, 0); // 重置类别计数器imshow(winName, img); // 显示清除后的图像}if (key == '0' || key == '1') // 切换类别{currentClass = key - '0'; // 根据按键设置当前类别}if (key == 'r') // 运行机器学习模型{double minVal = 0;minMaxLoc(classCounters, &minVal, 0, 0, 0); // 检查每个类别至少有一个点if (minVal == 0){printf("each class should have at least 1 point\n"); // 否则提示并继续循环continue;}img.copyTo(imgDst); // 将图像复制到目标图像上
#if _NBC_find_decision_boundary_NBC(); // 执行NBC算法找决策边界imshow("NormalBayesClassifier", imgDst); // 显示NBC的结果
#endif
#if _KNN_
// 使用K-最近邻算法找出决策边界,这里展示了两种不同的K值find_decision_boundary_KNN(3); // 使用k值为3来找到决策边界imshow("kNN", imgDst); // 显示k值为3的结果find_decision_boundary_KNN(15); // 使用k值为15来找到决策边界imshow("kNN2", imgDst); // 显示k值为15的结果
#endif#if _SVM_
// 使用支持向量机算法找出决策边界find_decision_boundary_SVM(1); // 使用C值为1来找到决策边界imshow("classificationSVM1", imgDst); // 显示C值为1的结果find_decision_boundary_SVM(10); // 使用C值为10来找到决策边界imshow("classificationSVM2", imgDst); // 显示C值为10的结果
#endif#if _DT_
// 使用决策树算法找出决策边界find_decision_boundary_DT(); // 执行决策树算法找到决策边界imshow("DT", imgDst); // 显示决策树的结果
#endif#if _BT_
// 使用提升树算法找出决策边界find_decision_boundary_BT(); // 执行提升树算法找到决策边界imshow("BT", imgDst); // 显示提升树的结果
#endif#if _GBT_
// 使用梯度提升树算法找出决策边界find_decision_boundary_GBT(); // 执行梯度提升树算法找到决策边界imshow("GBT", imgDst); // 显示梯度提升树的结果
#endif#if _RF_
// 使用随机森林算法找出决策边界find_decision_boundary_RF(); // 执行随机森林算法找到决策边界imshow("RF", imgDst); // 显示随机森林的结果
#endif#if _ANN_
// 使用人工神经网络算法找出决策边界Mat layer_sizes1(1, 3, CV_32SC1); // 设置神经网络的层数和每层的节点数layer_sizes1.at<int>(0) = 2; // 输入层节点数layer_sizes1.at<int>(1) = 5; // 隐藏层节点数layer_sizes1.at<int>(2) = (int)classColors.size(); // 输出层节点数,即类别数find_decision_boundary_ANN(layer_sizes1); // 执行人工神经网络算法找到决策边界imshow("ANN", imgDst); // 显示人工神经网络的结果
#endif
#if _EM_// 执行EM算法找决策边界find_decision_boundary_EM();// 显示EM算法的结果imshow("EM", imgDst);
#endif}}return 0; // 程序结束
}

这段代码实现了一个简单的机器视觉和机器学习应用程序。其主要功能是在图形用户界面中用鼠标标记出不同的类别点,然后通过多种机器学习模型(如正态贝叶斯分类器、K最近邻分类器、支持向量机等),学习这些点的分布规律,并预测整个图像坐标面中每个点的类别,并进行着色以区分不同类别。

代码的核心部分包括鼠标回调函数(on_mouse),它处理用户的鼠标事件,根据用户点击添加新的类别点;数据准备辅助函数,用于将标记的点转换为训练模型所需的格式;模型训练和预测函数,包括每个分类器独立的训练和预测逻辑;以及主函数,它负责初始化应用程序界面、处理用户输入并触发机器学习模型的训练和预测。

这段代码展示了多个不同的机器学习算法在机器视觉和机器人技术应用程序中确定决策边界的方法。每个#if块介绍了如何使用一个特定的算法来训练一个模型用于分类,并预测图像上每个像素点的类别,并用不同的颜色来表示不同类别的决策区域。具体来说,包括:

  1. 使用正态贝叶斯分类器(NBC)确定决策边界。

  2. 使用K最邻近算法(KNN)确定决策边界,K值可以调整。

  3. 使用支持向量机(SVM)确定决策边界,其中C为错误项的惩罚系数。

  4. 使用决策树(DT)来确定决策边界。

  5. 使用提升树(Boosted Trees, BT)来确定决策边界。

  6. 使用梯度提升树(Gradient Boosted Trees, GBT)来确定决策边界。

  7. 使用随机森林(Random Forest, RF)来确定决策边界。

  8. 使用人工神经网络(Artificial Neural Network, ANN)来确定决策边界,其中层的大小可以调整,通常由输入层、一个或多个隐藏层和输出层构成。

9. 期望最大化(Expectation Maximization, EM)算法在寻找决策边界的实现方式。EM是一种迭代优化算法,用于参数估计,特别适合处理有隐变量的概率模型。它通常用于聚类或者潜在变量模型的估计。在find_decision_boundary_EM函数中,这个算法先是为每个类别训练了一个EM模型。接着通过遍历图像上的每个像素,计算该像素属于每个模型的概率,然后选择概率最大的模型对应的类别,为该像素分配颜色。

这些算法通常用于机器视觉中的模式识别、分类任务或者机器人路径规划中的决策制定等应用场景。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/616358.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

卷积神经网络(CNN)笔记——多图深入理解

梗直哥、梗直哥丶的个人空间-梗直哥丶个人主页-哔哩哔哩视频 过去十年,卷积神经网络(CNN)如同科技领域的明星,以其卓越的表现撑起了人工智能的半边天。这种创新的网络模型,不仅在计算机视觉、语音识别等传统领域大放异彩,更为人工智能的快速发展和广泛应用奠定了坚实的基础。…

Day19-【Java SE进阶】网络编程

一、网络编程 1.概述 可以让设备中的程序与网络上其他设备中的程序进行数据交互(实现网络通信的)。java.net,*包下提供了网络编程的解决方案! 基本的通信架构 基本的通信架构有2种形式:CS架构(Client客户端/Server服务端)、BS架构(Browser浏览器/Server服务端)。 网络通信的…

【新版】系统架构设计师 - 知识点 - 结构化开发方法

个人总结&#xff0c;仅供参考&#xff0c;欢迎加好友一起讨论 文章目录 架构 - 知识点 - 结构化开发方法结构化开发方法结构化分析结构化设计 数据流图和数据字典模块内聚类型与耦合类型 架构 - 知识点 - 结构化开发方法 结构化开发方法 分析阶段 工具&#xff1a;数据流图、…

从0到1实现RPC | 12 限流

在服务提供者provider端添加限流逻辑 限流&#xff1a;指定时间内请求数超过指定阈值时就抛出异常。 在ProviderInvoker的调用过程中&#xff0c;添加限流逻辑&#xff1a; 使用滑动窗口SlidingTimeWindow统计30s的请求数&#xff1b;每个服务service对应一个滑动窗口&#…

神经网络--反向传播算法推导

神经网络–反向传播算法推导 文章目录 神经网络--反向传播算法推导概述神经网络模型反向传导算法 概述 以监督学习为例&#xff0c;假设我们有训练样本集 ( x ( i ) , y ( i ) ) (x^{(i)},y^{(i)}) (x(i),y(i))&#xff0c;那么神经网络算法能提供一种复杂且非线性的假设模型 …

route路由命令、ip route命令、default默认路由(0.0.0.0 )

文章目录 3. route语法3.1 查看路由表3.1 参数解释 3.2 添加路由记录3.2.1 添加到达单个目标主机的路由3.2.2 添加到达目标网络的路由3.2.3 添加默认路由 3.3 删除路由记录 4. ip route4.1 查看路由4.1.1 不带条件4.1.2 带条件 4.2 添加路由4.3 删除路由4.4 清空路由表&#xf…

elasticsearch7安全配置--最低安全等级,用户名密码

上一篇博客在centos7上安装了elasticsearch7 接下来对elasticsearch进行安全方面的配置 minimal security 最低安全等级&#xff0c;用户名密码 首先开启xpack vim config/elasticsearch.yml xpack.security.enabled: true由于我是单机配置的&#xff0c;还加了如下配置 d…

JavaScript:事件循环机制(同步、异步)(单、多线程)

事件循环机制: 多进程和多线程 1. 进程&#xff1a;程序的一次执行, 它占有一片独有的内存空间 2. 线程&#xff1a; CPU的基本调度单位, 是程序执行的一个完整流程 3. 进程与线程 * 一个进程中一般至少有一个运行的线程: 主线程 * 一个进程中也可以同时运行多个线程, 我们…

ADC的认识

ADC介绍 Q:ADC是什么&#xff1f; A&#xff1a;全称&#xff1a;Analog-to-Digital Converter&#xff0c;指模拟/数字转换器 ADC的性能指标 量程&#xff1a;能测量的电压范围分辨率&#xff1a;ADC能辨别的最小模拟量&#xff0c;通常以输出二进制数的位数表示&#xf…

有限差分法求解一维、二维波动方程

差分格式方法是数值计算方法中微分以及偏微分导数的一种离散化方法。具体来说&#xff0c;它使用相邻两个或者多个数值点的差分来取代偏微分方程中的导数或偏导数。选择差分格式是离散化偏微分方程的第一步&#xff0c;通过这种离散化&#xff0c;我们可以将连续空间区域上的问…

面试通关秘籍:一面到终面的秘密

在当今竞争激烈的职场中&#xff0c;面试已经成为求职者和企业之间互相了解和选择的重要环节。面试过程常常被划分为多个阶段&#xff0c;包括一面&#xff08;初次面试&#xff09;、二面&#xff08;二次面试&#xff09;、三面&#xff08;深入面试&#xff09;以及终面&…

入门:多层感知器Multiple-Layer Perceiver, MLP

本文将简单介绍多层感知器&#xff08;MLP&#xff09;的基本概念、原理和应用。MLP是一种前馈人工神经网络&#xff0c;由多层节点组成&#xff0c;每层节点通过权重和偏置与下一层节点相连。MLP在许多领域都有广泛的应用&#xff0c;如分类、回归、自然语言处理等。 本文将分…