OpenCV-Mat结构详解

Posted fcfc940503

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenCV-Mat结构详解相关的知识,希望对你有一定的参考价值。

前面博客中Mat函数谈到一些理解,但是理解的比较浅显,下面谈谈通道,行列等意义;

Mat的常见属性

                             技术图片

opencv中type类型·   

技术图片

技术图片

技术图片

                  CV_<bit_depth>(S|U|F)C<number_of_channels>
1--bit_depth---比特数---代表8bite,16bites,32bites,64bites---举个例子吧--比如说,
如果你现在创建了一个存储--灰度图片的Mat对象,这个图像的大小为宽100,高100,那么,现在这张
灰度图片中有10000个像素点,它每一个像素点在内存空间所占的空间大小是8bite,8位--所以它对应的就是CV_8

depth:深度,即每一个像素的位数(bits),在opencv的Mat.depth()中得到的是一个 0 – 6 的数字,分别代表不同的位数:enum CV_8U=0, CV_8S=1, CV_16U=2, CV_16S=3, CV_32S=4, CV_32F=5, CV_64F=6 ; 可见 0和1都代表8位, 2和3都代表16位,4和5代表32位,6代表64位;

2--S|U|F--

S--代表---signed int---有符号整形
U--代表--unsigned int--无符号整形
F--代表--float---------单精度浮点型


3--C<number_of_channels>----代表---一张图片的通道数,比如:

1--灰度图片--grayImg---是--单通道图像
2--RGB彩色图像---------是--3通道图像
   3--带Alph通道的RGB图像--是--4通道图像

如:CV_8UC1---则可以创建----8位无符号的单通道---灰度图片------grayImg
       CV_8UC3---则可以创建----8位无符号的三通道---RGB彩色图像---colorImg

channels:通道,矩阵中的每一个矩阵元素拥有的值的个数,比如说 3 * 4 矩阵中一共 12 个元素,如果每个元素有三个值,那么就说这个矩阵是 3 通道的,即 channels = 3。常见的是一张彩色图片有红、绿、蓝三个通道。

技术图片

上面是一个 3 X 4 的矩阵,假设其数据类型为 CV_8U,也就是单通道的 uchar 类型

                                              CV_8U 得到 M.depth() == 0, M.channels() == 1
这是一个二维矩阵,那么维度为 2 (M.dims == 2);
M.rows == 3; M.cols == 4;

step:是一个数组,定义了矩阵的布局,具体见上面图片分析,另外注意 step1 (step / elemSize1),M.step[m-1] 总是等于 elemSize,M.step1(m-1)总是等于 channels;

因为是二维矩阵,那么 step 数组只有两个值, step[0] 和 step[1] 分别代表一行的数据大小和一个元素的数据大小,则 M.step[0] == 4, M.step[1] == 1;
M.step1(0) == M.cols = 4; M.step1(1) == 1;

elemSize : 矩阵中每一个元素的数据大小,如果Mat中的数据的数据类型是 CV_8U 那么 elemSize = 1,CV_8UC3 那么 elemSize = 3,

CV_16UC2那么 elemSize = 4;

记住另外有个 elemSize1 表示的是矩阵中数据类型的大小,即 elemSize / channels 的大小

sizeof(uchar) = 1,那么每一个数据元素大小为 1 (M.elemSize() == 1, M.elemSize1() == 1);
CV_8U 得到 M.depth() == 0, M.channels() == 1;
技术图片

 

 假设上面的矩阵数据类型是 CV_8UC3,也就是三通道
M.dims == 2; M.channels() == 3;M.depth() == 0;
M.elemSize() == 3 (每一个元素包含3个uchar值) M.elemSize1() == 1 (elemSize / channels)
M.step[0] == M.cols * M.elemSize() == 12, M.step[1] == M.channels() * M.elemSize1() == M.elemSize() == 3;
M.step(0) == M.cols * M.channels() == 12 ; M.step(1) == M.channels() == 3;

上面博文参考:opencv数据结构-MAT结构详解

写到这里,我也只了解了行,列,通道等概念,但是step,step(0),elemSize1,elemSize()我感到很困惑,看看下面的理解:

