日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

查看Mat对象的数据的三种方法

發(fā)布時(shí)間:2025/4/16 编程问答 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 查看Mat对象的数据的三种方法 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

我們有了Mat的對(duì)象之后,就可以開(kāi)始對(duì)圖像進(jìn)行處理。

在圖像的處理過(guò)程中,對(duì)數(shù)據(jù)的查看并且對(duì)其進(jìn)行修改,這應(yīng)當(dāng)是比較頻繁的操作了。

這里講講官方手冊(cè)當(dāng)中給出的三種方法。

第一種方法:使用指向Mat數(shù)據(jù)部分的指針。

代碼如下:

1 Mat& ScanImageAndReduceC(Mat& I, const uchar* const table) 2 { 3 // accept only char type matrices 4 CV_Assert(I.depth() != sizeof(uchar)); 5 6 int channels = I.channels(); 7 8 int nRows = I.rows; 9 int nCols = I.cols * channels; 10 11 if (I.isContinuous()) 12 { 13 nCols *= nRows; 14 nRows = 1; 15 } 16 17 int i,j; 18 uchar* p; 19 for( i = 0; i < nRows; ++i) 20 { 21 p = I.ptr<uchar>(i); 22 for ( j = 0; j < nCols; ++j) 23 { 24 p[j] = table[p[j]]; 25 } 26 } 27 return I; 28 }

第11行使用isContinous函數(shù),是為了保證圖像的每一行之間是連續(xù)的,不存在某一行的行尾和下一行的開(kāi)頭的數(shù)據(jù)之間的內(nèi)存單元存放其他數(shù)據(jù)。如果該函數(shù)返回true,則我們可以把圖像當(dāng)成1行、row*col列的數(shù)據(jù)格式進(jìn)行遍歷。

第21行使用ptr函數(shù),它接受一個(gè)參數(shù)代表從0起始的行號(hào)。ptr的返回值默認(rèn)為uchar*或者const uchar*(const版本的重載)。另外ptr有模板的實(shí)現(xiàn),可以通過(guò)ptr<type>實(shí)現(xiàn)type*和const type*的返回值。這些返回值就是返回指向指定行號(hào)的指針。使用ptr方法返回的指針進(jìn)行遍歷,遍歷的是圖像的每一個(gè)字節(jié)(或者我們指定的type長(zhǎng)度),而非像素(注意第9行ncols的定義)。

第二種方法:使用迭代器。

代碼如下:

1 Mat& ScanImageAndReduceIterator(Mat& I, const uchar* const table) 2 { 3 // accept only char type matrices 4 CV_Assert(I.depth() != sizeof(uchar)); 5 6 const int channels = I.channels(); 7 switch(channels) 8 { 9 case 1: 10 { 11 MatIterator_<uchar> it, end; 12 for( it = I.begin<uchar>(), end = I.end<uchar>(); it != end; ++it) 13 *it = table[*it]; 14 break; 15 } 16 case 3: 17 { 18 MatIterator_<Vec3b> it, end; 19 for( it = I.begin<Vec3b>(), end = I.end<Vec3b>(); it != end; ++it) 20 { 21 (*it)[0] = table[(*it)[0]]; 22 (*it)[1] = table[(*it)[1]]; 23 (*it)[2] = table[(*it)[2]]; 24 } 25 } 26 } 27 28 return I; 29 }

MatIterator_是Mat的迭代器,同樣支持模板。在第12行和第19行的循環(huán)中,我們使用了Mat的begin和end函數(shù),使迭代器分別指向Mat數(shù)據(jù)部分的開(kāi)頭和結(jié)尾。begin和end的實(shí)現(xiàn)如下:

1 template<typename _Tp> inline MatIterator_<_Tp> Mat::begin() 2 { 3 CV_DbgAssert( elemSize() == sizeof(_Tp) ); 4 return MatIterator_<_Tp>((Mat_<_Tp>*)this); 5 } 6 7 template<typename _Tp> inline MatIterator_<_Tp> Mat::end() 8 { 9 CV_DbgAssert( elemSize() == sizeof(_Tp) ); 10 MatIterator_<_Tp> it((Mat_<_Tp>*)this); 11 it += total(); 12 return it; 13 }

注意到第4行和第10行使用了Mat_<_Tp>類型,這里可以把它看成是Mat針對(duì)特定類型的模板,不予深究。Mat_<_Tp>類型便于我們對(duì)圖像的數(shù)據(jù)進(jìn)行操作。舉個(gè)文檔里邊簡(jiǎn)單的例子:

1 Mat M(100, 100, CV_8U); 2 3 Mat_<float>& M1 = (Mat_<float>&)M; 4 5 M1(99, 99) = 1.f

Mat_類型可以方便地對(duì)數(shù)據(jù)進(jìn)行操作,因?yàn)镺penCV的開(kāi)發(fā)者對(duì)它的括號(hào)操作符進(jìn)行了重載。我們看看Mat_類型對(duì)3通道圖像的處理:

1 Mat_<Vec3b> img(240, 320, Vec3b(0, 255, 0)); 2 3 for (int i = 0; i < 100; i++) 4 img(i, i) = Vec3b(255, 255, 255); 5 // 對(duì)第三個(gè)通道(藍(lán)色)單獨(dú)操作 6 for (int i = 0; i < img.rows; i++) 7 for (int j = 0; j < img.cols; j++) 8 img(i, j)[2] ^= (uchar)(i ^ j);

在迭代器的操作中我們最常使用的就是++和*操作符,我們來(lái)看看它們是怎么被實(shí)現(xiàn)的:

1 template<typename _Tp> inline _Tp& MatIterator_<_Tp>::operator *() const { return *(_Tp*)(this->ptr); } 2 3 template<typename _Tp> inline MatIterator_<_Tp> MatIterator_<_Tp>::operator ++(int) 4 { 5 MatIterator_ b = *this; 6 MatConstIterator::operator ++(); 7 return b; 8 } 9 // 由于MatIterator_<_Tp>的自增實(shí)現(xiàn)調(diào)用MatConstIterator的自增運(yùn)算符,我們來(lái)看看后者的實(shí)現(xiàn) 10 inline MatConstIterator MatConstIterator::operator ++(int) 11 { 12 MatConstIterator b = *this; 13 *this += 1; 14 return b; 15 } 16 // 上述實(shí)現(xiàn)又依賴+=運(yùn)算法,sliceStart和sliceEnd實(shí)時(shí)跟住我們遍歷的當(dāng)前行的行首和行尾,避免受到Mat數(shù)據(jù)的行與行之間的不連續(xù)造成的影響 17 inline MatConstIterator& MatConstIterator::operator += (ptrdiff_t ofs) 18 { 19 if( !m || ofs == 0 ) 20 return *this; 21 ptrdiff_t ofsb = ofs*elemSize; 22 ptr += ofsb; 23 if( ptr < sliceStart || sliceEnd <= ptr ) 24 { 25 ptr -= ofsb; 26 seek(ofs, true); 27 } 28 return *this; 29 }

第三種方法:使用at方法或者M(jìn)at_類型。

使用at方法的好處是可以隨機(jī)訪問(wèn)你指定的數(shù)據(jù)。代碼如下:

1 Mat& ScanImageAndReduceRandomAccess(Mat& I, const uchar* const table) 2 { 3 // accept only char type matrices 4 CV_Assert(I.depth() != sizeof(uchar)); 5 6 const int channels = I.channels(); 7 switch(channels) 8 { 9 case 1: 10 { 11 for( int i = 0; i < I.rows; ++i) 12 for( int j = 0; j < I.cols; ++j ) 13 I.at<uchar>(i,j) = table[I.at<uchar>(i,j)]; 14 break; 15 } 16 case 3: 17 { 18 Mat_<Vec3b> _I = I; 19 20 for( int i = 0; i < I.rows; ++i) 21 for( int j = 0; j < I.cols; ++j ) 22 { 23 _I(i,j)[0] = table[_I(i,j)[0]]; 24 _I(i,j)[1] = table[_I(i,j)[1]]; 25 _I(i,j)[2] = table[_I(i,j)[2]]; 26 } 27 I = _I; 28 break; 29 } 30 } 31 32 return I; 33 }

在第13行,我們使用了at<uchar>(i, j),該方法返回第i行第j列的數(shù)據(jù)的引用。at方法還支持我們傳入cv::Point類型的參數(shù),例如at<uchar>(cv::Point2f(16, 18))。

我們注意到,第18行使用了Mat_<Vec3b>,我們上面也說(shuō)了,它可以看做是支持模板和隨機(jī)訪問(wèn)的Mat類的變形。Mat_重載了括號(hào)運(yùn)算符以支持隨機(jī)訪問(wèn),其代碼實(shí)現(xiàn)如下:

1 template<typename _Tp> inline const _Tp& Mat_<_Tp>::operator ()(int i0, int i1) const 2 { 3 CV_DbgAssert( dims <= 2 && data && 4 (unsigned)i0 < (unsigned)size.p[0] && 5 (unsigned)i1 < (unsigned)size.p[1] && 6 type() == DataType<_Tp>::type ); 7 return ((const _Tp*)(data + step.p[0]*i0))[i1]; 8 }

總結(jié)

以上是生活随笔為你收集整理的查看Mat对象的数据的三种方法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。