常见的像素访问方式有Mat::at访问,指针访问和迭代器访问。
比如可以将64阶的灰度图降为8阶的灰度图,主要通过整数的除法实现,因为整数的除法可以去尾。比如某像素点的值为M,降阶之后的值就为M/8*8,原先0~63连续值就变为{0, 8, 16, 24, 32, 40, 48, 56}的离散值。本文将处理3通道的彩色图,颜色缩减的倍数为32。
Mat::at方式
void color_reduce1(Mat &image)
{
for (int i=0; i<image.rows; i++)
for (int j=0; j<image.cols; j++)
{
if (image.channels() == 1)//如果是单通道图
image.at<uchar>(i, j) = image.at<uchar>(i, j) /32 * 32;
else if (image.channels() == 3)//如果是三通道图
{
image.at<Vec3b>(i, j)[0] = image.at<Vec3b>(i, j)[0] / 32 * 32;
image.at<Vec3b>(i, j)[1] = image.at<Vec3b>(i, j)[1] / 32 * 32;
image.at<Vec3b>(i, j)[2] = image.at<Vec3b>(i, j)[2] / 32 * 32;
}
}
}
指针
void color_reduce2(Mat &image)
{
int rows = image.rows;//行数
int rowsCount = image.cols * image.channels();//每行的元素个数
for (int i=0; i<rows; i++)
{
uchar* data = image.ptr<uchar>(i);//每行首元素地址
for (int j=0; j<rowsCount; j++)
data[j] = data[j] / 32 * 32;
}
}
- 如果是3通道图像,元素按照BRG通道的顺序排列,注意是BGRBGR…,而不是BB…GG…RR…
- 还可以通过Mat::data成员变量来访问像素,该成员是一个uchar指针类型,指向像素的首元素,指向i行j列元素的地址为
uchar* data = image.data+i*image.step+j*image.elemSize()
迭代器
void color_reduce3(Mat &image)
{
Mat_<Vec3b>::iterator iter = image.begin<Vec3b>();
for ( ; iter != image.end<Vec3b>(); iter++)
{
(*iter)[0] = (*iter)[0] / 32 * 32;//[]的优先级高,所以要先解引用
(*iter)[1] = (*iter)[1] / 32 * 32;
(*iter)[2] = (*iter)[2] / 32 * 32;
}
}
Mat_<Vec3b> image;
Mat_<Vec3b>::iterator beg = image.begin();
Mat_<Vec3b>::iterator end = image.end();
- 指向const元素的迭代器声明语句为
Mat_<Vec3b>::const_iterator iter;
- 如果使用Mat_定义图片,则begin()和end()就不需要写元素类型了,因为定义时写过了
测试方法 | Mat::at 访问 | 指针访问 | 迭代器访问 |
---|---|---|---|
Debug | 0.316153 | 0.003027 | 0.414347 |
Release | 0.00158968 | 0.00070958 | 0.00610587 |