免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
視覺(jué)SLAM——OpenCV之Mat結(jié)構(gòu)詳解 數(shù)據(jù)成員和構(gòu)造函數(shù) 創(chuàng)建Mat方法 遍歷Mat方法

前言

OpenCV1時(shí)代采用基于C語(yǔ)言接口構(gòu)建函數(shù)庫(kù),使用名為IplImage的結(jié)構(gòu)體在內(nèi)存中存儲(chǔ)圖像,其問(wèn)題在于需要用戶(hù)手動(dòng)管理內(nèi)存,如果不手動(dòng)釋放內(nèi)存會(huì)造成內(nèi)存泄漏。
OpenCV2引入面向?qū)ο缶幊趟枷?,加入了一個(gè)c 接口,使用Mat類(lèi)數(shù)據(jù)結(jié)構(gòu)作為主打,可以實(shí)現(xiàn)自動(dòng)內(nèi)存管理,且擴(kuò)展性大大提高。

Mat概述

對(duì)于Mat類(lèi),首先要知道的是
1)不必手動(dòng)為其開(kāi)辟空間;
2)不必再在不需要時(shí)將空間釋放。
但手動(dòng)做還也是可以的:大多數(shù)OpenCV函數(shù)仍會(huì)手動(dòng)地為輸出數(shù)據(jù)開(kāi)辟空間。當(dāng)傳遞一個(gè)已經(jīng)存在的 Mat 對(duì)象時(shí),開(kāi)辟好的矩陣空間會(huì)被重用。

Mat是一個(gè)類(lèi),由兩個(gè)數(shù)據(jù)部分組成:矩陣頭(包含矩陣尺寸、存儲(chǔ)方法、存儲(chǔ)地址等)和一個(gè)指向存儲(chǔ)所有像素值矩陣的指針。

Mat類(lèi)最重要的一點(diǎn)是淺拷貝和深拷貝問(wèn)題。由于OpenCV處理圖像時(shí)很多時(shí)候沒(méi)有必要重新復(fù)制一份圖像矩陣,因而采用了引用計(jì)數(shù)機(jī)制。其思路是讓每個(gè)Mat對(duì)象有自己的信息頭,但共享一個(gè)圖像矩陣(矩陣指針指向同一地址)。賦值運(yùn)算符和拷貝構(gòu)造函數(shù)只復(fù)制矩陣頭和矩陣指針,而不復(fù)制矩陣。

Mat A , C;A = imread(argv[1], CV_LOAD_IMAGE_COLOR); // 為矩陣開(kāi)辟內(nèi)存Mat B(A);                                 // 拷貝構(gòu)造函數(shù)C = A;                                    // 賦值

這里A、B、C矩陣頭不同,但指向了相同的圖像矩陣,其中一個(gè)對(duì)象對(duì)矩陣數(shù)據(jù)進(jìn)行改變也會(huì)影響其他對(duì)象。如果矩陣屬于多個(gè)Mat對(duì)象,由最后一個(gè)使用它的對(duì)象進(jìn)行內(nèi)存清理。這通過(guò)引用計(jì)數(shù)來(lái)判斷,每復(fù)制一個(gè)Mat對(duì)象,計(jì)數(shù)器加一,每釋放一個(gè)計(jì)數(shù)器減一,當(dāng)計(jì)數(shù)器值為0時(shí)矩陣就會(huì)被清理。

如果需要進(jìn)行對(duì)象的深拷貝可以采用clone()函數(shù)或者copyTo()。

Mat A;A = imread(argv[1], CV_LOAD_IMAGE_COLOR); Mat B = A.clone();Mat C;A.copyTo(C);

