OpenCV中矩陣類詳解之一:Mat
Mat::eye
返回一個恆等指定大小和型別矩陣。
C++: static MatExpr Mat::eye(int rows, int cols, inttype)
C++: static MatExpr Mat::eye(Size size, int type)
引數
rows –的行數。
cols– 的列數。
size –替代矩陣大小規格Size(cols, rows)的方法。
type – 建立的矩陣的型別。
該方法返回 Matlab 式恆等矩陣初始值設定項,類似 Mat::zeros()和 Mat::ones(),你可以用縮放操作高效地建立縮放的恆等矩陣:
/ / 建立4 x 4 的對角矩陣並在對角線上以0.1的比率縮小。
Mat A = Mat::eye(4, 4, CV_32F)*0.1;
Mat::create
分配新的陣列資料 (如果需要)。
C++: void Mat::create(int rows, int cols, int type)
C++: void Mat::create(Size size, int type)
C++: void Mat::create(int ndims, const int* sizes, inttype)
引數
ndims – 新陣列的維數。
rows –新的行數。
cols – 新的列數。
size – 替代新矩陣大小規格:Size(cols, rows)。
sizes – 指定一個新的陣列形狀的整數陣列。
type – 新矩陣的型別。
這是關鍵的Mat方法之一。大多數新樣式 OpenCV 函式和產生陣列的方法每個輸出陣列都呼叫這個方法。此方法使用如下演算法:
1.如果當前陣列形狀和型別匹配新的請立即返回。否則,通過呼叫 Mat::release()取消引用以前的資料。
2.初始化新矩陣頭。
3.分配新的 total()*elemSize() 個位元組的資料空間。
4.分配新的關聯資料的引用計數並將其設定為 1。
這項計劃使記憶體管理強大高效同時還為使用者減少了額外輸入。這意味著通常不需要顯式分配輸出陣列。也就是說,可以不寫成:
Mat color;
...
Mat gray(color.rows, color.cols,color.depth());
cvtColor(color, gray, CV_BGR2GRAY);
而寫成:
Mat color;
...
Mat gray;
cvtColor(color, gray, CV_BGR2GRAY);
因為 cvtColor,與大多數 OpenCV 函式相同,在輸出陣列時內部呼叫Mat::create()。
Mat::addref
計數器參考。
C++: void Mat::addref()
該方法遞增與矩陣資料關聯的引用計數。如果矩陣頭指向外部的資料集(見 Mat::Mat()),則引用計數為 NULL,並且該方法在這種情況下不起作用。通常情況下,為避免記憶體洩漏,不應顯式呼叫該方法。它是由該矩陣賦值運算子隱式呼叫。在支援的它平臺上,引用計數器遞增是一個原子操作。因此,對相同的矩陣,在不同的執行緒非同步操作是安全的。
Mat::release
在必要的情況下,遞減引用計數並釋放該矩陣。
C++: void Mat::release()
該方法遞減與矩陣的資料關聯的引用計數。當引用計數減為0時,矩陣的資料將被釋放,資料和引用計數器指標設定為 NULL。如果矩陣頭指向外部資料集 (見 Mat::Mat()), 引用計數為 NULL,並且該方法在這種情況下無效。
可以手動呼叫此方法強制矩陣資料釋放。但由於這種方法在解構函式中是自動呼叫的,或以更改資料指標的其他方法,因此通常不需要呼叫這個函式。在支援它的平臺上,引用計數器遞減並檢查是否為0 是一個原子操作。因此,在不同的執行緒非同步呼叫相同的矩陣是安全的操作。
Mat::resize
更改矩陣的行數。
C++: void Mat::resize(size_t sz)
C++: void Mat::resize(size_t sz, const Scalar& s)
引數
sz –新的行數。
s –分配給新新增的元素的值。
該方法更改矩陣的行數。如果矩陣重新分配,第一最少(Mat::rows,sz) 行數要保留下來。該方法模擬相應的 STL 向量類的方法。
Mat::reserve
保留一定數量的行的空間。
C++: void Mat::reserve(size_t sz)
引數
sz –的行數。
該方法sz行儲存空間。如果矩陣已經有足夠的空間來儲存sz行,沒有任何異常發生。如果矩陣重新分配,保留前(Mat::rows) 行。該方法模擬了相應的STL 向量類的方法。
Mat::push_back
將元素新增到矩陣的底部。
C++: template<typename T> voidMat::push_back(const T& elem)
C++: void Mat::push_back(const Mat& elem)
引數
elem –增加的一個或多個元素。
該方法將一個或多個元素新增到矩陣的底部。他們是模擬相應的 STL 向量類的方法。元素為Mat時,其型別和列的數目必須和矩陣容器是相同的。
Mat::pop_back
從底部的列表中刪除元素。
C++: template<typename T> voidMat::pop_back(size_t nelems=1)
引數
nelems –刪除的行的數目。如果它大於總的行數,則會引發異常。
該方法從底部的列表中刪除一行或多行。
Mat::locateROI
父矩陣內定位矩陣頭。
C++: void Mat::locateROI(Size& wholeSize,Point& ofs) const
引數
wholeSize–輸出引數,其中包含的整個矩陣包含大小 * 這是其中一部分。
ofs –輸出引數包含*this在整個的矩陣裡面的偏移量。你使用Mat::row()、 Mat::col()、 Mat::rowRange()、Mat::colRange()以及其他的方法從矩陣中提取子陣後該結果子陣只指向原始大矩陣的一部分。然而,每個子陣包含有助於重建的最初矩陣大小和提取子陣在原始矩陣中的位置資訊(由 datastart 和 dataend fields表示)。locateROI方法正是這樣做的。
Mat::adjustROI
調整子陣大小及其在父矩陣中的位置。
C++: Mat& Mat::adjustROI(int dtop, int dbottom,int dleft, int dright)
引數
dtop –頂部子陣邊界向上的平移量。
dbottom –底部子陣邊界向下的平移量。
dleft –左子陣邊界向左的平移量。
dright –右子陣邊界向右的平移量。
該方法是 Mat::locateROI() 的互補性方法。這些函式的典型應用是確定父矩陣中子陣的位置,然後以某種方式改變位置。尤其典型的是,當濾鏡操作中要考慮ROI外的畫素時就需要它。當方法的所有引數都是正的時候,ROI需要以指定量全方位增長,例如:
A.adjustROI(2, 2, 2,2);
在此示例中,每個方向 4 元素增加矩陣大小。矩陣向左側和上側分別平移2 個元素,這會產生5 x 5 核心的濾鏡所需的所有畫素。你的責任是確保 adjustROI 不超出父矩陣邊界。如果超出,該函式發出錯誤提示。OpenCV的濾鏡函式在內部呼叫該函式,像filter2D(),形態學的操作,等等。
另請參閱:
copyMakeBorder()
Mat::operator()
提取矩形子陣。
C++: Mat Mat::operator()(Range rowRange, RangecolRange) const
C++: Mat Mat::operator()(const Rect& roi) const
C++: Mat Mat::operator()(const Ranges* ranges) const
引數:
rowRange –提取的子陣的開始和結束的行。不包括的上限。若要選擇的所有行,請使用 Range::all()。
colRange –提取的子陣的開始和結束的列。不包括的上限。若要選擇的所有列,請使用 Range::all()。
roi – 抽出子陣 specified 作為一個矩形。
ranges – 選定範圍沿每個陣列維度的陣列。
該運算子為*this的子陣列建立新的頭。他們是Mat::row()、 Mat::col()、 Mat::rowRange(),和Mat::colRange()最普遍的形式。例如,A(Range(0, 10),Range::all()) 是相當於A.rowRange(0, 10)。與上述所有操作相同,該操作運算子是複雜度為O(1)的操作,就是沒有矩陣資料將被複制。
Mat::operator CvMat
建立矩陣 CvMat 頭。
C++: Mat::operator CvMat() const
該運算子建立矩陣 CvMat 的頭,而不復制的基礎資料。引用計數未被考慮到此操作中。因此,您應該確保CvMat 頭在使用的時候不釋放原始矩陣。該運算子對於新舊OpenCV API混用是有用的,例如:
Mat img(Size(320, 240), CV_8UC3);
...
CvMat cvimg = img;
mycvOldFunc( &cvimg, ...);
其中 mycvOldFunc 是用於OpenCV 1.x 資料結構的函式。
Mat::operator IplImage
建立IplImage矩陣頭。
C++: Mat::operator IplImage() const
運算子建立矩陣 IplImage 頭,而不復制的基礎資料。您應該確保使用IplImage頭時不釋放原矩陣。與Mat::operatorCvMat類似,該運算子在OpenCV新舊API混用中很有用。
Mat::total
返回陣列元素的總數。
C++: size_t Mat::total() const
該方法返回陣列元素(如果該陣列表示影象的畫素數)的數目。
Mat::isContinuous
返回矩陣是否連續。
C++: bool Mat::isContinuous() const
如果在每一行的結尾無間隙連續儲存矩陣的元素,該方法返回 true。否則,它將返回 false。很明顯,1 x 1 或 1xN 矩陣始終是連續的。使用 Mat::create() 建立矩陣是始終是連續的。但是,如果您提取的矩陣,使用 Mat::col()、 Mat::diag(),等等,或外部已分配的資料構造的矩陣頭的一部分,那麼這種矩陣可能不再具有此屬性。連續性標記在Mat::flags域內用一個位儲存,構造矩陣頭時可以自動計算出來。因此,連續性檢查是非常快速的操作,雖然理論上可以做,如下所示:
/ / 等價的Mat::isContinuous() 的執行情況
boolmyCheckMatContinuity(const Mat& m)
{
//返回 (m.flags & Mat::CONTINUOUS_FLAG) != 0;
return m.rows ==1 || m.step == m.cols*m.elemSize();
}
很多的OpenCV 函式中使用該方法。關鍵在於按元素操作(如算術和邏輯運算、 數學函式、 alpha 融合、顏色空間轉換,以及其他) 不依賴於影象的幾何形狀。因此,如果所有的輸入和輸出的陣列是連續的,該函式可以它們作為很長的單行的向量處理。下面的示例闡釋瞭如何實現 alpha 融合功能。
template<typename T>
void alphaBlendRGBA(const Mat& src1,const Mat& src2, Mat& dst)
{
const float alpha_scale =(float)std::numeric_limits<T>::max(),
inv_scale = 1.f/alpha_scale;
CV_Assert( src1.type() == src2.type()&&
src1.type() ==CV_MAKETYPE(DataType<T>::depth, 4) &&
src1.size() == src2.size());
Size size = src1.size();
dst.create(size, src1.type());
// 規定如下: 檢查陣列的連續性
//如果的確如此,陣列連續
// 把陣列看做一維的向量。
if( src1.isContinuous() &&src2.isContinuous() && dst.isContinuous() )
{
size.width *= size. height;
size.height = 1;
}
size.width *= 4;
for( int i = 0; i < size.height; i++ )
{// 當陣列連續,
// 外迴圈只執行一次
const T* ptr1 = src1.ptr<T>(i);
const T* ptr2 = src2.ptr<T>(i);
T* dptr = dst.ptr<T>(i);
for( int j = 0; j < size.width; j += 4 )
{
float alpha = ptr1[j+3]*inv_scale, beta =ptr2[j+3]*inv_scale;
dptr[j] =saturate_cast<T>(ptr1[j]*alpha + ptr2[j]*beta);
dptr[j+1] =saturate_cast<T>(ptr1[j+1]*alpha + ptr2[j+1]*beta);
dptr[j+2] =saturate_cast<T>(ptr1[j+2]*alpha + ptr2[j+2]*beta);
dptr[j+3] = saturate_cast<T>((1 -(1-alpha)*(1-beta))*alpha_scale);
}
}
}
這種方法,不僅很簡單,而且在簡單的元素的操作中可以提高10-20%效能,尤其在影象很小且操作非常簡單的時候。
在此函式中另一個 OpenCV 語法,目標陣列中Mat::create() 的呼叫會對沒有適當大小和型別的目標陣列分配空間。雖然新分配的陣列始終是連續的,但您仍需要檢查目標陣列,因為 Mat::create()不是總會分配一個新的矩陣。
Mat::elemSize
返回矩陣元素大小 (以位元組為單位)。
C++: size_t Mat::elemSize() const
該方法返回以位元組為單位的矩陣元素大小。例如,如果矩陣型別是 CV_16SC3,該方法返回3*sizeof(short)或 6。
Mat::elemSize1
以位元組為單位返回每個矩陣元素通道的大小。
C++: size_t Mat::elemSize1() const
該方法返回以位元組為單位的矩陣元素通道大小,也就是忽略通道的數量。例如,
如果矩陣型別是 CV_16SC3,該方法返回 sizeof(short) 或 2。
Mat::type
返回一個矩陣元素的型別。
C++: int Mat::type() const
該方法返回一個矩陣的元素型別。這是相容CvMat 型別系統,像 CV_16SC3識別符號
或 16 位有符號的3 通道陣列,等等。
Mat::depth
返回一個矩陣元素的深度。
C++: 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
返回矩陣通道的數目。
C++: int Mat::channels() const
該方法返回矩陣通道的數目。
Mat::step1
返回矩陣歸一化邁出的一步。
C + +: size_t const Mat::step1()
該方法返回以矩陣的step除以Mat::elemSize1()。它對快速訪問任意矩陣元素很有用。
Mat::size
返回一個矩陣大小。
C++: Size Mat::size() const
該方法返回一個矩陣大小:Size(cols, rows)。矩陣超過 2 維時返回大小為(-1,-1)。
Mat::empty
如果陣列有沒有 elemens,則返回 true。
C++: bool Mat::empty() const
如果 Mat::total() 是 0 或 Mat::data 為 NULL,則方法返回 true。因為pop_back() 和 resize()方法M.total()= = 0,並不意味著M.data = =NULL。
Mat::ptr
返回指定矩陣行的指標。
C++: uchar* Mat::ptr(int i=0)
C++: const uchar* Mat::ptr(int i=0) const
C++: template<typename _Tp> _Tp* Mat::ptr(inti=0)
C++: template<typename _Tp> const _Tp*Mat::ptr(int i=0) const
引數:
i –一個基於0的行索引。
該方法返回uchar*,或指向由輸入指定矩陣行的指標。參看Mat::isContinuous()的中示例瞭解如何使用這些方法。
Mat::at
返回對指定陣列元素的引用。
C++: template<typename T> T& Mat::at(int i)const
C++: template<typename T> const T&Mat::at(int i) const
C++: template<typename T> T& Mat::at(int i,int j)
C++: template<typename T> const T&Mat::at(int i, int j) const
C++: template<typename T> T& Mat::at(Pointpt)
C++: template<typename T> const T&Mat::at(Point pt) const
C++: template<typename T> T& Mat::at(int i,int j, int k)
C++: template<typename T> const T&Mat::at(int i, int j, int k) const
C++: template<typename T> T& Mat::at(constint* idx)
C++: 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<float>(k+4) 和 B.at<int>(2*i+1) 分別代替A.at<float>(0,k+4)和
B.at<int>(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::begin
返回矩陣迭代器,並將其設定為第一矩陣元。
C++: template<typename _Tp>MatIterator_<_Tp> Mat::begin()
C++: template<typename _Tp>MatConstIterator_<_Tp> Mat::begin() const
該方法返回矩陣的只讀或讀寫的迭代器。矩陣迭代器的使用和雙向 STL 迭代器的使用是非常相似的。在下面的示例中,alpha融合函式是使用矩陣迭代器重寫:
template<typename T>
void alphaBlendRGBA(const Mat& src1,const Mat& src2, Mat& dst)
{
typedef Vec<T, 4> VT;
const float alpha_scale =(float)std::numeric_limits<T>::max(),
inv_scale = 1.f/alpha_scale;
CV_Assert( src1.type() == src2.type()&&
src1.type() == DataType<VT>::type&&
src1.size() == src2.size());
Size size = src1.size();
dst.create(size, src1.type());
MatConstIterator_<VT> it1 =src1.begin<VT>(), it1_end = src1.end<VT>();
MatConstIterator_<VT> it2 =src2.begin<VT>();
MatIterator_<VT> dst_it =dst.begin<VT>();
for( ; it1 != it1_end; ++it1, ++it2,++dst_it )
{
VT pix1 = *it1, pix2 = *it2;
float alpha = pix1[3]*inv_scale, beta =pix2[3]*inv_scale;
*dst_it =VT(saturate_cast<T>(pix1[0]*alpha + pix2[0]*beta),
saturate_cast<T>(pix1[1]*alpha + pix2[1]*beta),
saturate_cast<T>(pix1[2]*alpha +pix2[2]*beta),
saturate_cast<T>((1 -(1-alpha)*(1-beta))*alpha_scale));
}
}
Mat::end
返回矩陣迭代器,並將其設定為 最後元素之後(after-last)的矩陣元。
C++: template<typename _Tp>MatIterator_<_Tp> Mat::end()
C++: template<typename _Tp>MatConstIterator_<_Tp> Mat::end() const
該方法返回矩陣只讀或讀寫的迭代器,設定為緊隨最後一個矩陣元素的點。