1. 存取像素值
//在一张图像上增加椒盐噪声,image为输入图像。n为噪点个数
void salt(Mat &image, int n)
{
for(int k = 0;k < n;k++)
{
//随机产生白色噪点
int i = qrand()%image.cols;
int j = qrand()%image.rows;
//假设是灰度图每一个像素的存取类型为uchar,即8bit整型数
if(image.channels() == 1){
image.at<uchar>(j,i) = 255;
}
//彩色图像有三个通道,像素存取类型为cv::Vec3b,即由三个uchar组成的向量。这里用下标[i]訪问每一个通道
else{
image.at<Vec3b>(j,i)[0] = 255;
image.at<Vec3b>(j,i)[1] = 255;
image.at<Vec3b>(j,i)[2] = 255;
}
}
}效果例如以下://颜色缩减函数,image为输入图像。div为缩减的倍数
void colorReduce(Mat&image, int div = 64)
{
int nl = image.rows; //图像的行数
//图像每行的像素数
int nc = image.cols * image.channels();
for(int j =0;j<nl;j++)
{
//得到第j行的首地址
uchar* data = image.ptr<uchar>(j);
//遍历每行的像素
for(int i =0;i<nc;i++)
{
data[i] = data[i]/div*div; //将每一个像素值都变为div的倍数,即将颜色数缩减了div倍
}
}
}效果例如以下://颜色缩减函数。image为输入图像,div为缩减的倍数
void colorReduce(Mat&image, int div = 64)
{
int nl = image.rows; //图像的行数
//图像每行的像素数
int nc = image.cols * image.channels();
//假设图像连续
if(image.isContinuous())
{
//reshape函数用于改变矩阵维度
//图像行数为1,列数为原先的行数乘上列数
image.reshape(1,image.cols*image.rows);
}
for(int j =0;j<nl;j++)
{
//得到第j行的首地址
uchar* data = image.ptr<uchar>(j);
//遍历每行的像素
for(int i =0;i<nc;i++)
{
data[i] = data[i]/div*div; //将每一个像素值都变为div的倍数,即将颜色数缩减了div倍
}
}
}
这块内存的首地址能够通过data成员变量得到。data是一个unsigned char型的指针,所以循环能够用下面方式:
//获得图像指针
uchar *data = image.data;
//获得第j行,第i列个像素值,step代表图像的行宽(包含填补像素)
data = image.data + j*image.step + i*image.elemSize();//颜色缩减函数。image为输入图像。div为缩减的倍数
void colorReduce(Mat&image, int div = 64)
{
//得到初始位置的迭代器
Mat_<Vec3b>::iterator it = image.begin<Vec3b>();
//得到终止位置的迭代器
Mat_<Vec3b>::iterator itend = image.end<Vec3b>();
//遍历全部像素
for(; it != itend; ++it){
(*it)[0] = (*it)[0]/div*div;
(*it)[1] = (*it)[1]/div*div;
(*it)[2] = (*it)[2]/div*div;
}
}效果与用指针遍历的一样。//at方法
void colorReduce1(Mat&image, int div = 64)
{
int nl = image.rows; //图像的行数
//图像每行的像素数
int nc = image.cols * image.channels();
for(int j =0;j<nl-2;j++)
{
for(int i =0;i<nc-2;i++)
{
image.at<Vec3b>(j,i)[0] = image.at<Vec3b>(j,i)[0]/div*div;
image.at<Vec3b>(j,i)[1] = image.at<Vec3b>(j,i)[1]/div*div;
image.at<Vec3b>(j,i)[2] = image.at<Vec3b>(j,i)[2]/div*div;
}
}
}
//行首指针方法
void colorReduce2(Mat&image, int div = 64)
{
int nl = image.rows; //图像的行数
//图像每行的像素数
int nc = image.cols * image.channels();
for(int j =0;j<nl;j++)
{
//得到第j行的首地址
uchar* data = image.ptr<uchar>(j);
//遍历每行的像素
for(int i =0;i<nc;i++)
{
data[i] = data[i]/div*div; //将每一个像素值都变为div的倍数,即将颜色数缩减了div倍
}
}
}
//一维数组
void colorReduce3(Mat&image, int div = 64)
{
int nl = image.rows; //图像的行数
//图像每行的像素数
int nc = image.cols * image.channels();
//假设图像连续
if(image.isContinuous())
{
//reshape函数用于改变矩阵维度
//图像行数为1,列数为原先的行数乘上列数
image.reshape(1,image.cols*image.rows);
}
for(int j =0;j<nl;j++)
{
//得到第j行的首地址
uchar* data = image.ptr<uchar>(j);
//遍历每行的像素
for(int i =0;i<nc;i++)
{
data[i] = data[i]/div*div; //将每一个像素值都变为div的倍数,即将颜色数缩减了div倍
}
}
}
//迭代器方法
void colorReduce4(Mat&image, int div = 64)
{
//得到初始位置的迭代器
Mat_<Vec3b>::iterator it = image.begin<Vec3b>();
//得到终止位置的迭代器
Mat_<Vec3b>::iterator itend = image.end<Vec3b>();
//遍历全部像素
for(; it != itend; ++it){
(*it)[0] = (*it)[0]/div*div;
(*it)[1] = (*it)[1]/div*div;
(*it)[2] = (*it)[2]/div*div;
}
}
//測试4种像素遍历方式执行时间
void calrunTime(int v,Mat&image)
{
double duration;
duration = static_cast<double>(getTickCount());
for(int i = 0;i<10;i++) //执行十次取平均值
{
switch(v)
{
case 1:
colorReduce1(image);
break;
case 2:
colorReduce2(image);
break;
case 3:
colorReduce3(image);
break;
case 4:
colorReduce4(image);
break;
default:
break;
}
}
duration = static_cast<double>(getTickCount()) - duration;
duration /= getTickFrequency()/100; //执行时间,以ms为单位
qDebug()<<"duration"<<v<<":"<<duration<<"ms";
}原文:http://www.cnblogs.com/mengfanrong/p/5184181.html