Opencv理解Mat与基本操作


数据类型

CV_8UC1*// 8位无符号单通道*

CV_8UC3*// 8位无符号3通道*

CV_8UC4

CV_32FC1*// 32位浮点型单通道*

CV_32FC3*// 32位浮点型3通道*

包括数据位深度8位、32位,数据类型U:uchar、F:float型以及通道数C1:单通道、C3:三通道、C4:四通道。

构造函数

1
2
3
4
5
6
7
cv::Mat a(cv::Size(5,5),CV_8UC1); // 单通道
cv::Mat b = cv::Mat(cv::Size(5,5),CV_8UC3); //3通道每个矩阵元素包含3个uchar值
cv::Mat img(20, 20, CV_8UC3, cv::Scalar(0,0,255));
Mat m =(Mat_(3,3)<<-3,-2,-1,0,1,2,3,4,5);
cv::Mat e = cv::Mat::eye(4,4,CV_64F);
cv::Mat o = cv::Mat::ones(2,2,CV_32F);
cv::Mat z = cv::Mat::zeros(3,3,CV_8UC1);

Create方法

该方法不能为矩阵设置初始值,只是在改变尺寸时为矩阵数据重新分配内存。

1
2
3
//创建一个4行4列有2个通道的矩阵:
Mat img;
img.create(4, 4, CV_8UC2);

几种特殊矩阵初始化方式的说明

1
2
3
cv::Mat e = cv::Mat::eye(4,4,CV_64F);// 4行4列的对角矩阵 
cv::Mat o = cv::Mat::ones(2,2,CV_32F);// 2行2列的单位矩阵
cv::Mat z = cv::Mat::zeros(3,3,CV_8UC1);// 3行3列的零矩阵

小矩阵的初始化

1
Mat m =(Mat_(3,3)<<-3,-2,-1,0,1,2,3,4,5);

矩阵运算

加减法

1
2
3
4
cv::Mat a= Mat::eye(Size(3,2), CV_32F);
cv::Mat b= Mat::ones(Size(3,2), CV_32F);
cv::Mat c= a+b;
cv::Mat d= a-b;

$$
\begin{bmatrix}
1 & 0 & 0 \
0 & 1 & 0
\end{bmatrix}+
\begin{bmatrix}
1 & 1 & 1 \
1 & 1 & 1
\end{bmatrix}=
\begin{bmatrix}
2 & 1 & 1 \
1 & 2 & 1
\end{bmatrix} \\
\begin{bmatrix}
1 & 0 & 0 \
0 & 1 & 0
\end{bmatrix}-
\begin{bmatrix}
1 & 1 & 1 \
1 & 1 & 1
\end{bmatrix}=
\begin{bmatrix}
0 & -1 & -1 \
-1 & 0 & -1
\end{bmatrix}
$$

矩阵乘法

1.按位相乘($A_{m*n}.B_{mn}$)

1
2
3
Mat in = Mat::eye(Size(3,2), CV_32F);
Mat out = Mat::eye(Size(3,2), CV_32F);
cv::multiply(in,out);

2.点乘法($A_{mn}B_{np}$)

1
Mat res = A*B;

$$
\begin{bmatrix}
1 & 0 & 0 \
0 & 1 & 0
\end{bmatrix}2=
\begin{bmatrix}
2 & 0 & 0 \
0 & 2 & 0
\end{bmatrix} \\
\begin{bmatrix}
2 & 1 & 1 \
1 & 2 & 1
\end{bmatrix}.

\begin{bmatrix}
4 & 3 & 3 \
3 & 4 & 3
\end{bmatrix}=
\begin{bmatrix}
8 & 3 & 3 \
3 & 8 & 3
\end{bmatrix}\\
\begin{bmatrix}
1 & 0 & 0 \
0 & 1 & 0
\end{bmatrix}*
\begin{bmatrix}
1 & 1 \
1 & 1 \
1 & 1
\end{bmatrix}=
\begin{bmatrix}
1 & 1 \
1 & 1
\end{bmatrix}
$$

矩阵的转置

1
2
3
Mat m1= Mat::eye(2,3, CV_32F);
Mat m1_t = m1.t();
transpose(m1, m1_t);

矩阵的逆

1
2
Mat me_inv = me.inv();
invert(in, out);

计算矩阵非零元素个数

1
int nonZerosNum = countNonZero(me);

矩阵的均值和标准差

1
2
3
4
5
6
7
8
9
10
11
12
13
14
meanStdDev(src, mean, stddev);
* src - 输入矩阵或图像
* mean - 均值,OutputArray
* stddev - 标准差,OutputArray

Mat mean, stddev;
meanStdDev(me, mean, stddev);



//多通道矩阵,则分别计算不同通道的均值与标准差
Mat m3(cv::Size(5,5),CV_8UC3,Scalar(255,200,100));
Mat mean3,stddev3;
meanStdDev(m3, mean3, stddev3);

求最大最小值

