Overview
This article uses a filtering chain based on Android Kawase V2 throughout. It starts by fitting a single-phase impulse response, examines the phase errors introduced by downsampling, and then introduces the polyphase supervision method from DPF: Differentiable Polyphase Filtering for Large-Kernel Approximation (SIGGRAPH 2026). Finally, it extends the optimization problem to downsampled blur with fixed, shared mipmap kernels, outlining how to solve for scale-dependent final sampling parameters under a fixed sampling budget.
Single-Phase Kawase Optimization
1. Shape Differences Between Kawase and Gaussian Blur
First, compare full-resolution Gaussian blur and Android Kawase V2 on the same sinc test image, with their blur widths matched to target values of . The Dual Kawase implementation preserves high-frequency information by blending the original image with the blurred result. Its blur shape differs substantially from a Gaussian at the same scale.
| Method | σ = 4 | σ = 8 | σ = 16 | σ = 40 |
|---|---|---|---|---|
| Gaussian | ![]() Image RMSE 0 | ![]() Image RMSE 0 | ![]() Image RMSE 0 | ![]() Image RMSE 0 |
| Android Kawase V2 | ![]() blurRadius=6 | ![]() blurRadius=17 | ![]() blurRadius=32 | ![]() blurRadius=90 |
2. The Kawase Processing Chain
The following diagram expands the Android Dual Kawase chain for a target of : an initial 4× downsample followed by one 2× downsample; on the way back, a 2× reconstruction blended with the saved image at that level, followed by a final 4× reconstruction blended with the original image.
Vertical dashed lines feed saved images from the top row into the blend stages below: Mᵢ(z) = αᵢ z + (1 − αᵢ) qᵢ; C_r(b) = β(r) b + (1 − β(r)) f.
The notation is as follows:
- and are the full-resolution input and output. denotes spatial coordinates before rearrangement, and denotes discrete pixel indices after rearrangement. Intermediate stages use their respective input pixels as coordinate units.
- performs upsampling reconstruction with a sampling kernel. The Android implementation determines internally from
blurRadius; is the reconstructed image before blending. - blends the reconstructed result with the previously saved downsampled image at the same level: .
- blends in the original image at small radii: , where is the integer
blurRadiusand .
For blurRadius=6, the intermediate images follow .





At the return to , the inter-level blend factor is approximately . The final output contains blurred content and of the original image. Consequently, this small-radius result retains sharp details, and its impulse response contains a spike from the original-image contribution. It is not a strict Gaussian.
3. Single-Phase Impulse-Response Optimization
A common way to quantify the difference between Kawase and a reference blur kernel is to use the response to a single impulse as the equivalent convolution kernel of a complex graphics pipeline.
Input, Output, and Cross-Section
To evaluate a blur chain, construct a discrete impulse : an image with a value of at the center pixel and everywhere else. Pass it through the complete processing chain and record the output weight distribution:
The resulting is the impulse response at that input location.
Its 2D image and center-row cross-section reveal its spread, peak, and shape. Comparing it with the target Gaussian also gives error metrics for parameter tuning.
Below, Android Kawase V2 (blurRadius=90) processes a unit impulse at phase . The full-resolution Gaussian is the reference, with the target scale still set to .



