• 前言
    这次主要介绍了Mat类中,一些区域的选取和数学计算,里面的函数和用法都已经在代码中进行了解释。
#include<opencv2\opencv.hpp>
#include<iostream>

using namespace std;
using namespace cv;

template <class T>
void display(string str, Mat& src) //将矩阵数据进行展示
{
	cout << str << endl;
	int cols = src.cols;
	int rows = src.rows;
	for (int i = 0; i < rows; i++)
	{
		for (int j = 0; j < cols; j++)
		{
			cout << src.at<T>(i, j) << ",";
		}
		cout << endl;
	}
}

int main()
{
	//----------------------------------------------------------------------
	//创建一个矩阵,并且获取其基本信息
	//----------------------------------------------------------------------
	Mat matrix = (Mat_<int>(5, 5) << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
		11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25);//创建一个5行5列的矩阵,int类型
	cout << "尺寸:" << (Size)matrix.size()<< endl; //打印尺寸
	cout << "通道数:" << matrix.channels() << endl;//打印通道数
	cout << "行数乘以列数:" << matrix.total() << endl;//和通道数无关
	cout << "维度:" << matrix.dims << endl;//矩阵维度

	//----------------------------------------------------------------------
	//获取Mat矩阵中的某一区域值
	//----------------------------------------------------------------------

	//1.使用成员函数row(i)或着col(j)
	Mat mr = matrix.row(3); //得到矩阵的第3行
	Mat mc = matrix.col(3); //得到矩阵的第3列
	display<int>("矩阵的行",mr);
	display<int>("矩阵的列",mc);

	//2.使用成员成员函数rowRange(),colRange()
	Mat r_rang = matrix.rowRange(Range(2, 4)); //获取matrix的第2,3行
	display<int>("获取第2,3行",r_rang);
	Mat c_rang = matrix.colRange(Range(2, 4)); //获取第2,3列
	display<int>("获取第2,3列",c_rang);
	//这里的c_rang和r_rang都是指向原来的矩阵的。他们的地址都是一样的

	//3.使用clone和copyTo
	r_rang = matrix.rowRange(2, 4).clone();//将第2,3行克隆一份,修改了r_rang,matrix也不会变
	matrix.colRange(2, 4).copyTo(c_rang); //将matrix中的第2,3列复制到c_rang中
	display<int>("赋值第2,3行", r_rang);
	display<int>("赋值第2,3列", c_rang);

	//4.使用Rect类
	// 一下三种方式都是获取一个区域
	/*
		1  2  3  4  5 
		6  7  8  9  10				8  9
		11 12 13 14 15    --->		13 14  
		16 17 18 19 20
		21 22 23 24 25
	*/
	Mat roi1 = matrix(Rect(Point(2, 1),Point(4, 3))); //左上角的坐标,右下角的坐标 区间:左闭右开
	Mat roi2 = matrix(Rect(2, 1, 2, 2));  //起始坐标+宽度和高度
	Mat roi3 = matrix(Rect(Point(2, 1), Size(2, 2)));//起始坐标+尺寸
	display<int>("获取矩阵的区域方法一:", roi1);
	display<int>("获取矩阵的区域方法二:", roi2);
	display<int>("获取矩阵的区域方法三:", roi3);

	//----------------------------------------------------------------------
	//关于矩阵的运算
	//----------------------------------------------------------------------

	//1.矩阵相加
	//方法一:利用重载运算符 一般用在矩阵类型相同的部分
	Mat src1 = (Mat_<int>(2, 3) << 23, 123, 90, 100, 250, 0);
	Mat src2 = (Mat_<int>(2, 3) << 125, 150, 60, 100, 10, 40);
	Mat dst = src1 + src2;
	display<int>("运算符矩阵相加",dst);

	//方法二:利用add函数
	src2.convertTo(dst, CV_8U);
	add(src1, dst, dst,Mat(),CV_64FC1);//可是用于不同的数据类型的矩阵
	//第四个类型参数 只有类型是相同的才可以使用默认值-1
	display<float>("add函数矩阵相加", dst);

	//2.矩阵相减
	//方法一:矩阵相减 利用重载运算符
	dst = src1 - src2;
	display<int>("运算符矩阵相减", dst);
	//方法二:使用subtract()
	subtract(src1, src2, dst);
	display<int>("substract矩阵相减", dst);

	//3.点乘运算   两个矩阵对应位置的数相乘
	//方法一,利用Mat里面的成员函数 mul
	dst = src1.mul(src2); //两个数据类型必须相同才可以
	display<int>("mul矩阵点乘", dst);
	//方法二:利用multiply函数,可以用于不同的数据类型
	multiply(src1, src2, dst);
	display<int>("multiply矩阵点乘", dst);

	//4.点除运算   两个矩阵对应位置相除
	dst = src1 / src2;
	display<int>("点除运算", dst);

	//5.矩阵乘法 
	//注意!!!矩阵乘法只能接受float或者double类型,对于其他类型的矩阵乘法会报错
	//注意!!!矩阵乘法只能接受float或者double类型,对于其他类型的矩阵乘法会报错
	//注意!!!矩阵乘法只能接受float或者double类型,对于其他类型的矩阵乘法会报错

	//方法一:利用重载运算符进行计算     
	Mat src3 = (Mat_<float>(2, 3) << 1.0, 2, 3, 4, 5, 6); 
	Mat src4 = (Mat_<float>(3, 2) << 6.0, 5, 4, 3, 2, 1);
	dst = src3*src4;
	display<float>("利用运算符进行矩阵乘法", dst);

	//注:如果是双通道,那就是当做一个复数矩阵相乘,列如     
	Mat src5 = (Mat_<Vec2f>(2, 1) << Vec2f(1, 2), Vec2f(3, 4));
	Mat src6 = (Mat_<Vec2f>(1, 2) << Vec2f(10, 20), Vec2f(5, 15));
	dst = src5*src6;
	display<Vec2f>("双通道矩阵乘法", dst);

	//方法二利用Opencv给出的gemm函数 (geem是generalized matrix multiplication的缩写)
	gemm(src3, src4, 1, NULL, 0, dst, 0); //函数参数flag为0时:和输出结果为:dst = src1*src2*alpha + src3*beta
	display<float>("gemm函数进行矩阵乘法", dst);
	//6.其他运算
	//(1)幂指数
	Mat src7 = (Mat_<float>(2,2) << 2, 3, 4, 5);
	pow(src7, 2, dst);
	display<float>("幂指数运算pow:", dst);

	//(2)开平方运算
	sqrt(src7, dst);
	display<float>("开放运算sqrt:", dst);

	//(3)指数运算
	exp(src7, dst);
	display<float>("指数运算exp:", dst);

	//(4)对数运算    log是以e为底的 也就是ln
	log(src7, dst);
	display<float>("对数运算log:", dst);

	system("pause");
	return 0;
}