1
2
3
void minMaxLoc(InputArray src, CV_OUT double* minVal,
CV_OUT double* maxVal=0, CV_OUT Point* minLoc=0,
CV_OUT Point* maxLoc=0, InputArray mask=noArray());
  • src – 输入单通道矩阵(图像).
  • minVal – 指向最小值的指针, 如果未指定则使用NULL
  • maxVal – 指向最大值的指针, 如果未指定则使用NULL
  • minLoc – 指向最小值位置(2维情况)的指针, 如果未指定则使用NULL
  • maxLoc – 指向最大值位置(2维情况)的指针, 如果未指定则使用NULL
  • mask – 可选的蒙版,用于选择待处理子区域
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 求极值 最大、最小值及其位置
Mat img = imread("Lena.jpg",0);
imshow("original image",img);

double minVal=0,maxVal=0;
cv::Point minPt, maxPt;
minMaxLoc(img,&minVal,&maxVal,&minPt,&maxPt);
cout<<"min value = "<<minVal<<endl;
cout<<"max value = "<<maxVal<<endl;
cout<<"minPt = ("<<minPt.x<<","<<minPt.y<<")"<<endl;
cout<<"maxPt = ("<<maxPt.x<<","<<maxPt.y<<")"<<endl;
cout<<endl;

cv::Rect rectMin(minPt.x-10,minPt.y-10,20,20);
cv::Rect rectMax(maxPt.x-10,maxPt.y-10,20,20);

cv::rectangle(img,rectMin,cv::Scalar(200),2);
cv::rectangle(img,rectMax,cv::Scalar(255),2);

imshow("image with min max location",img);
cv::waitKey();

其他矩阵运算

