您的位置:首页 > 运维架构

opencv图像像素操作方法

2017-01-08 19:29 246 查看

图像容器Mat

Mat和Matlab里的数组格式有点像,但一般是二维向量,如果是灰度图,一般存放<uchar>类型;如果是RGB彩色图,存放<Vec3b>类型。
单通道灰度图数据存放格式:



多通道的图像中,每列并列存放通道数量的子列,如RGB三通道彩色图:



有一点需要注意:图像的通道顺序是:BGR。通常情况内存足够大的话图像的每一行是连续存放的,也就是在内存上图像的所有数据存放成一行,这中情况在访问时可以提供很大方便。
好了,下面总结一下常见的访问图像像素的三种方法:使用at动态地址计算方式,使用iterator迭代器方式,使用ptr指针。先附代码:

#include <iostream>
#include<core/core.hpp>
#include<highgui/highgui.hpp>
using namespace cv;
using namespace std;
void colorReduceAt(Mat& srcImage, Mat& dstImageAt, int div);
void colorReduceIterator(Mat& srcImage, Mat& dstImageIterator, int div);
void colorReducePtr(Mat& srcImage, Mat& dstImagePtr, int div);
int main()
{
Mat image=imread("e:\\kobe.jpg");
Mat mv[3];
split(image,mv);
if(!image.data)
{
cout<<"you idiot!where did you hide kobe!"<<endl;
system("pause");
return -1;
}

//声明处理后图像变量
Mat dstImageAt, dstImageIterator, dstImagePtr;
dstImageAt = image.clone();
dstImageIterator = image.clone();
dstImagePtr = image.clone();
int div = 4;
//声明时间变量
double timeAt, timeIterator, timePtr;
timeAt = static_cast<double>(getTickCount());
colorReduceAt(image, dstImageAt, div);
timeAt = ((double)getTickCount() - timeAt) / getTickFrequency();
namedWindow("dstImageAt",CV_WINDOW_NORMAL);
imshow("dstImageAt",dstImageAt);
cout << "使用at()动态地址计算耗时:" << timeAt << endl << endl;

timeIterator = static_cast<double>(getTickCount());
colorReduceIterator(image, dstImageIterator, div);
timeIterator = ((double)getTickCount() - timeIterator) / getTickFrequency();
namedWindow("dstImageIterator",CV_WINDOW_NORMAL);
imshow("dstImageIterator",dstImageIterator);
cout << "使用iterator迭代器耗时:" << timeIterator << endl << endl;

timePtr = static_cast<double>(getTickCount());
colorReducePtr(image, dstImagePtr, div);
timePtr = ((double)getTickCount() - timePtr) / getTickFrequency();
namedWindow("dstImagePtr",CV_WINDOW_NORMAL);
imshow("dstImagePtr",dstImagePtr);
cout << "使用ptr指针耗时:" << timePtr << endl;
//等待按键
waitKey();
return 0;
}

//使用at动态地址计算方式
void colorReduceAt(Mat& srcImage, Mat& dstImageAt, int div)
{
int rowNumber = dstImageAt.rows;      //获取图像行数
int colNumber = dstImageAt.cols;      //获取图像列数

//对每个像素进行处理
for(int i = 0; i < rowNumber; i++)
{
for(int j = 0; j < colNumber; j++)
{
dstImageAt.at<Vec3b>(i,j)[0] = dstImageAt.at<Vec3b>(i,j)[0]/div*div;    //B通道
dstImageAt.at<Vec3b>(i,j)[1] = dstImageAt.at<Vec3b>(i,j)[1]/div*div;    //G通道
dstImageAt.at<Vec3b>(i,j)[2] = dstImageAt.at<Vec3b>(i,j)[2]/div*div;    //R通道
}
}

}

//使用iterator迭代器方式
void colorReduceIterator(Mat& srcImage, Mat& dstImageIterator, int div)
{
MatIterator_<Vec3b> imageIt = dstImageIterator.begin<Vec3b>();      //获取迭代器初始位置
MatIterator_<Vec3b> imageEnd = dstImageIterator.end<Vec3b>();       //获取迭代器结束位置

//对每个像素进行处理
for(;imageIt != imageEnd; imageIt++)
{
(*imageIt)[0] = (*imageIt)[0]/div*div;      //B通道
(*imageIt)[1] = (*imageIt)[1]/div*div;      //G通道
(*imageIt)[2] = (*imageIt)[2]/div*div;      //R通道
}
}

//使用ptr指针
void colorReducePtr(Mat& srcImage, Mat& dstImagePtr, int div)
{
int rowNumber = dstImagePtr.rows;                           //获取图像矩阵行数
int colNumber = dstImagePtr.cols*dstImagePtr.channels();    //三通道图像矩阵列树=图像列数x通道数

for(int i = 0; i < rowNumber; i++)
{
uchar* pixelPtr = dstImagePtr.ptr<uchar>(i);            //获取矩阵每行首地址指针
for(int j = 0; j < colNumber; j++)
pixelPtr[j] = pixelPtr[j] / div * div;
}
}
运行结果如下:



并且发现,使用ptr方式访问像素用时最少。

参考:
https://yq.aliyun.com/articles/9300 http://www.cnblogs.com/zjgtan/archive/2013/04/06/3002962.html http://blog.csdn.net/keith_bb/article/details/53071133
后来新发现一篇比较全的博文介绍:http://blog.csdn.net/xiaowei_cqu/article/details/19839019
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息