opencv学习(五)之像素遍历三种方式耗时分析

来源:互联网 发布:照片变成手绘软件 编辑:程序博客网 时间:2024/06/07 23:29

前面用两篇介绍了像素的颜色空间缩减、查找表、遍历像素的三种方式、程序计时等,也说了一下每种方法的优缺点,现在用一个综合型的程序进行对比。方式是用三种方式对lena图像(220x220)进行处理,使其颜色种类从256中变成64种。在颜色空间缩减方法中讲过这种方式,即每个像素值除以4向下取整然后再乘以4即可将其颜色种类缩减到64种。

#include <iostream>#include <opencv2/core.hpp>#include <opencv2/highgui.hpp>using namespace std;using namespace cv;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(){    //加载lena图像    Mat srcImage = imread("lena.jpg");    //判断图像是否加载成功    if(srcImage.empty())    {        cout << "图像加载失败!" << endl << endl;        return -1;    }    else        cout << "图像加载成功!" << endl << endl;    imshow("srcImage",srcImage);    //声明处理后图像变量    Mat dstImageAt, dstImageIterator, dstImagePtr;    dstImageAt = srcImage.clone();    dstImageIterator = srcImage.clone();    dstImagePtr = srcImage.clone();    int div = 4;    //声明时间变量    double timeAt, timeIterator, timePtr;    timeAt = static_cast<double>(getTickCount());    colorReduceAt(srcImage, dstImageAt, div);    timeAt = ((double)getTickCount() - timeAt) / getTickFrequency();    imshow("dstImageAt",dstImageAt);    cout << "使用at()动态地址计算耗时:" << timeAt << endl << endl;    timeIterator = static_cast<double>(getTickCount());    colorReduceIterator(srcImage, dstImageIterator, div);    timeIterator = ((double)getTickCount() - timeIterator) / getTickFrequency();    imshow("dstImageIterator",dstImageIterator);    cout << "使用iterator迭代器耗时:" << timeIterator << endl << endl;    timePtr = static_cast<double>(getTickCount());    colorReducePtr(srcImage, dstImagePtr, div);    timePtr = ((double)getTickCount() - timePtr) / getTickFrequency();    imshow("dstImagePtr",dstImagePtr);    cout << "使用ptr指针耗时:" << timePtr << endl;    waitKey(0);    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;    //Blue            dstImageAt.at<Vec3b>(i,j)[1] = dstImageAt.at<Vec3b>(i,j)[1]/div*div;    //Green            dstImageAt.at<Vec3b>(i,j)[2] = dstImageAt.at<Vec3b>(i,j)[2]/div*div;    //Red        }    }}//使用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;      //Blue        (*imageIt)[1] = (*imageIt)[1]/div*div;      //Green        (*imageIt)[2] = (*imageIt)[2]/div*div;      //Red    }}//使用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;    }}

运行结果如下:
这里写图片描述
三种方式在本程序中的耗时情况如下,值得注意的是程序耗时和电脑硬件和编译器等都有关系,在此我用的是cmake 3.5.1
这里写图片描述
从上述耗时分析来看使用指针方式是最快的处理方式,而迭代器的方式相对最慢。但是使用迭代器是较为安全的访问方式。
从上面程序中仔细分析指针式访问和at()动态地址分配访问方式的不同。可以找更大的图像对三种像素遍历方式进行分析,其耗时会由明显差别。
除了上面三种方式,其官方文档还提到了使用LUT()函数。在进行图像处理时将所给的所有图像值替换成其他的值,opencv中提供的LUT()函数可以批量实现这种功能。其用法如下:

Mat lookUpTable(1, 256, CV_8U);uchar* p = lookUpTable.data;for(int i = 0; i < 256; ++i)    p[i] = table[i];//然后调用函数(I是输入图像,J是输出图像)LUT(I, lookUpTable, J);

官方文档中通过对一幅(2560x1600)图像进行上百次的处理得出如下结论:
1. 如果可能的话尽可能使用opencv中提供的参数
2. 最快的方式是LUT()函数,因为opencv库通过Intel Threaded Building Blocks实现其多线程。
3. 如果写一个简单图像的遍历程序推荐使用指针方式。
4. 迭代器是相对来讲比较安全的访问方式,但其速度也相对较慢。
5. 在Debug模式下,动态地址计算方法是最慢的访问方式,但是在Release模式下它有可能比iterator访问方式快

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 穿越兽世:种田驭夫乐悠悠 不灭战神 我在宝可梦世界开餐厅 爸爸,我是来当你同学的 这个主角明明很强却异常谨慎 四合院:我的穿越为啥这么陋 甩了线上男友后我被亲哭了 人在南天坐看万古 为了成为英灵我只好在历史里搞事 我成了游戏里的反派之王 离婚后,前夫每天都想上位 霍格沃茨的风与鹰翼 攻略暴君后,我抱错大腿了 我的精灵模拟器 金鸾喜嫁 人在美漫,开局枪斗术 大国科技从手机开始 人住超神,渣在诸天 斗罗之王者吕布降临 从白蛇开始诸天改命 诸天之天外降临者 屠龙之前就读过龙族的路明非 足球盛宴,从收购欧洲俱乐部开始 在漫威驱魔的魔鬼神父 柯南之我的老姐毛利兰 重生在电影的世界 美漫第一仙 签到从遮天开始 风云饲养师 穿越异世:开局拥有空间神器 吞噬星空之超脱之路 穿梭两界:我携带的物品能变强 从开端开始的超凡之旅 相亲后,靳先生突然黏上我 港综世界的炼金术师 惊!帝君娇宠的小废柴竟然有空间 海上升明帝 开局十连抽,超跑豪宅拿来吧你! 柯学世界的普通警察 柯学世界里的柯研人 我只是个平平无奇的道士啊