一、源码分析和空间创建释放
1.1 内联特性
1.2 特性
inline关键字是一定要和函数体定义放在一起得,和声明结合是没有作用的。
1.2.1 调用开销的区别
实现太过简单,以至于他的消耗甚至是小于标准函数调用的消耗,其调用指令相对简单,如果此时我们又需要大量的调用函数,那伴随着的就是大量的指令开销;针对这种浪费情况,“寸土寸金”思想严重的开发人员就设计出了inline函数,又称内联函数。
内联函数最重要的作用就是针对函数调用开销大于函数指令开销的函数体而推出的!实现在编译阶段,将调用开销忽略,直接在函数处进行代码展开,且inline函数也就不会再生成函数符号了!
1.2.2 代码体的差异
(1)在debug版本上,inline是无作用的,只有在release版本下才可以!
(2)并非所有的inline函数都会被编译器处理成内联函数 例如递归可以;代码体太过庞大不易展开,要么是代码体是个贪得无厌的无底洞,不能展开;
1.3 Mat创建
1.3.1 构造方法创建
inline Mat::Mat(int _rows, int _cols, int _type)
例如
Mat mat(3000,4000,CV_8UC3);
1.3.2 Mat.Create()
inline void Mat::create(int _rows, int _cols, int _type)
例如
Mat mat; mat.create(3000,4000,CV_8UC1);
1.4 Mat释放
1.4.1 release()或者析构
引用计数为1时才会真正释放
二、遍历和修改连续Mat图像空间
2.1 遍历和修改连续的OpenCV Mat图像空间
int main(int argc, char* argv) { Mat image(3000, 4000, CV_8UC3); int es = image.elemSize(); int size = image.rows * image.cols * es; for (int i = 0; i < size; i += es) { image.data[i] = 255;//B image.data[i + 1] = 0;//G image.data[i + 2] = 0;//R } namedWindow("img"); imshow("img", image); waitKey(0); return 0; }
2.1.1 RGB存放方式(连续)
注:可能因为内存对齐等原因,第一行和第二行不是连续存储的,即第一行末不是第二行开始,而是可能空一些字节用于内存对齐。
2.2 判断是否连续isContinues()
2.2.1 判断存储空间是否连续
2.2.2 通过steps记录
2.3 使用opencv接口实现运行记时函数用来分析执行时间
int PrintMs(const char *text = "") { static long long last = 0; long long cur = getTickCount(); if (last == 0) { last = cur; } long long ms = ((double)(cur - last) / getTickFrequency()) *1000; if (*text != 0) { printf("%s = %d ms\n", text,ms); } return 0; }
优化禁用耗时39ms
优化使速度最大化22ms
注:debug版本开启使速度最大化需要设置:
1.项目属性 c/c+±>优化->使速度最大化
2.c/c+±>常规->调试信息-》程序数据库(/Zi)
3.c/c++ 代码生成->基本运行时检查->默认
2.4 遍历不连续的OpenCV Mat空间
for (int row = 0; row < image.rows; row++) { for (int col = 0; col < image.cols; col++) { (&image.data[row*image.step])[col*es] = 0;//B (&image.data[row*image.step])[col*es + 1] = 0;//G (&image.data[row*image.step])[col*es + 2] = 0;//R } }
2.5 ptr模板函数 遍历Mat并测试其性能
ptr访问 相比遍历访问 速度更接近于直接地址访问
for (int row = 0; row < image.rows; row++) { for (int col = 0; col < image.cols; col++) { Vec3b* c = image.ptr<Vec3b>(row, col); c->val[0] = 0; //B c->val[1] = 255; //G c->val[2] = 0; //R } }
2.6 at函数 遍历Mat并捕获异常
try{ //此处rows*2 特意测试异常 for (int row = 0; row < image.rows *2; row++) { for (int col = 0; col < image.cols; col++) { Vec3b &m = image.at<Vec3b>(row, col); m.val[0] = 0; //B m.val[1] = 255; //G m.val[2] = 0; //R } } } catch (cv::Exception &ex) { std::cout << ex.what() << std::endl; }
注:Release版本不会抛出异常 只有Debug 会抛出异常
2.7 迭代器 遍历Mat并总结遍历方法
auto it = image.begin<Vec3b>(); auto it_end = image.end<Vec3b>(); for (; it != it_end; it++) { (*it).val[0] = 0;//B (*it).val[1] = 0;//G (*it).val[2] = 255;//R }
2.7.1 特点
1>可以不用管mat的行列,大小,类型
2.8 总结遍历方法
1>通过地址直接访问 data
2>通过Ptr
3>通过at
4>通过迭代器
2.9 QT自定义opengl的Widget绘制Mat
具体不展开 后期贴上源码地