opencv——Mat对象

opencv中的数据结构

  • Mat对象 OpenCV2.0之后引进的图像数据结构、自动分配内存、不存在内存泄漏的问题,是面向对象的数据结构。分了两个部分,头部与数据部分

  • IplImage 是从2001年OpenCV发布之后就一直存在,是C语言风格的数据结构,需要开发者自己分配与管理内存,对大的程序使用它容易导致内存泄漏问题
    第一个是大写i不是小写L

以前的opencv中会用到IplImage,在算法或程序更新换代的时候会用opencv中提供的方法进行转换。
我们平时使用的时候直接用Mat对象就可以了

Mat对象

在这里插入图片描述

Mat对象是一个数据结构,将图像作为矩阵保存起来。每一个像素点是0~255的数据。

构成

Mat类由两部分数据组成:矩阵头(包含矩阵尺寸、存储方法、存储地址等)和一个指向存储所有像素值的矩阵(根据所选存储方法的不同,矩阵可以是不同的维数)的指针。Mat在进行赋值和拷贝时,只复制矩阵头,而不复制矩阵,提高效率。如果矩阵属于多个Mat对象,则通过引用计数来判断,当最后一个使用它的对象,则负责释放矩阵。

class CV_EXPORTS Mat
{
public/*..很多方法..*/
/*............*/
 
int flags;/*flags指定图像的颜色空间  
            flags > 0 3通道的彩色图像
            flags = 0 灰度图像
            flags < 0 不作改变
          */
int dims;  /*数据的维数*/
int rows,cols; /*行和列的数量;数组超过2维时为(-1,-1)*/
uchar *data;   /*指向数据*/
int * refcount;   /*指针的引用计数器; 阵列指向用户分配的数据时,指针为 NULL
/* 其他成员 */ 
...
};

存储方法

Mat中矩阵的每个元素可以使用不同的数据类型,最小的数据类型是char,占用一个字节或者8位,可以是有符号的(0到255)或者是无符号的(-127到127)。
在RGB颜色空间中,使用三个char类型可以表示1600万中颜色,但在图像处理的过程中有可能会使用到float或者double来表示图像的像素。

常用成员及含义

  • 1、data Mat
    对象中的一个指针,指向存放矩阵数据的内存(uchar* data)

  • 2、dims
    矩阵的维度,34的矩阵维度为2维,34*5的矩阵维度为3维

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

  • 4、depth
    深度,即每一个像素的位数,也就是每个通道的位数。在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位。

常用Mat对象构建方法

  • 1、Mat::Mat()
    无参数构造方法;

  • 2、Mat::Mat(int rows, int cols, int type)
    创建行数为 rows,列数为 col,类型为 type 的图像;

  • 3、Mat::Mat(Size size, int type)
    创建大小为 size,类型为 type 的图像;

  • 4、Mat::Mat(int rows, int cols, int type, const Scalar& s)
    创建行数为 rows,列数为 col,类型为 type 的图像,并将所有元素初始化为值 s;

  • 5、Mat::Mat(Size size, int type, const Scalar& s)
    创建大小为 size,类型为 type 的图像,并将所有元素初始化为值 s;

  • 6、Mat::Mat(const Mat& m)
    将m赋值给新创建的对象,此处不会对图像数据进行复制,m和新对象共用图像数据,属于浅拷贝;

  • 7、Mat::Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP)
    创建行数为rows,列数为col,类型为type的图像,此构造函数不创建图像数据所需内存,而是直接使用data所指内存,图像的行步长由
    step指定。

  • 8、Mat::Mat(Size size, int type, void* data, size_t step=AUTO_STEP)
    创建大小为size,类型为type的图像,此构造函数不创建图像数据所需内存,而是直接使用data所指内存,图像的行步长由step指定。

  • 9、Mat::Mat(const Mat& m, const Range& rowRange, const Range& colRange)
    创建的新图像为m的一部分,具体的范围由rowRange和colRange指定,此构造函数也不进行图像数据的复制操作,新图像与m共用图像数据;

  • 10、Mat::Mat(const Mat& m, const Rect& roi)
    创建的新图像为m的一部分,具体的范围roi指定,此构造函数也不进行图像数据的复制操作,新图像与m共用图像数据。

这些构造函数中,很多都涉及到类型type。
type可以是CV_8UC1,CV_16SC1,…,CV_64FC4 等。

里面的 8U 表示 8 位无符号整数,16S 表示 16 位有符号整数,64F表示 64 位浮点数(即 double 类型);
C 后面的数表示通道数,例如 C1 表示单通道的图像,C4 表示 4 个通道的图像,以此类推。如果你需要更多的通道数,需要用宏 CV_8UC(n),例如:

Mat M(3,2, CV_8UC(5));//创建行数为 3,列数为 2,通道数为 5 的图像。

代码示例

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
	Mat src;
	src = imread("C:/Users/86176/Desktop/pics/lena(1).tiff");
	if (!src.data)
	{
		cout << "fail to load img" << endl;
		return -1;
	}
	namedWindow("input img", CV_WINDOW_AUTOSIZE);
	imshow("input img", src);
	
	Mat dst;
	dst = Mat(src.size(), src.type());
	dst = Scalar(127, 0, 255);
	//全255就是全白,全0就是全黑
	namedWindow("output img", CV_WINDOW_AUTOSIZE);
	imshow("output img", dst);

	waitKey(0);
	return 0;
}

