5

When conv2d is on same mode, the image needs no padding, because the result is the same size as the image.

When conv2d is on full mode, the result is (image_width + kernel_width -1) * (image_height + kernel_height -1).

Then how do I pad the image?

Royi
  • 19,608
  • 4
  • 197
  • 238
Mage Front
  • 53
  • 2

1 Answers1

2

I created a MATLAB function which is basically conv2() applied in Frequency Domain:

function [ mO ] = ImageConvFrequencyDomain( mI, mH, convShape )
% ----------------------------------------------------------------------------------------------- %
% [ mO ] = ImageConvFrequencyDomain( mI, mH, convShape )
% Applies Image Convolution in the Frequency Domain.
% Input:
%   - mI                -   Input Image.
%                           Structure: Matrix.
%                           Type: 'Single' / 'Double' (Single Channel).
%                           Range: (-inf, inf).
%   - mH                -   Filtering Kernel.
%                           Structure: Matrix.
%                           Type: 'Single' / 'Double'.
%                           Range: (-inf, inf).
%   - convShape         -   Convolution Shape.
%                           Sets the convolution shape.
%                           Structure: Scalar.
%                           Type: 'Single' / 'Double'.
%                           Range: {1, 2, 3}.
% Output:
%   - mI                -   Output Image.
%                           Structure: Matrix (Single Channel).
%                           Type: 'Single' / 'Double'.
%                           Range: (-inf, inf).
% References:
%   1.  MATLAB's 'conv2()' - https://www.mathworks.com/help/matlab/ref/conv2.html.
% Remarks:
%   1.  A
% TODO:
%   1.  
%   Release Notes:
%   -   1.0.000     29/04/2021  Royi Avital     RoyiAvital@yahoo.com
%       *   First release version.
% ----------------------------------------------------------------------------------------------- %

CONV_SHAPE_FULL = 1; CONV_SHAPE_SAME = 2; CONV_SHAPE_VALID = 3;

numRows = size(mI, 1); numCols = size(mI, 2);

numRowsKernel = size(mH, 1); numColsKernel = size(mH, 2);

switch(convShape) case(CONV_SHAPE_FULL) numRowsFft = numRows + numRowsKernel - 1; numColsFft = numCols + numColsKernel - 1; firstRowIdx = 1; firstColIdx = 1; lastRowIdx = numRowsFft; lastColdIdx = numColsFft; case(CONV_SHAPE_SAME) numRowsFft = numRows + numRowsKernel; numColsFft = numCols + numColsKernel; firstRowIdx = ceil((numRowsKernel + 1) / 2); firstColIdx = ceil((numColsKernel + 1) / 2); lastRowIdx = firstRowIdx + numRows - 1; lastColdIdx = firstColIdx + numCols - 1; case(CONV_SHAPE_VALID) numRowsFft = numRows; numColsFft = numCols; firstRowIdx = numRowsKernel; firstColIdx = numColsKernel; % The Kernel when transformed is shifted (Namely its (0, 0) is top % left not middle). lastRowIdx = numRowsFft; lastColdIdx = numColsFft; end

mO = ifft2(fft2(mI, numRowsFft, numColsFft) .* fft2(mH, numRowsFft, numColsFft), 'symmetric'); mO = mO(firstRowIdx:lastRowIdx, firstColIdx:lastColdIdx);

end

It is fully compatible and validated.
The full code is available on my StackExchange Signal Processing Q74803 GitHub Repository (Look at the SignalProcessing\Q74803 folder).

Royi
  • 19,608
  • 4
  • 197
  • 238
  • I don't get how you're matching conv2 without centering mH, does MATLAB do something different with fft2 or ifft2? – OverLordGoldDragon Apr 17 '23 at 11:03
  • @OverLordGoldDragon, I am not sure what you mean. – Royi Apr 17 '23 at 11:04
  • Nevermind, you compensate by changing unpad indices. Looks good. – OverLordGoldDragon Apr 17 '23 at 11:29
  • @OverLordGoldDragon, If I got you write, then indeed, the fftshift() you use in your methods is not needed. For performance it is better not to use it. Just need to understand the axis system of the transformation. – Royi Apr 17 '23 at 11:39
  • If mH isn't reused and we're not aiming for circular convolution, yes. But it's more confusing to debug and doesn't enjoy offset-invariance in strided context. I'm so used to it that I forgot this alt case, I should mention it in my answer. – OverLordGoldDragon Apr 17 '23 at 11:44
  • @OverLordGoldDragon, Even for circular convolution there is not need to center it. On the contrary. – Royi Apr 17 '23 at 11:47
  • Output at index i won't correspond to the filter centered at index i. I don't think that's ever desired if we want input and output axes aligned? – OverLordGoldDragon Apr 17 '23 at 11:50
  • We like it, but for the analysis, not for the computation. Once you verify the implementation it is a black box. – Royi Apr 17 '23 at 11:55
  • You said no need for circular, meaning no padding. The axes get only more messed up with higher dimensions. If you're doing circular template matching, or anything that wants index 5 to be 2 centimeters for both input and output, the output is wrong without ifftshift2, and not even contiguous. – OverLordGoldDragon Apr 17 '23 at 12:04
  • @OverLordGoldDragon, Not sure what you're talking about. Circular convolution is by definition the multiplication in frequency. I have never had the issues you're talking about. – Royi Apr 17 '23 at 12:07
  • If $h$ is a bird and $x$ is unit impulse, both visually centered as in virtually any application with input images, then the bird will have legs for ears at output. The four quadrants are shifted in nonsensical manner. If $x$ is another bird and you want to find its location (obviously in original coordinate space), you will fail without ifftshift. – OverLordGoldDragon Apr 17 '23 at 12:09
  • Put such a question and we'll see :-). – Royi Apr 17 '23 at 13:24
  • Considering your self-admitted unfamiliarity, you should be the one to open it. I have also already shown it here. – OverLordGoldDragon Apr 17 '23 at 13:29
  • @OverLordGoldDragon, I am not unfamiliar, I think you're wrong. If you have doubts, you can ask. If not, it is OK on my side. I don't need any shift in my matched filter algorithms. – Royi Apr 17 '23 at 17:31