Function (函数名) Use (函数用处)
add 矩阵加法,A+B的更高级形式,支持mask
scaleAdd 矩阵加法,一个带有缩放因子dst(I) = scale * src1(I) + src2(I)
addWeighted 矩阵加法,两个带有缩放因子dst(I) = saturate(src1(I) * alpha + src2(I) * beta + gamma)
subtract 矩阵减法,A-B的更高级形式,支持mask
multiply 矩阵逐元素乘法,同Mat::mul()函数,与A*B区别,支持mask
gemm 一个广义的矩阵乘法操作
divide 矩阵逐元素除法,与A/B区别,支持mask
abs 对每个元素求绝对值
absdiff 两个矩阵的差的绝对值
exp 求每个矩阵元素 src(I) 的自然数 e 的 src(I) 次幂 dst[I] = esrc(I)
pow 求每个矩阵元素 src(I) 的 p 次幂 dst[I] = src(I)p
log 求每个矩阵元素的自然数底 dst[I] = log
sqrt 求每个矩阵元素的平方根
min, max 求每个元素的最小值或最大值返回这个矩阵 dst(I) = min(src1(I), src2(I)), max同
minMaxLoc 定位矩阵中最小值、最大值的位置
compare 返回逐个元素比较结果的矩阵
bitwise_and, bitwise_not, bitwise_or, bitwise_xor 每个元素进行位运算,分别是和、非、或、异或
cvarrToMat 旧版数据CvMat,IplImage,CvMatND转换到新版数据Mat
extractImageCOI 从旧版数据中提取指定的通道矩阵给新版数据Mat
randu 以Uniform分布产生随机数填充矩阵,同 RNG::fill(mat, RNG::UNIFORM)
randn 以Normal分布产生随机数填充矩阵,同 RNG::fill(mat, RNG::NORMAL)
randShuffle 随机打乱一个一维向量的元素顺序
theRNG() 返回一个默认构造的RNG类的对象 theRNG()::fill(…)
reduce 矩阵缩成向量
repeat 矩阵拷贝的时候指定按x/y方向重复
split 多通道矩阵分解成多个单通道矩阵
merge 多个单通道矩阵合成一个多通道矩阵
mixChannels 矩阵间通道拷贝,如Rgba[]到Rgb[]和Alpha[]
sort, sortIdx 为矩阵的每行或每列元素排序
setIdentity 设置单元矩阵
completeSymm 矩阵上下三角拷贝
inRange 检查元素的取值范围是否在另两个矩阵的元素取值之间,返回验证矩阵
checkRange 检查矩阵的每个元素的取值是否在最小值与最大值之间,返回验证结果bool
sum 求矩阵的元素和
mean 求均值
meanStdDev 均值和标准差
countNonZero 统计非零值个数
cartToPolar, polarToCart 笛卡尔坐标与极坐标之间的转换
flip 矩阵翻转
transpose 矩阵转置,比较 Mat::t() AT
trace 矩阵的迹
determinant 行列式
eigen 矩阵的特征值和特征向量
invert 矩阵的逆或者伪逆,比较 Mat::inv()
magnitude 向量长度计算 dst(I) = sqrt(x(I)2 + y(I)2)
Mahalanobis Mahalanobis距离计算
phase 相位计算,即两个向量之间的夹角
norm 求范数,1-范数、2-范数、无穷范数
normalize 标准化
mulTransposed 矩阵和它自己的转置相乘 AT * A, dst = scale(src - delta)T(src - delta)
convertScaleAbs 先缩放元素再取绝对值,最后转换格式为8bit型
calcCovarMatrix 计算协方差阵
solve 求解1个或多个线性系统或者求解最小平方问题(least-squares problem)
solveCubic 求解三次方程的根
solvePoly 求解多项式的实根和重根
dct, idct 正、逆离散余弦变换,idct同dct(src, dst, flags
dft, idft 正、逆离散傅立叶变换, idft同dft(src, dst, flags
LUT 查表变换
getOptimalDFTSize 返回一个优化过的DFT大小
mulSpecturms 两个傅立叶频谱间逐元素的乘法

Mat基础

  • 1、在计算机内存中,数字图像是采用矩阵的方式保存的。Opencv2中,保存图像像素信息的是数据结构Mat阵,它包含两部分:矩阵头和一个指向像素数据的矩阵针。矩阵头主要包含:矩阵尺寸、存储方式、存储地址、引用计数等。矩阵头的大小是一定的,不会随着图像的大小改变而改变,通常图像像素数据都会很大。因此,在图像的复制和传递过程中不需要复制整个Mat数据,只复制矩阵头和指向像素矩阵的指针即可。
  • 2、由此会出现多个Mat共用一个矩阵数据的情况,那么内存回收的时候会存在什么时候释放矩阵数据的问题,对于释放内存的时候引用计数就会起作用了,当Mat对象被复制一次时,引用计数会加一,而销毁一个Mat对象(共用同一个图像矩阵数据)时引用计数减一,当引用计数为0的时候,矩阵数据就会被除。
  • 3、在使用Mat的时候:
    a、OpenCV中内存通常是自动分配,特殊情况需要特别指定。
    b、使用OpenCV的C++接口时不用考虑内存释放问题。
    c、需要复制矩阵数据,可以使用Image.clone()和Image1.copyTo(Image2)。

Mat存储方法

Mat矩阵中不同的每个元素可以使用不同数据类型,最小的数据类型是char型,占用一个字节(1byte=8bits),可以是有符号(0到255)和无符号(-127到127)的。在RGB颜色空间中,使用三个char型可以表示1600万种颜色.在Opencv中可以使用cv::Scalar(b,g,r)或者CV_RGB(r,g,b)表示。

Mat的创建

1、构造函数

官方文档指定规则如下:

CV_[The number of bits per item][Signed or Unsigned][TypePrefix]C[The channel number]
四部分分别指定:元素的大小,是有符号还是无符号,数据类型以及通道数。
cv::Mat img(20, 20, CV_8UC3, cv::Scalar(0,0,255));
上述代码创建了一个20行20列的矩阵,矩阵元素使用8位无符号char类型保存,具有3通道,每个像素的初始值是(0,0,255)即红色,Scalar是short型的vector,提供矩阵的初始化。

2、Create方法

该方法不能为矩阵设置初始值,只是在改变尺寸时为矩阵数据重新分配内存。创建一个4行4列有2个通道的矩阵:

img.create(4, 4, CV_8UC2);

3、几种特殊矩阵初始化方式的说明

cv::Mat e = cv::Mat::eye(4,4,CV_64F);
cv::Mat o = cv::Mat::ones(2,2,CV_32F);
cv::Mat z = cv::Mat::zeros(3,3,CV_8UC1);
Mat e是4行4列的对角矩阵
Mat z是2行2列的单位矩阵
Mat o是3行3列的零矩阵

4、小矩阵的初始化

Mat m =(Mat_(3,3)<<-3,-2,-1,0,1,2,3,4,5);

Mat的输入输出

使用imread函数,向Mat对象中写入一个图像:

1
2
Mat m = cv::imread(".//res//lena.png");//读入图像imread的原型:
cv::Mat imread(const string& filename,int flags=1)

filename指定要读取图像的位置flags指定图像的颜色空间
flags > 0 三通道的彩色图像
flags = 0 灰度图像
flags < 0 不作改变也可以有以下的枚举值
CV_LOAD_IMAGE_ANYDEPTH
CV_LOAD_IMAGE_COLOR
CV_LOAD_IMAGE_GRAYSCALE
使用imwrite函数,将Mat对象保存到指定的文件中。imwrite的函数原型如下:

1
bool imwrite(const string& filename,InputArray img,constvector<int>& params=vector<int>())

filename,指定的文件
img 要保存的Mat对象
params 用来指定图像的保存编码方式。
使用filename的扩展名来指定图像的保存格式(.jpg .png .bmp),对于不同的图像保存类型,params是不同的值

  • JPEG,params用来指定图像的质量(0到100),CV_IMWRITE_JPEG_QUALITY
    默认的是95 .
  • PNG,params用来指定图像的压缩级别(0到9),压缩级别越高图像占用的空间越小,保存图像所用的时间越久。默认值是3. CV_IMWRITE_PNG_COMPRESSION
  • PPM,PGM,PBM,params是一个标记(0或者1),CV_IMWRITE_PXM_BINARY
    默认的是1。imwrite只能保存8位(或者是16位无符号(CV_16UC)的PNG,JPEG200或者TIFF图像)单通道或者三通道的图像,如果要保存的不是这样的图片,可以使用convertTo或者cvtColor来进行转变。

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!