机器学习第一天:
决策树:
#include<opencv2/opencv.hpp>
#include<opencv2/ml.hpp>
#include<iostream>
#include<fstream>
#include<cstdio>
using namespace std;
using namespace cv;
using namespace cv::ml;
//读取文件中的点坐标
int readFile(vector<Point> &trainedPoints, vector<int> &trainedPointsMarkers)
{
ifstream in;
in.open("points.txt");
if (!in.is_open())
{
cout << "Could not open the file" << "points.txt" << endl;
cout << "Program terminating.\n";
return 0;
}
int flge = 0;
int fpoint, flabel;
Point point;
while (!in.eof())
{
in >> fpoint;
//依次为横坐标,纵坐标,分类
if ((
flge % 3 == 0 ? point.x = fpoint :
flge % 3 == 1 ? point.y = fpoint :
flge % 3 == 2 ? flabel = fpoint : -1) < 0)
return -1;
if (flge %3==2)
{
trainedPoints.push_back(point);
trainedPointsMarkers.push_back(flabel);
}
flge++;
}
return 1;
}
//显示点
void showPoint(vector<Point> &trainedPoints, Mat &src, Mat &dst, vector<int> &trainedPointsMarkers)
{
vector<Vec3b> colors(2);
colors[0] = Vec3b(0, 255, 0);
colors[1] = Vec3b(0, 0, 255);
for (size_t i = 0;i < trainedPoints.size();i++)
{
//trainedPointsMarkers的值只能为0或1
Scalar c = colors[trainedPointsMarkers[i]];
//在图像矩阵上画圆
circle(src, trainedPoints[i], 3, c, -1);
circle(dst, trainedPoints[i], 3, c, -1);
}
imshow("points", src);
}
void showClass(Ptr<DTrees> &model, Mat &dst)
{`在这里插入代码片`
vector<Vec3b> colors(2);
colors[0] = Vec3b(0, 255, 0);
colors[1] = Vec3b(0, 0, 255);
Mat testSample(1, 2, CV_32FC1);
for (int y = 0;y < dst.rows;y +`在这里插入代码片`= 3)
{
for (int x = 0;x < dst.cols;x += 3)
{
testSample.at<float>(0) = (float)x;
testSample.at<float>(1) = (float)y;
int response = (int)model->predict(testSample);
//x,y的意思?
dst.at<Vec3b>(y, x) = colors[response];
}
}
imshow("Decision Tree", dst);
}
int main()
{
//template<typename_Tp>class Point{_Tp x;_Tp y}
vector<Point> trainedPoints;
vector<int> trainedPointsMarkers;
//读取文件中的点坐标x,y类别0或者1 例如:322 182 1
if (readFile(trainedPoints, trainedPointsMarkers) == 0)
exit(EXIT_FAILURE);
//绘图用的两种颜色值
vector<Vec3b> colors(2);
//绿色
colors[0] = Vec3b(0, 255, 0);
//红色
colors[1] = Vec3b(0, 0, 255);
//绘图用的两个点阵矩阵
Mat src, dst;
//创建480*640的3通道像素矩阵
src.create(480, 640, CV_8UC3);
//全部是黑色
src = Scalar::all(0);
//初始化目标矩阵同样颜色
src.copyTo(dst);
//绘制点
showPoint(trainedPoints, src, dst, trainedPointsMarkers);
//训练数据
Mat samples;
Mat(trainedPoints).reshape(1, (int)trainedPoints.size()).convertTo(samples, CV_32F);
Ptr<DTrees> model = DTrees::create();
model->setMaxDepth(8);
model->setMinSampleCount(2);
model->setUseSurrogates(false);
model->setCVFolds(0);
model->setUse1SERule(false);
model->setTruncatePrunedTree(false);
model->train(TrainData::create(samples, ROW_SAMPLE, Mat(trainedPointsMarkers)));
showClass(model, dst);
waitKey();
return 0;
}
运行结果图:
部分代码注释:
vector<Vec3b> colors(2);
1.VecXY:
X:取值 2,3,4,6表明由几个维度构成。对应图片就是每个像素有几个数据构成,即channel
Y:取值 b,w,s,i,f,d,依次对应
b=unsigned char,w=unsigned short,s=short,i=int,f=float,d=double.
即X所表示的每个数的类型
涉及到的知识点:像素值的读写方式:
(1)at()函数:
Mat img;
img.at<Vec3b>(i, j)[0];//blue
img.at<Vec3b>(i, j)[1];//green
img.at<Vec3b>(i, j)[2];//red
(2)使用迭代器: 使用了迭代器,而不是使用行数和列数来遍历,所以这儿没有了 i 和 j 变量。
MatIterator_<Vec3b> itr, itrEnd;
for (itr = img.begin<Vec3b>(), itrEnd = img.end<Vec3b>(); itr != itrEnd; ++itr)
{
(*itr)[0] = rand() % 256;//blue
(*itr)[1] = rand() % 256;//green
(*itr)[2] = rand() % 256;//red
}
(3)通过数据指针:通过指针操作来访问像素是非常高效的,C/C++中的指针操作是不进行类型以及越界检查的务必十分地小心。
for (int i = 0; i < img.rows; ++i)
{
//获取第 i 行首像素指针
Vec3b * p = img.ptr<Vec3b>(i);
for (int j = 0; j < img.cols; ++j)
{
p[j][0] = 255 - p[j][0]; //Blue
p[j][1] = 255 - p[j][1]; //Green
p[j][2] = 255 - p[j][2]; //Red
}
}
2.Mat(trainedPoints).reshape(1, (int)trainedPoints.size()).convertTo(samples, CV_32F);
reshape函数:
在opencv中,reshape函数比较有意思,它既可以改变矩阵的通道数,又可以对矩阵元素进行序列化,非常有用的一个函数。
函数原型:
C++: Mat Mat::reshape(int cn, int rows=0) const
参数比较少,但设置的时候却要千万小心。
cn: 表示通道数(channels), 如果设为0,则表示保持通道数不变,否则则变为设置的通道数。
rows: 表示矩阵行数。 如果设为0,则表示保持原有的行数不变,否则则变为设置的行数。
该函数具体见链接:https://blog.csdn.net/bonnenultcy/article/details/103465353
来源:CSDN
作者:bonnenultcy
链接:https://blog.csdn.net/bonnenultcy/article/details/103464823