0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

基于边缘的模板匹配适用部分遮挡和光照变化情形(附源码)

新机器视觉 来源:Shiju PK 作者:Shiju PK 2021-10-13 15:20 次阅读

介绍

模板匹配是一个图像处理问题,当其姿态(X,Y,θ)未知时,使用另一张搜索图像中的模板图像找到对象的位置。在本文中,我们实现了一种算法,该算法使用对象的边缘信息来识别搜索图像中的对象。

背景

由于其速度和可靠性问题,模板匹配本质上是一个棘手的问题。当对象部分可见或与其他对象混合时,该解决方案应对亮度变化具有鲁棒性,最重要的是,该算法应具有计算效率。解决这个问题主要有两种方法,基于灰度值的匹配(或基于区域的匹配)和基于特征的匹配(非基于区域的匹配)。

基于灰度值的方法:在基于灰度值的匹配中,归一化互相关 (NCC) 算法早在过去就已为人所知。这通常在每一步通过减去平均值并除以标准偏差来完成。模板 t(x, y) 与子图像 f(x, y) 的互相关为:

其中 n 是 t(x, y) 和 f(x, y) 中的像素数。[维基]

尽管该方法对线性光照变化具有鲁棒性,但当对象部分可见或对象与其他对象混合时,该算法将失败。此外,该算法的计算成本很高,因为它需要计算模板图像中所有像素与搜索图像之间的相关性。

基于特征的方法:在图像处理领域中使用了几种基于特征的模板匹配方法。与基于边缘的物体识别一样,物体边缘是用于匹配的特征,在广义霍夫变换中,物体的几何特征将用于匹配。

在本文中,我们实现了一种算法,该算法使用对象的边缘信息来识别搜索图像中的对象。此实现使用开源计算机视觉库作为平台。

编译示例代码

我们使用 OpenCV 2.0 和 Visual Studio 2008 来开发此代码。要编译示例代码,我们需要安装 OpenCV。

OpenCV 可以从这里免费下载。OpenCV的(开放源码ç动态数值V ision)是一种用于实时计算机视觉编程功能的库。下载 OpenCV 并将其安装在您的系统中。安装信息可以从这里阅读。

我们需要配置我们的 Visual Studio 环境。可以从此处阅读此信息。

算法

在这里,我们将解释基于边缘的模板匹配技术。边缘可以定义为数字图像中图像亮度急剧变化或具有不连续性的点。从技术上讲,它是一种离散微分运算,计算图像强度函数的梯度近似值。

边缘检测的方法有很多,但大多数可以分为两类:基于搜索的和基于过零的。基于搜索的方法通过首先计算边缘强度的度量来检测边缘,通常是一阶导数表达式,例如梯度幅度,然后使用计算的局部方向的估计来搜索梯度幅度的局部方向最大值边缘,通常是梯度方向。在这里,我们使用了一种由 Sobel 实现的方法,称为 Sobel 算子。操作员计算每个点的图像强度梯度,给出从明到暗的最大可能增加方向以及该方向的变化率。

我们在 X 方向和 Y 方向使用这些梯度或导数进行匹配。

该算法包括两个步骤。首先,我们需要为模板图像创建一个基于边缘的模型,然后我们使用这个模型在搜索图像中进行搜索。

创建基于边缘的模板模型

我们首先从模板图像的边缘创建一个数据集或模板模型,用于在搜索图像中查找该对象的姿态。

在这里,我们使用 Canny 边缘检测方法的变体来查找边缘。您可以在此处阅读有关 Canny 边缘检测的更多信息。对于边缘提取,Canny 使用以下步骤:

第一步:求图像的强度梯度

在模板图像上使用 Sobel 过滤器,它返回 X (Gx) 和 Y (Gy) 方向的梯度。根据这个梯度,我们将使用以下公式计算边缘大小和方向:

我们正在使用 OpenCV 函数来查找这些值。

