• OpenCV 对Mat矩阵加、减、乘、除、转置等操作的总结


    1、矩阵加

    1) 使用重载的 “+” 运算符

    矩阵的加法是指两个矩阵对于位置的数值相加,使用OpenCv重载的 “+” 运算符,假设两个矩阵都为uchar类型,例如:

    1 Mat src1 = (Mat_<uchar>(2,3) << 23, 123, 90, 100, 250, 0);
    2 Mat src2 = (Mat_<uchar>(2,3) << 125, 150, 60, 100, 10, 40);
    3 Mat dst = src1 + src2;

    123+150应该等于273, 因为两个矩阵的类型都是uchar, 所以"+“运算计算出来的和也是uchar类型, 但是uchar类型范围的最大值是255, 所以273限制为了255。

    利用”+“运算符计算计算Mat的和需注意:两个Mat的数据类型必须是一样的, 否则会报错。

    一个数值与一个Mat对象相加, 也可以使用”+"运算符, 但是无论这个数值是什么数据类型, 返回的Mat的数据类型都与输入的Mat相同,且结果是矩阵中的每个元素都与这个数值相加:
    例如:

    1 float value = 100.0;
    2 Mat dst1 = src1 + value;
    2) 使用add函数
    1 void add
    2 (
    3     InputArray src1, 
    4     InputArray src2, 
    5     OutputArray dst, 
    6     InputArray mask = noArray(), 
    7     int dtype = -1
    8 );

    例如:

    1 Mat src1 = (Mat_<uchar>(2,3) << 23, 123, 90, 100, 250, 0);
    2 Mat src2 = (Mat_<uchar>(2,3) << 125, 150, 60, 100, 10, 40);
    3 Mat dst;
    4 add(src1, src2, dst, Mat(), CV_64FC1);

    使用add函数时, 输入矩阵的数据类型可以不同, 二输出矩阵的数据类型可以根据情况自行指定, 只有当src1和src2的数据类型相同时, 才能令dtype = -1, 否则仍然会报错。

    3) 两个向量之间也可以做加法运算
    1 Vec3f v1 = Vec3f(1, 2, 3);
    2 Vec3f v2 = Vec3f(10, 1, 12);
    3 Vec3f v = v1 + v2;
    4)线性相加scaleAdd
    1 C++: void scaleAdd
    2 (
    3     InputArray src1,     // 第一个输入矩阵
    4     double alpha,        // 第一个输入矩阵的比例因子
    5     InputArray src2,     // 与src1大小和类型相同的第二个输入矩阵。
    6     OutputArray dst
    7 )

    它计算一个缩放数组和另一个数组的和:
    dst(I) = alpha * src(I) + src2(I)
    例如:

    scaleAdd(imageA,k,imageB,resultC);

    该函数也可以用矩阵表达式模拟,例如:

    1 Mat A(3, 3, CV_64F);
    2 ...
    3 A.row(0) = A.row(1)*2 + A.row(2);
    5)两个数组的加权和addWeighted
     1 C++: void addWeighted
     2 (
     3     InputArray src1,      // 第一个图像矩阵
     4     double alpha,         // 第一个数组元素的权重。
     5     InputArray src2,      // 与src1大小和通道相同的第二个输入图像矩阵。
     6     double beta,          // 第二个数组元素的权值。
     7     double gamma,         // 与输入数组具有相同大小和通道数的输出数组。
     8     OutputArray dst,      // 每个和加上一个标量。
     9     int dtype=-1          // 可选输出阵列深度;当两个输入数组具有相同的
    10                           // 深度时,可以将dtype设置为-1,这将等效于src1.depth()。
    11 )

    该函数可替换为矩阵表达式:
    dst = src1 * alpha + src2 * beta + gamma;
    例如:

    1     Mat img1=imread("./a1.jpg");
    2     Mat img2=imread("./a2.jpg");
    3     Mat dst;
    4     addWeighted(img1,0.5,img2,0.3,0,dst);

    2、矩阵减

    1)使用重载“-”运算符

    我们可以使用和**"-"**符号进行 矩阵减运算。
    例如:

    1 Mat a= Mat::eye(Size(3,2), CV_32F);  
    2 Mat b= Mat::ones(Size(3,2), CV_32F); 
    3 Mat d= a-b;
    CSDN图标

    注:如果图像是uchar类型的,144-240不会是 - 96,而是uchar能表示的最小值0

    2)减法函数subtract

    计算两个数组或数组与标量之间的每个元素的差。

    1 C++: void subtract
    2 (
    3     InputArray src1,           // 第一个输入数组或标量。
    4     InputArray src2,           // 第二个输入数组或标量。
    5     OutputArray dst,           // 与输入阵列相同大小、相同通道数的输出阵列。
    6     InputArray mask=noArray(), // 可选操作面具;这是一个8位的单通道数组,
    7                                // 指定要更改的输出数组的元素。
    8     int dtype=-1               // 输出数组的可选深度
    9 )

    例如:

    1 imshow("img1",img1);
    2 imshow("img2",img2);
    3 subtract(img1,img2,dst); // saturate(img1 - img2)
    4 //注意:要求被处理图片尺寸一致

    注:图像元素类型是uchar,如果相减小于0,结果值会变成0,如果大于255,变成255。

    3) 元素的绝对差absdiff
    计算两个数组或数组与标量之间的每个元素的绝对差。

    1 C++: void absdiff
    2 (
    3     InputArray src1,    // 第一个输入数组或标量。
    4     InputArray src2,    // 第二个输入数组或标量。
    5     OutputArray dst     // 与输入数组具有相同大小和类型的输出数组。
    6 )

     dst = saturate(|src1 - src2|)
    例如:

    1 imshow("img1",src1);
    2 imshow("img1",src2);
    3 Mat dst;
    4 absdiff(src1, src2, dst);//若dst<0,则dst=|dst|>=0

    3、矩阵乘

    1) 矩阵乘A*B

    是以数学运算中矩阵相乘的方式实现的,即Mat矩阵A和B被当做纯粹的矩阵做乘法运算,这就要求A的列数等于B的行数时,才能定义两个矩阵相乘。如A是m×n矩阵,B是n×p矩阵,它们的乘积AB是一个m×p矩阵。

    例如:

    1 Mat A=Mat::ones(2,3,CV_32FC1);
    2 Mat B=Mat::ones(3,2,CV_32FC1);
    3 ...
    4 AB=A*B;

    2) 点乘A.dot(B)(与MATLAB的概念有点区别)
    参与点乘的两个Mat矩阵的数据类型(type)只能是 CV_32F、 CV_64FC1、 CV_32FC2、 CV_64FC2 这4种类型中的一种。若选用其他类型,比如CV_8UC1,编译器会报错。

    说明: 对于向量a和向量b:

    在这里插入图片描述
    在这里插入图片描述
    a和b的点积公式为:

    A.dot(B)操作相当于数学向量运算中的点乘,也叫向量的内积、数量积。 对两个向量执行点乘运算,就是对这两个向量对应位一一相乘之后求和的操作,点乘的结果是一个标量。 Mat矩阵的dot方法扩展了一维向量的点乘操作,把整个Mat矩阵扩展成一个行(列)向量,之后执行向量的点乘运算,仍然要求参与dot运算的两个Mat矩阵的行列数完全一致。

    dot方法声明中显示返回值是double,所以A.dot(B)结果是一个double类型数据,不是Mat矩阵,不能把A.dot(B)结果赋值给Mat矩阵!

    例如:

    1 Mat A=Mat::ones(2,3,CV_8UC1);
    2 Mat B=Mat::ones(2,3,CV_8UC1);
    3 double AB;
    4 ...
    5 AB = A.dot(B);

    dot操作不对参与运算的矩阵A、B的数据类型做要求,CV_8UC1、CV_32FC1等,可以是任何Opencv定义的类型,如在2中使用的就是CV_8UC1。

    若参与dot运算的两个Mat矩阵是多通道的,则计算结果是所有通道单独计算各自.dot之后,再累计的和,结果仍是一个double类型数据。

    3) 计算两个Mat矩阵对应位的乘积A.mul(B)
    要求参与运算的矩阵A的行列和B的行列数一致。计算结果是跟A或B行列数一致的一个Mat矩阵。
    mul说明:

    1、mul操作不对参与运算的两个矩阵A、B有数据类型上的要求,但要求A,B类型一致,不然报错;
    2、Mat AB=A.mul(B),若声明AB时没有定义AB的数据类型,则默认AB的数据类型跟A和B保存一致;
    3、若AB精度不够,可能产生溢出,溢出的值被置为当前精度下的最大值;

    例如:

    1 Mat A=Mat::ones(2,3,CV_8UC1);
    2 Mat B=Mat::ones(2,3,CV_8UC1);
    3 ...
    4 Mat AB=A.mul(B);
    4) 矩阵与标量相乘

    使用“*”示矩阵与标量相乘;
    例如:

    1 Mat m1 = Mat::eye(2,3,CV_32FC1);
    2 ...
    3 Mat m2 = m1*2;

    4、矩阵除

    1)使用重载的 “/” 运算符

    A/B; alpha/A; A/alpha都是点除
    例如:

    1 Mat src1 = (Mat_<int>(2, 3) << 4, 7, 1, 5, 20, 24);  //2行3列的矩阵
    2 Mat src2 = (Mat_<int>(2, 3) << 2, 7, 5, 5, 4, 48);  //2行3列的矩阵
    3 Mat dst1, dst2, dst3;
    4 dst1 = src1 / 4;
    5 dst2 = 20 / src1;
    6 dst3 = src1 / src2;
    7 cout << "A/alpha:
    " << dst1 << endl << endl;
    8 cout << "alpha/A:
    " << dst2 << endl << endl;
    9 cout << "A/B:
    " << dst3 << endl;

    输出结果:

    CSDN图标

    2)矩阵除函数 divide

    对一个数组执行两个数组或一个标量的每个元素的除法。

    1 C++: void divide
    2 (
    3     InputArray src1,     // 第一个输入矩阵
    4     InputArray src2,     // 与src1大小和类型相同的第二个输入矩阵。
    5     OutputArray dst,     // 与src2大小和类型相同的输出矩阵。
    6     double scale=1,      // 标量的因子
    7     int dtype=-1         
    8 )

    函数将一个数组除以另一个数组:
             dst = saturate(src1*scale/src2)
    如果没有src1时:
             dst = saturate(scale/src2);
    例如:

    1 Mat img0 = cv::imread("img_0.jpg", -1);
    2 Mat img1 = cv::imread("img_1.jpg", -1);
    3 Mat img2;
    4 divide(img0, img1, img2, 50, -1);

    5、矩阵的转置

    由Mat类t()函数实现矩阵的转置
    例如:

    1 Mat m1 = Mat::eye(4,6,CV_32FC1);
    2 ...
    3 Mat m1t = m1.t();

    6、矩阵的逆

    其中inv(A)表示矩阵A的逆矩阵
    例如:

    1 Mat m1 = Mat::eye(5,5,CV_32FC1);
    2 ...
    3 Mat m1inv = m1.inv();

    7、矩阵中非零元素个数

    使用 countNonZero() 函数实现物体的像素或面积常需要用到计算矩阵中的非零元素个数
    例如:

    1 Mat m1 = Mat::eye(6,6,CV_32FC1);
    2 ...
    3 int m1num = countNonZero(m1);

    8、矩阵中均值和标准差

    OpenCV提供了矩阵均值和标准差计算功能,使用 meanStdDev(src,mean,stddev) 函数实现
    例如:

     1 Mat m1 = Mat::eye(5,5,CV_32FC1);
     2 Mat mean,stddev;
     3 ...
     4 meanStdDev(m1,mean,stddev);
     5 .
     6 .
     7 .
     8 Mat m3(Size(5,5),CV_8UC3,Scalar(255,200,100));
     9 Mat mean3,stddev3;
    10 ...
    11 meanStdDev(m3,mean3,stddev3);

    注:当src为多通道或多维矩阵时,则函数分别计算不同通道的均值与标准差,因此返回的mean和stddev为对应维度的向量;

     
  • 相关阅读:
    关于C#中timer类 (转)
    AutoResetEvent (转)
    给韬哥的回复
    sql中的case when 的用法涉及到大于小于号
    vba中获取当前日期
    vba中的小技巧
    sql server2000中的两个整数相除保留十位小数
    vba中新建文件,关闭文件,锁屏,覆盖同名文件
    无法切换到google.com的解决办法
    mysql 常用命令
  • 原文地址:https://www.cnblogs.com/ybqjymy/p/14577067.html
Copyright © 2020-2023  润新知