# OpenCV Mat之间的substact/add/abs/absdiff

# cv::substract

计算矩阵与矩阵之间每个元素的差值。

函数原型:

void subtract(InputArray src1, 
              InputArray src2, 
              OutputArray dst,
              InputArray mask = noArray(), 
              int dtype = -1);
  • src1可以是Mat/Scalar
  • src2可以是Mat/Scalar
  • dst可以是Mat/Scalar
  • mask掩码矩阵,类型需要为8UC18SC1,mask==0的位置取src1对应的值,不做减法
  • dtype控制输出矩阵的数据类型

实例:

#include <iostream>
#include <opencv2/core.hpp>

using namespace std;

void printMat(cv::Mat &m1);

int main()
{
    cv::Mat m1 = (cv::Mat_<float>(3,3) << -1.2f,2.1f,3.0f,
                                          2.3f,4.5f,5.6f,
                                          7.1f,2.5f,8.9f);
    
    cv::Mat m2 = (cv::Mat_<float>(3,3) << -1.2f,2.1f,3.0f,
                                          2.5f,4.8f,5.6f,
                                          7.1f,2.5f,8.9f);

    cv::Mat mc1 = cv::Mat::zeros(cv::Size(2, 2), CV_8SC3);
    cv::Mat mc2 = cv::Mat::zeros(cv::Size(2, 2), CV_8SC3);
    cv::Mat mask = cv::Mat::ones(cv::Size(2, 2), CV_8SC1);
    mask.at<uchar>(0, 0) = 0;
    mc2.setTo(cv::Scalar(2,2,2));
    cout << "mc1 = " << mc1 << " mc2 = " << mc2;
    cv::Scalar mcv = cv::Scalar(2, 3, 1);

    cv::Mat m;
    cv::subtract(m1, m2, m);
    printMat(m);

    cv::Scalar v(1.2);
    cv::subtract(m1, v, m);
    printMat(m);

    cv::subtract(mc1, mc2, m, mask);
    std::cout << "Mat: \n" << m << std::endl;

    cv::subtract(mc1, mcv, m);
    std::cout << "Mat: \n" << m << std::endl;

    cv::subtract(mc1, v, m, cv::noArray(), CV_32FC3);
    std::cout << "Mat: \n" << m << std::endl;
    return 0;
}

void printMat(cv::Mat &m1)
{
    cout << "Mat: \n";
    for (size_t i = 0; i < m1.rows; ++i)
    {
        for (size_t c = 0; c < m1.cols; ++c)
            cout << m1.at<float>(i, c) << " ";
        cout << endl;
    }
   
}

上面的例子中分别有:

  • 单通道Mat减去Mat
  • 单通道Mat减去Scalar
  • 多通道Mat减去‵Mat`
  • 多通道Mat减去多通道‵Scalar`
  • 多通道Mat减去单通道‵Scalar,只作用在Mat`对应的单个通道上

上面例子的输出结果:

mc1 = [  0,   0,   0,   0,   0,   0;
         0,   0,   0,   0,   0,   0] 
mc2 = [  2,   2,   2,   2,   2,   2;
         2,   2,   2,   2,   2,   2]
Mat: 
    [0 0 0;
     -0.2 -0.3 0;
     0 0 0]
Mat: 
    [-2.4 0.9 1.8;
     1.1 3.3 4.4;
     5.9 1.3 7.7]
Mat: 
    [  0,   0,   0,  -2,  -2,  -2;
       -2,  -2,  -2,  -2,  -2,  -2]
Mat: 
    [ -2,  -3,  -1,  -2,  -3,  -1;
    -2,  -3,  -1,  -2,  -3,  -1]
Mat: 
    [-1.2, 0, 0, -1.2, 0, 0;
     -1.2, 0, 0, -1.2, 0, 0]

如果cv::subtract(mc1, v, m, cv::noArray(), CV_32FC3);这里没有指定类型,输出的将是8SC1类型,结果为:

Mat: 
    [-1, 0, 0, -1, 0, 0;
     -1, 0, 0, -1, 0, 0]

# cv::add

cv::add是两个输入数据元素间相加,和substract基本相同。

函数原型:

void add(InputArray src1, 
         InputArray src2, 
         OutputArray dst,
         InputArray mask = noArray(), 
         int dtype = -1);

参数参考cv::substract

实例:

    cv::Mat m;
    cv::subtract(m1, m2, m);
    printMat(m);

    cv::Scalar v(1.2);
    cv::subtract(m1, v, m);
    printMat(m);

    cv::subtract(mc1, mc2, m, mask);
    std::cout << "Mat: \n" << m << std::endl;

    cv::subtract(mc1, mcv, m);
    std::cout << "Mat: \n" << m << std::endl;

    cv::subtract(mc1, v, m, cv::noArray(), CV_32FC3);
    std::cout << "Mat: \n" << m << std::endl;

结果,

Mat: 
    -2.4 4.2 6 
    4.8 9.3 11.2 
    14.2 5 17.8 
Mat: 
    0 3.3 4.2 
    3.5 5.7 6.8 
    8.3 3.7 10.1 
Mat: 
    [  0,   0,   0,   2,   2,   2;
    2,   2,   2,   2,   2,   2]
Mat: 
    [  2,   3,   1,   2,   3,   1;
    2,   3,   1,   2,   3,   1]
Mat: 
    [1.2, 0, 0, 1.2, 0, 0;
    1.2, 0, 0, 1.2, 0, 0]

可以看到和cv::substract的操作相同,除了减法变成了加法运算。

# cv::abs

对输入矩阵的每个元素取绝对值。

实例:

m = cv::abs(m);
printMat(m);

结果为:

Mat: 
    1.2 2.1 3 
    2.3 4.5 5.6 
    7.1 2.5 8.9

# cv::absdiff

cv::absdiff对输入的两个矩阵先做差再取绝对值。

函数原型:

void absdiff(InputArray src1, InputArray src2, OutputArray dst);

实例:

cv::absdiff(m1, m2, m);
printMat(m);

cv::absdiff(mcv, mcv, m);
cout << m << std::endl;

输出:

Mat: 
    0 0 0 
    0.2 0.3 0 
    0 0 0 

[0,0,0,0]

Scalar能中有四个元素Scalar_(_Tp v0, _Tp v1, _Tp v2=0, _Tp v3=0);,因此尽管输入是(2,3,1)打印出来的结果仍然是[0,0,0,0]

1.https://docs.opencv.org/4.8.0/dd/d4d/tutorial_js_image_arithmetics.html (opens new window)