opencv3.1学习笔记(4) Mat对象介绍

Mat对象介绍


Mat对象是从OpenCV2.0引入的对象,处理的对象其实是二维像素数组。

就像OpenCV官方教程中说的,下图中的车在CCD中看到的其实是一个二维的数组。Mat这个对象集成了一些操作这个数组数据的方法。

image.png

最初的opencv版本中,和Mat功能相似的是数据结构 lIplImage。

lIplImage是从2001年OpenCV发布之后就一直存在,是C语言风格的数据结构,
需要开发者自己分配与管理内存,
对大的程序使用它容易导致内存泄漏问题
lMat对象OpenCV2.0之后引进的图像数据结构、自动分配内存、不存在内存泄漏的问题,
是面向对象的数据结构。
分了两个部分,头部与数据部分


Mat的构造函数,和常用方法如下:

Mat()
Mat(int rows,int cols,int type)
Mat(Size 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 *sizes,int type)
Mat(int ndims,const int *sizes,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)


下面用代码测试一下上面的函数。

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

using namespace cv;
using namespace std;

double alpha = 1;
double beta = 50;
void changeContrastAndBright(const Mat& src, Mat& dst) {

	for (int i = 0; i < src.rows; i++)
	{
		for (int j = 0; j < src.cols; j++)
		{
			for (int k = 0; k < 3; k++)
			{
				dst.at<Vec3b>(i, j)[k] =
					saturate_cast<uchar>(alpha * (src.at<Vec3b>(i, j)[k]) + beta);
			}
		}
	}

}

int main(int argc, char** argv) {
	Mat src;
	src = imread("e:/5.png");
	if (src.empty()) {
		cout << "不能载入图片..." << endl;
		return -1;
	}
	namedWindow("input", CV_WINDOW_AUTOSIZE);
	imshow("input", src);

	Mat dst;
	//创建与src一样大小的,默认像素的颜色填充(205,205,205)图像
	dst = Mat(src.size(), src.type());
	//指定像素颜色,这里是红色,即(0,0,255)
	dst = Scalar(0, 0, 255);
	namedWindow("win1", CV_WINDOW_AUTOSIZE);
	imshow("win1", dst);
	//cout << "dst=" << endl << dst << endl;

	//创建一个4通道的,每个通道像素的值为(255,255,0,25)
	//深度为32,像素点有4*4 
	//的图像矩阵,效果见图2
	Mat dst1(4, 4, CV_32FC4, Scalar(255, 255, 0,25));
	namedWindow("win2", CV_WINDOW_AUTOSIZE);
	imshow("win2", dst1);
	cout << "dst1=" << endl << dst1 << endl;

	//复制图形矩阵
	//copyTo是深度复制
	Mat dst2(src.size(), src.type());
	//这种方式是浅复制,只复制Mat的头部分
	Mat dst3(src);
	src.copyTo(dst2);
	namedWindow("win3", CV_WINDOW_AUTOSIZE);
	imshow("win3", dst2);
	namedWindow("win4", CV_WINDOW_AUTOSIZE);
	imshow("win4", dst3);

	//把src的色彩空间转为CV_BGR2GRAY(灰度图),输出通道数量
	//效果见图3
	Mat dst4(src.size(), src.type());
	cvtColor(src, dst4, CV_BGR2GRAY);
	printf("src的通道数:%d\n", src.channels());
	printf("dst4的通道数:%d\n", dst4.channels());
	namedWindow("win5", CV_WINDOW_AUTOSIZE);
	imshow("win5", dst4);

	//create方法,跟构造函数作用差不多
	Mat dst5;
	dst5.create(src.size(), src.type());
	dst5 = Scalar(0, 255, 0);
	namedWindow("win6", CV_WINDOW_AUTOSIZE);
	imshow("win6", dst5);

	//掩模,提升图片对比度
	Mat csrc;
	Mat dst6 = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
	filter2D(src, csrc, -1, dst6);
	namedWindow("win7", CV_WINDOW_AUTOSIZE);
	imshow("win7", csrc);

	//提升图片对比度亮度,见图4
	Mat dst7=Mat::zeros(src.size(),src.type());
	double time0 = static_cast<double>(getTickCount());
	changeContrastAndBright(src, dst7);
	time0 = ((double)getTickCount() - time0) / getTickFrequency();
	cout << "直接遍历方法运行时间为:" << time0 << "秒" << endl;

	Mat dst8;
	time0 = static_cast<double>(getTickCount());
	src.convertTo(dst8, src.type(), alpha, beta);
	time0 = ((double)getTickCount() - time0) / getTickFrequency();
	cout << "convertTo方法运行时间为:" << time0 << "秒" << endl;
	namedWindow("win8", CV_WINDOW_AUTOSIZE);
	imshow("win8", dst8);


	waitKey(0);
	return 0;
}



image.png

(图2)


image.png

(图3)


image.png

(图4)


代码解释:


(1)Mat对象的浅复制与深度复制

