[笔记]OpenCV+FFmpeg+Qt实现视频编辑器之OpenCV核心类型 Mat

一、源码分析和空间创建释放

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 会抛出异常
原因:解决try-catch 在RELEASE版无法捕捉错误

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

具体不展开 后期贴上源码地址

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

二进制怪兽

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值