Mat類(lèi)的數(shù)據(jù)成員

	/*	flag的詳細(xì)解釋可以看 https://blog.csdn.net/yiyuehuan/article/details/43701797	0-2位 depth:每一個(gè)像素的位數(shù),也就是每個(gè)通道的位數(shù),即數(shù)據(jù)類(lèi)型(如CV_8U)		enum { CV_8U=0, CV_8S=1, CV_16U=2, CV_16S=3, CV_32S=4, CV_32F=5, CV_64F=6 }		8U 表示 8 位無(wú)符號(hào)整數(shù),16S 表示 16 位有符號(hào)整數(shù),64F表示 64 位浮點(diǎn)數(shù)	3-11位 number of channels:代表通道數(shù)channels,最高512位	0-11位共同代表type:矩陣元素的類(lèi)型,即通道數(shù)和數(shù)據(jù)類(lèi)型(如CV_8UC3、CV_16UC2)	14位 continuity flag:代表Mat的內(nèi)存是否連續(xù)	15位 submat flag:代表該Mat是否為某一個(gè)Mat的submatrix	16-31位 the magic signature:用來(lái)區(qū)分Mat的類(lèi)型,如果Mat和SparseMat	*/	int flags;	    //矩陣的維數(shù),一般大于2    int dims;        //矩陣的行數(shù)與列數(shù),超過(guò)2維矩陣時(shí)(-1,-1)    int rows, cols;        //指向存放矩陣數(shù)據(jù)的內(nèi)存    uchar* data;        //用來(lái)控制ROI區(qū)域,來(lái)獲取一些圖像的局部切片,減少計(jì)算量或者特殊需求的。    const uchar* datastart;    const uchar* dataend;    const uchar* datalimit;    	//如果需要?jiǎng)?chuàng)建一個(gè)新矩陣的內(nèi)存空間,會(huì)調(diào)用MatAllocator類(lèi)作為分配符進(jìn)行內(nèi)存的分配。    MatAllocator* allocator;        //interaction with UMat    //UMatData結(jié)構(gòu)體總有一個(gè)成員refcount:記錄了矩陣的數(shù)據(jù)被其他變量引用了多少次    UMatData* u;        //返回矩陣大小    MatSize size;        //矩陣元素尋址,step[i]表示第i維的總大小,單位字節(jié)    //對(duì)于2維矩陣:step[0]是矩陣中一行元素的字節(jié)數(shù),step[1]是矩陣中一個(gè)元素的字節(jié)數(shù)    //以下公式可以得到Mat中任意元素地址    //addr(M{i,j})=M.data M.step[0]?i M.step[1]?j;    MatStep step;

此外其他版本還存在以下成員:
elemSize :矩陣一個(gè)元素占用的字節(jié)數(shù),例如:type是CV_16SC3,那么elemSize = 3 * 16 / 8 = 6 bytes。
elemSize1 :矩陣元素一個(gè)通道占用的字節(jié)數(shù),例如:type是CV_16CS3,那么elemSize1 = 16 / 8 = 2 bytes = elemSize / channels。

Mat類(lèi)的構(gòu)造函數(shù)

//1、默認(rèn)構(gòu)造函數(shù),無(wú)參數(shù)Mat::Mat();	//2、行數(shù)為rows,列數(shù)為cols,類(lèi)型為type(如CV_8UC1、CV_16UC2)Mat(int rows, int cols, int type);//3、矩陣大小為size,類(lèi)型為type//注意size的構(gòu)造函數(shù)是Size_(_Tp _width,_Tp _height) 先列后行Mat(Size size, int type);//4、行數(shù)為rows,列數(shù)為cols(或矩陣大小為size),類(lèi)型為type,所有元素初始化為s//Scalar表示具有4個(gè)元素的數(shù)組,如Scalar(a,b,b),其原型為Scalar_<double>Mat(int rows, int cols, int type, const Scalar& s);Mat(Size size, int type, const Scalar& s);//5、矩陣維數(shù)為ndims,sizes為指定ndims維數(shù)組形狀的整數(shù)數(shù)組,所有元素初始化為sMat(int ndims, const int* sizes, int type);Mat(const std::vector<int>& sizes, int type);Mat(int ndims, const int* sizes, int type, const Scalar& s);Mat(const std::vector<int>& sizes, int type, const Scalar& s);//6、拷貝構(gòu)造函數(shù),將m賦值給新創(chuàng)建的對(duì)象,淺拷貝Mat(const Mat& m);//7、行數(shù)為rows,列數(shù)為cols,類(lèi)型為type,矩陣數(shù)據(jù)為data,直接使用data所指內(nèi)存,淺拷貝Mat(int rows, int cols, int type, void* data, size_t step=AUTO_STEP);Mat(Size size, int type, void* data, size_t step=AUTO_STEP);Mat(int ndims, const int* sizes, int type, void* data, const size_t* steps=0);Mat(const std::vector<int>& sizes, int type, void* data, const size_t* steps=0);//8、創(chuàng)建的新圖像為m的一部分,范圍由rowRange和colRange指定,新圖像與m共用圖像數(shù)據(jù),淺拷貝Mat(const Mat& m, const Range& rowRange, const Range& colRange=Range::all());Mat(const Mat& m, const Range* ranges);Mat(const Mat& m, const std::vector<Range>& ranges);//創(chuàng)建的新圖像為m的一部分,具體的范圍由矩陣對(duì)象roi指定//Rect的成員函數(shù)有x,y,width,height,分別為左上角點(diǎn)的坐標(biāo)好矩陣寬和高M(jìn)at(const Mat& m, const Rect& roi);

創(chuàng)建Mat對(duì)象

1、使用Mat()構(gòu)造函數(shù)

Mat M(2,2, CV_8UC3, Scalar(0,0,255)); 

需要指定行數(shù)、列數(shù)、存儲(chǔ)元素的數(shù)據(jù)類(lèi)型以及每個(gè)矩陣點(diǎn)的通道數(shù)。

