第二章-操作像素

一、加入椒盐噪声------访问像素值

//加入椒盐噪声
void salt(Mat image,int n)//n为噪声数量
{
	int i,j;
	for(int k=0;k<n;++k)
	{
		i=rand()%image.cols;
		j=rand()%image.rows;

		if(image.channels()==1)//或image.type()==CV_8UC1
		{
			image.at<uchar>(j,i)=255;//image.at<Vec2b/Vec3f/Vec3i/Vec3d>最后一位表示数据类型:f浮点,d双精度浮点,b向量
		}
		else if(image.channels()==3)
		{
			for(int l=0;l<3;l++)image.at<Vec3b>(j,i)[l]=255;
		}
	}
}

访问像素值除了image.at<uchar>(i,j)外,还可以Mat_<uchar> im(image),然后im(i,j)=0;即可

二、减色-----用指针扫描图像

void colorReduce(const Mat &image,Mat &out,int div=64)
{
	out.create(image.rows,image.cols,image.type());
	int nl=image.rows;
	int nc=image.cols*image.channels();//一般行的长度是4或8的整数倍,不够就填充,填充后的长度为有效宽度,可用step得到
	for(int j=0;j<nl;++j)
	{
		const uchar* data_in=image.ptr<uchar>(j);//用指针方法,返回第j行地址
		uchar* data_out=out.ptr<uchar>(j);
		for(int i=0;i<nc;++i)
			data_out[i]=data_in[i]/div*div+div/2;
	}
}

1.其他减色方案:位运算uchar mask=0xFF<<n;如div=16,则mask=0xF0;

                                        *data &=mask;

                                        *data++ +=div>>1;

2.对连续图像的高速扫描,判断是否连续isContinuous,然后也可以借助image.reshape(1,1)修改维数,第一个参数表示新通道数,第二个参数为新的行数

void colorReduce2(const Mat &image,Mat &out,int div=64)
{
	out.create(image.rows,image.cols,image.type());
	int nl=image.rows;
	int nc=image.cols*image.channels();//image.step==image.cols*image.elemSize()说明行没有填充
	if(image.isContinuous())
	{
		nc*=nl;nl=1;//可以用reshape替换
	}
	for(int j=0;j<nl;++j)
	{
		const uchar* data_in=image.ptr<uchar>(j);//用指针方法,返回第j行地址
		uchar* data_out=out.ptr<uchar>(j);
		for(int i=0;i<nc;++i)
			data_out[i]=data_in[i]/div*div+div/2;
	}
}

3.低层次指针算法:uchar* data=image.data;//image.data返回内存块的第一个元素地址

data+=image.step;//下一行

  不推荐使用

三、用迭代器扫描图像

void colorReduce3(const Mat &image,Mat &out,int div=64)
{
	Mat_<Vec3b>::const_iterator it=image.begin<Vec3b>();//指向常对象要用常迭代器const_iterator
	Mat_<Vec3b>::const_iterator itend=image.end<Vec3b>();
	for(;it!=itend;++it)
	{
		for(int k=0;k<3;++k)(*it)[k]=(*it)[k]/div*div+div/2;
	}
}
迭代器写法:1、Mat_<Vec3b>::iterator it;

2、MatIterator_<Vec3b> it;

若从第二行开始可以将迭代器写为:it=image.begin<Vec3b>()+image.cols;

四、高效的图像扫描循环

1、计算某代码段的运行时间

	const int64 start=getTickCount();
	colorReduce(image,image);
	double duration=(getTickCount()-start)/getTickFrequency();

2、几种方法比较:

位运算最快

.at 很慢,扫描图片尽量不用,随机访问时用

迭代器的时间也比较长,只是简化过程,减少出错

五、扫描图像并访问相邻像素

void sharpen(const Mat &image,Mat &out)//图像锐化
{
	out.create(image.size(),image.type());
	int nchannels=image.channels();
	for(int j=1;j<image.rows-1;++j)
	{
		const uchar* pre=image.ptr<uchar>(j-1);
		const uchar* cur=image.ptr<uchar>(j);
		const uchar* next=image.ptr<uchar>(j+1);
		uchar* output=out.ptr<uchar>(j);
		for(int i=nchannels;i<(image.cols-1)*nchannels;++i)
		{
			*output++=cv::saturate_cast<uchar>(5*cur[i]-cur[i+nchannels]-cur[i-nchannels]-pre[i]-next[i]);
			//锐化计算后的值很可能超出范围(0~255),saturate_cast功能将小于0的置为0,大于255的置为255
		}
	}
	out.row(0).setTo(Scalar(0,0,0));//单通道灰度图这里改为out.row(0).setTo(Scalar(0));
	out.row(out.rows-1).setTo(Scalar(0,0,0));
	out.col(0).setTo(Scalar(0,0,0));
	out.col(out.cols-1).setTo(Scalar(0,0,0));
}

借助filter2D函数锐化:需要#include<opencv/cv.hpp>

void sharpen2D(const Mat &image,Mat &out)//图像锐化
{
	//out.create(image.size(),image.type());
	Mat kernel(3,3,CV_32F,Scalar(0));
	kernel.at<float>(1,1)=5;
	kernel.at<float>(0,1)=-1;
	kernel.at<float>(1,0)=-1;
	kernel.at<float>(2,1)=-1;
	kernel.at<float>(1,2)=-1;
	filter2D(image,out,image.depth(),kernel);
}

或者Mat kernel=(Mat_<char>(3,3)<<0,-1,0,-1,5,-1,0,-1,0);

六、简单的图像运算(必须有相同的大小和类型)

	add(image,image2,out);//out[i]=image[i]+image2[i]
	add(image,Scalar(0,200,0),out);//out[i]=image[i]+Scalar(k)
	addWeighted(image,k1,image2,k2,k3,out);//out=k1*image+k2*image2+k3直接写这个效果相同
	scaleAdd(image,k1,image2,out);//out=image*k1+image2
	add(image,image2,out,mask)//if(mask[i])out[i]=image[i]+image2[i]
1、其他运算:subtract   absdiff    multiply   divide (减,差的绝对值、乘、除)
位运算:bitwise_and   bitwise_or    bitwise_xor    bitwise_not

最值:min  max

sqrt   pow   abs   cuberoot   exp   log

所有运算都会自动调用cv::saturate_cast

2、分割图像通道

vector<Mat>planes;//创建三通道向量
split(image,planes);//分割
planes[0]+=image2;//将蓝色通道加到image2上
merge(planes,out);//合并三通道

七、图像重映射

不修改图象值,而是把每个像素的位置重新映射到新的位置。可以创建图像特效或修正图像扭曲

void wave(const Mat &image,Mat &out)
{
	Mat X(image.rows,image.cols,CV_32F);
	Mat Y(image.rows,image.cols,CV_32F);
	for(int i=0;i<image.rows;++i)
	{
		for(int j=0;j<image.cols;++j)
		{
			X.at<float>(i,j)=j;//保持的同一列
			Y.at<float>(i,j)=i+15*sin(j/10.0);//第i行的像素,根据正弦曲线移动
		}
	}
	remap(image,out,X,Y,INTER_LINEAR);
}

即目标图像(i,j)位置的像素值从原始图像的(Y.at<float>(i,j),X.at<float>(i,j))处寻找


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值