学习OpenCV大家都会遇到一个对象叫做Mat,此对象非常神奇,支持各种操作。很多初学者因此被搞得头晕脑胀,它各种用法太多太杂,搞得初学者应接不暇,感觉有心无力、无处下手之感。这里我们首先要正本清源,从Mat对象的产生原因说起,然后再把Mat各种神奇用法一一梳理总结。

Mat对象起源:

当OpenCV 1.0发布时候没有Mat对象,是个C语言风格的数据结构IPlImage来表示内存中图像对象,但是OpenCV开发者在做复杂图像处理算法分析与计算时候,创建了很多IplImage这样的数据结构,偶尔最后可能忘记释放内存了,这样算法就有了内存泄漏,导致开发者浪费很多精力去寻找这个错误,这个已经跟图像处理算法没有关系了,但是它却困扰了很多OpenCV开发者。Intel发现自己做的库居然这么渣,广大群众不满意,决定从OpenCV 2.0开始使用一个新的内存对象Mat来表示内存中的图像对象。它是C++风格的数据结构,自动实现内存分配与回收,这样OpenCV开发者就再也不用担心因为使用OpenCV的图像对象数据结构而导致内存泄漏问题了。但是仍然有些开发者直到现在还在顽固的使用IplImage这个对象,Intel为了照顾他们,所以允许IplImage对象继续存在,还提供可以把IplImage对象转换成Mat对象的构造函数,作为开源SDK可谓仁至义尽。

Mat对象构造函数

自从OpenCV2.0引入Mat对象之后,在通过imread函数读入一张图像的时候开发者无需先分配内存然后使用完之后释放它,因为OpenCV框架会帮你完成这些事情,自动管理Mat相关的内存,那么在OpenCV中如何创建一个Mat对象,下列方法都是你的选择之一:

方法一:

通过读入一张图像,直接转换为Mat对象即可:

Mat image = imread("test.jpg");

其中 imread()方法需要传入String类型的值,一般都是图像文件路径。显示如下:

方法二:

使用无参数构造函数,创建Mat对象

Mat image = Mat();
image.create(4, 4, CV_8UC3);

此刻表示创建一个4x4大小的像素块,每个像素都是三通道每个通道的位数都是8位,一个字节的。上述CV_8UC3中的8表示8位、UC表示uchar类型、3表示三个通道。打印显示是这样的:

方法三:

使用行、列、类型带这个三个参数的构造函数创建Mat对象

Mat m = Mat(4, 4, CV_8UC3)

表示创建一个跟方法二一样的像素块,打印显示跟方法二内容一致:

方法四:

使用行、列、类型、Scalar向量四个参数的构造函数创建Mat对象

