2
$\begingroup$

I have 2D convolution with a large input image (512x1920). I am trying to partition the image across height and width to perform this convolution as N pieces. This would involve having an intersection between each sub-slice of the input image. I would like to understand how to calculate this intersection for various size of stride, padding and kernel size.

$\endgroup$
1

1 Answer 1

1
$\begingroup$

This is called tiling in image processing.
It is used to keep better locality of the calculations and improve performance.

Assume you have image of 512x512.
Assume we work on tiles of size 64x64.
So we have 64 tiles in the image each covers 64x64 of the image.

In case of doing a spatial operation we don't want to have boundary issues hence we add to each tile some padding.
The size of the padding depends on the radius of the kernel used.
Assume we work using convolution with a kernel of size 11x11 then the radius of the kernel is 5 hence we need to pad the tiles with 5 pixels in each direction.

enter image description here

So per tile we have and input of size 74x74 and output of 64x64.

I implemented this in Julia:

kernelLen = (2 * kernelRadius) + 1;
kernelNumPx = Float64(kernelLen * kernelLen);
mK      = Kernel{(-kernelRadius:kernelRadius, -kernelRadius:kernelRadius)}(@inline mW -> (sum(mW) / kernelNumPx));
mIPad   = PadImage(mI, (kernelRadius, kernelRadius));

mORef = map(mK, mIPad);
mORef = Float64.(mORef); #<! See https://github.com/stev47/StaticKernels.jl/issues/11

mO = zeros(size(mI));

# Working by the inner indices
for firstRowIdx in 1:tTileSize[1]:tSize[1], firstColIdx in 1:tTileSize[2]:tSize[2]
    lastRowIdx  = firstRowIdx + tTileSize[1] - 1;
    lastColIdx  = firstColIdx + tTileSize[2] - 1;
    
    # The padded image is basically shifted by `kernelRadius`
    firstRowIdxTile = firstRowIdx;
    lastRowIdxTile  = firstRowIdxTile + tTileSize[1] + (2 * kernelRadius) - 1;
    firstColIdxTile = firstColIdx;
    lastColIdxTile  = firstColIdxTile + tTileSize[2] + (2 * kernelRadius) - 1;
    @views map!(mK, mO[firstRowIdx:lastRowIdx, firstColIdx:lastColIdx], mIPad[firstRowIdxTile:lastRowIdxTile, firstColIdxTile:lastColIdxTile]);
end

The output is identical to working on the whole image:

enter image description here

enter image description here

The code is available at my StackExchange Codes Signal Processing GitHub Repository (Look at the SignalProcessing\Q81420 folder).

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.