A—A marks the cross-section. The overlaid curve below shows its raw values; the gray dashed curve is the Gaussian reference.
This approach to kernel evaluation is called single-impulse evaluation.
Although the Kawase baseline has a support size similar to the reference Gaussian, its peak is noticeably lower and its shape is flatter. Visually, the result looks somewhat “square.”
Single-Impulse Evaluation and the LSI Condition
The theoretical basis for single-impulse evaluation is the behavior of linear shift-invariant systems (LSI). If is both linear and shift-invariant, one impulse response determines its output for any input:
In that case, optimizing the impulse response is equivalent to optimizing the convolution kernel of the entire chain. Dual Kawase, however, is not an LSI system. This is the central issue explored in this article. For now, we follow the single-impulse approach and fit the Dual Kawase response at one location to a Gaussian as closely as possible. The next section introduces a method that addresses the missing supervision.
Defining the Optimization Variables
The kernels at each stage are shown below. Offsets are measured in input texels of the corresponding pass, and every lookup uses bilinear sampling.
All three kernel diagrams place the sampling center at the intersection of four input pixels. Squares represent complete input pixels, dots mark pixel centers, and hollow circles mark the stencil's sample positions. Coordinates are relative to the sampling center, with Δx pointing right and Δy pointing down, matching the implementation. Gray intensity represents accumulated pixel weights at this reference alignment, with a shared scale across all three diagrams. One complete ring of pixels is retained around the coverage area. The upsampling example uses s=2 (a=s/2=1); the dashed circle has radius a. These are reference diagrams of the kernel stencils, not actual output phases. During execution, the sampling center's alignment with the input pixels varies with the output phase, as do the interpolation weights.
These three kernels can be described by four variables: starting angle , number of outer samples , center weight , and ring radius .
The outer points are evenly spaced on a circle of radius . Point has angle and weight ; the center has weight . Drag the sliders or enter values to inspect the sample positions and bilinear interpolation weights. The sampling center remains at the intersection of four input pixels, the grayscale scale is fixed, and the coordinate range includes every affected pixel. Faint hollow dots indicate zero-weight samples.
For the three Kawase downsampling and upsampling kernels above:
| Kernel | Starting angle | Outer samples | Center weight | Ring radius |
|---|---|---|---|---|
There are also the inter-level blend factor and the final blurred-image fraction . For the chain below, the three kernels have four parameters each. With the two blend factors, this gives parameters. The three sample counts are discrete integers, fixed here to . The continuous optimization therefore uses for each kernel, plus : variables. For convenience, write each kernel's parameter group as , with taking the values , , and . A complete solution is .
Defining the Single-Phase Loss and Solving with Gradients
Let be the full-resolution discrete Gaussian kernel with target standard deviation , and let denote the complete Kawase chain. Place a unit impulse at the fixed center location, phase , and minimize the squared error against the target response:
Let and denote 4× and 2× downsampling with their respective kernels, denote 2× upsampling with its kernel, and denote fixed 4× bilinear reconstruction. For input , the intermediate images and two blends are
is the reconstructed, pre-blend image described in the processing-chain section. When , the output is the used in the loss.
The interactive demo below defaults to Levenberg–Marquardt (LM). It uses each output pixel's derivatives with respect to the parameters to estimate parameter sensitivities and interactions, then solves for a joint update direction. For background, see Ceres's explanation of LM.
This approach can be extended to all target values of , fitting Gaussian blur at arbitrary radii.
Comparing the Single-Phase Results
Drag the slider to compare the reference Gaussian, corrected Android Kawase V2, and single-phase impulse fits for target values . The 80 settings are solved independently. At , the original image passes through unchanged, giving 81 slider positions in total.
Loading response data…
The upper half shows the full blurred sinc image at 1×; the lower half shows a single-impulse response. Each half is 512×512, with independent mirror extension at every stage and no mixing across the boundary. All three methods use the same impulse field of view. Enhanced display uses the target Gaussian peak as a shared exposure reference to reveal weak responses. The solid curve is the impulse center row; the gray dashed curve is Gaussian. All three cards share a vertical scale. The grayscale toggle does not change the sinc image, raw curve weights, or impulse error metrics.
The Android baseline retains the level count, sampling kernels, and blend schedule determined by integer blurRadius, corrects the signs of the upsampling heptagon's STEP_4.x and STEP_6.x, and uses a fixed phase-zero registration. For each target , it selects the integer radius whose mean-response width is closest to the target, so its actual width need not match exactly. The optimized chain uses the level count for that setting, fixes the outer sample counts at , and fits each kernel's angle, center weight, and radius, together with the per-level and original-image blend factors.
Each setting supervises only a unit impulse at phase , using the full 2D squared error. L-BFGS-B starts from four fixed initializations and solutions at nearby scales; at , the single-phase parameters in Appendix D are added as initializations. A further refinement round uses the neighboring settings with the same level count, retaining the solution with the lowest error. “Best result” means the lowest-error numerical solution among these candidates, not a proven global optimum. Moving the slider loads the independently solved parameters for that setting and runs the full filtering chain on the GPU in real time. Cross-sections and errors are precomputed from the same parameters' float64 reference responses and cached, avoiding a GPU readback every frame. The Gaussian is sampled discretely at full resolution, truncated at , and normalized.
Each canvas has a width-to-height ratio of : the upper half shows the blurred full sinc image, and the lower half shows a single impulse. Each half is computed separately at . At every sampling stage, out-of-bounds coordinates are mirrored back into their own region before pixel lookup, so the two halves never mix across their boundary. Both Gaussian and Kawase use these mirror boundaries in the interactive figure. Its sinc-image edges therefore differ from the earlier static comparisons, which use clamp boundaries there.
The sinc image in the upper half is always displayed at . The “Enhanced impulse grayscale” toggle controls the lower half of all three images. When enabled, it uses the target Gaussian peak as a shared exposure reference, amplifying weak responses to reveal their shape. When disabled, it displays the raw unit-impulse amplitudes without exposure or peak normalization. This toggle does not change the sinc image, impulse cross-section, or impulse error.
5. Shifting the Input to Check Phase Error
Keep the single-phase optimized parameters for fixed. Call the resulting chain , the sinc test image , and a one-pixel rightward translation . If the chain is shift-invariant, shifting the input before blurring should equal shifting the blurred output:
The comparison must therefore use these two spatially corresponding outputs and inspect their difference:
The evaluation should avoid finite-image boundary effects, and the cross-sections must use consistent spatial coordinates. The actual shifted-image comparison is not yet included.
The input's position relative to the fixed downsampling grid is its phase here. Moving the same local signal changes the weights that enter the sampling grid; subsequent reconstruction spreads those samples back to full resolution.
Dual Kawase repeatedly downsamples and reconstructs on fixed grids. Although it remains linear, it is generally not shift-invariant under single-pixel translations. An impulse response at one phase cannot simply be treated as a convolution kernel shared by every location. A symmetric sampling stencil in an individual pass does not guarantee that the complete response at every input location is symmetric about that input point.
This exposes the omission in the single-impulse loss: even if the supervised response closely matches the Gaussian, responses at other phases remain unconstrained. Further reducing the loss at that one location cannot reveal errors at the others.
The limitation of the single-impulse objective is incomplete supervision. Even if reached zero, it would determine the response at only one location. Moving the impulse to another phase could still produce shape errors. The next step is to enumerate all phases, optimize them jointly, and test whether the same sampling budget allows further improvement.
Polyphase Kawase Optimization
1. Polyphase Impulse Responses
The Polyphase Supervision Framework
Section 4.2 of the DPF paper models fixed-grid multiresolution filtering chains as linear periodically shift-varying systems (LPSV). Away from boundaries, a one-pixel translation may change the response shape, but the response pattern repeats after a full sampling period.
The paper extends single-impulse supervision to polyphase impulse supervision. Offline, unit impulses are placed at different locations within one period and processed by the same chain. The target kernel is translated to each corresponding input location. The squared errors of all responses against their targets are summed, and differentiable filtering operations are used to optimize sparse sample positions and weights. At runtime, images are processed directly with the solved kernels; the multiple impulses are needed only for offline optimization.
The full DPF method also includes Spatial-to-Depth, asymmetric sampling of luminance and chrominance, and hierarchical selection for variable kernels. Here, only its polyphase supervision method is applied to the previously defined shared kernels and blend-parameter family, to test the effect of completing the supervised phase set. Sample counts, level counts, and parameter constraints remain the same as in B.
σ=4: Enumerating Every Input Phase
To show every phase explicitly, this section uses , with an initial 4× downsample followed by one 2× downsample. Single-phase fitting is repeated for this target to obtain B at this scale. The subsequent polyphase optimization also fixes , with the same level count and parameter bounds. First, inspect the single-phase fit at this scale:



Keep B's kernels unchanged and vary only the impulse location. For a chain with an initial 4× downsample, followed by levels of 2× downsampling and corresponding reconstruction, the per-axis phase period can be taken as
excludes the initial 4× downsample. At , , requiring input phases; at , , requiring . At a given scale, A, B, and C use the same chain structure and phase set.
Choose a reference location far from the boundaries, with both coordinates divisible by , and place the unit impulse at . Define the response relative to its own input location:
The center location supervised by single-phase fitting corresponds to . The figure below defaults to all 64 responses of B at ; Gaussian and A are also available. Each card identifies its phase coordinates. All plots for one method share a display gain and coordinate range; switching methods resets the gain and vertical axis as indicated. The curve's origin always corresponds to the input location. At small radii, A contains a spike from the original-image passthrough and therefore uses a lower display gain.
B · Single-impulse fit · All 64 input phases at σ=4, period 8 per axis. These 64 plots share 20× gain and a vertical range, reset when switching methods. Curves retain raw response values; gray dashed curves are Gaussian. Zero marks the input location.
































































Gaussian responses are identical across phases; A and B vary with phase. Response mass, centroid, and width statistics are provided in Appendix C.
Together, these responses determine the chain's behavior for any input. Away from boundaries, linear superposition gives
A universal convolution kernel can replace the chain only if all input-aligned are identical. B optimizes only one of them, so the next step is to include the entire response family in the loss.
Reevaluating the Single-Phase Fit with a Polyphase Loss
Following Equations (5) and (6) of the paper, translate the target Gaussian to each impulse location. For the complete B/C parameter set , define
translates the centered target kernel to . The right-hand side instead uses coordinates relative to each input point. The target moves with the input, while phase-dependent shape differences remain in the residuals.
Reevaluating all phases gives
where is the side length of one response image. The experiment in this section uses . Worst-phase RMSE is the largest per-phase RMSE. All-phase RMSE aggregates squared errors before taking the square root; it is not the arithmetic mean of the per-phase RMSE values.
Single-phase RMSE evaluates only the directly supervised location, whereas all-phase RMSE aggregates all 64 input phases. They are not interchangeable; numerical values appear in the error table below.
2. Polyphase Optimization at a Single σ
Keeping the Same Optimization Variables
Call the polyphase optimized method C. It retains B's three ring kernels, all blend factors, nonnegative unit-sum weights, radius bounds, and cross-level sharing. It also uses the same four initializations and L-BFGS-B solver. Only the supervised set changes: B uses , while C uses all phases.
Minimizing the Polyphase Loss
Minimizing the loss gives the polyphase optimized method C:
Computing Gradients of Weights and Sampling Offsets
Bilinear interpolation is piecewise differentiable with respect to sample positions, and a weighted sum is differentiable with respect to its weights. Both the single-phase and polyphase least-squares objectives can therefore propagate gradients through the complete chain. The first part uses the same gradient-based approach; this section adds input phases to the loss.
Updating Parameters and Comparing Results
At a fixed , compare the impulse and sinc outputs of Gaussian, single-phase B, and polyphase C. B and C each contain one , one , a cross-level shared , and per-level blend factors. At runtime, the same chain processes the entire image. Complete parameter tables for each scale are in Appendix D.



