Opencv中Mat矩陣相乘——點乘、dot、mul運算詳解

 

 

 

Opencv中Mat矩陣相乘——點乘、dot、mul運算詳解

版權聲明:本文爲博主原創文章,轉載請註明出處。 https://blog.csdn.net/dcrmg/article/details/52404580

 

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

 

 

  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的行數。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

 

 

  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_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聲明:

 

 

  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足夠的精度,防止溢出。
相關文章
相關標籤/搜索