文章目录
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
clock_t time_stt=clock();
在执行相关算法处理之后计算用时: (clock()-time_stt)/(double)CLOCKS_PER_SEC(见p46)
2. 头文件为:#include
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();
4.复制图像的方式:
1.直接赋值:在这种方式下的赋值,一旦对复制后的图像进行更改,则原图像也会改变
2.使用clone函数赋值:对复制后的图像更改不会影响到原图像
5. 遍历图像像素的方法:
参考:1.https://blog.youkuaiyun.com/keith_bb/article/details/53071133
对图像像素进行遍历时共有三种方法: 1). 动态地址计算
2). 迭代器iterator
3). C操作符[] (指针方式访问)
示例:
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
using namespace std;
using namespace cv;
void colorReduceAt(Mat& dstImageAt,int div);
void colorReduceIterator(Mat &dstImageIterator, int div);
void colorReducePtr(Mat &dstImagePtr, int div);
int main(int argc,char** argv)
{
Mat srcImg=imread(argv[1]);
if(argc!=1)
{
cout<<"usage:./total lena.png"<<endl;
}
imshow("lena.png",srcImg);
//声明处理后图像变量
Mat dstImageAt,dstImageIterator,dstImagePtr;
dstImageAt=srcImg.clone();
dstImageIterator=srcImg.clone();
dstImagePtr=srcImg.clone();
int div=50;
//声明时间变量
double timeAt,timeIterator,timePtr;
//at()
timeAt=static_cast<double>(getTickCount());
colorReduceAt(dstImageAt,div);
timeAt=((double)getTickCount()-timeAt)/getTickFrequency();
imshow("dstImageAt_lena.png",dstImageAt);
cout<<"使用at()动态地址计算耗时:"<<timeAt<<"s"<<endl<<endl;
//iterator
timeIterator=static_cast<double>(getTickCount());
colorReduceAt(dstImageIterator,div);
timeIterator=((double)getTickCount()-timeIterator)/getTickFrequency();
imshow("dstImageIterstor_lena.png",dstImageIterator);
cout<<"使用iterator迭代器计算耗时:"<<timeIterator<<"s"<<endl<<endl;
//ptr
timePtr=static_cast<double>(getTickCount());
colorReducePtr(dstImagePtr,div);
timePtr=((double)getTickCount()-timePtr)/getTickFrequency();
imshow("dstImagePtr_lena.png",dstImagePtr);
cout<<"使用ptr指针计算耗时:"<<timePtr<<"s"<<endl<<endl;
waitKey(0);
}
//使用at动态地址计算方式
//用函数at()来实现对矩阵中某个像素值进行读取
//以及进行赋值操作
void colorReduceAt( 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)[0]=dstImageAt.at<Vec3b>(i,j)[0]/div*div;//Green
dstImageAt.at<Vec3b>(i,j)[0]=dstImageAt.at<Vec3b>(i,j)[0]/div*div;//Red
}
}
}
//使用iterator迭代器方式
void colorReduceIterator(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 &dstImagePtr, int div)
{
int rowNumber=dstImagePtr.rows;
int colNumber=dstImagePtr.cols;
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;
}
}
}
三种遍历像素的方法对比:
从上述的运行结果中,我们可以看出指针方式是最快的处理方式,而迭代器的方式相对最慢。但是使用迭代器是较为安全的访问方式。
如果需要对图像像素进行遍历,不推荐使用at()函数,因为使用这个函数其效率不高,但是其可读性较好。
参考:1.https://www.cnblogs.com/cc111/p/9276411.html
声明:本人写博客只为记录学习点滴,加深印象。