Opencv中Mat矩阵相乘——点乘、dot、mul运算详解

2016年09月02日 00:00:36 -牧野- 阅读数:59593 标签: Opencv矩阵相乘点乘dotmul 更多

个人分类: OpenCV
所属专栏: OpenCV从入门到转行
 
版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/dcrmg/article/details/52404580

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列:

  1.  
    #include "core/core.hpp"
  2.  
    #include "iostream"
  3.  
     
  4.  
    using namespace std;
  5.  
    using namespace cv;
  6.  
     
  7.  
    int main(int argc,char *argv[])
  8.  
    {
  9.  
    Mat A=Mat::ones(2,3,CV_32FC1);
  10.  
    Mat B=Mat::ones(3,2,CV_32FC1);
  11.  
    Mat AB;
  12.  
     
  13.  
    A.at<float>(0,0)=1;
  14.  
    A.at<float>(0,1)=2;
  15.  
    A.at<float>(0,2)=3;
  16.  
    A.at<float>(1,0)=4;
  17.  
    A.at<float>(1,1)=5;
  18.  
    A.at<float>(1,2)=6;
  19.  
     
  20.  
    B.at<float>(0,0)=1;
  21.  
    B.at<float>(0,1)=2;
  22.  
    B.at<float>(1,0)=3;
  23.  
    B.at<float>(1,1)=4;
  24.  
    B.at<float>(2,0)=5;
  25.  
    B.at<float>(2,1)=6;
  26.  
     
  27.  
    AB=A*B;
  28.  
     
  29.  
    cout<<"A=\n"<<A<<endl<<endl;
  30.  
    cout<<"B=\n"<<B<<endl<<endl;
  31.  
    cout<<"AB=\n"<<AB<<endl<<endl;
  32.  
     
  33.  
    system("pause");
  34.  
    }

输出:

务必保证两个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)操作相当于数学向量运算中的点乘,也叫向量的内积、数量积。

函数声明:

  1.  
    //! computes dot-product
  2.  
    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验证:

  1.  
    #include "core/core.hpp"
  2.  
    #include "iostream"
  3.  
     
  4.  
    using namespace std;
  5.  
    using namespace cv;
  6.  
     
  7.  
    int main(int argc,char *argv[])
  8.  
    {
  9.  
    Mat A=Mat::ones(2,3,CV_8UC1);
  10.  
    Mat B=Mat::ones(2,3,CV_8UC1);
  11.  
     
  12.  
    A.at<uchar>(0,0)=1;
  13.  
    A.at<uchar>(0,1)=2;
  14.  
    A.at<uchar>(0,2)=3;
  15.  
    A.at<uchar>(1,0)=4;
  16.  
    A.at<uchar>(1,1)=5;
  17.  
    A.at<uchar>(1,2)=6;
  18.  
     
  19.  
    B.at<uchar>(0,0)=1;
  20.  
    B.at<uchar>(0,1)=2;
  21.  
    B.at<uchar>(0,2)=3;
  22.  
    B.at<uchar>(1,0)=4;
  23.  
    B.at<uchar>(1,1)=5;
  24.  
    B.at<uchar>(1,2)=6;
  25.  
     
  26.  
    double AB=A.dot(B);
  27.  
     
  28.  
    cout<<"A=\n"<<A<<endl<<endl;
  29.  
    cout<<"B=\n"<<B<<endl<<endl;
  30.  
    cout<<"double类型的AB=\n"<<AB<<endl<<endl;
  31.  
     
  32.  
    system("pause");
  33.  
    }

运行结果:

若对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声明:

  1.  
    //! per-element matrix multiplication by means of matrix expressions
  2.  
    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验证:

  1.  
    #include "core/core.hpp"
  2.  
    #include "iostream"
  3.  
     
  4.  
    using namespace std;
  5.  
    using namespace cv;
  6.  
     
  7.  
    int main(int argc,char *argv[])
  8.  
    {
  9.  
    Mat A=Mat::ones(2,3,CV_8UC1);
  10.  
    Mat B=Mat::ones(2,3,CV_8UC1);
  11.  
     
  12.  
    A.at<uchar>(0,0)=60;
  13.  
    A.at<uchar>(0,1)=2;
  14.  
    A.at<uchar>(0,2)=3;
  15.  
    A.at<uchar>(1,0)=4;
  16.  
    A.at<uchar>(1,1)=5;
  17.  
    A.at<uchar>(1,2)=6;
  18.  
     
  19.  
    B.at<uchar>(0,0)=60;
  20.  
    B.at<uchar>(0,1)=2;
  21.  
    B.at<uchar>(0,2)=3;
  22.  
    B.at<uchar>(1,0)=4;
  23.  
    B.at<uchar>(1,1)=5;
  24.  
    B.at<uchar>(1,2)=6;
  25.  
     
  26.  
    Mat AB=A.mul(B);
  27.  
     
  28.  
    cout<<"A=\n"<<A<<endl<<endl;
  29.  
    cout<<"B=\n"<<B<<endl<<endl;
  30.  
    cout<<"AB=\n"<<AB<<endl<<endl;
  31.  
     
  32.  
    system("pause");
  33.  
    }

