Opencv中Mat矩阵相乘——点乘、dot、mul运算详解
Mat矩阵点乘——A*B
Opencv重载了运算符“*”,姑且称之为Mat矩阵“点乘”,其中一个重载声明为:
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矩阵。
如上图所示,C=AB。C中第i行第j列所在元素C(i,j)等于A中第i行所有元素跟B中第j列所有元素一一对应的乘积之和。
更具有代表性的的:对于A、B都是2行2列矩阵的情况:
Opencv验证:
定义两个Mat矩阵A和B点乘,A为2行3列,B为3行2列:
- #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的行数。
2. 参与点乘的两个Mat矩阵的数据类型(type)只能是 CV_32F、 CV_64FC1、 CV_32FC2、 CV_64FC2 这4种类 型中的一种。若选用其他类型,比如CV_8UC1,编译器会报错:
Mat矩阵dot——A.dot(B)
Opencv中.dot操作才算得上是真正的“点乘”,A.dot(B)操作相当于数学向量运算中的点乘,也叫向量的内积、数量积。
函数声明:
- //! 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_8UC1、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");
- }
输出:
AB中第一个元素应该为60*60=360,但AB默认的类型为CV_8UC1,即最大值只能是255;所以执行mul运算一定要定义AB足够的精度,防止溢出。
Opencv中Mat矩阵相乘——点乘、dot、mul运算详解的更多相关文章
- opencv中mat矩阵如何debug
mat img 看type:img.type() rows:img.rows cols:img.cols channels:img.channels(),channels()这是一个函数,和上面两个有 ...
- OpenCV中Mat的列向量归一化
OpenCV中Mat的列向量归一化 http://blog.csdn.net/shaoxiaohu1/article/details/8287528 OpenCV中Mat的列向量归一化 标签: Ope ...
- opencv中mat类介绍
The class Mat represents an n-dimensional dense numerical single-channel or multi-channel array. It ...
- OpenCV中Mat的属性
OpenCV中Mat的属性 最近在做一OpenCV的图像轮廓检验,但当用到霍夫变换时才发现对Mat的属性了解不足.Mat在OpenCV中的地位是及其重要的,因此有必要做一个总结. 大体上来说,Mat是 ...
- OpenGL中的矩阵相乘
OpenGL中的矩阵相乘 1, 在OpenGL中所有的视图变换,模型变换 都是4×4矩阵,每个后续的glMultiMatrix*(N),或者变换函数,glTranslate* (),glRotate* ...
- OpenCV中Mat操作clone() 与copyto()的区别
OpenCV中Mat操作clone() 与copyto()的区别 // Mat is basically a class with two data parts: the matrix header ...
- OpenCV中Mat的基本用法:创建、复制
OpenCV中Mat的基本用法:创建.复制 一.Mat类的创建: 1.方法一: 通过读入一张图像,直接将其转换成Mat对象. Mat image = imread("test.jpg&quo ...
- PHP中IP地址与整型数字互相转换详解
这篇文章主要介绍了PHP中IP地址与整型数字互相转换详解,本文介绍了使用PHP函数ip2long与long2ip的使用,以及它们的BUG介绍,最后给出自己写的两个算法,需要的朋友可以参考下 IP转换成 ...
- ArcGIS中的北京54和西安80投影坐标系详解
ArcGIS中的北京54和西安80投影坐标系详解 1.首先理解地理坐标系(Geographic coordinate system),Geographic coordinate system直译为地理 ...
随机推荐
- wpf让图片自适应容器大小,而且又不会拉升变形
<Grid Grid.Column="3" Margin="0,4,0,0" Background="Black"> <V ...
- PHP获取文件后缀名
PHP获取文件后缀名是PHP学习者常见的一种操作,无论是在面试过程中还是PHP新手自学中.PHP获取文件后缀名都是很普遍的需要掌握的一个知识点. 下面我们就给大家总结介绍PHP获取文件扩展名也就是后缀 ...
- OI中坑点总结
以下是我个人OI生涯中遇到的坑点的一个小总结,可能是我太菜了,总是掉坑里,请大佬勿喷 1,多重背包的转移的循环顺序 //默认每个物品体积为一(不想打码……) //dp[i]表示占用背包容量i所能获得的 ...
- JavaScript常见的假值
值 说明 var a=false; 值等于false(假) var a =0; 值等于0 var a=''; 空的字符串 var a=10/'abc' NaN var a; 未赋值变量
- JavaScript常见的真值
值 说明 var a =true 值等于true: var a = 1 非0的数字 var a =“hello” 有内容的字符串 var a=20/5 运算结果非0 var a='true' 有内容 ...
- MVC4 下DropDownList使用方法(转)
与MVC3相比,差别很大: 表现形式一: public ActionResult Main() { List<SelectListItem> items = new List<Sel ...
- hdu 1875 给出每个结点的坐标 权值为两点间的距离 (MST)
Sample Input2210 10 //坐标20 2031 12 21000 1000 Sample Output1414.2 //最小权值和*100 保留1位小数oh! //不 ...
- HashTable、HashMap、ConcurrentHashMap的区别
HashTable是做了同步的,HashMap未考虑同步.所以HashMap在单线程情况下效率较高:HashTable在的多线程情况下,同步操作能保证程序执行的正确性. HashMap是非线程安全的, ...
- KNN分类算法补充
KNN补充: 1.K值设定为多大? k太小,分类结果易受噪声点影响:k太大,近邻中又可能包含太多的其它类别的点. (对距离加权,可以降低k值设定的影响) k值通常是采用交叉检验来确定(以k=1为基准) ...
- HDU3031 To Be Or Not To Be 左偏树 可并堆
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - HDU3031 题意概括 喜羊羊和灰太狼要比赛. 有R次比赛. 对于每次比赛,首先输入n,m,n表示喜羊羊和灰 ...