Chr*_*rry 11 matlab fft image-processing template-matching cross-correlation
我正在Matlab中的傅里叶域中进行模板匹配.这是我的图像(艺术家是DeviantArt上的RamalamaCreatures):
我的目标是在负鼠的耳朵周围放置一个边界框,就像这个例子(我使用normxcorr2执行模板匹配):
这是我正在使用的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);
Run Code Online (Sandbox Code Playgroud)
代码未按预期运行 - 它未识别正确的区域.这是失败的结果 - 错误的区域被装箱:

希望你能帮忙!谢谢.
ray*_*ica 23
您在代码中所做的事实上根本不是相关性.您正在使用模板并对输入图像执行卷积.如果从傅里叶变换中回想起,两个信号的频谱相乘等效于时间/空间域中两个信号的卷积.
基本上,您正在做的是您将模板用作内核并使用它来过滤图像.然后,您将找到此输出的最大响应,这就是模板所在的位置.响应被装箱的地方是有意义的,因为该区域是完全白色的,并且使用模板作为具有完全白色区域的内核将给出非常大的响应,这就是为什么它最有可能确定该区域是最大的响应.具体来说,该区域将具有许多高值(约255左右),并且自然地使用模板补丁进行卷积,并且由于操作是加权和,该区域将给出非常大的输出.因此,如果您在图像的暗区使用模板,
但是,您当然可以使用傅立叶变换来定位模板的位置,但我建议您使用相位相关.基本上,您不是计算两个光谱的乘法,而是计算交叉功率谱.R频域中两个信号之间的交叉功率谱定义为:

资料来源:维基百科
Ga并且Gb是频域中的原始图像和模板,并且*是共轭.这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);
Run Code Online (Sandbox Code Playgroud)
有了它,我得到以下图像:
在显示交叉功率谱的表面图时,我还得到以下信息:
有明确定义的峰值,其余输出的响应非常小.这实际上是相位相关的一个属性,很明显,最大值的位置是明确定义的,这是模板所在的位置.
希望这可以帮助!