部分复制:一般情况下只会复制Mat对象的头和指针部分,不会复制数据部分 
Mat A= imread(imgFilePath);
Mat B(A)  
完全复制:如果想把Mat对象的头部和数据部分一起复制,
可以通过如下两个API实现 Mat F = A.clone(); 或 Mat G; A.copyTo(G);
  • 输出图像的内存是自动分配的

  • 使用OpenCV的C++接口,不需要考虑内存分配问题

  • 赋值操作和拷贝构造函数只会复制头部分

  • 使用clone与copyTo两个函数实现数据完全复制

(2)Mat构造函数

Mat M(2,2,CV_8UC3, Scalar(0,0,255))
其中前两个参数分别表示行(row)跟列(column)、
第三个CV_8UC3中的8表示每个通道占8位、U表示无符号、C表示Char类型、
3表示通道数目是3,第四个参数是向量表示初始化每个像素值是多少,
向量长度对应通道数目一致

(3)create方法

它可以创建多维数组,虽然2维以上数组我们不常用。
下面的代码创建了3维数组。

创建多维数组cv::Mat::create
int sz[3] = {2,2,2};     
Mat  L(3,sz, CV_8UC1, Scalar::all(0));
Mat M;
M.create(4, 3, CV_8UC2);
M = Scalar(127,127);
cout << "M = " << endl << " " << M << endl << endl;
uchar* firstRow = M.ptr<uchar>(0);
printf("%d", *firstRow

结果:

image.png

(4)convertTo方法

这个方法用于数据类型的转换,请看下面的示例代码。

//验证 convertTo 是否支持in place  和 改变通道数
#include <opencv2/opencv.hpp>  //头文件
using namespace cv;  //包含cv命名空间
using namespace std;  

void main( )
{    
	// 【1】读入一张图片,载入图像
	Mat ImgColor = imread("1.jpg", IMREAD_COLOR);// CV_8UC3
	Mat ImgGray = imread("1.jpg", IMREAD_GRAYSCALE);// CV_8UC1
	cout << "original" << endl;
	cout << "ImgColor.type()" << ImgColor.type() << endl;
	cout << "ImgGray.type()" << ImgGray.type() << endl << endl;

	// 能否转为16位深度3通道
	Mat ImgColorC3;
	Mat ImgGrayC3;
	ImgColor.convertTo(ImgColorC3, CV_16UC3);
	ImgGray.convertTo(ImgGrayC3, CV_16UC3);
	cout << "convertTo CV_16UC3" << endl;
	cout << "ImgColorC3.type()" << ImgColorC3.type() << endl;
	cout << "ImgGrayC3.type()" << ImgGrayC3.type() << endl << endl;

	// 能否转为16位深度1通道
	Mat ImgColorC1;
	Mat ImgGrayC1;
	ImgColor.convertTo(ImgColorC1, CV_16UC1);
	ImgGray.convertTo(ImgGrayC1, CV_16UC1);
	cout << "convertTo CV_16UC1" << endl;
	cout << "ImgColorC1.type()" << ImgColorC1.type() << endl;
	cout << "ImgGrayC1.type()" << ImgGrayC1.type() << endl << endl;

	// convertTo是否支持in-place 操作
	ImgColor.convertTo(ImgColor, CV_16UC3);
	ImgGray.convertTo(ImgGray, CV_16UC3);
	cout << "in place" << endl;
	cout << "ImgColor.type()" << ImgColor.type() << endl;
	cout << "ImgGray.type()" << ImgGray.type() << endl << endl;

}

结果如下:

image.png

  • convertTo可以改变Mat的深度,例如可以把Mat的type从CV_8UC3改为CV_16SC3

  • convertTo不可以改变Mat的通道数,例如不可以把Mat的type从CV_8UC3改为CV_8UC1,即使你填入的转换类型通道数不同,输出的通道数还是与输入的通道数相同。

  • convertTo支持就地(in-place)操作

在本文的演示中,我们使用convertTo对图像的对比度和亮度的调整,主要是根据公式dst = alpha * src + beta(alpha控制对比度,beta控制亮度)。
代码中,我们演示了使用循环遍历像素的方法 
changeContrastAndBright()以及使用convertTo()的方法。
convertTo方法速度要快得多,不是一个数量级。


--------------------- 

作者:hackpig

来源:www.skcircle.com

版权声明:本文章代码及资料部分或全部来自贾志刚老师的视频,勇哥只是在个人理解的基础上做学习笔记,转载请附上博文链接!


本文出自勇哥的网站《少有人走的路》wwww.skcircle.com,转载请注明出处!讨论可扫码加群:

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

会员中心
搜索
«    2024年3月    »
123
45678910
11121314151617
18192021222324
25262728293031
网站分类
标签列表
最新留言
    热门文章 | 热评文章 | 随机文章
文章归档
友情链接
  • 订阅本站的 RSS 2.0 新闻聚合
  • 扫描加本站机器视觉QQ群,验证答案为:halcon勇哥的机器视觉
  • 点击查阅微信群二维码
  • 扫描加勇哥的非标自动化群,验证答案:C#/C++/VB勇哥的非标自动化群
  • 扫描加站长微信:站长微信:abc496103864
  • 扫描加站长QQ:
  • 扫描赞赏本站:
  • 留言板:

Powered By Z-BlogPHP 1.7.2

Copyright Your skcircle.com Rights Reserved.

鄂ICP备18008319号


站长QQ:496103864 微信:abc496103864