σ=4 · B/C: initial 4× downsample, 1 levels of 2× down/up · Outputs at 1×






| Method (σ=4) | Phase (0,0) RMSE | All-phase RMSE | Worst-phase RMSE | Sinc-image RMSE |
|---|---|---|---|---|
| B: Single-phase optimization | 3.803e-05 | 5.795e-04 | 8.595e-04 | 3.486e-02 |
| C: Polyphase optimization | 1.956e-04 | 2.357e-04 | 3.117e-04 | 1.531e-02 |
At this scale, all-phase RMSE decreases by approximately 59.34%, and sinc-image RMSE by approximately 56.07%. These metrics evaluate the full impulse-response family and this particular test image, respectively.
C has a larger error than B at , but a lower total squared error across all phases. Thus, B's single-location fit still leaves room for improvement: the same parameter family and sampling budget can produce another set of kernels and blend factors that better approximates Gaussian responses across all phases. C is still constrained by the finite sampling stencils, however, and does not guarantee identical responses at every phase.
3. Polyphase Optimization Across Multiple σ Values
Solving Each σ Independently
Each target scale requires its own level count and kernel parameters. The table below retains two independently solved scales. They establish results only for those two targets, not a continuous mapping from σ to parameters.
| Target σ | 2× downsampling levels N (after the initial 4×) | Per-axis phase period | 2D phase count |
|---|---|---|---|
| 4 | 1 | 8 | 64 |
| 40 | 3 | 32 | 1024 |
Fitting Parameters as Functions of σ
Rerunning the Complete Chain with Fitted Parameters
Polyphase Optimization of Downsampled Blur
1. A Downsampled Blur Chain with Fixed Mipmaps
This section applies polyphase supervision to a shared mipmap-pyramid blur method: first build a shared mipmap pyramid with fixed box kernels, then use a small kernel to sample a selected mip level for each final-resolution output pixel. Blur coverage comes from the combination of the mip level and the final sampling kernel.
This method samples the mipmap directly at the final resolution, rather than following Kawase's level-by-level upsampling chain. The constraints and solution procedure are outlined below; optimization results are not yet included.
2. Optimization Variables and Runtime Constraints
- Fixed, shared mipmap kernels. All σ values use the same fixed downsampling results. Only the final sampling weights and offsets are solved for each σ.
- Fixed sampling budget. Specify the sample count of the final pass and use the same budget for the original and optimized methods. Record the shared mipmap construction cost separately.
- Continuous blur radius. After parameter fitting, inspect outputs at neighboring σ values and around mip-level transitions.
- Retain the original mip-level selection rule. Level selection is not a variable in this round of continuous parameter optimization.
3. Polyphase Optimization Across Multiple σ Values
Solving Each σ Independently
With the shared mipmap and the level for that σ fixed, enumerate input phases and build a polyphase squared-error objective for the final sampling parameters.
Fitting the Final Sampling Parameters
Rerunning the Complete Chain with Fitted Parameters
4. Comparing the Original and Polyphase Optimized Methods
Appendix: Derivations, Additional Comparisons, and Reproduction
A. Revisions to the Android Baseline
A, B, C, and the interactive demos use the same Android-derived implementation. It retains V2's initial 4× scaling, subsequent 2× scaling, inter-level blending, and original-image blending, with the following two revisions. These describe the version used in this article; they do not imply that AOSP has incorporated the changes.
Two Signs in the Direction Constants
The pinned AOSP revision describes the upsampling directions as a regular heptagon, but the signs of STEP_4.x and STEP_6.x do not match the corresponding vertices:
| Constant | Original value | Value used here |
|---|---|---|
| STEP_4.x | +0.900968868 | −0.900968868 |
| STEP_6.x | −0.623489802 | +0.623489802 |
A retains the decimal precision of those constants. B/C and the interactive demo generate directions with the trigonometric functions of a regular heptagon. The heptagon's sample positions have a zero centroid, but are not symmetric about both the x and y axes. Nor does this guarantee that the discrete response's peak lies at its centroid.
Reference-Coordinate Compensation for Downsampling and Upsampling
This article uses input phase as its registration reference. With integer pixel indices, the original implementation's first 4× downsample is equivalent to averaging nonoverlapping input blocks. An impulse at falls into the block indexed , corresponding to low-resolution pixel . The original 4× reconstruction maps its center back to , adding a displacement of original-image pixels per axis to the blurred branch.
Compensation must be applied inside the sampling coordinates of every upsampling pass, before blending with a saved same-level image or the original image. For the current kernel parameters, first generate the downsampling pyramid from a fixed phase- impulse. Let be the centroid of level relative to its reference position, measured in that level's texels. Uncompensated 2× reconstruction maps the child centroid to , so the output displacement to subtract is
is the offset, in input texels, added to that pass's sampling coordinates. It gives the reconstructed branch the same reference centroid as the saved level- image; only then are they blended. The final 4× reconstruction uses , returning the blurred branch to the original-image reference position before the final blend.
These offsets are determined by the kernel parameters and the fixed reference impulse; they are not extra optimization variables. One parameter set uses the same offsets for the entire image and every phase, without repositioning based on the image being processed. Optimization also propagates the offsets' derivatives with respect to the kernel parameters. A zero reference response has no centroid, so a finite neutral fallback is used while retaining the zero response and its loss.
For A's original stencils, . The 2× downsampling weights give exactly , and the final 4× reconstruction requires an output correction of pixels per axis. The original and article sampling positions are then
This simplification does not extend to arbitrary optimized parameters. For example, if both and collapse to center-only sampling, the child response lies at index . Uncompensated 2× reconstruction centers it at parent index , whereas the saved parent response lies at . That 2× upsampling pass therefore needs an extra input texels per axis, correcting half a parent pixel to the left and up. Correcting only the final 4× reconstruction would still blend two internally misaligned branches first.
This procedure retains the downsampling and upsampling stencils and changes only a common coordinate offset for each group of samples. It adds neither prefiltering nor an extra image-translation pass. Once the kernel parameters are fixed, the reference probes and offsets can be precomputed; actual images run only the existing sampling and blending chain.
For blurRadius=6, the uncompensated phase- blurred branch is displaced by pixels per axis, or pixels after blending with the original image. Compensation returns both centroids to the input centroid within numerical error. This is coordinate compensation for a designated reference phase, not per-phase alignment. Other input locations within the same block still share the first-level samples. Moving the impulse diagonally to phases yields complete-output displacements of pixels per axis. These genuine phase differences enter the main polyphase loss unchanged.
The original per-pass audit is saved in android-coordinate-audit.json. The article's version of A is checked with verify_aosp_kawase_v2_skia --registered. Its original stencils have zero internal offsets; in the independent Skia execution, the final blur shader's matrix translation is set to original-image pixels before comparison with the float64 implementation. CPU F32 validation covers all 64 phases at , eight distributed phases each at , the sinc image, and odd-sized image boundaries. Results are recorded in android-registered-skia-validation.json.
For variable kernels, test_android_kawase_core.py additionally covers center-only and general kernels at . It compares per-level centroids before and after blending and checks final reference registration, other-phase differences, direct rendering against frequency-domain evaluation, and full gradients including offset derivatives. The interactive demo has corresponding TypeScript checks.
B. Gaussian5x5 Single-Stage Impulse Experiment
Centered Impulse
This single-stage chain illustrates impulse evaluation: Gaussian5x5 prefiltering, 2× decimation on the even grid, a Gaussian with at low resolution, and reconstruction with a triangle kernel. It isolates the decimation grid's effect on the impulse response. The main Kawase fits use a different, complete chain. Here, the processing chain is again denoted by , with centered impulse response .


