<<视觉slam十四讲>>_ch5 实践部分之imageBasics.cpp的代码解释及总结
1.关于int main(int argc,char** argv)中argc,argv参数的解释
argc参数表示命令行中参数的个数,其值是在输入命令时由系统按实际参数的个数自动赋值的
argv参数是字符串指针数组,存放命令行中的参数,长度即为参数个数argc
其中的第0个参数是程序的全名,之后的参数由用户输入的参数确定
2.关于 cv::waitKey(0)的解释:
在inshow之后必须要有waitKey(k),以便给予足够的时间显示图像,功能是不断刷新图像。waitKey(k)仅对窗口机制起作用,其中k的单位为ms:如果k=0,表示无线等待下去,直到有按键按下,无返回值;如果k>0,表示等待的时间,若在这段时间内没有任何操作则等待结束后返回-1,如在期间输入了字符,则最终返回字符的ASCII码
3.像素的表示:
如果是灰度图,用8位整数(unsigned char)表示一个像素,即表示0~255的值.
如果是RGB相机的深度图中,由于记录了各个像素与相机之间的距离(单位为毫米),而RGB相机的量程在十几米左右,超过了255,所以用16位整数(unsigned short)表示一个像素,即表示0~65536的值.
如果是彩色图像,常见的是用三个通道(即red,blue,green三个颜色)表示任意一种色彩,而每个通道占8位,所以用24位表示一个像素.
4.给算法计时:
1).头文件为:#include<ctime>
clock_t time_stt=clock();
在执行相关算法处理之后计算用时: (clock()-time_stt)/(double)CLOCKS_PER_SEC(见p46)
2).头文件为:#include <chrono>
chrono::steady_clock::time_point t1=chrono::steady_clock::now();
//...
//program...
//...
chrono::steady_clock::time_point t2=chrono::steady_clock::now();
chrono::duration<double> time_used=chrono::duration_cast<chrono::duration<double>>(t2-t1);
3)opencv计时函数:
double t=static_cast<double> (getTickCount());
//...
//program...
//...
t = ((double)getTickCount()-t)/getTickFrequency();
5.复制图像的方式:
1.直接赋值:在这种方式下的赋值,一旦对复制后的图像进行更改,则原图像也会改变
2.使用clone函数赋值:对复制后的图像更改不会影响到原图像
6. 遍历图像像素的方法:
参考:https://blog.csdn.net/keith_bb/article/details/53071133
对图像像素进行遍历时共有三种方法: 1). 动态地址计算
2). 迭代器iterator
3). C操作符[] (指针方式访问)
我们给出一个综合例程:
1 #include <iostream> 2 #include <opencv2/core.hpp> 3 #include <opencv2/highgui.hpp> 4 5 using namespace std; 6 using namespace cv; 7 8 void colorReduceAt(Mat& dstImageAt,int div); 9 void colorReduceIterator(Mat &dstImageIterator, int div); 10 void colorReducePtr(Mat &dstImagePtr, int div); 11 12 int main(int argc,char** argv) 13 { 14 Mat srcImg=imread(argv[1]); 15 if(argc!=1) 16 { 17 cout<<"usage:./total lena.png"<<endl; 18 } 19 imshow("lena.png",srcImg); 20 21 //声明处理后图像变量 22 Mat dstImageAt,dstImageIterator,dstImagePtr; 23 dstImageAt=srcImg.clone(); 24 dstImageIterator=srcImg.clone(); 25 dstImagePtr=srcImg.clone(); 26 27 int div=50; 28 29 //声明时间变量 30 double timeAt,timeIterator,timePtr; 31 32 //at() 33 timeAt=static_cast<double>(getTickCount()); 34 colorReduceAt(dstImageAt,div); 35 timeAt=((double)getTickCount()-timeAt)/getTickFrequency(); 36 imshow("dstImageAt_lena.png",dstImageAt); 37 cout<<"使用at()动态地址计算耗时:"<<timeAt<<"s"<<endl<<endl; 38 39 //iterator 40 timeIterator=static_cast<double>(getTickCount()); 41 colorReduceAt(dstImageIterator,div); 42 timeIterator=((double)getTickCount()-timeIterator)/getTickFrequency(); 43 imshow("dstImageIterstor_lena.png",dstImageIterator); 44 cout<<"使用iterator迭代器计算耗时:"<<timeIterator<<"s"<<endl<<endl; 45 46 //ptr 47 timePtr=static_cast<double>(getTickCount()); 48 colorReducePtr(dstImagePtr,div); 49 timePtr=((double)getTickCount()-timePtr)/getTickFrequency(); 50 imshow("dstImagePtr_lena.png",dstImagePtr); 51 cout<<"使用ptr指针计算耗时:"<<timePtr<<"s"<<endl<<endl; 52 53 waitKey(0); 54 } 55 56 //使用at动态地址计算方式 57 //用函数at()来实现对矩阵中某个像素值进行读取 58 //以及进行赋值操作 59 void colorReduceAt( Mat &dstImageAt, int div) 60 { 61 int rowNumber=dstImageAt.rows;//获取图像行数 62 int colNumber=dstImageAt.cols;//获取图像列数 63 64 //对每个像素进行处理 65 for(int i=0;i<rowNumber;++i) 66 { 67 for(int j=0;j<colNumber;++j) 68 { 69 dstImageAt.at<Vec3b>(i,j)[0]=dstImageAt.at<Vec3b>(i,j)[0]/div*div;//Blue 70 dstImageAt.at<Vec3b>(i,j)[0]=dstImageAt.at<Vec3b>(i,j)[0]/div*div;//Green 71 dstImageAt.at<Vec3b>(i,j)[0]=dstImageAt.at<Vec3b>(i,j)[0]/div*div;//Red 72 } 73 } 74 } 75 76 //使用iterator迭代器方式 77 void colorReduceIterator(Mat &dstImageIterator, int div) 78 { 79 MatIterator_<Vec3b> imageIt=dstImageIterator.begin<Vec3b>();//获取迭代器初始位置 80 MatIterator_<Vec3b> imageEnd=dstImageIterator.end<Vec3b>();//获取迭代器结束位置 81 82 for(;imageIt!=imageEnd;++imageIt) 83 { 84 (*imageIt)[0]=(*imageIt)[0]/div*div;//Blue 85 (*imageIt)[1]=(*imageIt)[1]/div*div;//Green 86 (*imageIt)[2]=(*imageIt)[2]/div*div;//Red 87 } 88 } 89 90 //使用ptr指针 91 void colorReducePtr(Mat &dstImagePtr, int div) 92 { 93 int rowNumber=dstImagePtr.rows; 94 int colNumber=dstImagePtr.cols; 95 96 for(int i=0;i<rowNumber;++i) 97 { 98 uchar* pixelPtr=dstImagePtr.ptr<uchar>(i);//获取矩阵每行首地址 99 for(int j=0;j<colNumber;++j) 100 { 101 pixelPtr[j]=pixelPtr[j]/div*div; 102 } 103 } 104 }
运行结果:
三种遍历像素的方法对比:
从上述的运行结果中,我们可以看出指针方式是最快的处理方式,而迭代器的方式相对最慢。但是使用迭代器是较为安全的访问方式。
如果需要对图像像素进行遍历,不推荐使用at()函数,因为使用这个函数其效率不高,但是其可读性较好。