cvSobel( src, gx, 1,0, 3 ); //gradient in X directioncvSobel( src, gy, 0, 1, 3 ); //gradient in Y direction
for( i = 1; i < Ssize.height-1; i++ ){    for( j = 1; j < Ssize.width-1; j++ )    {                  _sdx = (short*)(gx->data.ptr + gx->step*i);        _sdy = (short*)(gy->data.ptr + gy->step*i);        fdx = _sdx[j]; fdy = _sdy[j];        // read x, y derivatives
        //Magnitude = Sqrt(gx^2 +gy^2)        MagG = sqrt((float)(fdx*fdx) + (float)(fdy*fdy));        //Direction = invtan (Gy / Gx)        direction =cvFastArctan((float)fdy,(float)fdx);        magMat[i][j] = MagG;
        if(MagG>MaxGradient)            MaxGradient=MagG;            // get maximum gradient value for normalizing.

        // get closest angle from 0, 45, 90, 135 set        if ( (direction>0 && direction < 22.5) ||               (direction >157.5 && direction < 202.5) ||               (direction>337.5 && direction<360)  )            direction = 0;        else if ( (direction>22.5 && direction < 67.5) ||                   (direction >202.5 && direction <247.5)  )            direction = 45;        else if ( (direction >67.5 && direction < 112.5)||                  (direction>247.5 && direction<292.5) )            direction = 90;        else if ( (direction >112.5 && direction < 157.5)||                  (direction>292.5 && direction<337.5) )            direction = 135;        else            direction = 0;
        orients[count] = (int)direction;        count++;    }}

一旦找到边缘方向,下一步就是关联图像中可以追踪的边缘方向。有四种可能的方向来描述周围的像素:0 度、45 度、90 度和 135 度。我们将所有方向分配给这些角度中的任何一个。

步骤 2:应用非极大值抑制

找到边缘方向后,我们会做一个非极大值抑制算法。非极大值抑制沿边缘方向跟踪左右像素,如果当前像素幅度小于左右像素幅度,则抑制当前像素幅度。这将导致图像变薄。

