- 在我们使用OpenCV进行图像处理时,最常用到的就是对图像像素的访问,OpenCV支持5种访问方式,他们的访问速度和效率各不相同。这里以三通道图像为例简单说明一下。
访问速度:3>4>2>5>1
OpenCV Mat对象成员简介
- data: uchar型的指针,指向矩阵数据
- dims: 矩阵的维度
- rows:矩阵行数
- cols:矩阵列数
- channels:矩阵元素所拥有的通道数
- type:矩阵的元素类型和矩阵的通道数,其命名规则为CV_(位数)+(数据类型)+(通道数)如
CV_16UC2
,表示的是元素类型是一个16位的无符号整数,通道为2,这里U(unsigned integer)表示的是无符号整数,S(signed integer)是有符号整数,F(float)是浮点数 - depth:一个通道的数据类型,命名为
type
去掉通道数;type一般是在创建Mat对象时设定,如果要取得Mat的元素类型,则使用depth - elemSize:一个元素所占的字节数,如CV_16SC3,elemSize = 3 * 16 / 8 = 6
- elemSize1:一个元素每个通道占的字节数,如CV_16SC3,elemSize1 = 16 / 8 = 2
- step:step[0]是矩阵中一行元素的字节数,step[1]和
elemSize
含义一样 - step1:step / elemSize1
1. 使用at<>
访问
- 此方法类似二维数组的行列访问
for (int row = 0; row < img.rows; row++)
{
for (int col = 0; col < img.cols; col++)
{
img.at<Vec3b>(row, col)[0] = 255 - img.at<Vec3b>(row, col)[0];
img.at<Vec3b>(row, col)[1] = 255 - img.at<Vec3b>(row, col)[1];
img.at<Vec3b>(row, col)[2] = 255 - img.at<Vec3b>(row, col)[2];
}
}
2. 使用ptr<>(row, col)
访问
for (int row = 0; row < img.rows; row++){
for (int col = 0; col < img.cols; col++){
Vec3b* pData = img.ptr<Vec3b>(row, col);
(*pData)[0] = 255 - (*pData)[0];
(*pData)[1] = 255 - (*pData)[1];
(*pData)[2] = 255 - (*pData)[2];
//另一个方式
// uchar* pData = img.ptr<uchar>(row, col);
// *(pData + 0) = 255 - *(pData + 0);
// *(pData + 1) = 255 - *(pData + 1);
// *(pData + 2) = 255 - *(pData + 2);
}
}
3. 使用ptr<>(row)
访问
- 类似二维数组指针访问
for (int row = 0; row < img.rows; row++){
Vec3b* pData = img.ptr<Vec3b>(row);
for (int col = 0; col < img.cols; col++){
(*(pData + col))[0] = 255 - (*(pData + col))[0];
(*(pData + col))[1] = 255 - (*(pData + col))[1];
(*(pData + col))[2] = 255 - (*(pData + col))[2];
}
}
// 另一个方式
for (int row = 0; row < img.rows; row++){
uchar* pData = img.ptr<uchar>(row);
for (int col = 0; col < img.cols; col++){
*(pData + col*img.channels() + 0) = 255 - *(pData + col*img.channels() + 0);
*(pData + col*img.channels() + 1) = 255 - *(pData + col*img.channels() + 1);
*(pData + col*img.channels() + 2) = 255 - *(pData + col*img.channels() + 2);
}
}
4. data结合step访问
- step存的是图像一行所占的字节数
uchar* pData = img.data;
MatStep mst = img.step;
for (int row = 0; row < img.rows; row++){
for (int col = 0; col < img.cols; col++){
//*mst.p表示的是图像一行的长度(例如图像为500宽度的3通道图像,则该值为1500=500*3)
//cout << *mst.p << endl;
*(pData + row * *mst.p + col * img.channels() + 0) = 255 - *(pData + row * *mst.p + col * img.channels() + 0);
*(pData + row * *mst.p + col * img.channels() + 1) = 255 - *(pData + row * *mst.p + col * img.channels() + 1);
*(pData + row * *mst.p + col * img.channels() + 2) = 255 - *(pData + row * *mst.p + col * img.channels() + 2);
// 另一种
//*(pData + row * mst[0] + col * mst[1] + 0) = 255 - *(pData + row * mst[0] + col * mst[1] + 0);
//*(pData + row * mst[0] + col * mst[1] + 1) = 255 - *(pData + row * mst[0] + col * mst[1] + 1);
//*(pData + row * mst[0] + col * mst[1] + 2) = 255 - *(pData + row * mst[0] + col * mst[1] + 2);
}
}
5. 迭代器访问
for (int i = 0; i < testCount; i++){
MatIterator_<Vec3b> it = img.begin<Vec3b>();
MatIterator_<Vec3b> itEnd = img.end<Vec3b>();
//只读的迭代器,迭代器指向的值不可修改
MatConstIterator_<Vec3b> it = img.begin<Vec3b>();
MatConstIterator_<Vec3b> itEnd = img.end<Vec3b>();
//这样也可以
Mat_<Vec3b>::iterator it = img.begin<Vec3b>();
Mat_<Vec3b>::iterator itEnd = img.end<Vec3b>();
while (it!=itEnd){
(*it)[0] = 255 - (*it)[0];
(*it)[1] = 255 - (*it)[1];
(*it)[2] = 255 - (*it)[2];
it++;
}
}