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) |