opencv5-读取像素

题外话:像素大战,感兴趣的可以去看这个电影,就能更好的理解像素是个什么东东。

像素(pixel):由Picture图像和Element元素组成,是图片视频的基本单元。也就是我们通常说的分辨率。当图片尺寸以像素为单位时,每一厘米等于28像素,比如15*15厘米的图片,等于420*420像素的长度。

opencv 中经常出现通道,所以在单通道、多通道下的图像的像素是这样表示的

图画的不好看,明天补上!



1、存取像素at(int x,int y);

要指定元素所在的行和列。若图像是单通道,返回值是单个数值,若图像是多通道,返回值是一组向量(vector)。

cv::Mat的公有成员变量colsrows给出了图像的宽和高

at()函数的使用,有一点很重要,在编译时要知道图像的数据类型。

单通道:

image.at<uchar>(j,i)=value;

多通道:

image.at<Vec3b>(j,i)[0] =value;

image.at<Vec3b>( j,i)[1] =value;

image.at<Vec3b>( j,i)[2] =value;

 

at中(i,j)的顺序表示的是第i行第j列,跟Point(i,j)和Rect(i,j)中表示第j行第i列是相反的,所以上面都写为at(j,i).这一点不注意非常容易出现内存异常的错误。


图像遍历是图像处理中少不了的,一般有指针和迭代器两种方式。

2、指针遍历

其只能针对没有经过填充的连续图像。判断方法调用isContinuous,返回值为TRUEfalse

3迭代器

在面向对象编程中,遍历数据集合通常都是通过迭代器完成的。迭代器是一种特殊的类,专门用来遍历集合中的各个元素,同时隐藏在给定的集合上元素迭代的具体实现方式

/*
*本程序是学会使用:1、用下标访问像素,2、使用迭代器访问像素 , 3、使用指针访问像素
*4、把图像写入磁盘
*
*
*/

#include <opencv2/highgui/highgui.hpp>

//访问元素用下标
/*这个函数每次循环都将一个随机选取的像素的值设置为255,随机选取的像素的行号i和列j 是通过随机函数得到的。
通过检查图像的通道数来区分灰度和彩色图,对于灰度图直接将像素值设置为255,对于彩色图,需要将每一个通道值
都设置为255才能得到一个白色像素。
*/
void salt(cv::Mat &img , int n)
{
	for(int k = 0 ; k < n ; ++ k)
	{
		int i = rand() % img.cols ;
		int j = rand() % img.rows ;
		//灰度图
		if(1 == img.channels())
		{
			img.at<uchar>(j , i) = 255 ;
		}
		//彩色图
		else if(3 == img.channels())
		{
			img.at<cv::Vec3b>(j , i)[0] = 255 ;
			img.at<cv::Vec3b>(j , i)[1] = 255 ;
			img.at<cv::Vec3b>(j , i)[2] = 255 ;
		}
	}
	//扩展:
	//cv::Mat_<uchar> im1 = img ;
	//im1(50 , 100) = 0 ;//对于已经知道返回类型时 可以这样访问元素
}

//减少图像颜色数
void colorReduce(cv::Mat &img , int div = 64)
{
	//行数
	int rowsNum = img.rows ;
	//每行的元素个数
	int closPiexlNum = img.cols * img.channels() ;

	for(int i = 0 ; i < rowsNum ; ++ i)
	{
		//得到j行首地址
		uchar *data = img.ptr<uchar>(i) ;
		for(int j = 0 ; j < closPiexlNum ; ++ j)
		{
			//处理每个像素
			data[j] = data[j] / div * div + div / 2 ;
		}
	}
}


void colorReduce3(cv::Mat img , cv::Mat &result , int div = 64)
{
	result.create(img.rows , img.cols , img.type()) ;

	int rowsNum = img.rows ;
	int closPiexlNum = img.cols * img.channels() ;

	for(int i = 0 ; i < rowsNum ; ++ i)
	{
		uchar *data_in = img.ptr<uchar>(i) ;
		uchar *data_out = result.ptr<uchar>(i) ;
		for(int j = 0 ; j < closPiexlNum ; ++ j)
		{
			data_out[j] = data_in[j] / div * div + div / 2 ;
		}
	}
}

void colorReduce4(cv::Mat img , cv::Mat &result , int div = 64)
{
	//result.create(img.rows , img.cols , img.type()) ;
	result = img.clone() ;
	//注意两种迭代器的定义方法
	cv::MatIterator_<cv::Vec3b>   itStart = result.begin<cv::Vec3b>() ;
	cv::Mat_<cv::Vec3b>::iterator itEnd = result.end<cv::Vec3b>() ;

	while(itStart != itEnd)
	{
		(*itStart)[0] = (*itStart)[0] / div * div + div / 2 ;
		(*itStart)[1] = (*itStart)[1] / div * div + div / 2 ;
		(*itStart)[2] = (*itStart)[2] / div * div + div / 2 ;
		itStart ++ ;
	}
	//Const迭代器两种定义方法
	//cv::MatConstIterator_<cv::Vec3b> it ;
	//cv::Mat_<cv::Vec3b>::const_iterator it ;
}

void colorReduce5(cv::Mat img , cv::Mat &result , int div = 64)
{
	result = img.clone() ;

	int rNum = result.rows ;
	int cNum = result.cols ;

	if(result.isContinuous())
	{
		cNum *= rNum ;
		rNum = 1 ;
	}

	int n = static_cast<int>(log(static_cast<double>(div)) / log(2.0)) ;
	uchar mask = 0xFF << n ;

	for(int i = 0 ; i < rNum ; ++ i)
	{
		uchar *data = result.ptr<uchar>(i) ;
		for(int j = 0 ; j < cNum ; ++ j)
		{
			*data++ = *data & mask + div / 2 ;
			*data++ = *data & mask + div / 2 ;
			*data++ = *data & mask + div / 2 ;
		}
	}
}

void colorReduce6(cv::Mat img , cv::Mat &result , int div = 64)
{
	int n = static_cast<int>(log(static_cast<double>(div)) / log(2.0)) ;
	uchar mask = 0xFF << n ;

	result = (img & cv::Scalar(mask , mask , mask) 
		      + cv::Scalar(div / 2 , div / 2 , div / 2)) ;
}

int main()
{
	cv::Mat img ;
	img = cv::imread("E://Baboon.jpg") ; 

	cv::namedWindow("Original") ;
	cv::imshow("Original" , img) ;

	//salt(img , 3000) ;
	
	//colorReduce(img , 64) ;

	//cv::Mat imgClone = img.clone() ;

	cv::Mat result ;
	//colorReduce3(img , result) ;//使用指针
	//colorReduce4(img , result) ;//使用迭代器
	//colorReduce5(img , result) ;//使用位运算
	colorReduce6(img , result) ;//简洁的写法

	cv::namedWindow("Result") ;
	cv::imshow("Result" , result) ;

	//cv::imwrite("result.jpg" , img) ;//把图像写在磁盘上
	cv::waitKey() ;

	return 0 ;
}






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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值