比例和旋转不变的模板匹配

信息处理 计算机视觉 opencv 模板匹配
2021-12-20 05:45:01

我正在寻找一种缩放和旋转不变模板匹配的方法。我已经尝试了一些,但它们对我的示例并没有那么好,或者永远执行。SIFT 和 SURF 特征检测完全失败。我还尝试实现对数极坐标模板匹配功能,但我从未完成(不知道具体如何)。

在这些文章中(第一篇是德语)

http://cvpr.uni-muenster.de/teaching/ss08/seminarSS08/downloads/Wentker-Vortrag.pdf

http://www.jprr.org/index.php/jprr/article/viewFile/355/148

我读到了那个方法。映射极坐标有效,但我不知道它是否正确。图像看起来像这样。

source_log_polar.png http://www.shareimages.com/images/pics/0/0/3/62394-pZSfl5WenZysnpyVnKg-source_log_polar.png

template_log_polar.png

在将这两个图像与 OpenCV 的模板匹配功能匹配后,我得到了结果

match_log_polar.png

现在我不知道如何继续。

我的模板始终是构建蓝图和蓝图本身的简单符号。符号的大小和方向可能不同。

例如我的简单蓝图:

在此处输入图像描述

还有我的模板

在此处输入图像描述

在这个例子中只有一个模板,但是在蓝图中它应该找到所有的出现,即使是那些有大小和/或方向的。

有没有人有办法解决这个问题?

编辑:

安德烈方法的补充。径向轮廓的距离捕获算法。(使用 EmguCV)

private float[] getRadialProfile( Image<Gray, byte> image, Point center, int resolution )
 {

 var roi = image.ROI;

 if ( !roi.Contains( center ) )
  {
   return null;
  }

 var steps = resolution;
 var degreeSteps = 360 / (double)resolution;
 var data = image.Data;
 var peak = 0.0f;
 var bottom = double.MaxValue;
 var bottomIndex = 0;
 var width = roi.Width;
 var height = roi.Height;
 var minX = roi.X;
 var minY = roi.Y;

 float[] distances = new float[resolution];
 for ( var i = 0; i < steps; i++ )
  {
   var degree = i * degreeSteps;
   var radial = degree * Math.PI / 180.0;
   var dy = Math.Sin( radial );
   var dx = Math.Cos( radial );

   var x = (double)center.X;
   var y = (double)center.Y;

   while ( true )
    {
    x += dx;
    y += dy;
    if ( x >= minX + width || y >= minY + height || x <= minX || y <= minY )
     {
      x = -1;
      y = -1;
      break;
     }
    var pixel = data[(int)y, (int)x, 0];
    if ( pixel == 0 )
     {
      break;
     }
    }

    float distance = 0.0f;
    if ( x != -1 && y != -1 )
    {
      distance = (float)Math.Sqrt( Math.Pow( (center.X - x), 2 ) + Math.Pow( (center.Y - y), 2 ) );
    }

    distances[i] = distance;
    if ( distance > peak )
    {
      peak = distance;
    }
    if ( distance < bottom )
    {
      bottom = distance;
      bottomIndex = i;
    }
   }

    // Scale invariance. Divide by peak
   for ( var i = 0; i < distances.Length; i++ )
   {
     distances[i] /= peak;
   }

    // rotation invariance, shift to lowest value
   for ( var i = 0; i < bottomIndex; i++ )
   {
     distances.ShiftLeft(); // Just rotates the array nothing special
   }

   return distances;
}
4个回答

我认为您可以以更简单的方式解决您的问题。考虑到您正在处理蓝图,您不应该担心边缘连接、噪声以及 SIFT 和 SURF 为适应而构建的许多其他事情。您的模板是具有特定边缘形状的空心形状。

因此,我的建议是:

  • 绕着周边走一圈,找到模板中心周围边缘距离的轮廓。这是模板的径向轮廓。除以最大距离,以保持尺度不变。旋转向量,使最小的距离是第一个,以保持旋转不变。(如果您的模板没有显性距离,您可以稍后更改第 2 步)

在此处输入图像描述

  • 查找图像中的斑点。计算第 (1) 部分中描述的径向轮廓,并通过归一化相关比较两个向量。如果您的模板没有显性距离,则相关性变为归一化互相关,并选择最大值)。那些通过某个阈值的人被视为匹配。