2、使用Mat()構(gòu)造函數(shù)2

int sz[3] = {2,2,2}; Mat L(3,sz, CV_8UC(1), Scalar::all(0));

常用于創(chuàng)建一個(gè)超過(guò)兩維的矩陣:指定維數(shù),然后傳遞一個(gè)指向一個(gè)數(shù)組的指針,這個(gè)數(shù)組包含每個(gè)維度的尺寸,其余的相同

3、為已存在IplImage指針創(chuàng)建信息頭(一般不用)

IplImage* img = cvLoadImage("greatwave.png", 1);Mat mtx(img); // convert IplImage* -> Mat

4、利用create()函數(shù)
這個(gè)創(chuàng)建方法不能為矩陣設(shè)初值,它只是在改變尺寸時(shí)重新為矩陣數(shù)據(jù)開(kāi)辟內(nèi)存

 M.create(4,4, CV_8UC(2));//4X4的圖像矩陣,通道數(shù)為2,沒(méi)有初值

5、MATLAB形式的初始化方式: zeros(), ones(), eyes()

 Mat E = Mat::eye(4, 4, CV_64F);//4X4的單位矩陣      Mat O = Mat::ones(2, 2, CV_32F);//2X2的全為1矩陣 Mat Z = Mat::zeros(3,3, CV_8UC1);//3X3的零矩陣

6、小矩陣使用逗號(hào)分隔式初始化

 Mat C = (Mat_<double>(3,3) << 1, 0, 0, 0, 1, 0, 0, 0, 1); //3X3的單位矩陣

7、使用clone()或copyto()為已存在對(duì)象創(chuàng)建新信息頭

Mat RowClone = C.row(1).clone();//復(fù)制 C中的第2行[0,1,0]作為新矩陣(深拷貝)

遍歷Mat對(duì)象

首先假設(shè)需要對(duì)圖像將那些顏色空間縮減,如imgnew=imgold/10?10img_{new} = img_{old} / 10 * 10imgnew?=imgold?/10?10。對(duì)于較大的圖像,一般不是對(duì)每個(gè)像素點(diǎn)每個(gè)通道的值進(jìn)行如上計(jì)算,而是預(yù)先計(jì)算所有可能的值,構(gòu)建查找表,然后利用查找表對(duì)其直接復(fù)制。

	//構(gòu)建查找表table	int divideWith;     cin >> divideWith;    uchar table[256];     for (int i = 0; i < 256;   i)       table[i] = divideWith* (i/divideWith);

1、ptr指針單像素單通道值訪(fǎng)問(wèn)
即通過(guò)uchar* ptr =img.ptr<char>(i); 得到第i行首地址,然后采用指針運(yùn)算( )或者操作符[]遍歷。

