opencv基本知识

提示:基于windows10、vs2015、OpenCv4.1.0。


1、Mat类简介

OpenCv提供了Mat类用来存储矩阵类型数据,包括向量、矩阵、图像等数据。Mat类分为分为矩阵头和指向存储数据的矩阵指针两部分。矩阵头包含矩阵的尺寸、存储方法、地址和引用次数。矩阵头是一个常数,绝大数情况下,矩阵头的大小远小于矩阵数据量的大小。

#include <opencv2\opencv.hpp>
#include <iostream>
 
using namespace std;
using namespace cv;
 
int main()
{
	Mat a;
	a = imread("D:\\lena.jpg"); //向a中赋值图像数据
	Mat b = a;//只是复制了矩阵头和指向存储数据的指针(指向的是同一个矩阵数据)
	waitKey();
	return 0;
}

声明一个指定类型的Mat类:

Mat b = Mat_<double>(3, 3);//创建一个3*3的矩阵存放double类型数据

通过OpenCv数据类型创建Mat类

Mat a(640, 480, CV_8UC3)//创建一个640*480的3通道矩阵用于存放彩色图像
Mat a(3, 3, CV_8UC1);//创建一个3*3的8位无符号整数的单通道矩阵
Mat a(3, 3, CV_8U);//创建单通道矩阵,C1标识可以省略

2、Mat类的构造与赋值

2.1、Mat类的构造

【1】默认构造函数

cv::Mat::Mat();

这种构造方式,不需要传递任何参数,在后续给变量赋值的时候会自动判断矩阵的类型与大小,实现灵活的存储,常用于存储读取的图像数据和某个函数运算的输出结果。
【2】根据输入矩阵尺寸和类型构造

cv::Mat::Mat(int rows,int cols,int type)

其中rows:构造矩阵的行数;cols:矩阵的列数;type:矩阵存储的数据类型,例如CV_8UC1之类。
【3】用Size()结构构造Mat类

cv::Mat::Mat(Size size(), int type);

其中size:为二位数组变量尺寸,通过Size(cols,rows)进行赋值(列在前,行在后);type:矩阵存储的数据类型,例如CV_8UC1之类。
示例:

cv::Mat a(Size(480,580), CV_8UC1);//构造一个行580,列480的单通道矩阵

【4】利用已有矩阵构造Mat类

cv::Mat::Mat(const Mat & a);

这种构造方式只是复制了Mat类的矩阵头,矩阵指针指向是同一个地址。(浅复制)
若要深复制,可用

b = a.clone();

【5】构造已有Mat的子类

cv::Mat::Mat(const Mat & a,const Range & rowRange, const Range & colRange=Range::all);

其中,m:已经构建完成的Mat;rowRange:在已有的矩阵中需要获取的行数范围,是一个Range变量,例如从第二行到第五行表示为Range(2,5);colRange也是一样,在已有的矩阵中需要获取的列数范围,是一个Range变量,例如从第二列到第五列表示为Range(2,5)省略时,所有的列都会被截取。(注意:这种方式构造的类与已有Mat类共享数据。)

cv::Mat b(a, Range(2, 5), Range(1, 4));//从a中截取第二行到第五行,第一列到第四列的内容
cv::Mat b(a, Range(2, 5));//从a中截取第二行到第五行的内容

2.2、Mat类的赋值

在构造时赋值

cv::Mat::Mat(int rows, int cols, int type, const Scalar & s)

其中rows:矩阵的行数; cols:矩阵的列数;type:存储数据的类型;s:给矩阵中每个橡树赋值的参数变量,例如Scalar(0,0,255)

例如:

cv::Mat a(2, 2, CV_8UC3, cv::Scalar(0, 0, 255));//创建一个3通道矩阵,每个像素都是0,0,255
cv::Mat a(2, 2, CV_8UC2, cv::Scalar(0, 255));//创建一个2通道矩阵,每个像素都是0,255
cv::Mat a(2, 2, CV_8UC1, cv::Scalar(255));//创建一个单通道矩阵,每个像素都是255

枚举法赋值:

cv::Mat a= (cv::Mat_<int>(3,3)<<1,2,3,4,5,6,7,8,9);
cv::Mat a = (cv::Mat_<double>(2, 3) << 1.0, 2.0, 3.0, 4.0, 5.0, 6.0);

