1、访问元素
使用Mat的at(int x int y)可以访问指定位置的元素。
如:
image.at<uchar>(j,i)=255;//将j行i列的像素点的值设为255
2、用指针扫描图像
使用指针访问图像的每个像素,将其值设为原来的1/8
void colorReduce(cv::Mat image,int div=64)
{
int rows=image.rows;
int num_per_rows=image.cols*image.channels();//每行元素的数量
for(int j=0;j<rows;i++)
{
uchar* data=image.ptr<uchar>(j);//uchar指向第j行的地址
for(int i=0;i<num_per_row;i++)
data[i]=data[i]/div*div+div/2;//处理每个像素
}
}
3、使用迭代器扫描图像
要得到cv::Mat实例的迭代器,先要创建一个cv::MatIterator_的对象;
如:
cv::MatIterator_<cv::Vec3b> it;
或者是:
cv::Mat_<cv::Vec3b>::iterator it;
比如获取一个图像的开始和结尾的迭代器:
cv::Mat_<cv::Vec3b>::iterator begin=image.begin<cv::Vec3b>();//开始位置
cv::Mat_<cv::Vec3b>::iterator end=image.end<cv::Vec3b>();//结尾位置
for(;begin!=end;begin++)
{
(*begin)[0]=(*begin)[0]+10;
(*begin)[1]=(*begin)[1]+15;
(*begin)[2]=(*begin)[2]+20;
}
常量迭代器定义:
cv::MatConstIterator_<cv::Vec3b> it;
//或者
cv::Mat_<cv::Vec3b>::const_iterator it;
4、扫描并访问相邻像素
在图像处理中计算像素值时,经常需要用它的相邻像素值。如果相邻像素在上一行火下一行,就需要同事扫描图像的多行。
以图像锐化为例子;在图像处理领域,如果从图像中减去拉普拉斯算子部分,图像的边缘就会放大,因而图像会变得尖锐;
锐化方法:
sharpened_pixel=5*current-left-right-up-down;
但是第一行,最后一行,第一列,最后一列的像素值是无法计算的。
void sharpen(const cv::Mat& iamge,cv::Mat& result)
{
result.create(image.size(),image.type());//分配图像空间
int nchannels=image.channels();//读取通道数
for(int j=1;j<image.rows-1;j++)//处理除了第一行和最后一行的所有行
{
const uchar* previous=image.ptr<const uchar>(j-i);//上一行
const uchar* current=image.ptr<const uchar>(j);//当前行
const uchar* next=image.ptr<const uchar>(j+i);//下一行
uchar* output=result.ptr<uchar>(j);//输出行
for(int i=nchannels;i<(image.cols-1)*nchannels;i++)
{
*output++=cv::saturate_cast<uchar>(5*current[i]-current[i-nchannels]-current[i+nchannels]-previous[i]-next[i]);
}
}
//未处理的像素设置为0
result.row(0).setTo(cv::Scalar(0));
result.row(result.rows-1).setTo(cv::Scalar(0));
result.col(0).setTo(cv::Scalar(0));
result.col(result.rows-1).setTo(cv::Scalar(0));
}
cv::saturate_cast函数将结果调整到8位无符号整数范围内,就是将大于255的设为255,小于0的设为0;
setTo方法可以对矩阵中的所有元素赋值。
在对像素领域进行计算时,通常用一个核心矩阵来表示,这个矩阵展示了为得到预期的结果,如何将计算相关的像素组合起来。
cv::filter2D函数只需要一个内核,调用函数并传入图像和内核,即可返回滤波后的图像;
void sharpen2D(const cv::Mat& image,cv::Mat& result)
{
//构造内核
cv::Mat kernel(3,3,CV_32F,cv::Scalar(0));
//对内核赋值
kernel.at<float>(1,1)=5.0;
kernel.at<float>(0,1)=-1.0;
kernel.at<float>(2,1)=-1.0;
kernel.at<float>(1,0)=-1.0;
kernel.at<float>(1,2)=-1.0;
//对图像滤波
cv::filter2D(image,result,image.depth(),kernel);
}
5、图像运算
//c[i]=a[i]+b[i];
cv::add(imageA,imageB,resultC);
//c[i]=a[i]+k;
cv::add(imageA,cv::Scalar(k),resultC);
//c[i]=k1*a[i]+k2*b[i]+k3;
cv::addWeighted(imageA,k1,image2,k2,k3,resultC);
6、图像重映射
图像重映射的过程不会修改图像的值,而是把每个像素的位置重新映射到新的位置。
void wave(const cv::Mat& iamge,cv::Mat& result)
{
cv::Mat srcX(image.rows,image.cols,CV_32F);
cv::Mat srcY(image.rows,image.cols,CV_32F);
for(int i=0;i<image.rows;i++)
for(int j=0;j<image.clos;j++)
{
srcX.at<float>(i,j)=j;
srcY.at<float>(i,j)=i+5*sin(j/10.0);
}
}