Mat& ScanImage(Mat& img,const uchar* const table){	CV_Assert(img.depth() != sizeof(uchar))//只接收uchar類(lèi)型矩陣	int channels = img.channel();	int nRows = img.rows * channels;//注意行數(shù)乘以通道數(shù)	int nCols = img.cols;		if(img.isContinuous())//如果存儲(chǔ)連續(xù)則可以使用一次循環(huán)	{		nCols *= nRows;		nRows = 1; 	}	uchar* ptr;	for(int i=0; i<nRows;   i)	{		ptr = img.ptr<char>(i);		for( j=0; j<nCols;   j)		{			ptr[j] = table[ptr[j]]			//*ptr   =  table[*ptr]		}	}	return I;}

2、ptr指針單像素訪(fǎng)問(wèn)
利用cv::Vec3b *ptr =img.ptr<cv::Vec3b>(i);得到第i行第一個(gè)像素的3個(gè)通道地址。

Mat& ScanImage(Mat& img,const uchar* const table){	CV_Assert(img.depth() != sizeof(uchar))//只接收uchar類(lèi)型矩陣	int channels = img.channel();	int nRows = img.rows;//每一行	int nCols = img.cols;	Vec3b *ptr;	for(int i=0; i<nRows;   i)	{		ptr = img.ptr<Vec3b>(i);		for( j=0; j<nCols;   j)		{			ptr[j][0] = table[ptr[j][0]];			ptr[j][1] = table[ptr[j][1]];			ptr[j][2] = table[ptr[j][2]];		}	}	return I;}

3、對(duì)data操作
data會(huì)從Mat中返回指向矩陣第一行第一列的指針。常用來(lái)檢查圖像是否被成功讀入(如果指針為NULL則表示無(wú)輸入)。當(dāng)矩陣式連續(xù)存儲(chǔ)時(shí),可以通過(guò)data遍歷矩陣。
也可以采用addr(M{i,j})=M.data M.step[0]?i M.step[1]?j;得到每個(gè)元素的地址,但是不常用。

if(I.isContinuous()){	uchar* p = img.data;	for( unsigned int i =0; i < ncol * nrows;   i)    	*p   = table[*p];}

4、迭代器iterator訪(fǎng)問(wèn)
使用迭代器操作像素,與STL庫(kù)用法相似,只需要獲得圖像矩陣的begin和end,然后增加迭代直至從begin到end。將*操作符添加在迭代指針前,即可訪(fǎng)問(wèn)當(dāng)前指向的內(nèi)容。
迭代器可以采用MatIterator_以及Mat的模板子類(lèi)Mat_,它重載了operator()。

MatIterator_<uchar> it = img.begin<uchar>();Mat_<uchar>::iterator it = img.begin<uchar>();
Mat& ScanImage(Mat& I,const uchar* const table){	CV_Assert(img.depth() != sizeof(uchar));	const int channels = img.channels();	switch(channels)	{		case 1:			{				Mat_<uchar>::iterator it = img.begin<uchar>();				Mat_<uchar>::iterator itend = img.end<uchar>();				for(;it != itend;   it)					*it = table[*it];				break;			}		case 3:			{				Mat_<Vec3b>::iterator it = img.begin<uchar>();				Mat_<Vec3b>::iterator itend = img.end<uchar>();				for(; it != itend ;   it)				{					(*it)[0] = table[(*it)[0]];					(*it)[1] = table[(*it)[1]];					(*it)[2] = table[(*it)[2]];				}			}	}	return img;}

5、動(dòng)態(tài)地址計(jì)算(at)
該方法一般用于獲取或更改圖像中的某個(gè)元素(或隨機(jī)元素),而不用于進(jìn)行全圖掃描。它的基本用途是要確定你試圖訪(fǎng)問(wèn)的元素的所在行數(shù)與列數(shù)。
在debug模式下該方法會(huì)檢查你的輸入坐標(biāo)是否有效或者超出范圍,如果坐標(biāo)有誤則會(huì)輸出一個(gè)標(biāo)準(zhǔn)的錯(cuò)誤信息;在release模式下,它和其他的區(qū)別僅僅是對(duì)于矩陣的每個(gè)元素,都會(huì)獲取一個(gè)新的行指針,然后通過(guò)該指針和[]操作獲取元素。

Mat& ScanImage(Mat& img,const uchar* const table){	CV_Assert(img.depth() != sizeof(uchar));	const int channels = img.channels();	switch(channels)	{		case 1:			{				for(int i=0; i<img.rows;   i)					for(int j=0; j<img.cols;   i)						img.at<uchar>(i,j) = table[img.at<uchar>(i,j)];				break;			}		case 3:			{				for(int i=0; i<img.rows;   i)				{					for(int j=0; j<img.cols;   i)					{						img.at<vec3b>(i,j)[0] = table[img.at<vec3b>(i,j)[0]];						img.at<vec3b>(i,j)[1] = table[img.at<vec3b>(i,j)[1]];						img.at<vec3b>(i,j)[2] = table[img.at<vec3b>(i,j)[2]];					}				}				break;			}	}	return img;}

6、LUT函數(shù)
LUT(Look up table)被官方推薦用于實(shí)現(xiàn)批量圖像元素查找和更改。對(duì)于修改像素值,OpenCV提供函數(shù)operationsOnArray:LUT()<lut>,直接實(shí)現(xiàn)該操作,而不需要掃描圖像。

//建立mat類(lèi)對(duì)象用于查表Mat LookUpTable(1,256,CV_8U);uchar* p = LookUpTable.data;for(int i=0; i<256;   i)	p[i] = table[i];//調(diào)用函數(shù)(I時(shí)輸入,J是輸出)LUT(I, LookUpTable, J);

一般認(rèn)為,采用ptr指針訪(fǎng)問(wèn)圖像像素的效率更高;而迭代器則被認(rèn)為是更安全的方式,僅需要獲得圖像矩陣的begin和end;at方法一般不用于對(duì)圖像進(jìn)行遍歷;而調(diào)用LUT函數(shù)可以獲得最快的速度,因?yàn)镺penCV庫(kù)可以通過(guò)英特爾線(xiàn)程架構(gòu)啟用多線(xiàn)程。其他也存在一些比較偏的遍歷方法,不過(guò)這幾種最為常見(jiàn),效率和安全性也相對(duì)較好。

來(lái)源:http://www.icode9.com/content-4-148551.html
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶(hù)發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
Opencv系列1.4--圖像和大型數(shù)據(jù)類(lèi)型
圖像銳化(拉普拉斯算子):
opencv Mat 像素操作
opencv中mat,cvmat,Iplimage構(gòu)造體定義以及格式互相轉(zhuǎn)換
OpenCV參考手冊(cè)之Mat類(lèi)詳解(三)
OpenCV中:CvArr、CvMat、IplImage、cv::Mat和cv::InputArray的相關(guān)總結(jié)
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服