本文将接着OpenCV Mat实例详解继续介绍OpenCV Mat类的操作符及公有成员函数。
Mat & operator =
Mat & operator= (const Mat &m)
将一个Mat对象赋值个另一个Mat对象。
Mat & operator= (const MatExpr &expr)
将一个Mat表达式值赋值给Mat对象
Mat & operator= (const Scalar &s)
将一个标量赋值给Mat对象。
Mat & operator= (Mat &&m)
是一个移动赋值操作符,它允许你将一个 Mat
对象的资源“移动”到另一个 Mat
对象,而不是进行传统的拷贝。这样做可以节省大量时间和内存,因为资源只是在指针级别上被转移,而不是实际的数据。
新建一个控制台应用程序,来演示上面赋值操作符的应用方法,在程序中加入如下代码:
// OpenCVMatTest6.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
int main()
{
//**********Example for operator =
Mat src = imread("1.png");
if (src.empty())
{
cout << "Cann't open the image!" << endl;
return -1;
}
Mat dst = src;
imshow("Dst", dst);
Mat m1 = (Mat_<uchar>(3, 3) << 1, 2, 3, 4, 5, 6, 7, 8, 9);
Mat m2 = (Mat_<uchar>(3, 3) << 10, 11, 12, 13, 14, 15, 16, 17, 18);
MatExpr me = m1.mul(m2, 1);
Mat dst1 = me;
cout << "dst1:" << endl;
cout << dst1 << endl;
Mat dst2(5, 5, CV_8UC3);
dst2 = Scalar(255, 0, 0);
cout << "dst2:" << endl;
cout << dst2 << endl;
Mat dst3 = move(src);
imshow("Dst3", dst3);
waitKey(0);
return 1;
}
试运行,结果如下:
void pop_back (size_t nelems=1)
从Mat对象矩阵的底部移除元素,该方法从矩阵底部删除一行或多行。
nelems 移除元素的行数。
void push_back (const _Tp &elem)
将元素添加到Mat对象数据矩阵的底部。这些方法将一个或多个元素添加到矩阵的底部。它们模拟STL向量类的相应方法。当 elem 为 Mat 时,其类型和列数必须与容器矩阵中的相同。
elem 添加的元素
将上面示例程序中无关的代码注释掉,插入新代码来演示上面两个函数的用法,插入的代码如下:
//**********Example for pop_back(),push_back()
Mat m1 = (Mat_<uchar>(3, 3) << 1, 2, 3, 4, 5, 6, 7, 8, 9);
m1.pop_back(1);
cout << "m1 rows after pop back:" << endl;
cout << m1.rows << endl;
Mat m2 = (Mat_<uchar>(1, 3) << 11, 11, 11);
m1.push_back(m2);
cout << "m1 rows after push back:" << endl;
cout << m1.rows << endl;
cout << "m1 after push back:" << endl;
cout << m1 << endl;
试运行,结果如下:
数据指针ptr
uchar * ptr (int i0=0)
const uchar * ptr (int i0=0) const
返回指向指定矩阵行的指针。这些方法返回 uchar* 或指向指定矩阵行的类型化指针。上面两个函数的区别在与接受的参数不同
i0 从0开始的行索引。
重载函数:
为方便起见OpenCV Mat提供l了很多重载成员函数。它与上述函数的不同之处仅在于它接受的参数。
uchar * ptr (int row, int col)
const uchar * ptr (int row, int col) const
uchar * ptr (int i0, int i1, int i2)
const uchar * ptr (int i0, int i1, int i2) const
uchar * ptr (const int *idx)
const uchar * ptr (const int *idx) const
template<int n> _Tp * ptr (const Vec< int, n > &idx)
template<int n> const _Tp * ptr (const Vec< int, n > &idx) const
template<typename _Tp > _Tp * ptr (int i0=0)
template<typename _Tp > const _Tp * ptr (int i0=0) const
template<typename _Tp > _Tp * ptr (int row, int col)
template<typename _Tp > const _Tp * ptr (int row, int col) const
template<typename _Tp > _Tp * ptr (int i0, int i1, int i2)
template<typename _Tp > const _Tp * ptr (int i0, int i1, int i2) const
template<typename _Tp > _Tp * ptr (const int *idx)
template<typename _Tp > const _Tp * ptr (const int *idx) const
template<typename _Tp , int n> _Tp * ptr (const Vec< int, n > &idx)
template<typename _Tp , int n> const _Tp * ptr (const Vec< int, n > &idx) const
将上面示例程序中无关的代码注释掉,插入新代码来演示上面函数的用法,插入的代码如下:
//*********Example for ptr
//uchar* ptr(int i0 =0), cost uchar* ptr(int i0 =0) const
Mat m1(3, 3, CV_8UC1);
for (size_t i = 0; i <3; i++)
{
int j = 0;
while (j<3)
{
uchar* puchar= m1.ptr(i);
puchar[j] = j;
j++;
}
}
cout << "m1:" << endl;
for (size_t i = 0; i < 3; i++)
{
int j = 0;
while (j < 3)
{
uchar* puchar = m1.ptr(i);
cout << (int)puchar[j] << " ";
j++;
}
cout << endl;
}
//uchar* ptr(int row, int col), const uchar* ptr(int row, int col) const
Mat m2(3, 3, CV_8UC1);
for (size_t i = 0; i < 3; i++)
{
int j = 0;
while (j < 3)
{
uchar* puchar = m2.ptr(i, j);
*puchar = j + 1;
j++;
}
}
cout << "m2:" << endl;
for (size_t i = 0; i < 3; i++)
{
int j = 0;
while (j < 3)
{
uchar* puchar = m2.ptr(i, j);
cout << (int)*puchar << " ";
j++;
}
cout << endl;
}
//ucahr* ptr(int i0, int i1, int in2), const ucahr* ptr(int i0, int i1, int in2) const
Mat m3(5, 5, CV_8UC3);
for (size_t i = 0; i < 5; i++)
{
for (size_t j = 0; j < 5; j++)
{
int k = 0;
while (k < 3)
{
uchar* puchar = m3.ptr((i, j), k);
*puchar = k;
k++;
}
}
}
cout << "m3:" << endl;
for (size_t i = 0; i < 5; i++)
{
for (size_t j = 0; j < 5; j++)
{
int k = 0;
while (k < 3)
{
uchar* puchar = m3.ptr((i, j), k);
cout <<(int)*puchar << " ";
k++;
}
}
cout << endl;
}
//uchar* ptr(onst int* idx), const uchar* ptr(onst int* idx) const
Mat m4(5, 5, CV_8UC1);
int idx[] = {0,1,2,3,4};
for (size_t i = 0; i < 5; i++)
{
uchar* puchar = m4.ptr(idx);
int j = 0;
while(j < 5)
{
puchar[j] = j;
j++;
}
puchar++;
}
cout << "m4:" << endl;
for (size_t i = 0; i < 5; i++)
{
uchar* puchar = m4.ptr(idx);
int j = 0;
while (j < 5)
{
cout << (int)puchar[j] << " ";
j++;
}
cout << endl;
puchar++;
}
//template<int n> _Tp* ptr (const Vec< int, n > &idx), template<int n> _Tp* ptr (const Vec< int, n > &idx), const _Tp* ptr (const Vec< int, n > &idx) const
Mat m5(5, 5, CV_8UC1);
Vec<int, 5> vec1 = {0,1,2,3,4};
for (size_t i = 0; i < 5; i++)
{
uchar* puchar = m5.ptr(vec1);
int j = 0;
while (j < 5)
{
puchar[j] = 255 -j;
j++;
}
puchar++;
}
cout << "m5:" << endl;
for (size_t i = 0; i < 5; i++)
{
uchar* puchar = m5.ptr(vec1);
int j = 0;
while (j < 5)
{
cout <<(int) puchar[j] << " ";
j++;
}
puchar++;
cout << endl;
}
//template<typename _Tp > _Tp* ptr (int i0 = 0), template<typename _Tp > const _Tp* ptr (int i0 = 0) const
Mat M6(5, 5, CV_8UC1);
for (size_t i = 0; i < 5; i++)
{
uchar* puchar = M6.ptr(i);
int j = 0;
while (j < 5)
{
puchar[j] = 127 - j;
j++;
}
puchar++;
}
cout << "m6:" << endl;
for (size_t i = 0; i < 5; i++)
{
uchar* puchar = M6.ptr(i);
int j = 0;
while (j < 5)
{
cout << (int)puchar[j] <<" ";
j++;
}
cout << endl;
puchar++;
}
//template<typename _Tp > _Tp* ptr (int row, int col), template<typename _Tp > const _Tp* ptr (int row, int col) const
Mat m7(3, 3, CV_8UC3);
for (size_t i = 0; i < 3; i++)
{
int j = 0;
while (j < 3)
{
uchar* puchar = m7.ptr(i,j);
puchar[0] = 255;
puchar[1] = 0;
puchar[2] = 0;
j++;
}
}
cout << "m7:" << endl;
for (size_t i = 0; i < 3; i++)
{
int j = 0;
while (j < 3)
{
uchar* puchar = m7.ptr(i,j);
cout <<(int) puchar[0] << " " << (int)puchar[1] << " " << (int)puchar[2] << endl;
j++;
}
}
//template<typename _Tp > _Tp* ptr (int i0, int i1, int i2), template<typename _Tp > const _Tp* ptr (int i0, int i1, int i2) const
Mat m8(5, 5, CV_8UC3);
for (size_t i = 0; i < 5; i++)
{
for (size_t j = 0; j < 5; j++)
{
int k = 0;
while (k < 3)
{
uchar* puchar = m8.ptr((i, j), k);
*puchar = k;
k++;
}
}
}
cout << "m8:" << endl;
for (size_t i = 0; i < 5; i++)
{
for (size_t j = 0; j < 5; j++)
{
int k = 0;
while (k < 3)
{
uchar* puchar = m8.ptr((i, j), k);
cout <<(int)*puchar;
k++;
}
}
cout << endl;
}
//template<typename _Tp > _Tp* ptr (const int* idx), template<typename _Tp > const _Tp* ptr (const int* idx) const
//Mat m9(5, 5, CV_8UC1);
Mat m9 = Mat_<uchar>(5, 5);
int idx1[] = { 0,1,2,3,4 };
for (size_t i = 0; i < 5; i++)
{
uchar* puchar = m9.ptr(idx1);
int j = 0;
while (j < 5)
{
puchar[j] = j;
j++;
}
puchar++;
}
cout << "m9:" << endl;
for (size_t i = 0; i < 5; i++)
{
uchar* puchar = m9.ptr(idx1);
int j = 0;
while (j < 5)
{
cout << (int)puchar[j] << " ";
j++;
}
cout << endl;
puchar++;
}
//template<typename _Tp, int n> _Tp* ptr (const Vec< int, n > &idx), template<typename _Tp, int n> const _Tp* ptr (const Vec< int, n > &idx) const
//Mat m10(5, 5, CV_8UC1);
Mat m10 = Mat_<uchar>(5, 5);
Vec<int, 5> vec2 = { 0,1,2,3,4 };
for (size_t i = 0; i < 5; i++)
{
uchar* puchar = m10.ptr(vec2);
int j = 0;
while (j < 5)
{
puchar[j] = 255 - j;
j++;
}
puchar++;
}
cout << "m10:" << endl;
for (size_t i = 0; i < 5; i++)
{
uchar* puchar = m10.ptr(vec2);
int j = 0;
while (j < 5)
{
cout << (int)puchar[j] << " ";
j++;
}
puchar++;
cout << endl;
}
试运行,结果如下:
template<typename _Tp > std::reverse_iterator< MatIterator_< _Tp > > rbegin ()
template<typename _Tp > std::reverse_iterator< MatConstIterator_< _Tp > > const
template<typename _Tp > std::reverse_iterator< MatIterator_< _Tp > > rend ()
template<typename _Tp > std::reverse_iterator< MatConstIterator_< _Tp > > rend () const
rebegin()与begin()相同,但是反向遍历。
rend()与end()相同,但是反向遍历。
将上面示例程序中无关的代码注释掉,插入新代码来演示上面函数的用法,插入的代码如下:
//for template<typename _Tp > reverse_iterator< MatIterator_<_Tp>> rbegin(),rend();
Mat m(3, 3, CV_8UC1);
typedef MatIterator_<uchar> T1;
typedef MatConstIterator_<uchar> T2;
reverse_iterator<T1> it1 = m.rbegin<uchar>();
reverse_iterator<T1> it2 = m.rend<uchar>();
reverse_iterator<T2> it3 = m.rbegin<uchar>();
reverse_iterator<T2> it4 = m.rend<uchar>();
int i = 1;
while (it1 < it2)
{
*it1 = i;
i++;
it1++;
}
cout << "m: " << endl;
cout << m << endl;
while (it3 <it4)
{
cout << (int)*it3 << " ";
it3++;
}
cout << endl;
试运行,结果如下:
void release ()
递减参考计数器并取消分配矩阵。
该方法递减与矩阵数据相关联的参考计数器。当引用计数器达到 0 时,矩阵数据被释放,数据和引用计数器指针被设置为 NULL。如果矩阵头指向外部数据集(参见 Mat::Mat ),则引用计数器为 NULL,并且该方法在这种情况下不起作用。
在上面程序中插入以下代码:
试运行,结果如下:
可见输出矩阵为一个空矩阵。
void reserve (size_t sz)
为一定数量的行保留空间。
该方法为 sz 行保留空间。如果矩阵已经有足够的空间来存储 sz 行,则不会发生任何情况。如果重新分配矩阵,则保留前 Mat::rows 行。该方法模拟STL向量类的相应方法。
sz 行数
void reserveBuffer (size_t sz)
为一定数量的字节保留空间。
该方法保留 sz 字节的空间。如果矩阵已经有足够的空间来存储 sz 字节,则不会发生任何情况。如果必须重新分配矩阵,其先前的内容可能会丢失。
sz 字节数
上面两个程序的调用十分简单,这里就不做实例演示了。
Mat reshape (int cn, int rows=0) const
更改 2D 矩阵的形状和/或通道数,而不复制数据。
Mat reshape (int cn, int newndims, const int *newsz) const
Mat reshape (int cn, const std::vector< int > &newshape) const
后两个函数是重载函数,其作用相似,接受的参数不同。
参数:
cn 新的通道数
rows 新的rows
newndims 新的维度
newsz 所有维度均具有新矩阵大小的数组。如果某些尺寸为零,则假定这些尺寸中的原始尺寸。
newshape 所有维度具有新矩阵大小的向量。如果某些尺寸为零,则假定这些尺寸中的原始尺寸。
注释掉上面程序的无关代码,插入新代码来演示改程序的用法。插入的代码如下:
//for resahpe()
Mat src = imread("1.png");
if (src.empty())
{
cout << "Cann't open the image!" << endl;
return -1;
}
imshow("src", src);
Mat dst1 = src.reshape(src.channels(), src.rows/2);
imshow("Dst1", dst1);
Mat src1 = (Mat_<uchar>(3, 3) << 1, 2, 3, 4, 5, 6, 7, 8, 9);
const int newsz[] = {3, 4};
Mat dst2 = src1.reshape(1,2, newsz);
cout << "dst2 cols:"<< dst2.cols << endl;
cout <<"dst2 rows: "<< dst2.rows << endl;
cout << "dst2 channels: "<< dst2.channels() << endl;
cout << "dst2 size: " << dst2.size() << endl;
cout << "dst2 type: " << dst2.type() << endl;
Mat src2(Size(2, 2), CV_8UC3, Scalar(1, 2, 3));
vector<int> new_shape{ 4, 3 };
Mat dst3 = src2.reshape(1, new_shape);
cout << "dst3 cols:" << dst3.cols << endl;
cout << "dst3 rows: " << dst3.rows << endl;
cout << "dst3 channels: " << dst3.channels() << endl;
cout << "dst3 size: " << dst3.size() << endl;
cout << "dst23 type: " << dst3.type() << endl;
试运行,结果如下:
void resize (size_t sz)
改变矩阵的rows
void resize (size_t sz, const Scalar &s)
改变矩阵的rows及矩阵值
参数 :
sz 新的矩阵rows
s 矩阵的新值。
注释掉上面程序中无关的代码,添加新代码,来演示该函数的用法,添加的新代码如下:
//Example for resize()
Mat src(500, 500, CV_8UC3, Scalar(255, 0, 0));
imshow("src", src);
src.resize(300);
imshow("src resied first", src);
src.resize(400, Scalar(0, 0, (uchar)255));
imshow("src resied second", src);
试运行,结果如下:
Mat row (int y) const
为指定的矩阵行创建矩阵头,不copy数据
Mat rowRange (int startrow, int endrow) const
为指定的row跨度创建矩阵头,不copy数据
Mat rowRange (const Range &r) const
为指定的row跨度创建矩阵头,不copy数据
这几个函数与前面讲过的col (int x) const,colRange (int startcol, int endcol) const,colRange (const Range &r) const原理类似前者是针对row,后面针对的是row,这里就不再做演示。
Mat & setTo (InputArray value, InputArray mask=noArray())
将全部或部分数组元素设置为指定值。
This is an advanced variant of the Mat::operator=(const Scalar& s) operator.
参数:
Value 分配的标量转换为实际的数组类型。
mask 与 *this 大小相同的操作掩码。它的非零元素表示哪些矩阵元素需要复制。掩码必须为 CV_8U 类型,并且可以有 1 个或多个通道。
注释掉上面程序中无关的代码,插入新代码,来演示·该·函数的用法,插入代码如下:
//Example for setTo (InputArray value, InputArray mask=noArray())
Mat m1(5, 5, CV_8UC1, Scalar(110));
Mat mask(5, 5, CV_8UC1, Scalar(255));
for (size_t i = 0; i < 5; i++)
{
int j = 1;
while (j <3)
{
mask.at<uchar>(j, i) = 0;
j++;
}
}
Scalar newVal(115);
m1.setTo(newVal, mask);
m1.setTo(newVal, mask);
cout << m1 << endl;
试运行,结果如下:
size_t step1 (int i=0) const
返回一个标准化步长。
该方法返回除以 Mat::elemSize1() 的矩阵步长。快速访问任意矩阵元素非常有用。
注释掉上面程序中无关代码,插入新代码,来演示该函数的用法,插入代码如下:
//Example for step1()
Mat m1(5, 5, CV_8UC3, Scalar(0,0,255));
cout << "m1 elmentsize: " << m1.elemSize() << endl;
cout << "m1 elmentsize1: " << m1.elemSize1() << endl;
cout << "m1 step: " << m1.step << endl;
cout << "m1 step1: " << m1.step1() << endl;
试运行,结果如下:
MatExpr t () const
转置矩阵,即返回该Mat对象数据矩阵的转置矩阵。
注释掉上面演示程序的无关代码,插入新代码,来演示该函数的用法,插入代码如下:
//Example for t()
Mat m1 = (Mat_<uchar>(3,3) <<1,2,3,4,5,6,7,8,9);
cout << "m1:" << endl;
cout << m1 << endl;
Mat m2 = m1.t();
cout << "m2:" << endl;
cout << m2 << endl;
试运行,结果如下:
size_t total () const
返回Mat对象数据矩阵element的总数。
size_t total(int startDim, int endDim=INT_MAX) const
该方法返回某个子数组切片内的元素数量
int type() const
返回element type
注释掉上面演示程序中无关的代码,插入新代码,演示上面几个函数的用法,插入代码如下:
//Example for total(),type()
Mat m1(10, 10, CV_8UC3,Scalar(0,0,255));
cout <<"m1 total: "<< m1.total() << endl;
cout << "m1 total2: " << m1.total((int)3, (int)9) << endl;
cout << "m1 type: " << m1.type() << endl;
试运行,结果如下:
到此,OpenCV Mat类的成员函数已介绍完毕。
博文示例是基于OpenCV4.8(opencv目录位于d盘根目录下)及VS2022。示例源码已上传到CSDN,其链接为:https://download.csdn.net/download/billliu66/88874033