复制MATLAB';s`conv2()`使用傅里叶域卷积
我想拍摄两幅图像,并在Matlab中使用2D FFT将它们卷积在一起,而无需使用复制MATLAB';s`conv2()`使用傅里叶域卷积,matlab,image-processing,fft,convolution,Matlab,Image Processing,Fft,Convolution,我想拍摄两幅图像,并在Matlab中使用2D FFT将它们卷积在一起,而无需使用conv2函数。然而,我不确定矩阵应该如何正确填充和准备卷积 数学运算如下: A*B=C 在上面的例子中,*是卷积算子() 下面的Matlab程序显示了填充和不填充矩阵之间的区别。我怀疑不填充矩阵会导致循环卷积,但我希望执行线性卷积而不产生锯齿 如果我对两个矩阵进行填充,那么如何截断卷积的输出,使C与A和B的大小相同 A = rgb2gray(im2double(imread('1.png'))); % input
conv2
函数。然而,我不确定矩阵应该如何正确填充和准备卷积
数学运算如下:
A*B=C
在上面的例子中,*是卷积算子()
下面的Matlab程序显示了填充和不填充矩阵之间的区别。我怀疑不填充矩阵会导致循环卷积,但我希望执行线性卷积而不产生锯齿
如果我对两个矩阵进行填充,那么如何截断卷积的输出,使C与A和B的大小相同
A = rgb2gray(im2double(imread('1.png'))); % input A
B = rgb2gray(im2double(imread('2.png'))); % kernel B
figure;
imagesc(A); colormap gray;
title ('A')
figure;
imagesc(B); colormap gray;
title ('B')
[m,n] = size(A);
mm = 2*m - 1;
nn = 2*n - 1;
C = (ifft2(fft2(A,mm,nn).* fft2(B,mm,nn)));
figure;
imagesc(C); colormap gray;
title ('C with padding')
C0 = (ifft2(fft2(A).* fft2(B)));
figure;
imagesc(C0); colormap gray;
title ('C without padding')
以下是程序的输出:
如您所指出,如果不填充,结果将等价于循环卷积。对于线性卷积,在卷积2幅图像(2D信号)A*B时,完整输出的大小为
Ma+Mb-1 x Na+Nb-1
,其中Ma x Na,Mb x Nb
图像A和B的大小分别为
填充到预期大小后,通过ifft2进行乘法和变换,可以保留结果图像的中心部分(通常对应于A和B中最大的一个)
现在,使用conv2D
% space-domain convolution result
F = conv2(A,B,'same');
figure; imshow(F,[]);
结果在视觉上是相同的,两者之间的总误差(由于四舍五入)为
e-10。
我创建了一个MATLAB函数,基本上是conv2()
频域:
function[mO]=ImageConvFrequencyDomain(mI、mH、convShape)
% ----------------------------------------------------------------------------------------------- %
%[mO]=ImageConvFrequencyDomain(mI、mH、convShape)
%在频域中应用图像卷积。
%输入:
%-mI-输入图像。
%结构:矩阵。
%键入:“单通道”/“双通道”(单通道)。
%范围:(-inf,inf)。
%-mH-过滤内核。
%结构:矩阵。
%键入:'单'/'双'。
%范围:(-inf,inf)。
%-convShape-卷积形状。
%设置卷积形状。
%结构:标量。
%键入:'单'/'双'。
%范围:{1,2,3}。
%输出:
%-mI-输出图像。
%结构:矩阵(单通道)。
%键入:'单'/'双'。
%范围:(-inf,inf)。
%参考资料:
% 1. MATLAB的“conv2()”-https://www.mathworks.com/help/matlab/ref/conv2.html.
%备注:
% 1. A.
%待办事项:
% 1.
%发行说明:
%-1.0.000 2021年4月29日Royi AvitalRoyiAvital@yahoo.com
%*第一版。
% ----------------------------------------------------------------------------------------------- %
CONV_SHAPE_FULL=1;
CONV_SHAPE_SAME=2;
CONV_SHAPE_VALID=3;
numRows=尺寸(mI,1);
numCols=大小(mI,2);
numRowsKernel=大小(mH,1);
numColsKernel=尺寸(mH,2);
开关(convShape)
箱子(箱型箱满)
numRowsFft=numRows+numRowsKernel-1;
numColsFft=numCols+numColsKernel-1;
firstRowIdx=1;
firstColIdx=1;
lastRowIdx=numRowsFft;
lastColdIdx=numColsFft;
外壳(转换形状相同)
numRowsFft=numRows+numRowsKernel;
numColsFft=numCols+numColsKernel;
firstRowIdx=ceil((numRowsKernel+1)/2);
firstColIdx=ceil((numColsKernel+1)/2);
lastRowIdx=firstRowIdx+numRows-1;
lastColdIdx=firstColIdx+numCols-1;
案例(CONV_SHAPE_有效)
numRowsFft=numRows;
numColsFft=numCols;
firstRowIdx=numRowsKernel;
firstColIdx=numColsKernel;
%转换时的内核被移位(即它的(0,0)是top)
%左边(不是中间)。
lastRowIdx=numRowsFft;
lastColdIdx=numColsFft;
结束
mO=ifft2(fft2(mI,NUMROWSFT,numColsFft)。*fft2(mH,NUMROWSFT,numColsFft),“对称”);
mO=mO(firstRowIdx:lastRowIdx,firstColIdx:lastColdIdx);
结束
它完全兼容并经过验证。完整的代码可以在我的上找到。这太棒了,gevang。谢谢你这么完整的回答!一个问题:既然卷积运算与相关性有关,我会对两个矩阵的2D相关性做同样的操作吗?
ifft2(fft2(M1,mm,nn).*fft2(fliplr(flipud(M2)),mm,nn)
是相关性的Matlab代码,然后我会以与上面的答案相同的方式保留图像的中心部分吗?此外,如果A和B是复矩阵,卷积(或相关性)会不会操作代码的工作方式完全相同?因为卷积(和傅里叶变换)是线性运算,并且是加法分布的,所以对于A+Aj
形式的信号,等效性将保持不变,也就是说,在原始大小的图像的实部和虚部的组合之间,将有一个卷积和。您可以用上面的复杂矩阵替换A和B进行检查。如果两者都很复杂,请可视化输出的abs()
,或者比较F和D部分的real()
和imag()
之间的差异。再次感谢gevang。是的,经过一些实验,我可以确认卷积码在Matlab中对A+Aj
形式的信号有效。此外,使用Matlabxcorr2<
% space-domain convolution result
F = conv2(A,B,'same');
figure; imshow(F,[]);