第一行创建一个3*3的 矩阵,数据类型为int型,一行一行的存入
循环法赋值:

cv::Mat a = (cv::Mat_<int>(3, 3));//定义一个3*3的矩阵
for(int i = 0; i < a.cols;i++) //矩阵行数循环
{
	for (int j; j < a.cols; j++) //矩阵列数循环
	{
		a.at<int>(i, j) = i + j;
	}
}

利用类方法赋值示例:

	cv::Mat a = cv::Mat::eye(3, 3, CV_8UC1);
	cv::Mat b = (cv::Mat_<int>(1, 3) << 1, 2, 3);
	cv::Mat c = cv::Mat::diag(b);
	cv::Mat d = cv::Mat::ones(3, 3, CV_8UC1);
	cv::Mat e = cv::Mat::zeros(3, 2, CV_8UC3);

利用数组进行赋值:

3、Mat类支持的运算

3.1Mat类的加减乘除运算:

cv::Mat a = (cv::Mat_<int>(3, 3) << 1, 2, 3, 4, 5, 6, 7, 8, 9);
cv::Mat b = (cv::Mat_<int>(3, 3) << 1, 2, 3, 4, 5, 6, 7, 8, 9);
cv::Mat c = (cv::Mat_<double>(3, 3) << 1.0, 2.0, 3.0, 4.0,5.0, 6.0, 7.0, 8.0, 9.0);
cv::Mat d = (cv::Mat_<double>(3, 3) << 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0);
cv::Mat e, f, g, h,i;
e = a + b;
f = c - d;
g = 2 * a;
h = d / 2.0;
i = a - 1;

当两个类进行加减运算时,需保证数据要一致,比如int和double类型数据的两个类不能进行加减运算。常数与Mat类变量运算,结果的数据类型保留Mat类变量的数据类型。

3.2两个Mat类矩阵的乘法运算

cv::Mat a = (cv::Mat_<int>(3, 3) << 1, 2, 3, 4, 5, 6, 7, 8, 9);
cv::Mat b = (cv::Mat_<int>(3, 3) << 1, 2, 3, 4, 5, 6, 7, 8, 9);
cv::Mat c = (cv::Mat_<double>(3, 3) << 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0);
cv::Mat d = (cv::Mat_<double>(3, 3) << 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0);
cv::Mat e, f;
double k;
e = c*d;//数学乘积
k = a.dot(b);//内积
f=a.mul(b)//对应位乘积

4、Mat类元素的读取

4.1多通道数据的存储

在这里插入图片描述
3通道3*3矩阵存储方式
先存储第一个元素的三个通道数据,再存储第二个元素三个通道数据

4.2Mat类常用属性和成员方法

属性作用
cols矩阵的列数
rows矩阵的行数
steps以字节为单位的有效宽度
dims矩阵的维度
手机
elemSize ()每个元素的字节数
tota l()矩阵中元素的个数
channels ()矩阵的通道数

4.3通过at读取Mat类单通道矩阵的元素

	cv::Mat a = (cv::Mat_<int>(3, 3) << 1, 2, 3, 4, 5, 6, 7, 8, 9);
	int b = a.at<int>(0, 0);

通过at读取元素需要跟上“<数据类型>”,类型不匹配则会报错。该方法以坐标的形式给出需要读取的元素坐标(行数,列数)。

4.4通过at读取Mat类多通道矩阵的元素

因为单通道图像是一个二维矩阵,所以 at方法的最后给出二维坐标即可访问对应位置元素。在OpenCv中,针对三通道,定义了,cv::Vec3b、cv::Vec3s、cv::Vec3w、cv::Vec3d、cv::Vec3f、cv::Vec3i共6种类型,其中数字表示通道数,最后一位是类型的缩写,b是uchar的缩写,s是short类型的缩写,w是ushort类型的缩写,d是double类型的缩写,f是float类型的缩写,i是int类型的缩写。

	cv::Mat a(3,4,CV_8UC3,Scalar(2,0,255));
	cv::Vec3b b = a.at<Vec3b>(0, 0);
	int first = b[0];  //值为2
	int second = b.val[1];//值为0
	int third = b.val[2];//值为255

4.5通过指针ptr读取Mat矩阵种的元素

