机器学习(一)

自古美人都是妖i 提交于 2019-12-16 07:34:24

机器学习第一天:
决策树:

#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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!