opencv中Mat的使用与存取

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/jianjian1992/article/details/49254667

特征存取是机器学习过程中的一步,因为数据量很大的话,如果直接对数据提取特征然后进行训练需要花很多时间,如果中途出了点问题那运行这么久就白做了。

所以把提取的特征进行保存就是很重要的一个步骤啦。

我打算使用opencv的Mat进行数据的保存,那么Mat如何构造,如何保存,如何读取呢?

Mat的构造

如下是创建一个Mat的方式,Size里边先填列数,再填行数!!这点和一般习惯有些不同,要记住哦!
CV_32FC1则表示存取的数据是32位float数据,C是Channel,表示1通道。如果是double数据,写出CV_64FC1。
如果是存取图片数据,因为像素信息在0~255之间,可以用8位无符号表示,所以可以写出CV_8UC1(灰白图片)或CV_8UC3(彩色图片)
Mat featureMat = Mat(Size(columnNumber, <span style="font-family: Arial, Helvetica, sans-serif;">rowNumber</span>), CV_32FC1);
如果我们想保存一个sampleNum*featureNum的矩阵,那么便可以按照上面的方式进行Mat的创建,行数为sampleNum,列数为featureNum。
那么如何把数据放到Mat里边呢?

行向量的保存

比如说我用hog提取了一张图片的特征,用vector<float>保存特征,那么如何把它复制到Mat里边呢?
featureMat是一个1*descriptorFloat.size()的行向量,featureMat.at<float>(i)访问的便是这个行向量的第i个元素。
	HOGDescriptor *hog =  new HOGDescriptor(cvSize(32,32),cvSize(16,16),cvSize(8,8),cvSize(8,8),9);
	Mat img = imread("E:\\p1.jpg");
	Mat resizedImg;
	vector<float> descriptorsFloat;
	resize(img, resizedImg, Size(32,32));
	hog->compute(resizedImg, descriptorsFloat,Size(1,1), Size(0,0)); //调用计算函数开始计算  
	for (int i = 0; i < 10; i++)
	{
		cout << descriptorsFloat[i] << " ";
	}
	cout << endl;
	Mat featureMat = Mat(Size(descriptorsFloat.size(), 1), CV_32FC1);
	for (int i = 0; i < descriptorsFloat.size(); i++)
	{
		featureMat.at<float>(i) = descriptorsFloat[i];
	}

矩阵的保存

如果有很多个样本呢?用vector<vector<double>>保存数据,那该怎么复制到矩阵里边呢?
如下所示,dataMat2.at<double>(i,j)访问了矩阵的第i行第j列,注意矩阵创建时Size的顺序不要弄错了!
代码中创建的是一个arFeature.getSampleNum()*arFeature.getFeatureDimension()大小的矩阵!
	ARFeature arFeature;
	arFeature.extractTrainData();
	vector<vector<double>> f =arFeature.getFeatures();
	Mat dataMat2 = Mat(Size(arFeature.getFeatureDimension(), arFeature.getSampleNum()), CV_64FC1);
	for (int i = 0; i < arFeature.getSampleNum(); i++)
	{
		for (int j = 0; j < arFeature.getFeatureDimension(); j++)
		{
			dataMat2.at<double>(i, j) = f[i][j];
		}
	}

Mat的保存和读取

Mat是以xml文件的格式进行保存的,使用FileStorage类进行操作。
下面代码中创建FileStorage对象时的两个参数分别表明
1.在当前目录下新建dataMat2.xml文件保存Mat
2.使用写方式
写入的这句倒是挺有意思的,将dataMat2写入"dataMat2",通过fsFeature,所以是fsFeature<<"dataMat2"<<dataMat2;
	FileStorage fsFeature("./dataMat2.xml", FileStorage::WRITE);
	fsFeature<<"dataMat2"<<dataMat2;
	fsFeature.release();
最后不要忘记了release啊!

看看dataMat2.xml文件是怎样的吧。
记录了矩阵的行与列,dt属性则记录了矩阵里边的数据类型,d表示的是double
data属性里边是则将数据按行进行存储。
<?xml version="1.0"?>
<opencv_storage>
<dataMat2 type_id="opencv-matrix">
  <rows>1274</rows>
  <cols>324</cols>
  <dt>d</dt>
  <data>
    5.8231703937053680e-002 4.6796485781669617e-002
    1.9085651636123657e-001 2.6005533337593079e-001
    2.6005533337593079e-001 2.2189404070377350e-001
    1.0163319855928421e-001 3.2928720116615295e-002
    3.4803047776222229e-002 8.1096969544887543e-002
    7.1655549108982086e-002 2.0455005764961243e-001

读取矩阵则是按照如下方式进行,依然是创建一个FileStorage对象,
读入的方式也挺有意思的,通过fsRead对象,找到“dataMat2”,并将它写入readMat矩阵里边。
感觉像是个数组查找,嗯嗯,这个让我想到是不是可以同时写入多个矩阵呢?
<pre name="code" class="cpp">	Mat readMat;
	FileStorage fsRead("./dataMat2.xml", FileStorage::READ);
	fsRead["dataMat2"]>>readMat;
<span style="white-space:pre">	</span>fsRead.release();
 
    

