方法一:通过指针访问像素

为了简化指针运算,Mat类中提供了ptr函数可以得到图像任意行的首地址,ptr是一个模板类,使用时应声明变量的类型,比如在加载CV_8UC3图像时,每个像素的三个通道为uchar型所以指针类型为uchar,uchar型的指针加1后,相对原来偏移了一个uchar的大小,而不是3个通道的大小(注意和迭代法区别)

关键语句:

uchar *p = inputImage.ptr<uchar>(i)//定义指向矩阵任一行首地址的指针。

方法二:通过迭代器进行访问

   意思是定义一个迭代器来实现访问像素的过程。首先定义iterator it,是图像的开始指针。然后定义iterator itend,是图像结束像素的指针。然后通过遍历迭代器来访问图像的全部像素。用begin方法,在开始位置(本例中为图像的左上角)初始化迭代器。对于cv::Mat实例,可以使用image.begin<cv::Vec3b>()。还可以在迭代器上使用数学计算,例如若要从图像的第二行开始,可以用image.begin<cv::Vec3b>()+image.cols初始化cv::Mat迭代器。可以用运算符++来移动到下一个元素,也可以指定更大的步幅。例如用it+=10,对每10个像素处理一次。it指针加一后偏移的是一个像素(含三个通道)的大小

关键语句:

Mat_<Vec3b>::iterator it = inputImage.begin<Vec3b>();//起始位置
	Mat_<Vec3b>::iterator itend = inputImage.end<Vec3b>();//终止位置

方法三:通过动态地址访问at 方法

Mat对象的成员函数at(int y,int x)可以用来读取图像元素,但必须要知道图像的数据类型。需要注意到,要保证指定的数据类型要和 矩阵中的数据类型相符合。

关键语句:

inputImage.at<Vec3b>(i, j)[0] = inputImage.at<Vec3b>(i, j)[0] / div * div + div / 2;

以上三种方法对图像进行颜色空间缩减;代码如下

#include <opencv2/opencv.hpp>
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
#include <string>
using namespace cv;
void UsePointerAcccssPixel(Mat &inputImage, int div);//方法一通过指针访问图像像素
void UseIteratorAccessPixel(Mat&inputImage, int div);//方法二通过迭代器访问
void UseAtAccessPixel(Mat &inputImage,int div);//方法三通过动态地址访问
void UsePointerAcccssPixel(Mat &inputImage, int div)
{
	int rowNum = inputImage.rows;
	int colNum = inputImage.cols*inputImage.channels();
	for(int i=0;i<rowNum;i++)
	{
		uchar *p = inputImage.ptr<uchar>(i);
		for (int j = 0; j < colNum; j++)
			p[j] = p[j] / div * div + div / 2;
	}
}
void UseAtAccessPixel(Mat &inputImage, int div)
{
	int rowNum = inputImage.rows;
	int colNum = inputImage.cols;
	for(int i =0;i<rowNum;i++)
		for (int j = 0; j < colNum; j++)
		{
			inputImage.at<Vec3b>(i, j)[0] = inputImage.at<Vec3b>(i, j)[0] / div * div + div / 2;
			inputImage.at<Vec3b>(i, j)[1] = inputImage.at<Vec3b>(i, j)[1] / div * div + div / 2;
			inputImage.at<Vec3b>(i, j)[2] = inputImage.at<Vec3b>(i, j)[2] / div * div + div / 2;
		}

}
void UseIteratorAccessPixel(Mat&inputImage, int div)
{
	Mat_<Vec3b>::iterator it = inputImage.begin<Vec3b>();
	Mat_<Vec3b>::iterator itend = inputImage.end<Vec3b>();
	for (; it != itend; it++)
	{
		(*it)[0] = (*it)[0] / div * div + div / 2;
		(*it)[1] = (*it)[1] / div * div + div / 2;
		(*it)[2] = (*it)[2] / div * div + div / 2;
	}
	//对于三个通道的图像,迭代时,it++要跳过三个uchar变量的长度,Vec3b代表3个uchar型变量。
	//
}
int main()
{
	
	Mat srcImage = imread("timg.jpg");
	UsePointerAcccssPixel(srcImage, 30);//通过指针访问
	//UseAtAccessPixel(srcImage, 40);//通过动态地址访问
	imshow("颜色空间缩减后的图像", srcImage);
	waitKey(0);
	return 1;
}