Gaussian5x5 single-stage equivalent kernel

Impulse Shifted One Pixel to the Right
Keep the chain and kernel parameters fixed, and move only the input impulse one pixel to the right. If the system is shift-invariant, the new output must be exactly the original response shifted right:
Using the same Gaussian5x5 single-stage demo chain and changing only the input position gives:


Gaussian5x5 single-stage equivalent kernel

Compared with the centered response, the output changes shape as well as position:
The decimation grid remains fixed. An impulse at an even location and one at an odd location place prefiltered weights on different sample positions, changing the values that enter the low-resolution image. Reconstruction then spreads those samples back to high resolution. The input's position relative to this fixed grid is its phase.
C. Per-Phase Response Statistics
Gaussian responses are identical across phases; Kawase-chain responses can still vary with phase. A, B, and C all use period , giving 64 phases at and 1024 at . The metrics enumerate every phase.
Response mass is the sum of the weights. Centroid displacement uses the input point as the origin, and per-axis is calculated from the second moment about the response's own centroid. Equal mass and centroid do not imply equal width, peak, or shape. The upsampling kernel is a heptagon, so responses must not be additionally averaged with their reflections about both axes. The mean-response width used for radius calibration also differs from the range of single-phase widths.
| Method | Phase count | Zero responses | Response mass range | Nonzero per-axis σ range | Max per-axis centroid displacement / px |
|---|---|---|---|---|---|
| Gaussian | 64 | 0 | 1.000000 – 1.000000 | 4.0000 – 4.0000 | 0.0000 |
| Android Kawase V2 | 64 | 0 | 1.000000 – 1.000000 | 3.7924 – 4.1115 | 1.8000 |
| B · Single-impulse fit | 64 | 0 | 0.011936 – 1.516197 | 3.9149 – 4.0019 | 7.9551 |
| Method | Phase count | Zero responses | Response mass range | Nonzero per-axis σ range | Max per-axis centroid displacement / px |
|---|---|---|---|---|---|
| Gaussian | 1024 | 0 | 1.000000 – 1.000000 | 39.9997 – 39.9997 | 0.0000 |
| Android Kawase V2 | 1024 | 0 | 1.000000 – 1.000000 | 39.6610 – 40.0073 | 3.0000 |
| B · Single-impulse fit | 1024 | 0 | 0.987726 – 1.018213 | 38.9098 – 40.7909 | 3.8414 |
D. Complete Parameters, Additional Comparisons, and Error Analysis
Kernel Parameters and Fit Metrics at Two Target Scales
A uses the Kawase baseline parameters described above. B and C are solved with single-phase and polyphase objectives, respectively. The tables below summarize parameters and impulse errors at and . Each scale uses its own parameters; B and C share the same sampling budget and parameter bounds.
| Method | Kernel | θ / rad | w_c | a / input texels |
|---|---|---|---|---|
| B · Single-impulse fit | K_d,4 | 0.535265 | 0.369428 | 1.752996 |
| B · Single-impulse fit | K_d,2 | 2.013296 | 0.999963 | 0.398384 |
| B · Single-impulse fit | K_u | 0.496114 | 0.026407 | 0.250000 |
| C · Polyphase optimization | K_d,4 | 0.785398 | 0.000009 | 1.404174 |
| C · Polyphase optimization | K_d,2 | 0.785398 | 0.199184 | 1.335039 |
| C · Polyphase optimization | K_u | 0.161356 | 1.000000 | 0.250000 |
| Method | α_0 | β |
|---|---|---|
| B · Single-impulse fit | 0.988770 | 1.000000 |
| C · Polyphase optimization | 0.914917 | 0.996897 |
| Method | Kernel | θ / rad | w_c | a / input texels |
|---|---|---|---|---|
| B · Single-impulse fit | K_d,4 | 0.785398 | 0.002948 | 1.410899 |
| B · Single-impulse fit | K_d,2 | 0.769632 | 0.297705 | 1.503566 |
| B · Single-impulse fit | K_u | -0.113638 | 0.389194 | 1.573893 |
| C · Polyphase optimization | K_d,4 | 0.785398 | 0.000000 | 1.414104 |
| C · Polyphase optimization | K_d,2 | 0.783856 | 0.019230 | 1.140882 |
| C · Polyphase optimization | K_u | 0.004392 | 0.373370 | 1.546569 |
| Method | α_0 | α_1 | α_2 | β |
|---|---|---|---|---|
| B · Single-impulse fit | 0.999995 | 0.999846 | 1.000000 | 1.000000 |
| C · Polyphase optimization | 1.000000 | 1.000000 | 1.000000 | 1.000000 |
| Method | (0,0) RMSE | All-phase RMSE | Worst-phase RMSE |
|---|---|---|---|
| Gaussian | 0 | 0 | 0 |
| Android Kawase V2 | 3.262e-3 | 3.159e-3 | 3.262e-3 |
| B · Single-impulse fit | 3.803e-5 | 5.795e-4 | 8.595e-4 |
| C · Polyphase optimization | 1.956e-4 | 2.357e-4 | 3.117e-4 |
| Method | (0,0) RMSE | All-phase RMSE | Worst-phase RMSE |
|---|---|---|---|
| Gaussian | 0 | 0 | 0 |
| Android Kawase V2 | 1.760e-6 | 1.864e-6 | 2.049e-6 |
| B · Single-impulse fit | 2.063e-7 | 8.268e-7 | 1.399e-6 |
| C · Polyphase optimization | 3.026e-7 | 5.494e-7 | 1.027e-6 |
σ=4: phase-(0,0) RMSE is 3.803e-5 for B and 1.956e-4 for C. All-phase RMSE changes from 5.795e-4 (B) to 2.357e-4 (C), a 59.34% reduction.
σ=40: phase-(0,0) RMSE is 2.063e-7 for B and 3.026e-7 for C. All-phase RMSE changes from 8.268e-7 (B) to 5.494e-7 (C), a 33.55% reduction.
Additional Sinc-Image Comparisons
First, compare Gaussian, Kawase baseline A, and single-phase B at ; then compare Gaussian, B, and C at . Image computation and AE display conventions are given in Appendix E.
σ=4 · A: Android blurRadius=6; B: initial 4× downsample, 1 levels of 2× down/up · Outputs at 1×






