《OpenCV3编程入门》学习笔记5 Core组件进阶(一)访问图像中的像素

第5章 Core组件进阶

5.1 访问图像中的像素

5.1.1 图像在内存中的存储方式

1.图像矩阵大小取决于通道数,矩阵中的子列个数与通道数相等。
2.如果内存足够大,可以实现连续存储,有助于提升图像扫描速度,可以用isContinuous()判断矩阵是否连续存储。

5.1.2 颜色空间缩减

1.颜色空间缩减:将现有颜色空间值除以某个输入值,以获得较少的颜色数
2.如,0~9范围的像素值为0,10~19范围的像素值为10等
3.颜色空间缩减算法:(1)遍历图像矩阵的每一个像素(2)对像素应用公式int I=(I/10)*10;
4.打表:

int divideWith = 10;
	uchar table[256];
	for (int i = 0; i < 256; i++)
		table[i] = divideWith * (i / divideWith);

5.1.3 LUT函数:Look up table操作

1.operationsOnArrays:LUT()函数:用于批量进行图像元素查找、扫描与操作图像
2.使用方法:

//首先建立一个mat型用于查表
	Mat lookUpTable(1, 256, CV_8U);
	uchar* p = lookUpTable.data;
	for(int i = 0; i < 256; i++)
	{
		p[i]= table[i];
	}
	//调用函数(I是输入J是输出)
	for(int i = 0; i < times; ++i)
	{
		LUT(image, lookUpTable, dstImage);
	}

5.1.4 计时函数

1.getTickCount()函数:返回CPU自某个事件(如启动电脑)以来走过的时钟周期数
2.getTickFrequency()函数:返回CPU一秒钟所走的时钟周期数。
3.示例:

#include
#include
using namespace cv;
using namespace std;

int main()
{
	//记录起始时间
	double time0 = static_cast<double>(getTickCount()); 
	
	//进行图像处理操作
	Mat image = imread("1.jpg");
	Mat dstImage;
	blur(image, dstImage, Size(7, 7));
	imshow("[1]image proc", dstImage);

	//计算方法运行时间
	time0 = ((double)getTickCount() - time0) / getTickFrequency();
	cout << "此方法运行时间为:" << time0 << "秒" << endl;
	
	waitKey(0);
	return 0;
}

5.1.5 访问图像中像素的三类方法

1.指针访问:C操作符[]
2.迭代器iteator
3.动态地址计算

例:将源图像中的颜色数量由256种减少到64种

#include
#include
#include
using namespace cv;
using namespace std;

void colorReduce(Mat& inputImage, Mat& outputImage, int div);

int main()
{
	//创建原始图并显示
	Mat srcImage = imread("1.jpg");
	imshow("原始图像", srcImage);

	//[2]按原始图像的参数规格来创建效果图
	Mat dstImage;
	dstImage.create(srcImage.rows, srcImage.cols, srcImage.type());//效果图的大小、类型与原图片相同

	//[3]记录起始时间
	double time0 = static_cast<double>(getTickCount());

	//[4]调用颜色空间缩减函数
	colorReduce(srcImage, dstImage, 32);

	//[5]计算运行时间并输出
	time0 = ((double)getTickCount() - time0) / getTickFrequency();
	cout << "此方法运行时间为:" << time0 << "秒" << endl;

	//[6]显示效果图
	imshow("效果图", dstImage);

	waitKey(0);
	return 0;
}
//【方法一】用指针访问像素
void colorReduce(Mat& inputImage, Mat& outputImage, int div)
{
	//参数准备
	outputImage = inputImage.clone();//复制实参到临时变量
	int rowNumber = outputImage.rows;//行数
	int colNumber = outputImage.cols*outputImage.channels();//列数*通道数=每一行元素的个数

	//双重循环,遍历所有的像素值
	for (int i = 0; i < rowNumber; i++)
	{
		uchar* data = outputImage.ptr<uchar>(i); //获取第i行的首地址(Mat类的ptr函数可以得到图像任意行的首地址)
		for (int j = 0; j < colNumber; j++)
		{
			//处理每个像素
			data[j] = data[j] / div * div + div / 2;
		}
	}
}
//【方法二】用迭代器操作像素
void colorReduce(Mat& inputImage, Mat& outputImage, int div)
{
	//参数准备
	outputImage = inputImage.clone();//复制实参到临时变量
	//获取迭代器
	Mat_<Vec3b>::iterator it = outputImage.begin<Vec3b>(); //初始位置的迭代器
	Mat_<Vec3b>::iterator itend = outputImage.end<Vec3b>(); //终止位置的迭代器

	//存取彩色图像像素
	for (; it != itend; ++it)
	{
		//开始处理每个像素
		(*it)[0] = (*it)[0] / div * div + div / 2;
		(*it)[1] = (*it)[1] / div * div + div / 2;
		(*it)[1] = (*it)[1] / div * div + div / 2;
	}
}
//【方法三】动态地址计算
void colorReduce(Mat& inputImage, Mat& outputImage, int div)
{
	//参数准备
	outputImage = inputImage.clone();//复制实参到临时变量
	int rowNumber = outputImage.rows;//行数
	int colNumber = outputImage.cols;//列数

	//存取彩色图像像素
	for (int i = 0; i < rowNumber; i++)
	{
		for (int j = 0; j < colNumber; j++)
		{
			//对于彩色图像,每个像素有三个部分构成,三个8位数组成的向量分别代表三个通道,Vec3b即由三个unisigned char组成的向量,image.at(i,j)[channel]=value;是为图像image第i行第j列的像素点的channel分量赋值
			//开始处理每个像素(成员函数at(int y,int x)可以用来存取元素,但是必须在编译期知道图像的数据类型)
			outputImage.at<Vec3b>(i, j)[0] = outputImage.at<Vec3b>(i, j)[0] / div * div + div / 2; //蓝色通道
			outputImage.at<Vec3b>(i, j)[1] = outputImage.at<Vec3b>(i, j)[1] / div * div + div / 2; //绿色通道
			outputImage.at<Vec3b>(i, j)[2] = outputImage.at<Vec3b>(i, j)[2] / div * div + div / 2; //红色通道
		}
	}
}

你可能感兴趣的:(OpenCV)