多个矩阵的写入与读取

我设计存储1个2*10大小的矩阵,1个1*10的行向量以及若干个1*1的变量。
vector<vector<float>> storedData;
	vector<float> data1;
	vector<float> data2;
	for (int i = 0; i < 10; i++)
	{
		float f1 = 0.0 + i;
		float f2 = 1.0 + i;
		data1.push_back(f1);
		data2.push_back(f2);
	}
	storedData.push_back(data1);
	storedData.push_back(data2);
	Mat testMat1 = Mat(Size(10, 2), CV_32FC1);
	for (int i = 0; i < 2; i++)
	{
		for (int j = 0; j < 10; j++)
		{
			testMat1.at<float>(i, j) = storedData[i][j];
		}
	}

	Mat testMat2 = Mat(data1, true);
	Mat testMat3 = Mat(Size(1, 1), CV_8UC1);
	testMat3.at<byte>(0) = 1; 
	Mat testMat4 = Mat(Size(1, 1), CV_8SC1);
	testMat4.at<byte>(0) = -1; 
	Mat testMat5 = Mat(Size(1, 1), CV_16UC1);
	testMat5.at<unsigned short>(0) = 1; 
	Mat testMat6 = Mat(Size(1, 1), CV_16SC1);
	testMat6.at<short>(0) = -1; 
	Mat testMat7 = Mat(Size(1, 1), CV_32SC1);
	testMat7.at<int>(0) = -1; 

	FileStorage fs("./testMat.xml", FileStorage::WRITE);
	fs<<"mat1"<<testMat1;
	fs<<"mat2"<<testMat2;
	fs<<"mat3"<<testMat3;
	fs<<"mat4"<<testMat4;
	fs<<"mat5"<<testMat5;
	fs<<"mat6"<<testMat6;
	fs<<"mat7"<<testMat7;
	fs.release();

	Mat readMat1, readMat2, readMat3, readMat4;
	FileStorage fsRead("./testMat.xml", FileStorage::READ);
	fsRead["mat1"]>>readMat1;
	fsRead["mat2"]>>readMat2;
	fsRead["mat3"]>>readMat3;
	fsRead["mat6"]>>readMat4;
	for (int i = 0; i < readMat1.rows; i++)
	{
		for (int j = 0; j < readMat1.cols; j++)
		{
			cout << readMat1.at<float>(i, j) << " ";
		}
		cout << endl;
	}
	for (int i = 0; i < readMat2.rows; i++)
	{
		cout << readMat2.at<float>(i) << " ";
	}
	cout << endl;
	cout << (unsigned int)readMat3.at<byte>(0) << endl;
	cout << (int)readMat4.at<short>(0) << endl;
	fsRead.release();



实验演示了多个矩阵是可以同时正确进行存储的,那它们是通过什么来区分的呢?
来看看xml文件。
看到了吧,
<mat1 type_id="opencv-matrix">

这一句在开头便记录了变量的名字哦!

<?xml version="1.0"?>
<opencv_storage>
<mat1 type_id="opencv-matrix">
  <rows>2</rows>
  <cols>10</cols>
  <dt>f</dt>
  <data>
    0. 1. 2. 3. 4. 5. 6. 7. 8. 9. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.</data></mat1>
<mat2 type_id="opencv-matrix">
  <rows>10</rows>
  <cols>1</cols>
  <dt>f</dt>
  <data>
    0. 1. 2. 3. 4. 5. 6. 7. 8. 9.</data></mat2>
<mat3 type_id="opencv-matrix">
  <rows>1</rows>
  <cols>1</cols>
  <dt>u</dt>
  <data>
    1</data></mat3>
<mat4 type_id="opencv-matrix">
  <rows>1</rows>
  <cols>1</cols>
  <dt>c</dt>
  <data>
    -1</data></mat4>
<mat5 type_id="opencv-matrix">
  <rows>1</rows>
  <cols>1</cols>
  <dt>w</dt>
  <data>
    1</data></mat5>
<mat6 type_id="opencv-matrix">
  <rows>1</rows>
  <cols>1</cols>
  <dt>s</dt>
  <data>
    -1</data></mat6>
<mat7 type_id="opencv-matrix">
  <rows>1</rows>
  <cols>1</cols>
  <dt>i</dt>
  <data>
    -1</data></mat7>
</opencv_storage>

变量类型

变量类型也是需要注意的一点。
CV_8UC1           CV_8SC1          CV_16U C1       CV_16SC1 
CV_8UC2          
 CV_8SC2          CV_16UC2        CV_16SC2 
CV_8UC3          
 CV_8SC3          CV_16UC3        CV_16SC3 
CV_8UC4          
 CV_8SC4          CV_16UC4        CV_16SC4 
CV_32SC1        
 CV_32FC1         CV_64FC1
CV_32SC2        
 CV_32FC2         CV_64FC2
CV_32SC3        
 CV_32FC3         CV_64FC3
CV_32SC4        
 CV_32FC4         CV_64FC4


上面便是可以支持的类型,我们看整数里边,只有8,16位是有无符号类型的,32为只有有符号类型。另外浮点数则只有32位和64位。










猜你喜欢

转载自blog.csdn.net/jianjian1992/article/details/49254667