v9.1.1
Menu

Separable Filter Optimization

hardFREELinear FilteringFilteringCV: Image Processing

Implement efficient separable convolution using the separability property.

A 2D filter K is separable if K=hvTK = \mathbf{h} \mathbf{v}^T (outer product of two 1D filters).

Computational advantage:

  • Direct 2D convolution: O(N2⋅k2)O(N^2 \cdot k^2) for k×k kernel
  • Separable: O(N2⋅2k)O(N^2 \cdot 2k) - much faster!

Algorithm:

  1. Check if kernel is separable (rank-1 matrix)
  2. If separable, extract h and v vectors
  3. Convolve image with h horizontally
  4. Convolve result with v vertically

Output: return {'result': ..., 'is_separable': ...} where result has the same size as the image (pixels outside the image are treated as 0), with every value rounded to 4 decimal places. Treat the kernel as separable when its second singular value is negligible (<10−10< 10^{-10}) relative to its first.

Gaussian, box, and Sobel filters are all separable!

Example

Input
image = [[0,0,0,0,0],[0,0,0,0,0],[0,0,1,0,0],[0,0,0,0,0],[0,0,0,0,0]]
kernel = [[1,2,1],[2,4,2],[1,2,1]]  # Separable (Gaussian-like)
Output
{'result': [[0.0, 0.0, 0.0, 0.0, 0.0], [0.0, 1.0, 2.0, 1.0, 0.0], [0.0, 2.0, 4.0, 2.0, 0.0], [0.0, 1.0, 2.0, 1.0, 0.0], [0.0, 0.0, 0.0, 0.0, 0.0]], 'is_separable': True}
Reasoning
  • Inputs: image is a 5×55 \times 5 grayscale grid of zeros with a single 1 at the centre (row 2, column 2) — an impulse. kernel is a 3×33 \times 3 grid of weights.
  • Separability: every row of the kernel is a multiple of [1,2,1][1, 2, 1] (rows are 1×1\times, 2×2\times, 1×1\times it), so the matrix has rank 1 and factors as K=hvTK = \mathbf{h}\mathbf{v}^T with h=v=[1,2,1]\mathbf{h} = \mathbf{v} = [1, 2, 1]. Hence is_separable is True.
  • Horizontal pass: filtering each row with [1,2,1][1, 2, 1] leaves every row zero except the middle one, which becomes [0,1,2,1,0][0, 1, 2, 1, 0].
  • Vertical pass: filtering each column with [1,2,1][1, 2, 1] spreads column 2's value 2 into 2,4,22, 4, 2 down rows 1–3, and columns 1 and 3 into 1,2,11, 2, 1.
  • Output: the kernel itself, centred on the impulse, with zeros on the border — pixels outside the image count as 0. Notice this equals direct 2D convolution, but costs 2k=62k = 6 multiplies per pixel instead of k2=9k^2 = 9.

Constraints

  • image: 2D grayscale array
  • kernel: 2D convolution kernel
  • Return: Dict with 'result' and 'is_separable' boolean
  • If separable, use optimized method; otherwise direct convolution

Learn this in

More from CV: Image Processing

solution.py

Test results

Sign in to run your code against the test cases.