创建Mat空间
(1) 通过Mat 构造函数直接创建
Mat mat(3000,4000,CV_8UC3);
(2) 使用mat.Create创建
mat.Create(rows,cols,CV_8UC1)
Opencv 提供了isContinuous来判断存储空间是否是连续的,通过step记录
Opencv 遍历图像像素
1) 访问连续空间
直接地址访问连续空间
int size = mat.rows*mat.cols*mat.elemSize();
int es = mat.elemSize();
for(int i= 0;i< size;i+= es)
{
mat.data[i] = 0; //B
mat.data[i+1] = 0; //G
mat.data[i+2] = 0; //R
}
2)访问不连续空间
方法一:直接地址访问不连续空间
for(int i = 0; i < mat.rows;i++)
{
for(int j = 0; j < mat.cols; j++)
{
(&mat.data[i*mat.step])[j*mat.elemSize()] = 255; //B
(&mat.data[i*mat.step])[j*mat.elemSize()+1] = 255; //G
(&mat.data[i*mat.step])[j*mat.elemSize()+2] = 255; //R
}
}
方法二: 通过ptr接口遍历Mat (模板函数)
(1) mat.ptr<Vec3b>(row) ; //返回的指针 可以直接只取某一行的数据
(2) mat.ptr<Vec3b>(row,col); //可以直接支取某一行某一列的数据,除了代码的简洁性之外,还有一个好处就是在C++当中它会抛出异常,直接地址访问一旦发生异常不确定,有可能程序直接宕掉有可能继续运行出现更意外的错误,而通过ptr遍历Mat它会程序一旦发生错误,它会抛出一个异常,我们可以通过捕获这个异常做相对于的处理。
for(int row = 0;row <mat.rows; row++)
{
for(int col = 0; col < mat.cols; col++)
{
Vec3b *c = mat.ptr<Vec3b>(row,col);
c->val[0] = 0; //B
c->val[1] = 0; //B
c->val[2] = 0; //B
}
}
方法三: 通过at接口遍历Mat (模板函数)
与ptr不同的是不操作地址,而是直接操作对象,接口最简单的遍历方法 。
(1) mat.at<Vec3b>(row,col)[0] = 255;
(2) mat.at<Vec3b>(row,col)[1] = 0;
(3) mat.at<Vec3b>(row,col)[2] = 255;
for(int row = 0;row <mat.rows; row++)
{
for(int col = 0; col < mat.cols; col++)
{
Vec3b &m = mat.at<Vec3b>(row,col); //定义一个引用变量,一定要定义引用变量,把一个引用赋给一个普通变量会做拷贝,引用本身可以说不占内存,跟编译器有关。
m[0] = 100; //B
m[1] = 100; //G
m[2] = 100; //R
}
}
方法四:通过迭代器遍历Mat
好处:可以不用管mat 的行列(大小)、类型
auto it = mat.begin<Vec3b>0;
auto it_end = mat.end<Vec3b>0;
for(; it != it_end;++it)
{
(*it).val[0] = 0;
(*it).val[1] = 255;
(*it).val[2] = 0;
}