Opencv中Mat矩阵相乘——点乘、dot、mul运算详解
Mat矩阵点乘——A*B
Opencv重载了运算符“*”,姑且称之为Mat矩阵“点乘”,其中一个重载声明为:html
CV_EXPORTS MatExpr operator * (const Mat& a, const Mat& b);
点乘说明:
1. A*B是以数学运算中矩阵相乘的方式实现的,即Mat矩阵A和B被当作纯粹的矩阵作乘法运算,这就要求A的列数等 于B的行数时,才能定义两个矩阵相乘。如A是m×n矩阵,B是n×p矩阵,它们的乘积AB是一个m×p矩阵。ios

如上图所示,C=AB。C中第i行第j列所在元素C(i,j)等于A中第i行全部元素跟B中第j列全部元素一一对应的乘积之和。express
更具备表明性的的:对于A、B都是2行2列矩阵的状况:函数
Opencv验证:spa
定义两个Mat矩阵A和B点乘,A为2行3列,B为3行2列:.net
-
#include "core/core.hpp"
-
#include "iostream"
-
-
using namespace std;
-
using namespace cv;
-
-
int main(int argc,char *argv[])
-
{
-
Mat A=Mat::ones( 2,3,CV_32FC1);
-
Mat B=Mat::ones( 3,2,CV_32FC1);
-
Mat AB;
-
-
A.at< float>(0,0)=1;
-
A.at< float>(0,1)=2;
-
A.at< float>(0,2)=3;
-
A.at< float>(1,0)=4;
-
A.at< float>(1,1)=5;
-
A.at< float>(1,2)=6;
-
-
B.at< float>(0,0)=1;
-
B.at< float>(0,1)=2;
-
B.at< float>(1,0)=3;
-
B.at< float>(1,1)=4;
-
B.at< float>(2,0)=5;
-
B.at< float>(2,1)=6;
-
-
AB=A*B;
-
-
cout<<"A=\n"<<A<<endl<<endl;
-
cout<<"B=\n"<<B<<endl<<endl;
-
cout<<"AB=\n"<<AB<<endl<<endl;
-
-
system( "pause");
-
}
输出:

务必保证两个Mat矩阵中第一个矩阵A的列数等于第二个矩阵B的行数。3d
2. 参与点乘的两个Mat矩阵的数据类型(type)只能是 CV_32F、 CV_64FC一、 CV_32FC二、 CV_64FC2 这4种类 型中的一种。若选用其余类型,好比CV_8UC1,编译器会报错:code
Mat矩阵dot——A.dot(B)
Opencv中.dot操做才算得上是真正的“点乘”,A.dot(B)操做至关于数学向量运算中的点乘,也叫向量的内积、数量积。htm
函数声明:blog
-
//! computes dot-product
-
double dot(InputArray m) const;
dot说明:
1. 对两个向量执行点乘运算,就是对这两个向量对应位一一相乘以后求和的操做,点乘的结果是一个标量。
对于向量a和向量b:
a和b的点积公式为:

要求向量a和向量b的行列数相同。
Mat矩阵的dot方法扩展了一维向量的点乘操做,把整个Mat矩阵扩展成一个行(列)向量,以后执行向量的点乘运算,仍然要求参与dot运算的两个Mat矩阵的行列数彻底一致。
2. dot方法声明中显示返回值是double,因此A.dot(B)结果是一个double类型数据,不是Mat矩阵,不能把A.dot(B)结 果赋值给Mat矩阵!
Opencv验证:
-
#include "core/core.hpp"
-
#include "iostream"
-
-
using namespace std;
-
using namespace cv;
-
-
int main(int argc,char *argv[])
-
{
-
Mat A=Mat::ones( 2,3,CV_8UC1);
-
Mat B=Mat::ones( 2,3,CV_8UC1);
-
-
A.at<uchar>( 0,0)=1;
-
A.at<uchar>( 0,1)=2;
-
A.at<uchar>( 0,2)=3;
-
A.at<uchar>( 1,0)=4;
-
A.at<uchar>( 1,1)=5;
-
A.at<uchar>( 1,2)=6;
-
-
B.at<uchar>( 0,0)=1;
-
B.at<uchar>( 0,1)=2;
-
B.at<uchar>( 0,2)=3;
-
B.at<uchar>( 1,0)=4;
-
B.at<uchar>( 1,1)=5;
-
B.at<uchar>( 1,2)=6;
-
-
double AB=A.dot(B);
-
-
cout<<"A=\n"<<A<<endl<<endl;
-
cout<<"B=\n"<<B<<endl<<endl;
-
cout<<"double类型的AB=\n"<<AB<<endl<<endl;
-
-
system( "pause");
-
}
运行结果:
若对AB声明为Mat,则在编译阶段就会报错。
3. dot操做不对参与运算的矩阵A、B的数据类型作要求,CV_8UC一、CV_32FC1等,能够是任何Opencv定义的类 型,如在2中使用的就是CV_8UC1。
4. 若参与dot运算的两个Mat矩阵是多通道的,则计算结果是全部通道单独计算各自.dot以后,再累计的和,结果还是一个double类型数据。
Mat矩阵mul——A.mul(B)
Opencv中mul会计算两个Mat矩阵对应位的乘积,因此要求参与运算的矩阵A的行列和B的行列数一致。计算结果是跟A或B行列数一致的一个Mat矩阵。
Opencv中mul声明:
-
//! per-element matrix multiplication by means of matrix expressions
-
MatExpr mul(InputArray m, double scale=1) const;
以简单的状况为例,对于2*2大小的Mat矩阵A和B:

对A和B执行mul运算:
mul说明:
1. mul操做不对参与运算的两个矩阵A、B有数据类型上的要求,但要求A,B类型一致,否则报错;
2. Mat AB=A.mul(B),若声明AB时没有定义AB的数据类型,则默认AB的数据类型跟A和B保存一致;
3. 若AB精度不够,可能产生溢出,溢出的值被置为当前精度下的最大值;
Opencv验证:
-
#include "core/core.hpp"
-
#include "iostream"
-
-
using namespace std;
-
using namespace cv;
-
-
int main(int argc,char *argv[])
-
{
-
Mat A=Mat::ones( 2,3,CV_8UC1);
-
Mat B=Mat::ones( 2,3,CV_8UC1);
-
-
A.at<uchar>( 0,0)=60;
-
A.at<uchar>( 0,1)=2;
-
A.at<uchar>( 0,2)=3;
-
A.at<uchar>( 1,0)=4;
-
A.at<uchar>( 1,1)=5;
-
A.at<uchar>( 1,2)=6;
-
-
B.at<uchar>( 0,0)=60;
-
B.at<uchar>( 0,1)=2;
-
B.at<uchar>( 0,2)=3;
-
B.at<uchar>( 1,0)=4;
-
B.at<uchar>( 1,1)=5;
-
B.at<uchar>( 1,2)=6;
-
-
Mat AB=A.mul(B);
-
-
cout<<"A=\n"<<A<<endl<<endl;
-
cout<<"B=\n"<<B<<endl<<endl;
-
cout<<"AB=\n"<<AB<<endl<<endl;
-
-
system( "pause");
-
}
输出: