一、opencv宽高对应关系:

Mat.rows = Mat.size().height = 高
Mat.cols = Mat.size().width = 宽

int sz_1[2] = { 200, 400 }; // {高,宽}  {Mat.rows,Mat.cols}
Mat m = cv::Mat(2, sz_1, CV_8UC1,Scalar::all(255));
or
Mat m = cv::Mat::ones(2, sz_1, CV_8UC1);
or
Mat m = cv::Mat::zeros(200, 400, CV_8UC1); // 高:200   宽:400

 二、opencv矩阵创建以及元素级访问

2.1 二维、三维数据的创建和访问

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

using namespace std;
using namespace cv;

int main(){
	Mat img = imread("123.jpg");
	Mat gray;
	cvtColor(img, gray, COLOR_BGR2GRAY);

        cv::Mat retMat = cv::Mat(600, 800, CV_8UC3, Scalar::all(255));  // 高, 宽, 通道数, 像素值

	// 创建单通道图片
	int sz[2] = { gray.rows, gray.cols };  // {高,宽}
        // 或者使用:Mat fgCount = Mat(2, sz, CV_8UC1, Scalar::all(0));
	Mat fgCount = cv::Mat::zeros(2, sz, CV_8UC1);
	cv::imshow("fgCount", fgCount);
	cv::waitKey(2000);
	fgCount.at<uchar>(20, 20) = 20;
	fgCount.at<uchar>(21, 21) = 21;
	std::cout << "hahhahh------------------" << std::endl;
	std::cout << int(fgCount.at<uchar>(20, 20)) << std::endl;
	std::cout << int(fgCount.at<uchar>(21, 21)) << std::endl;

	// 创建三维矩阵
	int samples_size[3];
	int height = gray.size().height;
	int width = gray.size().width;
	samples_size[0] = 20;
	samples_size[1] = gray.rows;
	samples_size[2] = gray.cols;
	Mat m_3 = cv::Mat::zeros(3, samples_size, CV_8UC1);
	std::cout << "Yes" <<std::endl;
	cout << "三维图像的维度:" << m_3.dims << endl;
	cout << "三维图像的通道数:" << m_3.channels() << endl;

	// 创建二维多通道(类似三维矩阵)
	typedef cv::Vec<double, 20> Vec20f;
	Mat m_2 = cv::Mat::zeros(gray.size().width, gray.size().height, CV_64FC(20));
	std::cout << "Yes" << std::endl;
	cout << "图像的维度:" << m_2.dims << endl;
	cout << "图像的通道数:" << m_2.channels() << endl;
	m_2.at<Vec20f>(20, 20)[11] = 123.33;
	cout << m_2.at<Vec20f>(20, 20)[11] << endl;

        // 遍历图片
        Mat src = imread("haha.png");
	Mat img = imread("haha.png");
	Mat img_2 = imread("haha.png");
	int nl = img.rows; //行数
	int nc = img.cols * img.channels(); //每行元素的总元素数量
	int div = 64;
	int cols = img.cols;
	// 采用指针
	double start_time = (double)getTickCount();
	for (int j = 0; j < nl; j++)
	{
		uchar* data = img.ptr<uchar>(j);
		for (int i = 0; i < cols; i++)
		{
			data[i* img.channels()] = 151;
		}               
	}
	double end_time = (double)getTickCount();
	double fps = (end_time - start_time) / getTickCount();
	cout << "采用指针所消耗时间:" << fps << endl;

	// 采用内置at方法
	start_time = (double)getTickCount();
	for (int j = 0; j < nl; j++)
	{
		for (int i = 0; i < cols; i++)
		{
			img_2.at<Vec3b>(j, i)[1] = 151;
		}
	}
	end_time = (double)getTickCount();
	fps = (end_time - start_time) / getTickCount();
	cout << "采用内置at方法消耗时间:" <<fps << endl;

	imshow("src", src);
	imshow("dst", img);
	imshow("img_2", img_2);
	waitKey(0);

}

opencv 三维点 opencv 三维矩阵_opencv 三维点

 初始化Mat对象:

Mat grad_x = (Mat_<int>(3, 3) << -1, 0, 1, -2, 0, 2, -1, 0, 1);
Mat grad_y = (Mat_<int>(3, 3) << -1, -2, -1, 0, 0, 0, 1, 2, 1);
cout << grad_x << endl;
cout << grad_y << endl;

opencv 三维点 opencv 三维矩阵_#include_02

2.2 四、五等高维数据创建和访问:

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

using namespace std;
using namespace cv;

int main() {
	int size4[4] = { 100, 100, 100, 100 };
	cv::Mat mat4D(4, size4, CV_8UC1, cv::Scalar(0));         // 创建四维Mat对象

	cout << (int)mat4D.ptr<uchar>(0, 0, 0)[4] << endl;
	mat4D.ptr<uchar>(0, 0, 0)[4] = 111;                      // 给(0,0,0,4)赋值
	cout << (int)mat4D.ptr<uchar>(0, 0, 0)[4] << endl;
	cout << endl;



	int size5[5] = {100,100,100,100,100};
	cv::Mat mat5D(5, size5, CV_8UC1, cv::Scalar(0));          // 创建五维Mat对象

	// 输出[1,2,3,4,5]位置的值
	cout << (int)*(mat5D.data + 1 * 100 * 100 * 100 * 100 + 2 * 100 * 100 * 100 + 3 * 100 * 100 + 4 * 100 + 5) << endl;
	*(mat5D.data + 1 * 100 * 100 * 100 * 100 + 2 * 100 * 100 * 100 + 3 * 100 * 100 + 4 * 100 + 5) = 112;
	cout << (int)*(mat5D.data + 1 * 100 * 100 * 100 * 100 + 2 * 100 * 100 * 100 + 3 * 100 * 100 + 4 * 100 + 5) << endl;
	cout << endl;


	cv::Mat mat5D_float(5, size5, CV_16FC1, cv::Scalar(0));   // 创建五维Mat对象

	// 输出[1,2,3,4,5]位置的值
	// *((float*)(mat5D_float.data + 1 * 100 * 100 * 100 * 100 + 2 * 100 * 100 * 100 + 3 * 100 * 100 + 4 * 100 + 5))这样也可以
	cout << *((float*)mat5D_float.data + 1 * 100 * 100 * 100 * 100 + 2 * 100 * 100 * 100 + 3 * 100 * 100 + 4 * 100 + 5) << endl;
	*((float*)mat5D_float.data + 1 * 100 * 100 * 100 * 100 + 2 * 100 * 100 * 100 + 3 * 100 * 100 + 4 * 100 + 5) = 113;
	cout << *((float*)mat5D_float.data + 1 * 100 * 100 * 100 * 100 + 2 * 100 * 100 * 100 + 3 * 100 * 100 + 4 * 100 + 5) << endl;
	cout << endl;

	waitKey(10000);
}

大于四维的Mat,既不能使用at,也不能使用ptr访问元素。解释一下上面的方法:使用Mat类中的data成员变量,它指向Mat数据区的首地址,对于Mat类型的数据,它们是按照线性方式存值的,我们知道首地址之后,就可以通过指针偏移的方式,去索引任意元素的值。对于 100x100x100x100x100 的五维Mat,如果索引要 [a,b,c,d,e] 中的值,则可以使用下面的方式:

uchar a = *(mat5D.data + a*100*100*100*100 + b*100*100*100 + c*100*100 + d*100 + e);

如果你在Mat中存储的不是CV_8UC1,而是别的类型,比如是CV_32FC1,那么就不能直接使用data,因为它默认是uchar类型的指针,需要将它强转为float类型。代码如下: 

float a = *((float*)mat5D.data + a*100*100*100*100 + b*100*100*100 + c*100*100 + d*100 + e);

上述代码结果:

opencv 三维点 opencv 三维矩阵_opencv 三维点_03

其他方式访问:

// 利用Mat的 Mat(int ndims, const int* sizes, int type, void* data, const size_t* steps=0) 这一成员函数

int p = 1;
int q = 2;
int t = 3;
int u = 4;
int sizes[] = { p,q,t,u };
int all = p * q*t*u;
float *d1 = new float[all];
for (int i = 0; i < all; i++)
{
	d1[i] = i * 1.0f;
}

Mat a = Mat(4, sizes, CV_32S, d1);


int n, c, h, w, id;
//四维数据的访问为:
for (n = 0; n < p; n++)
{
	for (c = 0; c < q; c++)
	{
		for (h = 0; h < t; h++)
		{
			for (w = 0; w < u; w++)
			{
				id = a.step[0] * n + a.step[1] * c + a.step[2] * h + w * a.step[3];
				//cout << id << endl;
				float *p = (float*)(a.data + id);
				cout << *p << endl;
			}
		}
	}
}

三、opencv矩阵运算

3.1 基础运算

现在opencv的Mat类矩阵运算操作已经和numpy很像了,一些案例如下:

void matOP() {
	Mat mat_1(4, 9, CV_16SC1);
	Mat mat_2(4, 9, CV_16SC1);
	Mat mat_3(4, 9, CV_16SC1);

	RNG rng(unsigned int(time(NULL)));
	rng.fill(mat_1, RNG::UNIFORM, -4, 4, true);
	rng.fill(mat_2, RNG::UNIFORM, 0, 10, true);

	mat_3 = mat_1 + mat_2;

	cout << "mat_1:" << endl;
	cout << mat_1 << endl;
	cout << "mat_2:" << endl;
	cout << mat_2 << endl;
	cout << "mat_3:" << endl;
	cout << mat_3 << endl;

	Mat big_zero = Mat::zeros(4, 9, CV_16SC1);
	big_zero = mat_3 >= 0;
	cout << "big_zero:" << endl;
	cout << big_zero << endl;

	Mat ret_1 = Mat::zeros(4, 9, CV_16SC1);
	bitwise_and(mat_3, mat_3, ret_1, big_zero);
	cout << "ret_1:" << endl;
	cout << ret_1;

	int a;
	cin >> a;
}

结果截图:

opencv 三维点 opencv 三维矩阵_#include_04

 3.2 乘除运算

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

using namespace std;
using namespace cv;

int main() {
	//点乘运算:矩阵的点乘即两个矩阵对应位置的数值相乘
	// 点乘方法一
	Mat m1 = (Mat_<uchar>(3, 2) << 200, 12, 21, 22, 31, 32);
	Mat m2 = (Mat_<uchar>(3, 2) << 150, 11, 22, 21, 32, 31);
	Mat dst = m1.mul(m2);     // 这种方法的两个Mat对象的数据类型必须相同才可以进行点乘,返回的矩阵的数据类型不变
	cout << "方法一点乘运算结果为:" << dst << endl;

	// 点乘方法二
	Mat m1a = (Mat_<uchar>(3, 2) << 200, 12, 21, 22, 31, 32);
	Mat m2a = (Mat_<float>(3, 2) << 150, 11, 22, 21, 32, 31);

	Mat dsta;
	multiply(m1a, m2a, dsta, 1.0, CV_64FC1);
	cout << "方法二点乘运算结果为:" << dsta << endl;


	// 点除运算:矩阵的点乘即两个矩阵对应位置的数值相除
	// 点除方法一
	Mat m1b = (Mat_<uchar>(3, 2) << 301, 22, 21, 22, 31, 32);
	Mat m2b = (Mat_<uchar>(3, 2) << 150, 11, 22, 21, 32, 0);

	Mat dstb = m1b / m2b;  // 如果分母为0的除法运算时,默认得到的值为0
	cout << "方法一点除运算结果为:" << dstb << endl;

	// 点除方法二
	Mat m1c = (Mat_<uchar>(3, 2) << 200, 12, 21, 22, 31, 32);
	Mat m2c = (Mat_<float>(3, 2) << 150, 11, 22, 21, 32, 31);

	Mat dstc;
	divide(m1c, m2c, dstc, 1.0, CV_64FC1);
	cout << "方法二点除运算结果为:" << dstc << endl;


	// 矩阵运算
	// 单通道矩阵运算
	Mat m1d = (Mat_<float>(3, 2) << 11, 12, 21, 22, 31, 32);
	Mat m2d = (Mat_<float>(2, 3) << 11, 12, 13, 21, 22, 23);

	Mat dstd = m1d * m2d;  // 两个Mat只能同时是float或者double类型
	cout << "单通道矩阵运算结果为:" << dstd << endl;


	waitKey(10000);
}

opencv 三维点 opencv 三维矩阵_数组_05

        需要说明的是,对于多通道矩阵乘法opencv有特殊处理,即将两通道矩阵当做复数相乘。详细可前往这里。乘除运算也参考Ta。

四、opencv产生随机数

比RNG方便,如下(每次产生的随机是一样的):

void rand_test() {
	Mat R = Mat(3, 2, CV_16SC3);
	// randu(dst, low, high);dst – 输出数组或矩阵 ;low – 区间下界(闭区间); high - 区间上界(开区间)
	randu(R, -4, 5);                         // 返回均匀分布的随机数,填入数组或矩阵
	cout << R << endl;

	// randn(dst, mean, stddev);dst – 输出数组或矩阵; mean – 均值; stddev - 标准差
	randn(R, -4, 4);                        // 返回高斯分布的随机数,填入数组或矩阵
	cout << R << endl;

	/*randShuffle(InputOutputArray dst,     输入输出数组(一维)
					double iterFactor = 1., 决定交换数值的行列的位置的一个系数...
					RNG* rng = 0)          (可选)随机数产生器,0表示使用默认的随机数产生器,即seed = -1。rng决定了打乱的方法*/
	unsigned int seed = time(NULL);
	RNG rng(seed);
	randShuffle(R, 1, &rng);                // 将原数组(矩阵)打乱
	cout << R << endl;
}

结果:

opencv 三维点 opencv 三维矩阵_opencv_06