下面是一些 Matlab 代码供您开始使用 - 我编写了查找特定 blob 的距离剖面并为模板计算它的部分:

function Doors
    im = imread('http://i.stack.imgur.com/Tf8EV.png');
    im = im(:,:,1);
    template = imread('http://i.stack.imgur.com/PlP4i.png');
    template = template(:,:,1);

    blobs = regionprops(template>0,'Area','Image');
    largestBlob = GetLargestBlob(blobs);
    [prof,edgeImage] = GetBlobRadialProfile(largestBlob);

    figure;
    subplot(1,2,1);plot(prof); title('Radial profile')
    subplot(1,2,2);imshow(edgeImage); title('Template');

end

function [prof,edgeImage] = GetBlobRadialProfile(blob)
    paddedImage = padarray( blob.Image,[8 8]);
    erodedImage = imerode(paddedImage,strel('disk',1));
    edgeImage = xor(erodedImage,paddedImage);

    c = regionprops(paddedImage,'Centroid');
    cx  = c.Centroid(1);
    cy  = c.Centroid(2);

    [y,x] = find(edgeImage);
    rad = (x(:)-cx).^2 + (y(:)-cy).^2;
    [~,minIndex] = min(rad);
    contour = bwtraceboundary(edgeImage, [y(minIndex), x(minIndex)],'N');
    prof = (contour(:,2)-cx).^2 + (contour(:,1)-cy).^2;
    prof = prof./max(prof);
end

function largestBlob = GetLargestBlob(blobs)    
    area = [blobs.Area];
    [~,index] = max(area);
    largestBlob = blobs(index);
end

这是我所知道的可以做的基本想法,基于 IIT Madras 的 Anurag Mittal 教授的演讲。

这个想法是基于形状的对象检测,但显然也可以扩展到其他地方。

  1. 使用伯克利边缘检测器计算边缘。
  2. 连接获得的边。“全局对象边界检测”。
  3. 使用倒角距离或 Houstoff 距离进行形状匹配。

他的论文可在:Multi-Stage Contour based Detection of Deformable Objects 上找到。

另一方面,我认为 SIFT 应该像角点检测算法一样工作在你那里的模板特征上。

注意:SIFT 不是完全旋转不变的。它无法应对 > 60 度左右的旋转。所以形成多个模板是个好主意。

与基于对数极性的傅里叶-梅林变换一样:由于变换的采样方式,它们会导致信息丢失。

我没有考虑太多,但我很确定使用经典的傅里叶描述符 (FD) 可以轻松获得强大的解决方案。我认为您的问题可能是一个非常好的候选者。不要认为你需要做边缘检测 b/c 你有黑线图。只需开始光栅扫描,直到碰到任何像素,然后执行以下操作:

只需将您的房间周边视为一维信号,其中信号幅度是与物体质心的正常距离,以某种稳定的速率采样。所以,为门做一个简单的FD模型。然后,使用一种凸面滤波器扫描每个房间的参数,寻找上升沿、峰值和下降,从而设置“信号”的开始/停止窗口以进行捕获。对捕获的“信号”执行 FFT 或类似的 FD 算法,并与 FD 模板进行比较。也许模板比较步骤可以是与触发匹配的阈值的简单关联。因为只有你的门有圆边,这应该是一个非常简单的 FD 匹配问题。

可以把它想象成使用 FD 从数据库中检索图像或音乐。很多白皮书都在这方面。

这是一个关于使用 FD 来近似形状的好教程: 我怀疑你会需要它,但你也可以首先将图像转换为极坐标框架来处理旋转,就像本文中提出的那样: 基于形状的图像检索使用通用傅里叶描述符

看看他们 FD 如何参数化苹果周边检测?和你的门一样的想法。

顺便说一句,我很确定将整个示意图映射到极坐标不会有助于旋转不变性 - 你需要对每扇门的质心做这件事,这正是你的问题开始的地方。这就是为什么我认为您只想捕获候选门,并可能将它们映射到极坐标以匹配 FD 门模板,就像上面链接的那篇论文中所做的那样。

如果您尝试这种方法,请告诉我情况如何。

也许你会发现我写的这个 Matlab 代码很有用: Fractal Mosaics

它在一个艺术应用程序中实现了论文“使用对数极坐标变换的鲁棒图像配准”(pdf),该应用程序比我发现的传统方法需要更多的鲁棒性。