σ=40 · B/C: initial 4× downsample, 3 levels of 2× down/up · Outputs at 1×






σ=4: sinc-image RMSE is 3.486e-2 for B and 1.531e-2 for C, a 56.07% decrease. This percentage compares only B/C, with identical sampling budgets, parameter families, and boundary rules.
σ=40: sinc-image RMSE is 4.631e-3 for B and 4.596e-3 for C, a 0.75% decrease. This percentage compares only B/C, with identical sampling budgets, parameter families, and boundary rules.
The tables report all-phase impulse errors and sinc-image errors separately. All-phase supervision improves the response objective over the full kernel support. Finite images also involve per-level clamp boundaries and the structure of the particular input. These two metrics are not interchangeable.
Mean-Kernel Shape Error and Phase Variation
To distinguish mean-shape approximation error from phase variation, take the mean of the input-aligned responses:
The squared error has the exact decomposition
The cross term vanishes because . Even if the mean response closely matches a Gaussian, the total error remains nonzero while the phases differ. The last two table columns divide these two terms by the response pixel count and take their square roots. The sum of their squares therefore equals the square of the all-phase RMSE.
| Method | Image RMSE | Max AE | Interior RMSE | Mean-kernel shape RMSE | Phase variation RMS |
|---|---|---|---|---|---|
| Gaussian | 0 | 0 | 0 | 4.838e-19 | 0 |
| Android Kawase V2 | 5.722e-2 | 4.984e-1 | 5.966e-2 | 3.145e-3 | 2.986e-4 |
| B · Single-impulse fit | 3.486e-2 | 3.066e-1 | 3.633e-2 | 3.870e-4 | 4.314e-4 |
| C · Polyphase optimization | 1.531e-2 | 2.209e-1 | 1.604e-2 | 2.000e-4 | 1.247e-4 |
| Method | Image RMSE | Max AE | Interior RMSE | Mean-kernel shape RMSE | Phase variation RMS |
|---|---|---|---|---|---|
| Gaussian | 0 | 0 | 0 | 1.925e-19 | 0 |
| Android Kawase V2 | 4.809e-3 | 2.889e-2 | 2.187e-3 | 1.817e-6 | 4.121e-7 |
| B · Single-impulse fit | 4.631e-3 | 3.029e-2 | 1.826e-3 | 4.441e-7 | 6.974e-7 |
| C · Polyphase optimization | 4.596e-3 | 3.055e-2 | 1.713e-3 | 2.874e-7 | 4.682e-7 |
“Interior RMSE” excludes a 32-pixel border on all four sides of the original image. For the large-support kernel, that region may still be affected by boundaries; it is not a fully boundary-free experiment.
B's single-impulse objective constrains one designated response; moving from B to C fills in the missing phase supervision. A, B, and C use the same chain structure. A only matches an integer radius, whereas B/C optimize kernel and blend parameters. The polyphase loss does not separately guarantee reductions in centroid error, worst-phase error, or error on every image.
Impulse Metrics and Actual Image Error
For input noise with independent, zero-mean, equal-variance pixels, expected output-error energy is proportional to the summed squared response errors. Real images have spatial correlations, so response errors from different locations can cancel or reinforce one another. Downsampled blur should therefore be evaluated using both the complete polyphase impulse responses and actual images: the former measures approximation across input locations; the latter tests the result for specific images and boundary conditions.
E. Numerical Configuration and Reproduction
Matching the Android Radius to the Target σ
A uses the baseline defined in Appendix A. Its stencil weights, level schedule, sampling distances, and blend factors are determined by integer blurRadius. This radius is not the Gaussian standard deviation, and the width at one phase cannot represent the whole chain.
For every candidate radius , align all responses in its full period to their respective input locations and average them, producing unit-mass . Let its centroid be . The matching scale is the mean of the two central variances:
This step matches spread only; it does not fit weights or offsets using Gaussian response-shape error. The numerical implementation propagates moments through every sample and interpolation, and is verified by explicitly enumerating all phases. It includes the initial downsample, progressive reconstruction, inter-level blending, final 4× enlargement, and small-radius blend. Measuring width with central moments does not shift the output: images and losses still use the input point as their origin.
Targets select integer radii , with mean-response standard deviations of approximately . Integer steps are coarse at small radii, so width matching itself has a residual; see the table above.
To reproduce Android's internal radius schedule, the numerical port follows the source directly: , continuous depth , , and . The source's step, denoted by , is uniquely determined by these quantities; radius matching searches only over . In shader coordinates,
When , set . In an exactly 2× upsampling pass, shader pixels correspond to input texels.
Static figures and numerical metrics use float64 linear luminance; the interactive σ-slider images use float32 shaders. The scope of the independent Skia checks is described in Appendix A. These are neither Android-device screenshots nor performance measurements.
Impulse Responses and Solver Configuration
is centered on the input impulse. The loss sums every pixel of the full 2D response; cross-sections are only a visualization. Fitting retains raw response values without peak or mass normalization, and evaluation does not separately recenter output centroids. The Gaussian target is truncated at per axis and normalized. The fixed-parameter B/C comparisons use with response canvases at , and with canvases at . The final figures cover the complete kernel support. During search, if a candidate exceeds that support, the evaluation canvas expands automatically to avoid circular-convolution aliasing. Impulse rendering uses a larger zero background to isolate boundaries.
Although the residuals form a least-squares objective, the full multilevel chain depends nonlinearly on sample distances and weights. The fixed-parameter B/C comparison uses L-BFGS-B with analytic gradients and parameter bounds. It solves from four initializations for at most 180 iterations each, then retains the lowest-loss result. The solver scales the loss only by a fixed target energy, which does not change the optimum. “Optimized result” means the best result found within these bounds and initializations, not a proven global optimum.
The σ slider's 80 single-phase fits allow up to 250 iterations per initialization, with nearby-scale solutions and the same-scale single-phase parameters from Appendix D as additional starts. This parameter table is stored independently; the later all-phase statistics for B/C still correspond to the fixed parameters in Appendix D. Slider rendering and RMSE computation use , while fitting adapts the canvas to kernel support. Both contain the complete response, so the ratio of squared error to target energy is unaffected by the amount of zero background.
The large-scale chain has 1024 phases. To avoid retaining 1024 large response images during optimization, the numerical implementation uses correlation operations on the cascaded filters to compute the exact all-phase squared error and its gradient. This is equivalent to summing the objectives for every phase individually. The final kernels are also checked against an independent per-pixel sampling and blending chain, and evaluation explicitly enumerates all phases.
Image and Error Display Conventions
Each comparison identifies its participating methods in the headings. Static images are computed in float64 linear luminance. A/B/C use clamp boundaries inside the pyramid and mirror boundaries for final reconstruction; Gaussian uses clamp. In comparisons with AE, each column shows the actual output above its absolute error relative to Gaussian: .
All static outputs are displayed at . Within one scale, AE uses the fixed gain indicated in the figure, with white representing zero error and no display clipping. The two scales use different gains, so error magnitudes cannot be compared across scales by darkness alone. Gaussian's error against itself is entirely white. The σ slider's raw mode displays response on white as ; enhanced mode uses . Display values are clamped to ; raw curves and metrics do not use this mapping.
Reproduction Commands and Validation Scope
The four opening Gaussian / Android V2 comparisons can be generated separately with python3 -m scripts.generate_android_sinc_comparison. Radii, image errors, and the source-image hash are recorded in content/blog/differentiable-polyphase-filtering/android-sinc-comparison-data.json.
Regenerate σ-slider parameters with python3 -m scripts.fit_single_phase_sweep, which requires NumPy, SciPy, and Numba. --resume continues from saved settings, and --workers 1 uses one process. After the first round, run python3 -m scripts.fit_single_phase_sweep --polish to add neighboring same-level settings as initializations. single-phase-sweep-data.json stores each setting's parameters, coordinate compensation, integer radius, initializations, and final losses. Then run bun scripts/generate_single_phase_cache.ts to package shader parameters, float64 cross-sections, and errors into one compressed cache, without storing images for every setting. python3 -m unittest scripts.test_single_phase_sweep checks full spatial rendering, frequency-domain loss, and gradients. bun test content/blog/differentiable-polyphase-filtering/single-phase-response.test.ts checks all 80 reference responses, zero-scale passthrough, and agreement between the cache, source parameters, center-row samples, and errors. single-phase-image.test.ts separately checks software mirror extension, Gaussian agreement with direct 2D convolution, and preservation of the existing impulse responses and constant inputs under mirror boundaries.
Reproduction. Running python3 -m scripts.fit_polyphase_dual_kawase solves B/C again and generates the figures and content/blog/differentiable-polyphase-filtering/four-way-blur-data.json. Add --reuse-fits to regenerate results directly from saved parameters. The data records the source-image hash, sampling conventions, final positions and weights, all-phase metrics, and losses from the four initializations. The optimizable full chain is in scripts/android_kawase_core.py; the Android V2 port and radius calibration are in scripts/aosp_kawase_v2.py. Validate with python3 -m unittest scripts.test_android_kawase_core scripts.test_polyphase_dual_kawase scripts.test_aosp_kawase_v2 scripts.test_aosp_kawase, covering per-pass sampling, analytic gradients, all-phase loss, an independent renderer, and image metrics.
Optionally install skia-python==144.0.post2 and run python3 -m scripts.verify_aosp_kawase_v2_skia --registered --sigmas 4 8 16 40 to check the article baseline. Omitting --registered checks the historical version in scripts/aosp_kawase_v2_reference.py, which changes only the two signs. Validation records for both versions and an explanation of their position differences are in Appendix A.
F. Legacy Android Kawase Reference
AOSP also includes the older KawaseBlurFilter.cpp. Its initial 4× downsample already uses radius-dependent offsets. It then runs up to four blur passes at the same low resolution, each sampling the center and four diagonals with weight per tap. Its sampling coverage and pyramid structure differ from the V2 implementation used for A.
Matching the legacy implementation to using the same mean-response width criterion selects blurRadius=92. Its first pass has an original-image offset of and sampling centers at . It reads only input pixels whose per-axis indices are congruent to one or two modulo four, completely missing impulses in 12 of the 16 phases. The original V2 implementation covers the complete initial block, avoiding these complete omissions; the main article uses the coordinate convention defined in Appendix A. The legacy numerical port and validation are retained in scripts/aosp_kawase.py and scripts/test_aosp_kawase.py, and are not included in A's data.




