1.任何图像处理算法,都是基于对每个像素的操作。

    2.任何opencv提供的图像处理库函数,只要了解算法原理,都可以写出具有相同功能的程序。

访问图像中每个像素的值:

方法一:用指针访问像素

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);//ptr函数可以获取图像第i行的首地址
  for (int j = 0; j < colNumber; j++)//列循环
  {
   //开始处理每个像素
   data[j] = data[j] / div*div + div / 2;
  }
 }
}

    备注:.clone、.rows、.cols、.channels()分别表示图像复制、读取图像行数、列数、通道数,灰度图像通道数为1,RGB图像通道数为3。opencv中的Mat类提供了ptr函数(作用:读取图像任意行的首地址),data[j]则表示第i行j列的具体像素值。

方法二:用迭代器操作像素

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)[2] = (*it)[2] / div*div + div / 2;
  }
}

    备注:使用迭代器读取图像像素,可以防止访问越界的问题。迭代法通过获取图像矩阵的初始位置begin和终止位置end,*it表示访问当前指向的内容,++it表示从初始位置访问到终止位置。

方法三:用动态地址计算

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++)//列循环
    {
        outputImage.at<Vec3b>(i, j)[0] = outputImage.at<Vec3b>(i, j)[0] / div*div + div / 2;//[0]蓝色通道
        outputImage.at<Vec3b>(i, j)[1] = outputImage.at<Vec3b>(i, j)[1] / div*div + div / 2;//[1]绿色通道
        outputImage.at<Vec3b>(i, j)[2] = outputImage.at<Vec3b>(i, j)[2] / div*div + div / 2;//[2]红色通道
        /*outputImage.at<uchar>(i, j) = outputImage.at<uchar>(i, j)/ div*div + div / 2; */ //单通道
    }
 }
}

    备注:opencv中的Mat类提供了成员函数 at(int y, int x) 可以用来存取图像元素,但必须要知道图像的数据类型和通道数。彩色图像由三通道构成:蓝色通道、绿色通道、红色通道(BGR存储方式),每个通道8位,因而使用Vec3b。具体参考如下表格:  c1,c2,c3......表示通道数,灰度图只有1个通道(c1)。


c1

c2

c3

c4

c6

uchar

uchar

Vec2b

Vec3b

Vec4b


short

short

Vec2s

Vec3s

Vec4s


int 

int

Vec2i

Vec3i

Vec4i


float

float

Vec2f

Vec3f

Vec4f

Vec6f

double

double

Vec2d

Vec3d

Vec4d

Vec6d

  附录:数据类型及其取值范围


数值

具体类型

取值范围

CV_8U

8 位无符号整数

(0…..255)

CV_8S

8 位符号整数

(-128…..127)

CV_16U

16 位无符号整数

(0……65535)

CV_16S

16 位符号整数

(-32768…..32767)

CV_32S

32 位符号整数

(-2147483648……2147483647)

CV_32F

32 位浮点数

(-FLT_MAX ………FLT_MAX,INF,NAN)

CV_64F

64 位浮点数

(-DBL_MAX ……….DBL_MAX,INF,NAN)