这节记录下图像加载或者读取后的内存对象Mat的相关知识。
包括:Mat对象和IplImage对象,Mat对象的使用,Mat定义数组。
1、Mat对象和IplImage对象:
IplImage对象:是从2001年OpenCV发布就一直存在的,是C语言风格的数据结构,需要开发者自己分配和管理内存,对大的程序来说,使用IplImage对象容易造成内存泄漏的问题。
Mat对象:OpenCV2.0以后引入的图像数据结构,自动分配内存,不存在内存泄漏的问题,是面向对象的数据结构。分成了两个部分,头部与数据部分。
上一节中说道:
还是先看Mat的存储形式。Mat和Matlab里的数组格式有点像,但一般是二维向量,如果是灰度图,一般存放
单通道灰度图数据存放格式:
多通道的图像中,每列并列存放通道数量的子列,如RGB三通道彩色图:
注意通道的顺序反转了:BGR。通常情况内存足够大的话图像的每一行是连续存放的,也就是在内存上图像的所有数据存放成一行,这中情况在访问时可以提供很大方便。可以用 isContinuous()函数来判断图像数组是否为连续的。
所以:应尽量避免使用IplImage对象,进行算法迁移的时候尽量将IplImage对象转换成Mat对象。
2、Mat对象构造函数和常用方法:
构造函数:
Mat();
Mat(int rows,int cols,int type);
Mat(Szie size,int type);
Mat(int rows,int cols,int type,const Scalar &s);
Mat(Size size,int type,const Scalar &s);
Mat(int ndims,const int* size,int type);
Mat(int ndims,const int* size,int type,const Scalar &s);
常用方法:
void copyTo(Mat mat);//完全复制一份
void convertTo(Mat dst,int type);//转换类型
Mat Clone();//完全复制一份
int channels();
int depth();
bool empty();
uchar * ptr(i=0);
3、Mat对象的使用
部分复制:一般情况下只会复制Mat对象的头和指针部分,不会复制数据部分。Mat A=imread(imageFile);
Mat B(A);//只复制
完全复制:如果想把Mat对象的头部和数据部分一起复制,可以通过如下两个API实现:Mat C=A.clone();
或Mat D;A.copyTo(D);
4、Mat对象使用的四个要点:
输出图像的内存是自动分配的;
使用OpenCV的C++接口,不需要考虑内存泄漏的问题;
复制操作和拷贝构造函数只会复制头部分;
使用clone和copyTo两个函数实现数据的完全复制。
5、Mat对象的创建
Mat M(3, 3, CV_8UC3, Scalar(0, 0, 255));//前面两个3代表行和列。UC表示无符号,8代表位数,后面的3代表通道数
创建高维对象:
int sz[3] = { 2,2,2 };
Mat L(3, sz, CV_8UC1, Scalar::all(0));
Mat::create方法不想上面的可以直接赋值,需要单独写Scalar赋值:
Mat M;
M.create(4, 3, CV_8UC2);
M = Scalar(127, 127);
定义小数组:像是上一节的掩模mask
Mat kernel=(Mat_
filter2D(src,dst,-1,kernel);
相关代码:
#include
#include
using namespace cv;
using namespace std;
int main(int argc, char **argv) {
Mat src = imread("C:\\Users\\admin\\Desktop\\demo.jpg", IMREAD_COLOR);
if (src.empty())
{
printf("Could not load image...");
return -1;
}
namedWindow("Demo image", CV_WINDOW_AUTOSIZE);
imshow("Demo image", src);
Mat dst;
//完全拷贝:法1
//dst = Mat(src.size(), src.type());
//src.copyTo(dst);//复制
//完全拷贝:法2
//dst = src.clone();
cvtColor(src, dst, CV_BGR2GRAY);
printf("The channels of src: %d\n", src.channels());
printf("The channels of dst: %d\n", dst.channels());
const uchar* ptr1 = dst.ptr(0);
printf("first pixel value : %d", *ptr1);
int cols = dst.cols;
int rows = dst.rows;
printf("cols:%d rows:%d\n", cols, rows);
namedWindow("Copy image", CV_WINDOW_AUTOSIZE);
imshow("Copy image", dst);
//构造函数集合
//Mat M(3, 3, CV_8UC3, Scalar(0, 0, 255));
//cout << "M=" << endl << M << endl;
//imshow("Copy image", M);
//Mat B(dst);
//namedWindow("B image", CV_WINDOW_AUTOSIZE);
//imshow("B image", B);
Mat M;
M.create(4, 3, CV_8UC2);
M = Scalar(127, 127);
cout << "M=" << endl << M << endl << endl;
uchar *firstRow = M.ptr(0);
printf("FirstRow's value:%d\n", *firstRow);
Mat dd;
Mat kernel = (Mat_(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
filter2D(src, dd, -1, kernel);
Mat dd2;
dd2 = Mat::zeros(dst.size(), dst.type());
namedWindow("Black window", CV_WINDOW_AUTOSIZE);
imshow("Black window", dd2);
//小数组
Mat m2 = Mat::zeros(2, 2, CV_8UC1);
//Mat m2 = Mat::eye(2, 2, CV_8UC1);
cout << "m2=" << endl << m2 << endl;
waitKey(0);
return 0;
}