方法一:通过指针访问像素
为了简化指针运算,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;
}