学习《OpenCV2计算机视觉编程手册》第二章的学习体会
关键词:图像处理-图像变换-点运算-图像遍历-淡化像素
首先,看一下的基础代码,实现了图片遍历淡化每个像素;
void main() { Mat image = imread("lena.jpg"); namedWindow("Image"); colorReduce1(image); imshow("Image", image); waitKey(0); }
void colorReduce1(Mat &image, int div = 64) //time=2.43ms { int n1 = image.rows; int nc = image.cols*image.channels(); for (int j = 0; j < n1; j++) { uchar* data = image.ptr(j); for (int i = 0; i < nc; i++) data[i] = data[i] / div*div + div / 2;//(data[i]/div)*div } }
书中给了多个图像遍历的方法,附上全部代码,代码如下:
#include#include using namespace cv; void colorReduce1(Mat &image, int div = 64) //time=2.43ms { int n1 = image.rows; int nc = image.cols*image.channels(); for (int j = 0; j < n1; j++) { uchar* data = image.ptr (j); for (int i = 0; i < nc; i++) data[i] = data[i] / div*div + div / 2;//(data[i]/div)*div } } void colorReduce2(Mat &image, int div = 64)//time=2.06ms { int n1 = image.rows; int nc = image.cols*image.channels(); if (image.isContinuous())//*** { nc = n1*nc; n1 = 1; } for (int j = 0; j < n1; j++) { uchar* data = image.ptr (j); for (int i = 0; i < nc; i++) data[i] = data[i] / div*div + div / 2;//(data[i]/div)*div } } void colorReduce3_iterator(Mat &image, int div = 64)//time=58.15ms { Mat_ ::iterator it = image.begin (); Mat_ ::iterator itend = image.end (); 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; } } void colorReduce4(Mat &image, int div = 64) // mermory slip out //time=97.67ms { int n1 = image.rows; int nc = image.cols; //is not nc= image.cols*image.channels(); for (int j = 0; j < n1; j++) { for (int i = 0; i < nc; i++) { image.at (j, i)[0] = image.at (j, i)[0] / div*div + div / 2; image.at (j, i)[1] = image.at (j, i)[1] / div*div + div / 2; image.at (j, i)[2] = image.at (j, i)[2] / div*div + div / 2; } } } void colorReduce5_fast(Mat &image, int div = 64)//time=1.13ms { int n1 = image.rows; int nc = image.cols; if (image.isContinuous())//*** { nc = n1*nc; n1 = 1; } int n = static_cast<int>(log(static_cast<double>(div))/log(2.0)); uchar mask = 0xff << n; for (int j = 0; j < n1; j++) { uchar* data = image.ptr (j); for (int i = 0; i < nc; i++) { *data++ = *data&mask + div / 2; *data++ = *data&mask + div / 2; *data++ = *data&mask + div / 2; } } } void main() { Mat image = imread("lena.jpg"); //Time test double tTime; tTime = (double)getTickCount(); const int nTimes = 100; for (int i = 0; i < nTimes; i++) { //algrithom to be test ; colorReduce4(image); } tTime = 1000 * ((double)getTickCount() - tTime) / getTickFrequency(); tTime /= nTimes; std::cout << tTime << std::endl; namedWindow("Image"); imshow("Image", image); waitKey(0); }
main()函数中,增加了Time test 函数,为了测试不同的图像遍历方法的运行效率。经过测试,每个遍历方法的运行时间,我已经注释在每一个colorReduce函数的后面。
从以上的结果来看,效率最高最低的排序是:colorReduce5_fast()>colorReduce2()>colorReduce1()>colorReduce3_iterator()>colorReduce4();
效率最高只需要占用1.13ms,效率最低要占用97.67ms。效率相差100倍左右,性能将提升90%以上;
从代码易读性上来排序(个人主观):
colorReduce3_iterator()>colorReduce4()>colorReduce1()>colorReduce2()>colorReduce5_fast();
综合考虑算法处理效率与代码易读性,我通常选择:
colorReduce1()>colorReduce2();
分析,不同的图像遍历方法:
colorReduce5_fast()
遍历方法:使用指针,减少嵌套循环
>colorReduce2()
遍历方法:使用指针,减少嵌套循环
>colorReduce1()
遍历方法:使用指针
>colorReduce3_iterator()
遍历方法:使用迭代器
>colorReduce4()
遍历方法:使用迭代器at()
从上面的不同的遍历方法来看,得出结论:为了提高遍历效率,尽量使用指针,而不是迭代器;尽量减少嵌套循环;