zoukankan      html  css  js  c++  java
  • Opencv中Mat矩阵相乘——点乘、dot、mul运算详解

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

    版权声明:本文为博主原创文章,转载请注明出处。 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= "<<A<<endl<<endl;
    30.  
      cout<<"B= "<<B<<endl<<endl;
    31.  
      cout<<"AB= "<<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= "<<A<<endl<<endl;
    29.  
      cout<<"B= "<<B<<endl<<endl;
    30.  
      cout<<"double类型的AB= "<<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= "<<A<<endl<<endl;
    29.  
      cout<<"B= "<<B<<endl<<endl;
    30.  
      cout<<"AB= "<<AB<<endl<<endl;
    31.  
       
    32.  
      system("pause");
    33.  
      }

    输出:


    AB中第一个元素应该为60*60=360,但AB默认的类型为CV_8UC1,即最大值只能是255;所以执行mul运算一定要定义AB足够的精度,防止溢出。
  • 相关阅读:
    洛谷P1421 小玉买文具
    洛谷P1035 级数求和
    洛谷 P2337 【[SCOI2012]喵星人的入侵】
    洛谷P1002 过河卒
    洛谷 P4073 [WC2013]平面图
    洛谷 P4705 玩游戏
    python3.7-初学篇-06
    python3.7-初学篇-04
    python3.7-初学篇-03
    python3.7-初学篇-02
  • 原文地址:https://www.cnblogs.com/timssd/p/10556281.html
Copyright © 2011-2022 走看看