技术图片

 

 上图中: int matSize[] = 5,8,10;//每一维元素的个数:8:行,10:列  

              Mat mat1(3,matSize, CV_16UC3, Scalar::all(0);

对于mat1,3通道,一个像素点在内存空间大小是16bit;每一个像素的位数(bits)是2(深度);

 

三维矩阵,一共有三维,我们分别类比为

面:每个二维矩阵,表示第1维的元素

线:矩阵的每一行,表示第2维的元素

点:矩阵中每行的每个元素,表示第3维的元素

那么这样子就可以解释清楚每一维元素的含义了。

以step[i]为例

step[0]:面的大小,第1维的元素的大小,也就是二维矩阵的大小,一个二维矩阵有8行,所以step[0]=step[1]*8=480

step[1]:线的大小,第2维的元素的大小,也就是二维矩阵每一行的大小,由于每个元素大小为6,每行有10个元素,所以step[1]=10*6=60

step[2]:点的大小,第3维的元素的大小,这里矩阵的每个元素类型为CV_16UC3,所以step[2]=2*3=6个字节

这里注意:

1.step的大小是字节

2.注意下标与维数的对应关系:下标2对应点,1对应线,0对应面

3.矩阵有几维,step[]数组就有几个元素,如3维,则有3个元素,step[0],step[1],step[2].分别对应面,线,点
只要记住,最后一个总是表示点,然后依次向前为线,面…

4.第2,3 点 ,对于size和step1()也一样。

step1(i):每一维元素的通道数

step[i]:每一维元素的大小,单位字节;(包含所有通道)

size[i]:每一维元素的个数

elemSize():每个元素大小,单位字节

elemSize1():每个通道大小,单位字节

elemSize  表示每个元素的大小(单位字节),每个元素可能有多个通道,示例中,每个元素有三个通道,而每个通道类型为CV_16U,算3个通道的总数, 2*3=6

elemSize1 每个通道的大小(单位字节),CV_16=2字节

step1[i] = step.p[i]/elemSize1();

step1[0] = step[0]/elemSize1 = 240 bytes

step1[1] = step[1]/elemSize1 = 30 bytes

step1[2] = step[2]/elemSize1 = 3 bytes

代码如下:

#include"sift.h"
#include<fstream>
#include<iostream>
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <opencv2/core/core.hpp>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)


	//////////////////Demo1(3维矩阵)///////////////////////////////////////////
	printf("//////////////////////Demo1(3维矩阵)////////////////////////\\n");
	//最后面的两个数:(行,列),确定了一个面
	//是一个依次降维的过程
	//8,10组成了面,5个面,组成了立方体
	int matSize[] =  5,8,10 ;//每一维元素的个数:8:行,10:列
	Mat mat1(3, matSize, CV_16UC3, Scalar::all(0));

	//求step[i]的大小:每一维元素的大小(单位字节)
	printf("\\n///////step[i]的大小//////////\\n");
	printf("step[0]:%d\\n", mat1.step[0]);//480=8*60:面的大小(第一维)
	printf("step[1]:%d\\n", mat1.step[1]);//60=6*10:线的大小(第二维)
	printf("step[2]:%d\\n", mat1.step[2]);//6=2*3:点的大小(第三维)

										 //求size[i]:每一维元素的个数
	printf("\\n///////size[i]的大小///////\\n");
	printf("size[0]:%d\\n", mat1.size[0]);//5:面
	printf("size[1]:%d\\n", mat1.size[1]);//8:线
	printf("size[2]:%d\\n", mat1.size[2]);//10:点

										 //求step1(i):每一维元素的通道数
	printf("\\n///////step1(i)的大小///////\\n");
	printf("step1(0):%d\\n", mat1.step1(0));//240:面
	printf("step1(1):%d\\n", mat1.step1(1));//30:线
	printf("step1(2):%d\\n", mat1.step1(2));//3:点

										   //求elemSize:每个元素的大小(单位字节)
	printf("\\n///////elemSize的大小///////\\n");
	printf("elemSize:%d\\n", mat1.elemSize());//6:每个元素的大小

											 //求elemSize1:每个通道的大小(单位字节)
	printf("\\n///////elemSize1的大小///////\\n");
	printf("elemSize1:%d\\n", mat1.elemSize1());//2:每个通道的大小
	system("pause");
	return 0;

  技术图片

 

 改成.jpg图片

/求step[i]的大小:每一维元素的大小(单位字节)
//step[i]
	printf("\\n///////step[i]的大小///////\\n");
	printf("step[0]:%d\\n", mat2.step[0]);//1200=3*400:线
	printf("step[1]:%d\\n", mat2.step[1]);//3=1*3:点

										 //size[i]
	printf("\\n///////size[i]的大小///////\\n");
	printf("size[0]:%d\\n", mat2.size[0]);//250:线
	printf("size[1]:%d\\n", mat2.size[1]);//400:点

										 //step1(i)
	printf("\\n///////step1(i)的大小///////\\n");
	printf("step1(0):%d\\n", mat2.step1(0));//1200:第一维的通道数
	printf("step1(1):%d\\n", mat2.step1(1));//3:第二维的通道数

										   //elemSize
	printf("\\n///////elemSize的大小///////\\n");
	printf("elemSize:%d\\n", mat2.elemSize());//3:每个元素的大小

											 //elemSize1
	printf("\\n///////elemSize1的大小///////\\n");
	printf("elemSize1:%d\\n", mat2.elemSize1());//1:每个通道的大小,也就是单通道数据类型


	system("pause");
	return 0;

  技术图片技术图片

 

以上是关于OpenCV-Mat结构详解的主要内容,如果未能解决你的问题,请参考以下文章

OpenCV - Mat::convertTo() 断言错误。

opencv学习笔记详解基本图像容器Mat以及常用数据结构和函数

详解用OpenCV的轮廓检测函数findContours()得到的轮廓拓扑结构(hiararchy)矩阵的意义以及怎样用轮廓拓扑结构矩阵绘制轮廓拓扑结构图

详解OpenCV的Mat类(构造方法初始化方法常用属性常用成员函数常用操作)

(详解)opencv里的cv2.resize改变图片大小Python

详解图像形态学中的击中击不中变换操作(HMT),并提醒大家OpenCV4中的击中击不中变换操作是有问题的