for( i = 1; i < Ssize.height-1; i++ ){    for( j = 1; j < Ssize.width-1; j++ )    {        switch ( orients[count] )        {            case 0:                leftPixel  = magMat[i][j-1];                rightPixel = magMat[i][j+1];                break;            case 45:                leftPixel  = magMat[i-1][j+1];                rightPixel = magMat[i+1][j-1];                break;            case 90:                leftPixel  = magMat[i-1][j];                rightPixel = magMat[i+1][j];                break;            case 135:                leftPixel  = magMat[i-1][j-1];                rightPixel = magMat[i+1][j+1];                break;        }        // compare current pixels value with adjacent pixels        if (( magMat[i][j] < leftPixel ) || (magMat[i][j] < rightPixel ) )            (nmsEdges->data.ptr + nmsEdges->step*i)[j]=0;        Else            (nmsEdges->data.ptr + nmsEdges->step*i)[j]=                                 (uchar)(magMat[i][j]/MaxGradient*255);        count++;    }}

第三步:做滞后阈值

用滞后做阈值需要两个阈值:高和低。我们应用高阈值来标记那些我们可以相当确定是真实的边缘。从这些开始,使用先前导出的方向信息,可以通过图像追踪其他边缘。在跟踪边缘时,我们应用较低的阈值,只要我们找到一个起点,我们就可以跟踪边缘的微弱部分。

_sdx = (short*)(gx->data.ptr + gx->step*i);_sdy = (short*)(gy->data.ptr + gy->step*i);fdx = _sdx[j]; fdy = _sdy[j];
MagG = sqrt(fdx*fdx + fdy*fdy); //Magnitude = Sqrt(gx^2 +gy^2)DirG =cvFastArctan((float)fdy,(float)fdx);     //Direction = tan(y/x)
////((uchar*)(imgGDir->imageData + imgGDir->widthStep*i))[j]= MagG;flag=1;if(((double)((nmsEdges->data.ptr + nmsEdges->step*i))[j]) < maxContrast){    if(((double)((nmsEdges->data.ptr + nmsEdges->step*i))[j])< minContrast)    {        (nmsEdges->data.ptr + nmsEdges->step*i)[j]=0;        flag=0; // remove from edge        ////((uchar*)(imgGDir->imageData + imgGDir->widthStep*i))[j]=0;    }    else    {   // if any of 8 neighboring pixel is not greater than max contraxt remove from edge        if( (((double)((nmsEdges->data.ptr + nmsEdges->step*(i-1)))[j-1]) < maxContrast) &&            (((double)((nmsEdges->data.ptr + nmsEdges->step*(i-1)))[j]) < maxContrast)   &&            (((double)((nmsEdges->data.ptr + nmsEdges->step*(i-1)))[j+1]) < maxContrast) &&            (((double)((nmsEdges->data.ptr + nmsEdges->step*i))[j-1]) < maxContrast)     &&            (((double)((nmsEdges->data.ptr + nmsEdges->step*i))[j+1]) < maxContrast)     &&            (((double)((nmsEdges->data.ptr + nmsEdges->step*(i+1)))[j-1]) < maxContrast) &&            (((double)((nmsEdges->data.ptr + nmsEdges->step*(i+1)))[j]) < maxContrast)   &&            (((double)((nmsEdges->data.ptr + nmsEdges->step*(i+1)))[j+1]) < maxContrast))        {            (nmsEdges->data.ptr + nmsEdges->step*i)[j]=0;            flag=0;            ////((uchar*)(imgGDir->imageData + imgGDir->widthStep*i))[j]=0;        }    }}

第 4 步:保存数据集

提取边缘后,我们将所选边缘的 X 和 Y 导数与坐标信息一起保存为模板模型。这些坐标将重新排列以反映作为重心的起点。

找到基于边的模板模型

算法中的下一个任务是使用模板模型在搜索图像中找到对象。我们可以看到我们从包含一组点的模板图像创建的模型:

,以及它在 X 和 Y 方向上的梯度

,其中i = 1…n,n是模板 (T) 数据集中的元素数。

我们还可以在搜索图像 (S) 中找到梯度

,其中 u = 1.。。搜索图像中的行数,v = 1.。。搜索图像中的列数。

在匹配过程中,应使用相似性度量将模板模型与所有位置的搜索图像进行比较。相似性度量背后的思想是取模板图像梯度向量的所有归一化点积之和,并在模型数据集中的所有点上搜索图像。这会导致搜索图像中每个点的分数。这可以表述如下:

如果模板模型和搜索图像之间存在完美匹配,则此函数将返回分数 1。该分数对应于搜索图像中可见的对象部分。如果搜索图像中不存在对象,则分数将为 0。

cvSobel( src, Sdx, 1, 0, 3 );  // find X derivativescvSobel( src, Sdy, 0, 1, 3 ); // find Y derivativesfor( i = 0; i < Ssize.height; i++ ){    for( j = 0; j < Ssize.width; j++ )    {         partialSum = 0; // initilize partialSum measure        for(m=0;m        {            curX    = i + cordinates[m].x ;    // template X coordinate            curY    = j + cordinates[m].y ; // template Y coordinate            iTx    = edgeDerivativeX[m];    // template X derivative            iTy    = edgeDerivativeY[m];    // template Y derivative
            if(curX<0 ||curY<0||curX>Ssize.height-1 ||curY>Ssize.width-1)                continue;
            _Sdx = (short*)(Sdx->data.ptr + Sdx->step*(curX));            _Sdy = (short*)(Sdy->data.ptr + Sdy->step*(curX));
            iSx=_Sdx[curY]; // get curresponding  X derivative from source image            iSy=_Sdy[curY];// get curresponding  Y derivative from source image
            if((iSx!=0 || iSy!=0) && (iTx!=0 || iTy!=0))            {                //partial Sum  = Sum of(((Source X derivative* Template X drivative)                //+ Source Y derivative * Template Y derivative)) / Edge                //magnitude of(Template)* edge magnitude of(Source))                partialSum = partialSum + ((iSx*iTx)+(iSy*iTy))*                            (edgeMagnitude[m] * matGradMag[curX][curY]);
            }

在实际情况下,我们需要加快搜索过程。这可以使用各种方法来实现。第一种方法是使用平均的属性。在寻找相似性度量时,如果我们可以为相似性度量设置一个最小分数(Smin,我们就不需要评估模板模型中的所有点为了检查特定点 J 处的部分分数 Su,v,我们必须找到部分总和 Sm。点 m 处的 Sm 可以定义如下:

0cf1416a-2183-11ec-82a8-dac502259ad0.png

很明显,和的剩余项小于或等于 1。因此,如果 ,我们可以停止评估

0d2a7502-2183-11ec-82a8-dac502259ad0.png

另一个标准可以是任何点的部分分数应大于最低分数。即,

0d56cac6-2183-11ec-82a8-dac502259ad0.png

使用此条件时,匹配将非常快。但问题是,如果先检查对象的缺失部分,部分和会很低。在这种情况下,对象的该实例不会被视为匹配项。我们可以用另一个标准修改它,我们用安全停止标准检查模板模型的第一部分,用硬标准检查其余部分,

0d99eb08-2183-11ec-82a8-dac502259ad0.png

.用户可以指定贪婪参数 (g),其中使用硬标准检查模板模型的部分。所以如果g=1,模板模型中的所有点都用硬标准检查,如果g=0,所有点将只用安全标准检查。我们可以将这个过程表述如下。

部分分数的评估可以在以下位置停止:

0da9e256-2183-11ec-82a8-dac502259ad0.png

// stoping criterias to search for modeldouble normMinScore = minScore /noOfCordinates; // precompute minumum score double normGreediness = ((1- greediness * minScore)/(1-greediness)) /noOfCordinates;// precompute greedniness
sumOfCoords = m + 1;partialScore = partialSum /sumOfCoords ;// check termination criteria// if partial score score is less than the score than// needed to make the required score at that position// break serching at that coordinate.if( partialScore < (MIN((minScore -1) +         normGreediness*sumOfCoords,normMinScore*  sumOfCoords)))    break;

这种相似性度量有几个优点:相似性度量对非线性光照变化是不变的,因为所有梯度向量都是归一化的。由于边缘过滤没有分割,它将显示对光照任意变化的真实不变性。更重要的是,当对象部分可见或与其他对象混合时,这种相似性度量是稳健的。

增强功能

该算法有多种可能的增强。为了进一步加快搜索过程,可以使用金字塔方法。在这种情况下,搜索以低分辨率和小图像尺寸开始。这对应于金字塔的顶部。如果在此阶段搜索成功,则在金字塔的下一层继续搜索,该层代表更高分辨率的图像。以这种方式,继续搜索,从而细化结果,直到达到原始图像大小,即到达金字塔底部。

通过扩展旋转和缩放算法,可以实现另一种增强。这可以通过创建用于旋转和缩放的模板模型并使用所有这些模板模型执行搜索来完成。

原文作者:Shiju PK 原文链接:

https://www.codeproject.com/articles/99457/edge-based-template-matching

翻译整理:Color Space

编辑:jq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 边缘检测
    +关注

    关注

    0

    文章

    92

    浏览量

    18206
  • OpenCV
    +关注

    关注

    31

    文章

    635

    浏览量

    41340

原文标题:OpenCV实现基于边缘的模板匹配--适用部分遮挡和光照变化情形(附源码)

文章出处:【微信号:vision263com,微信公众号:新机器视觉】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    基于无操作系统的STM32单片机开发源码

    现在非常多的的MCU性能都还不错,同时用户也会去扩展一些外部RAM,这样如果高效便捷的管理这些内存是一个重要话题。 今天给大家分享一份源码:基于无操作系统的STM32单片机开发,功能强大,可申请
    的头像 发表于 11-15 11:24 428次阅读

    手写图像模板匹配算法在OpenCV中的实现

    OpenCV中的模板匹配是支持基于NCC相似度查找的,但是不是很好用,一个主要的原因是查找最大阈值,只能匹配一个,自己比对阈值,又导致无法正确设定阈值范围,所以问题很多。于是我重新写了纯Python版本的NCC图像
    的头像 发表于 11-11 10:12 234次阅读
    手写图像<b class='flag-5'>模板</b><b class='flag-5'>匹配</b>算法在OpenCV中的实现

    如何应对UWB室内定位信号被遮挡

    遇到信号被遮挡的问题,这会影响到定位的准确性和稳定性。那么,面对信号被遮挡的情况,我们应该如何解决呢?本文将为您详细介绍。  首先,我们需要了解UWB室内定位的工作原理。UWB技术
    的头像 发表于 11-01 11:25 211次阅读
    如何应对UWB室内定位信号被<b class='flag-5'>遮挡</b>

    无人机巡检系统解决光伏电站遮挡问题

    无人机巡检系统解决光伏电站遮挡问题 光伏电站中的遮挡问题会显著影响光伏电板的发电效率,导致发电量下降。随着科技的发展,光伏电站配备无人机巡检系统成为了解决光伏电站运维遮挡难题的得力助手。以下是无人机
    的头像 发表于 08-29 16:47 348次阅读

    光敏电阻在光照下阻值是减小还是增大

    光敏电阻是一种特殊的电阻元件,其电阻值会随着光照强度的变化而发生变化。在光照下,光敏电阻的阻值是减小还是增大,取决于光敏电阻的类型和材料。 一、光敏电阻的工作原理 光敏电阻是一种半导体
    的头像 发表于 08-27 10:50 1249次阅读

    光敏电阻在无光照射时呈什么状态

    光敏电阻是一种特殊的电阻器,其电阻值会随着光照强度的变化变化。在无光照射时,光敏电阻的电阻值会显著增大,表现出高阻抗的特性。 一、光敏电阻的工作原理 光敏电阻的工作原理基于光敏材料的
    的头像 发表于 08-27 10:39 517次阅读

    光敏电阻随光照强度的变化规律

    光敏电阻是一种半导体材料,其电阻值会随着光照强度的变化变化。这种特性使得光敏电阻在许多领域得到广泛应用,如光控开关、光度计、自动控制等。 一、光敏电阻的工作原理 光敏电阻的工作原理基于半导体材料
    的头像 发表于 08-27 10:31 2047次阅读

    光敏电阻与光照强度的关系是什么

    光敏电阻是一种特殊的电阻元件,其电阻值会随着光照强度的变化变化。 一、光敏电阻的工作原理 光敏电阻是一种半导体材料制成的电阻元件,其电阻值会随着光照强度的
    的头像 发表于 08-27 10:29 1292次阅读

    怎么导出python边缘计算中的APP?

    怎么导出python边缘计算中的APP,想进行修改又找不到源码
    发表于 07-25 06:13

    DSP国产教学实验箱_实验案例_操作教程:5-11 边缘检测

    一、实验目的 学习Canny边缘检测的原理,掌握图像的读取方法,并实现边缘检测。 二、实验原理 边缘检测 在数字图像中,边缘是指图像局部变化
    发表于 07-19 10:38

    荣耀终端发布指纹匹配专利,聚焦电子设备领域

    此项技术研究揭示了一种指纹匹配方法及其对应的电子设备应用,具有增强指印解锁图像与指纹模板图像配对成功率的优势,从而提升用户的使用体验。其具体策略包括:在指印解锁图像无法与电子设备指纹模板图像相
    的头像 发表于 03-21 09:43 592次阅读
    荣耀终端发布指纹<b class='flag-5'>匹配</b>专利,聚焦电子设备领域

    LabVIEW模板匹配位置信息导出

    大家好,我在利用ni vision assistant生成的模板匹配界面时,想要将每一个匹配物体的位置信息导出到word或者Excel,但是他这个匹配个数不确定,怎么样把
    发表于 03-11 20:22

    OneFlow Softmax算子源码解读之WarpSoftmax

    写在前面:近来笔者偶然间接触了一个深度学习框架 OneFlow,所以这段时间主要在阅读 OneFlow 框架的 cuda 源码。官方源码基于不同场景分三种方式实现 Softmax,本文主要介绍其中一种的实现过程,即 Warp 级别 Softmax,
    的头像 发表于 01-08 09:24 842次阅读
    OneFlow Softmax算子<b class='flag-5'>源码</b>解读之WarpSoftmax

    如何用3D Occupancy处理遮挡问题下的图像匹配

    图像匹配是各种视觉应用中基本且关键的任务,如同时定位与地图构建( Simultaneous Localization and Mapping,SLAM )和图像检索,这些应用都需要精确的位姿估计。
    的头像 发表于 01-06 10:24 665次阅读
    如何用3D Occupancy处理<b class='flag-5'>遮挡</b>问题下的图像<b class='flag-5'>匹配</b>?

    如何使用CMW500测试频谱模板

    ,频谱模板被用于评估和验证无线信号性能,并帮助发现和解决潜在的无线干扰问题。CMW500是一款常用的无线通信测试设备,特别适用于频谱分析和信号生成等应用。 接下来,我们将详细介绍如何使用CMW500测试频谱模板。我们将分为以下几
    的头像 发表于 12-25 15:10 1618次阅读