在这里插入图片描述
创建了一个相同大小的图片

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

int main()
{
	Mat src;
	src = imread("C:/Users/86176/Desktop/pics/lena(1).tiff");
	if (!src.data)
	{
		cout << "fail to load img" << endl;
		return -1;
	}
	namedWindow("input img", CV_WINDOW_AUTOSIZE);
	imshow("input img", src);
	
	Mat dst(3, 3, CV_8UC3, Scalar(0, 0, 255));
	//3 x 3的图像,3通道8位无符号
	cout << "dst =" << endl << dst << endl;
	namedWindow("output img", CV_WINDOW_AUTOSIZE);
	imshow("output img", dst);

	waitKey(0);
	return 0;
}

在这里插入图片描述
打印如下
在这里插入图片描述

其他Mat对象构建方法

Mat::Create:创建新的阵列数据

void Mat::create(int rows, int cols, int type)
void Mat::create(Size size, int type)
void Mat::create(int ndims, const int* sizes, inttype)
  • ndims – 新数组的维数。
  • rows – 新的行数。
  • cols – 新的列数。
  • size – 替代新矩阵大小规格:Size(cols, rows)。
  • sizes – 指定一个新的阵列形状的整数数组。
  • type – 新矩阵的类型。

Mat::resize:重新定义图片大小

void Mat::resize(size_t sz)
void Mat::resize(size_t sz, const Scalar& s)
  • sz – 新的行数
  • s – 分配给新添加的元素的值。

Mat::type:返回一个矩阵元素的类型

int Mat::type() const

该方法返回一个矩阵的元素类型。兼容CvMat 类型系统,像 CV_16SC3标识符 或 16 位有符号的3 通道阵列等

Mat::depth:返回一个矩阵元素的深度

int Mat::depth() const
  • 该方法返回矩阵元素深度(每个单独的通道类型)的标识符。例如,对于16位有符号的3通道数组,该方法返回CV_16S。矩阵类型的完整列表包含以下内容值:
  • CV_8U - 8 位无符号整数 (0……255)
  • CV_8S - 8 位符号整数 ( - 128……127)
  • CV_16U - 16 位无符号整数 (0……65535)
  • CV_16S - 16 位符号整数 ( - 32768……32767)
  • CV_32S - 32 位符号整数 ( - 2147483648……2147483647)
  • CV_32F - 32 位浮点数 ( - FLT_MAX ………FLT_MAX,INF,NAN)
  • CV_64F - 64 位浮点数( - DBL_MAX ……….DBL_MAX,INF,NAN)

Mat::channels:返回矩阵通道的数目

int Mat::channels() const

Mat::size:返回一个矩阵大小

Size Mat::size() const

Mat::at:返回对指定数组元素的引用

template<typename T> T& Mat::at(int i)const
template<typename T> const T&Mat::at(int i) const
template<typename T> T& Mat::at(int i,int j)
template<typename T> const T&Mat::at(int i, int j) const
template<typename T> T& Mat::at(Pointpt)
template<typename T> const T&Mat::at(Point pt) const
template<typename T> T& Mat::at(int i,int j, int k)
template<typename T> const T&Mat::at(int i, int j, int k) const
template<typename T> T& Mat::at(constint* idx)
template<typename T> const T&Mat::at(const int* idx) const
//参数
//i –索引 0 维度
//j – 1 维度的索引
//k – 沿 2 维度的索引
//pt – Point(j, i) 作为指定元素的位置。
//idx – Mat::dims 数组的索引。
//该模板方法返回指定数组元素的引用。为了具有更高的性能,索引范围检查只在调试配置下执行。请注意使用具有单个索引(i) 的变量可以访问的单行或单列的2 维的数组元素。也就是比方说,如果A是1 x N 浮点矩阵和B是M x 1的整数矩阵,您只需编写A.at(k + 4) 和 B.at(2 * i + 1) 分别代替A.at(0, k + 4)和
//B.at(2 * i + 1, 0)。
 
//下面的示例将初始化希尔伯特矩阵:
Mat H(100, 100, CV_64F);
for(inti=0; i<H.rows; i++)
for(intj=0; j<H.cols; j++)
H.at<double>(i,j)=1./(i+j+1);

Mat优势

  • 1.图像的内存分配和释放由Mat类自动管理。

  • 2.Mat类由两部分数据组成:矩阵头(包含矩阵尺寸、存储方法、存储地址等)和一个指向存储所有像素值的矩阵(根据所选存储方法的不同,矩阵可以是不同的维数)的指针。Mat在进行赋值和拷贝时,只复制矩阵头,而不复制矩阵,提高效率。如果矩阵属于多个Mat对象,则通过引用计数来判断,当最后一个使用它的对象,则负责释放矩阵。

  • 3.可以使用clone和copyTo函数,不仅复制矩阵头还复制矩阵。

注意事项

  • 1.OpenCV中的内存分配是自动完成的(不是特别指定的话)

  • 2.使用OpenCV的C++ 接口时不需要考虑内存释放问题

  • 3.Mat的赋值运算和拷贝构造函数只会拷贝矩阵头,仍然共同同一个矩阵

  • 4.如果要复制矩阵数据,可以使用clone和copyTo函数

Mat F = A.clone();  
//或者
Mat G; A.copyTo(G);
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Spark!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值