Mat m = Mat(4, 4, CV_8UC3, Scalar(0, 255, 255);

同样表示创建一个4x4的像素块,唯一不一样的是颜色不是默认值而是我们指定的三通道颜色值向量Scalar(0, 255, 255)。其中Scalar向量数目永远是等于通道数目,打印显示如下

方法五:

使用大小、类型两个参数的构造函数创建Mat对象

Mat m = Mat(Size(4, 4), CV_8UC3);

同样创建一个4x4的每个通道8位三个通道的像素块,打印显示如下:

方法六:

使用大小、类型、Scalar向量三个参数的构造函数创建Mat对象

Mat m = Mat(Size(4, 4), CV_8UC3, Scalar(255, 0, 0));

同样创建一个4x4的每个通道8位三个通道的像素块,打印显示如下:

方法七:

使用Mat::zeros函数实现,两个参数一个是Size表示图像宽与高,另外一个表示类型

Mat m = Mat::zeros(Size(4,4), CV_8UC3);

同样创建一个4x4的每个通道8位三个通道的像素块,打印显示如下:

方法八:

使用Mat::ones函数实现,两个参数一个是Size表示图像宽与高,另外一个表示类型

Mat m = Mat::ones(Size(4,4), CV_8UC1);

同样创建一个4x4的每个通道8位一个通道的像素块,打印显示如下:

注意这次类型是CV_8UC1表示创建的是一个通道类型数据。

复制Mat对象

在OpenCV中可以通过如下几种方法对Mat对象进行复制

Mat m2;
Mat m1 = imread("test.jpg");
m2 = m1;

或者

Mat m1 = imread("test.jpg");
Mat m2(m1);

通过上述两种方法Mat对象只会复制头部分和指向像素数据的指针,不会真正复制数据部分。通过如下方法Mat可以实现数据对象的完全复制

Mat src = imread("test.jpg");
Mat dst = src.clone();

或者

Mat src = imread("test.jpg");
Mat dst;
src.copyTo(dst);

Mat对象中获取像素

方法一:通过指针读取像素值,实现像素值操作。函数Mat.ptr(row)其中row表示行索引,从零开始基数,表示每一行的结果。

Mat src = imread("test.jpg");

const uchar* currentRow = src.ptr(row) ;

表示获取指定行int row = 0的像素数组指针。

演示代码:

	Mat resultImg = Mat::zeros(src.size(), CV_8UC3);
for (int row = 0; row < src.rows; row++) {
for (int col = 0; col < src.cols; col++) {
const uchar* currentRow = src.ptr(row);
uchar* myrow = resultImg.ptr(row); if (src.channels() == 1) {
myrow[col] = 255 - currentRow[col];
} else if(src.channels() == 3) {
myrow[col*3] = 255 - currentRow[col*3];
myrow[col*3+1] = 255 - currentRow[col*3+1];
myrow[col*3+2] = 255 - currentRow[col*3+2];
} else {
printf("image type is unknown...\n");
}
}
}

方法二:通过随机进入像素点读取像素值,实现像素操作。函数Mat.at<type>(row, col)支持获取单通道或者多通道的图像,通过这种方式的时候,需要提前预知图像的类型。代码演示如下:

	for (int row = 0; row < src.rows; row++) {
for (int col = 0; col < src.cols; col++) { if (src.channels() == 1) {
resultImg.at<uchar>(row, col) = 255 - src.at<uchar>(row, col);
}
else if (src.channels() == 3) {
Vec3b pixels = src.at<Vec3b>(row, col);
resultImg.at<Vec3b>(row, col)[0] = 255 - pixels[0];
resultImg.at<Vec3b>(row, col)[1] = 255 - pixels[1];
resultImg.at<Vec3b>(row, col)[2] = 255 - pixels[2];
}
else {
printf("image type is unknown...\n");
}
}
}

结果显示如下:

  

Mat作为OpenCV 2.0之后推出新图像内存对象数据结构,是每个学习OpenCV的开发者必须熟知与掌握的。

OpenCV教程二 - Mat对象与它各种用法的更多相关文章

  1. QT中使用 slot 传递 opencv 中得Mat对象以及 使用多线程集成开源代码。

    关于 slot传递 Mat 对象 以前一直是使用 Qtimer 定时器,设定超时后读取 dialog 对象的 Mat成员实现在 UI 里显示图像,发现这样对以后集成其他面向过程的代码增加了复杂度. 所 ...

  2. 跟我一起学opencv 第三课之图像在opencv中的表示-Mat对象

    1.下面第一章图是一位美女图像,和其他数据一样图像在计算机中也是以二进制存储,下面第二张图 2.在摄像头眼里一幅图像就是一个矩阵或者说是二维数组,数组元素是像素值 3.opencv中以Mat对象表示图 ...

  3. 图像处理---《Mat对象 与 IplImage对象》

    图像处理---<认识 Mat对象> Mat对象 与 IplImage对象 (1)Mat对象:OpenCV2.0之后引进的图像数据结构.自动分配内存.不存在内存泄漏的问题,是面向对象的数据结 ...

  4. opencv:Mat对象

    Mat对象:图像文件的内存数据对象 读取为 Mat 对象 读取图像位Mat对象,获取图像的相关信息 #include <opencv2/opencv.hpp> #include <i ...

  5. openCV - 3. Mat对象

    Mat对象与IplImage对象.Mat对象使用.Mat定义数组 Mat对象与IplImage对象 Mat对象OpenCV2.0之后引进的图像数据结构.自动分配内存.不存在内存泄漏的问题,是面向对象的 ...

  6. OpenCV——创建Mat对象、格式化输出、常用数据结构和函数(point,vector、Scalar、Size、Rect、cvtColor)

    创建Mat对象:

  7. Mat对象与像素操作 OpenCV C++

    Mat对象,分为两个部分,头部和数据部分 Mat对象拷贝之后是相互独立的 Mat对象有三种创建方法 CV_8UC1单通道,CV_8UC2双通道,CV_8UC3三通道,通道数 Scalar(0-255, ...

  8. OpenCV中对Mat里面depth,dims,channels,step,data,elemSize和数据地址计算的理解 (转)

    cv::Matdepth/dims/channels/step/data/elemSizeThe class Mat represents an n-dimensional dense numeric ...

  9. OpenCV中对Mat里面depth,dims,channels,step,data,elemSize和数据地址计算的理解

    原文:OpenCV中对Mat里面depth,dims,channels,step,data,elemSize和数据地址计算的理解 Title : cv::Mat depth/dims/channels ...

随机推荐

  1. SIFT

    简介 SIFT(scale invariant feature transform)——尺度不变特征转换,用来检测和描述局部特征,运用范围包括object recognition(目标检测), rob ...

  2. Windows Server 2012 在个人终端上使用的推荐设置

    Windows Server 2012,也就是 Windows 8 的服务器版本,相对于 Windows 8 企业版而言,增强了作为服务器的功能,弱化了作为终端系统的功能. 目前微软官方提供了 Win ...

  3. MC34063中文资料及应用实例(转)

    源:http://blog.chinaunix.net/uid-26199686-id-3207838.html MC34063A(MC33063)芯片器件简介 该器件本身包含了DC/DC变换器所需要 ...

  4. strace 分析 跟踪 进程错误

    strace是什么? 按照strace官网的描述, strace是一个可用于诊断.调试和教学的Linux用户空间跟踪器.我们用它来监控用户空间进程和内核的交互,比如系统调用.信号传递.进程状态变更等. ...

  5. nginx 生成 缩略图 and 生成缩略图到硬盘

    nginx  编译的时候增加  ./configure --with-http_image_filter_module 配置如下 server { listen     80; server_name ...

  6. matlab中gatbx工具箱的添加

    1. 从http://crystalgate.shef.ac.uk/code/下载工具箱压缩包gatbx.zip 2. 解压gatbx.zip,将其子文件夹genetic放在matlab安装目录too ...

  7. location下的属性集锦

    location.protocol="http:"//即,协议 location.hostname="zhidao.baidu.com"//即,主机域名

  8. NMEA协议 上位机 C# (转)

    源:NMEA协议 上位机 c# 前些时间写做了两款用NMEA协议的上位机,在这里做一个总结和记录.和大家分享,也为了以后不会忘记. NMEA协议总体来说,相对简单,是气象上比较成熟的协议. 主要有以下 ...

  9. axis2开发实例(一)

    主要参考<axis2之webservice新手超详细教程http://wenku.baidu.com/view/6eae036d011ca300a6c390a4.html> <axi ...

  10. (简单) HDU 3397 Sequence operation,线段树+区间合并。

    Problem Description lxhgww got a sequence contains n characters which are all '0's or '1's. We have ...