输出:

AB中第一个元素应该为60*60=360,但AB默认的类型为CV_8UC1,即最大值只能是255;所以执行mul运算一定要定义AB足够的精度,防止溢出。

Opencv中Mat矩阵相乘——点乘、dot、mul运算详解的更多相关文章

  1. opencv中mat矩阵如何debug

    mat img 看type:img.type() rows:img.rows cols:img.cols channels:img.channels(),channels()这是一个函数,和上面两个有 ...

  2. OpenCV中Mat的列向量归一化

    OpenCV中Mat的列向量归一化 http://blog.csdn.net/shaoxiaohu1/article/details/8287528 OpenCV中Mat的列向量归一化 标签: Ope ...

  3. opencv中mat类介绍

    The class Mat represents an n-dimensional dense numerical single-channel or multi-channel array. It ...

  4. OpenCV中Mat的属性

    OpenCV中Mat的属性 最近在做一OpenCV的图像轮廓检验,但当用到霍夫变换时才发现对Mat的属性了解不足.Mat在OpenCV中的地位是及其重要的,因此有必要做一个总结. 大体上来说,Mat是 ...

  5. OpenGL中的矩阵相乘

    OpenGL中的矩阵相乘 1, 在OpenGL中所有的视图变换,模型变换 都是4×4矩阵,每个后续的glMultiMatrix*(N),或者变换函数,glTranslate* (),glRotate* ...

  6. OpenCV中Mat操作clone() 与copyto()的区别

    OpenCV中Mat操作clone() 与copyto()的区别 // Mat is basically a class with two data parts: the matrix header ...

  7. OpenCV中Mat的基本用法:创建、复制

    OpenCV中Mat的基本用法:创建.复制 一.Mat类的创建: 1.方法一: 通过读入一张图像,直接将其转换成Mat对象. Mat image = imread("test.jpg&quo ...

  8. PHP中IP地址与整型数字互相转换详解

    这篇文章主要介绍了PHP中IP地址与整型数字互相转换详解,本文介绍了使用PHP函数ip2long与long2ip的使用,以及它们的BUG介绍,最后给出自己写的两个算法,需要的朋友可以参考下 IP转换成 ...

  9. ArcGIS中的北京54和西安80投影坐标系详解

    ArcGIS中的北京54和西安80投影坐标系详解 1.首先理解地理坐标系(Geographic coordinate system),Geographic coordinate system直译为地理 ...

随机推荐

  1. LeetCode(2):Add Two Numbers 两数相加

    Medium! 题目描述: 给定两个非空链表来表示两个非负整数.位数按照逆序方式存储,它们的每个节点只存储单个数字.将两数相加返回一个新的链表. 你可以假设除了数字 0 之外,这两个数字都不会以零开头 ...

  2. web----WSGI

    概念: WSGI协议其实是定义了一种server与application解耦的规范 WSGI规范简单理解:一方面给Server提供接口,凡是以这种接口的web服务器,都是遵循WSGI规范的 另一方面给 ...

  3. 学习Struts2经验总结

    一.struts 访问路径问题 1) Struts2的思想:主要围着“action”转,只要找到“action”它就知道自己该干嘛了. 首先配置struts.xml ,我们可以明白的看到,action ...

  4. python 全栈开发,Day116(可迭代对象,type创建动态类,偏函数,面向对象的封装,获取外键数据,组合搜索,领域驱动设计(DDD))

    昨日内容回顾 1. 三个类 ChangeList,封装列表页面需要的所有数据. StarkConfig,生成URL和视图对应关系 + 默认配置 AdminSite,用于保存 数据库类 和 处理该类的对 ...

  5. python 全栈开发,Day69(Django的视图层,Django的模板层)

    昨日内容回顾 相关命令: 1 创建项目 django-admin startproject 项目名称 2 创建应用 python manage.py startapp app名称 3 启动项目 pyt ...

  6. Linux权限命令

    Linux 基础——权限管理命令chmod   一.Linux中的文件权限与目录权限 Linux中定义了3种访问权限,分别是r.w.x.其中r表示对象是可读的,w表示对象是可写的,x表示对象是可执行的 ...

  7. Spring 核心API

    BeanFactory: 这是一个工厂,用于生产任意Bean,采用延迟加载,第一次getBean时才会加载 ApplicationContext: 是BeanFactory的一个子接口,功能更强大(国 ...

  8. 01_kettle源码部署

    一 kettle源码部署概述 1.从git上选择合适的版本,并down下来: 2.创建一个java项目,建立core,dbdialog,engine,ui,plugins文件夹,和一个lib文件夹: ...

  9. Codeforces Round #468 (Div. 2, based on Technocup 2018 Final Round)

    A.B都是暴力搞一搞. A: #include<bits/stdc++.h> #define fi first #define se second #define mk make_pair ...

  10. Codeforces Round #369 (Div. 2)-D Directed Roads

    题目大意:给你n个点n条边的有向图,你可以任意地反转一条边的方向,也可以一条都不反转,问你有多少种反转的方法 使图中没有环. 思路:我们先把有向边全部变成无向边,每个连通图中肯定有且只有一个环,如果这 ...