使用 FFT 的 Matlab 模板匹配

标签 matlab image-processing fft template-matching cross-correlation

我在 Matlab 的傅立叶域中努力进行模板匹配。这是我的图片(艺术家是 DeviantArt 上的 RamalamaCreatures):

possum.jpg
possum_ear.jpg

我的目标是在负鼠的耳朵周围放置一个边界框,就像这个例子(我使用 normxcorr2 执行模板匹配):

Goal: possum ear bounded

这是我正在使用的 Matlab 代码:

clear all; close all;

template = rgb2gray(imread('possum_ear.jpg'));
background = rgb2gray(imread('possum.jpg'));

%% calculate padding
bx = size(background, 2); 
by = size(background, 1);
tx = size(template, 2); % used for bbox placement
ty = size(template, 1);

%% fft
c = real(ifft2(fft2(background) .* fft2(template, by, bx)));

%% find peak correlation
[max_c, imax]   = max(abs(c(:)));
[ypeak, xpeak] = find(c == max(c(:)));
figure; surf(c), shading flat; % plot correlation 

%% display best match
hFig = figure;
hAx  = axes;
position = [xpeak(1)-tx, ypeak(1)-ty, tx, ty];
imshow(background, 'Parent', hAx);
imrect(hAx, position);

代码未按预期运行 - 它没有识别正确的区域。这是失败的结果 - 错误的区域被装箱:
failed template matching

这是失败匹配的相关性曲面图:
surf plot for failed template matching

希望你能帮上忙!谢谢。

最佳答案

您在代码中所做的实际上根本不是相关性。您正在使用模板和 执行卷积 与输入图像。如果您记忆一下傅立叶变换,两个信号的频谱相乘相当于两个信号在时域/空间域中的卷积。

基本上,您正在做的是将模板用作内核并使用它来过滤图像。然后,您将找到此输出的最大响应,这就是模板所在的位置。响应被装箱的地方是有意义的,因为该区域是完全白色的,并且使用模板作为具有完全白色区域的内核会给你一个非常大的响应,这就是为什么它最有可能确定该区域是最大的回应。具体来说,该区域将具有很多高值(~255 左右),并且自然地与模板补丁执行卷积,并且由于操作是加权和,该区域将为您提供非常大的输出。因此,如果您在图像的暗区使用模板,输出会很小 - 这是错误的,因为模板也由暗像素组成。

但是,您当然可以使用傅立叶变换来定位模板所在的位置,但我建议您使用 Phase Correlation相反。基本上,不是计算两个谱的乘积,而是计算互功率谱。交叉功率谱R频域中两个信号之间的定义为:



来源:Wikipedia
GaGb是原图和频域模板,*是共轭。 o是所谓的 Hadamard 乘积或元素级乘积。我还想指出,这个分数的分子和分母的除法也是按元素进行的。使用交叉功率谱,如果您找到 (x,y)此处产生绝对最大响应的位置,这是模板应位于背景图像中的位置。

因此,您只需更改计算“相关性”的代码行,以便计算互功率谱。不过,我想指出一些非常重要的事情。当您执行 normxcorr2 ,相关性从图像的左上角开始。模板匹配从这个位置开始,它与一个窗口进行比较,该窗口是模板大小的窗口,其中左上角是原点。查找模板匹配的位置时,该位置相对于匹配窗口的左上角。一旦计算 normxcorr2 ,您传统上添加最大响应的一半行和一半列以找到 中心位置 .

因为我们或多或少地对 FFT/频域进行模板匹配(滑动窗口、相关等)的相同操作,所以当你在这个相关数组中找到峰值时,你 还必须考虑到这一点 .但是,您调用 imrect无论如何,要在模板匹配的位置周围绘制一个矩形在边界框的左上角,因此无需在此处进行偏移。因此,如果想找到匹配的中心位置,我们将稍微修改该代码,但在稍后使用此代码时请记住偏移逻辑。

我也修改了您的代码以直接从 StackOverflow 读取图像,以便它可以重现:

clear all; close all;

template = rgb2gray(imread('http://i.stack.imgur.com/6bTzT.jpg'));
background = rgb2gray(imread('http://i.stack.imgur.com/FXEy7.jpg'));

%% calculate padding
bx = size(background, 2); 
by = size(background, 1);
tx = size(template, 2); % used for bbox placement
ty = size(template, 1);

%% fft
%c = real(ifft2(fft2(background) .* fft2(template, by, bx)));

%// Change - Compute the cross power spectrum
Ga = fft2(background);
Gb = fft2(template, by, bx);
c = real(ifft2((Ga.*conj(Gb))./abs(Ga.*conj(Gb))));

%% find peak correlation
[max_c, imax]   = max(abs(c(:)));
[ypeak, xpeak] = find(c == max(c(:)));
figure; surf(c), shading flat; % plot correlation    

%% display best match
hFig = figure;
hAx  = axes;

%// New - no need to offset the coordinates anymore
%// xpeak and ypeak are already the top left corner of the matched window
position = [xpeak(1), ypeak(1), tx, ty];
imshow(background, 'Parent', hAx);
imrect(hAx, position);

这样,我得到以下图像:

enter image description here

显示交叉功率谱的表面图时,我还得到以下信息:

enter image description here

有一个明确定义的峰值,其余输出的响应非常小。这实际上是相位相关的一个属性,因此很明显,最大值的位置是明确定义的,这就是模板所在的位置。

希望这可以帮助!

关于使用 FFT 的 Matlab 模板匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32664481/

相关文章:

python - 如何使用 Python OpenCV 从 OCR 图像中去除噪声伪影?

c# - 没有从 Exocortex FFT 获得预期的输出

matlab - Matlab中矩阵相等元素的位置对

matlab - 在 MATLAB 中使用 'fill' 函数时如何更改边线颜色?

java - 突出显示图像之间的差异

c++ - OpenCV 质量中心点

linux - 一些 Matlab ctrl 快捷方式在 Linux 中不起作用

arrays - Matlab数组的动态切片

iphone - 是否有用于在 iPhone 上执行 FFT 的开源库?

matlab - Matlab中函数的解析傅立叶变换与FFT