博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
标准的基于欧式距离的模板匹配算法优源码化和实现(附源代码)。
阅读量:7112 次
发布时间:2019-06-28

本文共 4360 字,大约阅读时间需要 14 分钟。

     很久没有出去溜达了,今天天气好,就放松放松去,晚上在办公室没啥事,把以前写的一个基于标准的欧式距离的模板匹配代码共享吧。

     opencv有模板匹配的代码,我没看他是如何优化的,所以不管他吧,我只描述我自己实现。

     基于欧式距离的模板匹配就是遍历被匹配图的每一个像素,然后计算以该像素为中心,和模板图重叠部分的像素的欧式距离,当模板图越大时,计算就急剧增加,因此做优化才能有真正的实用价值。

     两个标量的欧式距离表达式为 (a - b) * (a - b),展开后为 a^2 + b^ 2 - 2ab,我们每一个像素点的计算就是WM * HM个像素色阶值的距离的累加和(WM和HM分别为模板图的宽度和高度),模板匹配中,模板图所有像素的平方和是固定的,可以提前计算,而被匹配图中每个像素点周边WM * HM的像素的平方和可以使用类似BoxBlur中懒惰算法快速的得到,而只有两者的成绩项是必须每个点重新计算,这也是整个计算过程中最为耗时的部分,如果直接用C的代码写出来,恐怕等到花儿都谢了。

     我在一文中曾经给出过一种基于SSE的的快速卷积的算法,他可以一次性计算出16个字节的乘法,速度因此也得到了大的提升,因此,完全可以用在上述的计算a * b的过程中,这样我们的模板匹配速度就能有质的提高。

    计算模板图的像素自乘平方和代码非常简单,也没啥耗时,简单代码如下:

int GetPowerSum(TMatrix *Src)            //    无需注释{    if (Src == NULL || Src->Data == NULL) return 0;    if (Src->Depth != IS_DEPTH_8U) return 0;    int X, Y, Sum, Width = Src->Width, Height = Src->Height;    unsigned char *LinePS;        if (Src->Channel == 1) { for (Y = 0, Sum = 0; Y < Height; Y++) { LinePS = Src->Data + Y * Src->WidthStep; for (X = 0; X < Width; X++) { Sum += LinePS[X] * LinePS[X]; } } } else { for (Y = 0, Sum = 0; Y < Height; Y++) { LinePS = Src->Data + Y * Src->WidthStep; for (X = 0; X < Width; X++) { Sum += LinePS[0] * LinePS[0] + LinePS[1] * LinePS[1] + LinePS[2] * LinePS[2]; LinePS += 3; } } } return Sum; }   而计算被匹配图中每个像素为中心,WH*WM范围内像素的自乘平方和的O(1)算法也比较简单:
/// /// 计算图像的局部平方和,速度已经优化,支持1和3通道图像。(2015.10.5日)/// /// 待求平方和的图像。/// 平方和数据,需要使用int类型矩阵保存,大小为Src->Width - SizeX + 1, Src->Height - SizeY + 1,程序内部分配数据。/// 在水平方向使用的模板大小,如果是半径模式,对应的量为2 * Radius + 1。/// 在垂直方向使用的模板大小,如果是半径模式,对应的量为2 * Radius + 1。/// 
1:使用了类似BoxBlur里的优化算法,耗时和参数基本无关。
///
2:也可以使用积分图实现。
IS_RET GetLocalSquareSum(TMatrix *Src, TMatrix **Dest, int SizeX, int SizeY){ if (Src == NULL || Src->Data == NULL) return IS_RET_ERR_NULLREFERENCE; if (Src->Depth != IS_DEPTH_8U || Src->Channel == 4) return IS_RET_ERR_NOTSUPPORTED; if (SizeX < 0 || SizeY < 0) return IS_RET_ERR_ARGUMENTOUTOFRANGE; int X, Y, Z, SrcW, SrcH, DestW, DestH, LastIndex, NextIndex, Sum; int *ColSum, *LinePD; unsigned char *SamplePS, *LastAddress, *NextAddress; IS_RET Ret = IS_RET_OK; SrcW = Src->Width, SrcH = Src->Height; DestW = SrcW - SizeX + 1, DestH = SrcH - SizeY + 1; Ret = IS_CreateMatrix(DestW, DestH, IS_DEPTH_32S, 1, Dest); if (Ret != IS_RET_OK) goto Done; ColSum = (int*)IS_AllocMemory(SrcW * sizeof(int), true); if (ColSum == NULL) {Ret = IS_RET_ERR_OUTOFMEMORY; goto Done;} if (Src->Channel == 1) { for (Y = 0; Y < DestH; Y++) { LinePD = (int *)((*Dest)->Data + Y * (*Dest)->WidthStep); if (Y == 0) { for (X = 0; X < SrcW; X++) { Sum = 0; for (Z = 0; Z < SizeY; Z++) { SamplePS = Src->Data + Z * Src->WidthStep + X; Sum += SamplePS[0] * SamplePS[0] ; } ColSum[X] = Sum; } } else { LastAddress = Src->Data + (Y - 1) * Src->WidthStep; NextAddress = Src->Data + (Y + SizeY - 1) * Src->WidthStep; for (X = 0; X < SrcW; X++) { ColSum[X] -= LastAddress[X] * LastAddress[X] - NextAddress[X] * NextAddress[X]; } } for (X = 0; X < DestW; X++) { if (X == 0) { Sum = 0; for (Z = 0; Z < SizeX; Z++) { Sum += ColSum[Z]; } } else { Sum -= ColSum[X - 1] - ColSum[X + SizeX - 1]; } LinePD[X] = Sum; } } } else if (Src->Channel == 3) { for (Y = 0; Y < DestH; Y++) { LinePD = (int *)((*Dest)->Data + Y * (*Dest)->WidthStep); if (Y == 0) { for (X = 0; X < SrcW; X++) { Sum = 0; for (Z = 0; Z < SizeY; Z++) { SamplePS = Src->Data + Z * Src->WidthStep + X * 3; // 三通道累加到一起 Sum += SamplePS[0] * SamplePS[0] + SamplePS[1] * SamplePS[1] + SamplePS[2] * SamplePS[2]; } ColSum[X] = Sum; } } else { LastAddress = Src->Data + (Y - 1) * Src->WidthStep; NextAddress = Src->Data + (Y + SizeY - 1) * Src->WidthStep; for (X = 0; X < SrcW; X++) { ColSum[X] += NextAddress[0] * NextAddress[0] + NextAddress[1] * NextAddress[1] + NextAddress[2] * NextAddress[2] - LastAddress[0] * LastAddress[0] - LastAddress[1] * LastAddress[1] - LastAddress[2] * LastAddress[2]; LastAddress += 3; NextAddress += 3; } } for (X = 0; X < DestW; X++) { if (X == 0) { Sum = 0; for (Z = 0; Z < SizeX; Z++) { Sum += ColSum[Z]; } } else { Sum -= ColSum[X - 1] - ColSum[X + SizeX - 1]; } LinePD[X] = Sum; } } } Done: IS_FreeMemory(ColSum); return Ret; }
  上述代码思路类似于BoxBlur的实现方式,如果还想更快点,可以参考)一文的基于SSE的处理方式,有兴趣的朋友可以自研。

       其实速度也不快,但是有些应用场合模板图很小(比如16*16的),被匹配图也不大,比如640 * 480的,这个时候大概也就30ms左右吧,如果是灰度的匹配那就能更快了。

       其实代码如果想优化,还是可以用线程并行的。

a

      代码下载:(解压密码: Buy me a beer)

 

 

转载于:https://www.cnblogs.com/Imageshop/p/6108764.html

你可能感兴趣的文章
Netflix Zuul 了解
查看>>
磁盘格式化
查看>>
zabbix 修改管理员用户密码
查看>>
正则表达式个人总结(一):正则表达式语法的深入理解第一部分--转
查看>>
UVA 10081 Tight Words
查看>>
php curl常见错误:SSL错误、bool(false)
查看>>
23个全屏照片为背景的网站
查看>>
浅析Windows操作系统中的线程局部存储(TLS)机制
查看>>
HTTP
查看>>
FaceBook的NoScript策略
查看>>
QC+SQL2005,连接数据库时提示"属性不正确"
查看>>
基于CentOS的Linux基本网络配置,包括网卡eth0、DNS、Host等
查看>>
[转载]从今天开始,调试脚本,远离alert
查看>>
pku 1442 Black Box 优先队列
查看>>
Emacs学习笔记(9):org-mode,最好的文档编辑利器,没有之一
查看>>
.NET设计规范二:类型成员设计
查看>>
Flash Builder4.6 无法启动,并且报 Failed to create the Java Virtual Machine(1-不行的话可以参考下2)...
查看>>
责任链模式
查看>>
select 下的option删除,复制,修改
查看>>
QML与c++交互学习笔记(八) qt c++直接调用QML中的函数, 直接设置属性
查看>>