矩阵中每一行的每个元素都是挨着放的,如果能找到每一行元素的起始地址位置,那么读取矩阵中每一行不同位置的元素时将指针在起始位置向后移动若干位即可。

	cv::Mat a(3,4,CV_8UC3,Scalar(2,0,255));
	for (int i = 0; i < a.rows;i++)
	{
		uchar *ptr = a.ptr<uchar>(i);
		for (int j = 0; j < a.cols*a.channels(); j++)
		{
			cout << (int)ptr[j] << endl;
		}
	}

当读取第2行数据中第3个数据时,可直接用a.ptr(1)[2]直接访问

4.6通过迭代器访问Mat类矩阵中的元素

Mat类变量也是一个容器变量,故Mat类变量拥有迭代器,用于访问Mat变量中的数据,通过迭代器可以实现对矩阵中每一个元素的遍历。

	cv::Mat a = (cv::Mat_<uchar>(3, 3) << 3, 4, 5, 1, 6, 7, 8, 0, 1);
	cv::MatIterator_<uchar> it = a.begin < uchar > ();
	cv::MatIterator_<uchar> it_end = a.end < uchar >();
	for (int i = 0;it!=it_end;it++)
	{
		cout << (int)(*it) << " ";
		if (++i%a.channels()==0)
		{
			cout << endl;
		}
 
	}

Mat类的迭代器变量类型是cv::MatIterator_< >,在定义时同样需要在括号中声明数据的变量类型。Mat类迭代器的起始是Mat.begin< >(),结束是Mat.end< >(),与其他迭代器用法相同,通过“++”运算实现指针位置向下迭代,数据的读取方式是先读取第一个元素的每一个通道,之后再读取第二个元素的每一个通道,直到最后一个元素的最后一个通道。

5.OpenCV矩阵之一平均值、方差、协方差、特征向量

【1】Scalar类

scalar的意思是标量

typedef struct Scalar
{
	double val[4];
}Scalar;

scalar是由一个由长度为4的数组作为元素构成的结构体,最多可以存储四个值,没有提供的默认值为0。
常使用的场景如下:

Mat M(7,7,CV_32FC2,Scalar(1,3));

上面的代码表示:创建一个2通道,且每个通道的值都为(1,3),深度为32,7行7列的图像矩阵。CV_32F表示每个元素的值的类型为32位浮点数,C2表示通道数位为2,Scalar(1,3)表示对矩阵每个元素都赋值为(1,3),第一个通道中的值都是1,第二个通道中的值都是3.

【2】cv::mean()

cv::Scalar cv::mean(
 	cv::InputArray src,
	cv::InputArray mask=cv::noArray(),     //Optional,do only where nonzero
	 );

函数cv::mean()计算输入矩阵src中未被屏蔽的所有像素的平均值。如果src是多通道,则以每个通道为基础计算结果。

【3】cv::meanStdDev()

void cv::meanStdDev(
	cv::InputArray src,
	cv::OutputArray mean,
	cv::OutputArray stddev,
	cv::InputArray mask = cv::noArray(), //optional,do only where nonzero
	);

函数cv::meanStdDev()计算输入矩阵src中未被屏蔽的像素的平均值以及它们的标准差。如果src是多通道的,则以每个通道为基础计算平均值和标准差。

【4】cv::calcCovarMatrix()

void cv::calCovarMatrix(
	const cv::Mat* samples,
	int nsamples,
	cv::Mat& covar,
	cv::Mat& mean,
	int flags,
	int ctype=cv::F64
	}
void cv::calCovarMatrix(
	cv::InputArray samples,
	cv::Mat& covar,
	cv::Mat& mean,
	int flags,
	int ctype=cv::F64
	}

给定一些向量,假设这些向量表示的点是近似高斯分布的,cv::calcCovarMatrix()将计算这些点的均值和协方差矩阵。
cv::calcCovarMatrix()有两个基本的调用方法,第一种是指向cv::Mat 对象矩阵的指针和表示矩阵中的矩阵数量的nsamples一起传入函数。这种情况下,矩阵可以是nx1或1xn.第二种是传入一个nxm的矩阵。
特征值与特征向量(eigen value\eigen vector)

bool cv::eigen(
	cv::InputArray src,
	cv::OutputArray eigenvalues,
	cv::OutputArray eigenvectors,
	int lowindex = -1,
	int highindex = -1
	);

给定一个对称矩阵mat,必须为浮点类型之一。特征值矩阵以递减的顺序包含mat的特征值,特征向量则以行的的形式存储在矩阵中。

  • 15
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值