基于VS与OpenCV的模板匹配学习(3):OpenCV Mat快速遍历

基于VS与OpenCV的模板匹配学习(3):

OpenCV Mat 快速遍历



前言

在前文的模板匹配中,基于边缘的模板匹配的速度并不友好,尝试对算法进行时间的优化。其中,对OpenCV的Mat遍历操作十分普遍,本文结合OpenCV的Mat的存储结构,试图找到一种的高效遍历Mat的方法,为后续进行时间优化作铺垫。
网上有类似文章可供参考:
opencv Mat遍历速度实验 https://blog.csdn.net/fanghtao/article/details/80995997
opencv高效遍历图像 https://blog.csdn.net/jacke121/article/details/94432519


一、OpenCV图像类型

OpenCV的图像类型的格式:CV_[bite](U|S|F)C [channels]
bite : 比特数,位数,对应在Mat中每个像素的所占的空间大小。
U|S|F :
U : unsigned int , 无符号整型
S : signed int , 有符号整型
F : float , 单精度浮点型
channels:图像的通道数

本场景中,使用的图像类型为CV_8UC1,即单通道的uchar格式,与CV_32FC1的单通道float格式在运算速度上差异较大。

cv::Mat resultImage;
resultImage.create(5000, 5000, CV_8UC1);

二、OpenCV指针ptr

OpenCV提供了方便访问Mat元素的指针ptr,正常的访问格式如下:

resultImage.create(5000, 5000, CV_8UC1);
int resultImageRow = 0;
int resultImageCol = 0;
//先访问行指针,再访问相应元素
uchar * resultImagePtr = resultImage.ptr<uchar>(resultImageRow);
resultImagePtr[resultImageCol] = 1;
//直接访问相应元素
resultImage.ptr<uchar>(resultImageRow)[resultImageCol]= 1;

通过上述代码,我们注意到:
resultImage.ptr(resultImageRow)返回的是一个行指针头
resultImage.ptr(resultImageRow)[resultImageCol]返回的是相应的元素
这点在后续时间的讨论中,两者的差异性会愈发明显。

注意事项:uchar指针对应CV_8UC1,int指针对应CV_32SC1,float指针对应CV_32FC1


三、遍历时间对比

在场景设计中,我们使用VS的release模式,与debug模式时间差异性较大。

(1)直接遍历目标元素:

	for (int resultImageRow = 0; resultImageRow < 5000; resultImageRow++)
		for (int resultImageCol = 0; resultImageCol < 5000; resultImageCol++)
			resultImage.ptr<uchar>(resultImageRow)[resultImageCol]= 1;

代码精简,利用ptr直接遍历目标元素,效率最低
Run Time:0.035s

(2)行指针逐行遍历目标元素:

	uchar* resultImagePtr;
	for (int resultImageRow = 0; resultImageRow < 5000; resultImageRow++)
	{
		resultImagePtr = resultImage.ptr<uchar>(resultImageRow);
		for (int resultImageCol = 0; resultImageCol < 5000; resultImageCol++)
			resultImagePtr[resultImageCol] = 1;
	}

先访问行指针ptr,再依次遍历目标元素,效率中等
Run Time:0.004s

(3)指针按行列遍历目标元素:
除ptr指针之外,OpenCV还提供Image.data指向数据的首部。在大部分场景中,OpenCV的数据是连续存储的,可以通过isContinuous()判断矩阵元素在每行末尾是否连续存储而没有间隙。经过一些场景测试,目前未发现网上提到的行结尾不满4Byte会自动补零的情况。

	uchar* resultImageDataStart = resultImage.data;
	for (int resultImageRow = 0; resultImageRow < 5000; resultImageRow++)
		for (int resultImageCol = 0; resultImageCol < 5000; resultImageCol++)
			*(resultImageDataStart++) = 1;

利用元素存储的连续性,按行列滑动指针位置遍历目标元素,效率较高
Run Time:0.003s

注意事项:resultImage.data默认uchar格式,倘若图像格式为CV_32FC1,需要强制格式转化

float* resultImageDataStart = (float*) resultImage.data;

(4)指针单循环遍历目标元素:

	uchar* resultImageDataStart = resultImage.data;
	for (int resultImageSeq = 0; resultImageSeq < 25000000; resultImageSeq++)
		*(resultImageDataStart++) = 1;

指针连续遍历目标元素,代码精简,效率最高
Run Time:0.003s


总结

综上所述:
遍历速度:ptr(row)[col] < ptr(row) < data

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

飞翔的维京号

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

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

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

打赏作者

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

抵扣说明:

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

余额充值