一、访问图像中像素的方法
解析:任何图像处理算法,都是从对每个像素的操作开始的,这是对图像处理算法的基本原理的理解和运用的基础,对Opencv中的函数理解和能够写出其相应功能的函数打下基础。
1.1 操作使用的主程序
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
using namespace std;
using namespace cv;
// 函数声明
void ImgColorReduce(Mat& inputImage, Mat& outputImage, int div);
int main()
{
// 载入图像并显示
Mat originImage = imread("lena.png", 1);
imshow("original", originImage);
// 创建效果图
Mat resultImage;
resultImage.create(originImage.rows, originImage.cols, originImage.type());
// 记录时间
double timeClock = static_cast<double>(getTickCount());
// 调用颜色空间缩减函数
ImgColorReduce(originImage, resultImage, 32);
// 输出时间
timeClock = ((double)getTickCount() - timeClock) / getTickCount();
cout << "run time:" << timeClock << "seconds" << endl;
// 显示结果图
imshow("result_colorReduce",resultImage);
waitKey(0);
return 0;
}
1.2 用指针访问图像元素(run time:3.37536e-08seconds)
利用C语言中的操作符[],速度快,但是相对理解抽象。
// 用指针访问像素
void ImgColorReduce(Mat& inputImage, Mat& outputImage, int div)
{
outputImage = inputImage.clone(); // 参数克隆
int rowNum = outputImage.rows; // 行
//列(每一行元素的个数=列x通道数)
int colNUm = outputImage.cols*outputImage.channels();
for (int i = 0; i < rowNum; i++) // 遍历行
{
uchar* data = outputImage.ptr<uchar> (i); // 获得行的首地址
for(int j = 0; j < colNUm; j++) // 遍历列
{
data[j] = data[j] / div*div + div/2;
}
}
}
1.3 迭代器访问图像像素(run time:5.51654e-08seconds)
需要获取图像矩阵的开始和结尾,遍历开始和结尾,通过*操作符访问相关内容,相对于指针比较安全。
// 用迭代器访问像素
void ImgColorReduce(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;
}
}
1.4 动态地址访问图像像素(run time:3.32831e-08seconds)
相对于比较好理解,方法直观。其中cols 和rows 对应图像的宽和高。成员函数at(int y, int x)用来存取图像元素。
对于一个包含彩色图像的Mat ,会返回一个由三个8位数组组成的向量。OpenCV将此类型的向量定义为Vec3b,即由三个unsigned char 组成的向量。OpenCV中的颜色分量是BGR。
// 动态地址访问图像像素
void ImgColorReduce(Mat& inputImage, Mat& outputImage, int div)
{
outputImage = inputImage.clone(); // 克隆参数
// 获取图像的行列
int rowNum = outputImage.rows;
int colNum = outputImage.cols;
// 处理图像像素值
for(int i = 0; i < rowNum; i++)
{
for (int j = 0; j < colNum; j++)
{
//分别处理蓝、绿、红通道
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;
}
}
}
1.5 编译和运行结果