最近在做一个实验,需要对 X∗XT 求取特征值,所以需要进行矩阵相乘操作。
我的Mat是以灰度方式读取图片得来。
数据获取的代码如下:
vector<Mat> images;
vector<int> labels;
string imgPath;
for (int i = 1; i <= 15; i++)
for (int j = 1; j <= 8; j++)
{
if (i<10)
imgPath = format("D:/database/orl/orl_00%d_00%d.bmp", i, j);
else
imgPath = format("D:/database/orl/orl_0%d_00%d.bmp", i, j);
cout << imgPath << endl;
Mat img = imread(imgPath.c_str(), CV_LOAD_IMAGE_GRAYSCALE);
Mat resizedImg;
resize(img, resizedImg, Size(30,30));
Mat imgNorm;
cv::normalize(resizedImg, imgNorm, 0, 255, NORM_MINMAX, CV_8UC1);
images.push_back(imgNorm);
labels.push_back(i);
}
int featureDim = images[0].cols*images[0].rows;
Mat pcaMat(images.size(), featureDim, CV_8UC1);
for (int i = 0; i < images.size(); i++)
{
memcpy((uchar*)pcaMat.data + i*featureDim, (uchar*)images[i].data, sizeof(uchar)*featureDim);
}
当我进行如下操作的时候报错了!
Mat pcaM = pcaMat*pcaMat.t();(pcaMat.t()为pcaMat的转置。)
从错误可以看出,A*B矩阵相乘要求
于是我产生了两个问题:
Mat的所有类型可以参考这里。
~~~
uchar a[8] = {1, 2, 3, 4, 5, 6, 7, 8};
Mat mat1(2,4, CV_8UC1);
memcpy(mat1.data, a, sizeof(uchar)*8);
cout << "type " << mat1.type() << endl;
cout << "depth " <<mat1.depth() << endl;
cout << "channels " << mat1.channels() << endl;
读取图片是8UC1,转化成64FC1会出现什么问题呢?
如下所示
Mat img = imread("D:/database/orl/orl_001_001.bmp", CV_LOAD_IMAGE_GRAYSCALE);
imshow("beforConvert", img);
img.convertTo(img, CV_64FC1);
imshow("afterConvert", img);
waitKey(0);
结果为:
为什么会这样呢?
因为颜色空间在整数上是0~255,在浮点数上则是在0~1之间,也就是说img转换成CV_64FC1之后,我们显示图片,只会显示0~1的值,而那些大于1的值则直接就不显示了,所以变成了白色。
来输出一下转换前后mat的第一行的值,值是相同的:
convertTo函数它的使用具体是怎样的呢?
opencv的doc可以在doc这里根据版本具体查看。
我看的是2.4.10版本的,里边对这个函数的描述如下:
void ocl::oclMat::convertTo(oclMat& m, int rtype, double alpha=1, double beta=0) const
/*
Parameters:
m – the destination matrix. If it does not have a proper size or type before the operation, it will be reallocated.
rtype – the desired destination matrix type, or rather, the depth (since the number of channels will be the same with the source one). If rtype is negative, the destination matrix will have the same type as the source.
alpha – optional scale factor.
beta – optional delta added to the scaled values.
*/
m就是目的矩阵,rtype就是数据转换后的类型,也就是CV_16SC1之类的。
至于alpha,beta,我用 α,β 来表示
它们的作用是这样的,比如对于m中的一个像素 m(i,j)=m(i,j)∗α+β 。
所以上面图像转换出的问题就在于使用默认的缩放参数等价于没有对数值做变化,只是变了数据的类型,就像是1,从uchar的1变成了double的1。
现在我修改一下参数,注意是1/255.0这样才是double值,如果写出1/255其实就是0了!:
img.convertTo(img, CV_64FC1, 1/255.0);
两个Mat相乘挺简单的,只需要写成A*B就可以了。
可是*对矩阵的数据类型进行了限制,所以要事先转化成32F或64F来计算。
下面进行一段演示:
int a[8] = {1, 2, 3, 4, 5, 6, 7, 8};
int b[4] = {1, 2, 3, 4};
Mat mat1(2,4, CV_32SC1);
Mat mat2(4,1, CV_32SC1);
memcpy(mat1.data, a, sizeof(int)*8);
memcpy(mat2.data, b, sizeof(int)*4);
mat1.convertTo(mat1, CV_64FC1);
mat2.convertTo(mat2, CV_64FC1);
Mat mat3 = mat1*mat2;
cout << "Mat1\n " << mat1 << endl;
cout << "Mat2\n " << mat2 << endl;
cout << "Mat3\n " << mat3 << endl;