How to Fix Lens Distortion in Video: Barrel, Fisheye and the Crop Tax
18 October 2026

How to Fix Lens Distortion in Video: Barrel, Fisheye and the Crop Tax

Your horizon curves up at the edges, the doorframe in the corner leans, and the wide shot looks like it was filmed through a marble. That’s lens distortion, and it’s the one problem every phone, action camera and wide lens adds for free. I spent a day measuring what FFmpeg does when you correct it, and two results changed how I shoot: the lens distortion fix always costs frame area, and the value most tutorials recommend overshoots by about 25%.

The part nobody warns you about: the lens distortion filter doesn’t just bend the image back. Push it the wrong way and it paints up to 28% of a 1080p frame with fill colour. Zoom in first to make room for the correction, and nothing changes at all, not one pixel.

What you’ll learn

  • Which direction k1 has to go, and why the sign isn’t obvious
  • How much of the frame a lens distortion correction eats, measured at four strengths
  • The command I ran on a real clip, and why the zoom has to come after it

What lens distortion is

Every lens bends light more at the edges than the middle. Barrel distortion pushes straight lines outward at the frame edge, which is what a wide lens does; pincushion pulls them in, which is what a long zoom does at its close end. A fisheye isn’t a stronger barrel: it’s a different projection, and that distinction decides which tool you need.

FFmpeg models barrel and pincushion with a radial polynomial. For each output pixel it computes r² from the distance to the centre, normalised so r² = 1 at the frame corner, then samples the input at centre + (1 + k1*r² + k2*r⁴) * offset. That last detail is what people miss. The polynomial runs on the output pixel’s radius, not the source’s, which is why a lens distortion correction isn’t the negative of the distortion.

Which way the lens distortion correction has to go

I put a 1920×1080 lattice on a flat grey field, one line every 240 pixels, and ran the filter at nine strengths. The results are unambiguous, and they’re the opposite of what “negative for barrel” suggests if it sounds like a strength dial.

k1 Fill pixels Share of frame What happens to the content
-0.4 0 0.00% zoomed in hard, corners pushed off frame
-0.2 0 0.00% zoomed in, whole frame still filled
+0.1 221,588 10.69% image shrinks, fill appears at the edges
+0.2 375,517 18.11% more shrink, thicker fill border
+0.4 585,808 28.25% the corners are gone

Negative values magnify. Positive values shrink and leave a border. So for a barrel-distorted wide shot, where the image already spreads outward at the edges, you want the negative direction and you pay in field of view. A lens distortion correction at the frame edge always costs frame area, because you’re asking for content the sensor recorded closer to the border.

One number makes it concrete. At k1 = -0.2 the sampling multiplier is 0.848 at the middle of the left edge and 0.800 at the corner. The filter reads source pixels 15% to 20% closer to the centre than the output pixel it fills, so every corrected frame is a slightly different framing. Cut against an uncorrected angle and it jumps.

k2 is the corner term, not a second strength

The two terms of a lens distortion model don’t do the same job at different volumes. Because k2 multiplies r⁴, it barely touches the middle and hits the corners hardest. Measured at matched magnitudes, k1 and k2 leave the corner in nearly the same place (0.850 against 0.851), but k1 pulls the mid-edge much further in (0.886 against 0.914):

Setting Mid-edge Corner Corner ÷ edge
k1 = -0.15 0.886 0.850 0.959
k2 = -0.15 0.914 0.851 0.931
k2 = -0.30 0.828 0.702 0.848

If only the corners bend, move k2. If the whole edge bows, move k1. Most lenses want a small mix, and most tutorials hand you a single value and stop.

The crop tax, and the order that decides it

The crop tax of a lens distortion fix: zooming before the filter leaves 437,511 fill pixels at every level, zooming after it clears them at 1.2x
Scaling before the filter changes nothing at all. Correction, then scale, then crop.

A correction that magnifies has to give something back, and that something is the corners. You can hide the fill by zooming into the corrected frame, but only if the zoom happens on the right side of the filter. I tested both orderings at five zoom levels.

Zoom Scale, crop, then correct Correct, then scale and crop Resolution after
1.00x 437,511 fill px 437,511 fill px 1920×1080
1.10x 437,511 fill px 119,391 fill px 1745×981
1.20x 437,511 fill px 0 fill px 1600×900
1.40x 437,511 fill px 0 fill px 1371×771

The left column doesn’t move by one pixel across all five levels. Scaling up and cropping back to the same size before the filter hands it exactly the frame it would have had, so the fill is identical. The lens distortion correction has to come first, then the scale, then the crop. At 1.2x the fill is gone and you’re left with the centre 1600×900 of a 1080p frame, which is the honest price. That’s also the argument for shooting wider than you need, and the crop guide covers the same arithmetic.

Finding the right lens distortion value without a profile

Residual bow after a lens distortion correction on a 1080p clip: 34.5 pixels uncorrected, 6.0 at k1 -0.15, and 27.5 at the mirror value
The mirror value overshoots: -0.15 leaves 6 pixels of bow where -0.25 leaves 27.5.

Without a lens profile you estimate by sweeping and watching a straight edge. I built a grid, distorted it with k1 = +0.25 to stand in for a wide lens, then swept the correction in nine steps and traced the top line column by column.

The uncorrected clip bowed 34.5 pixels across 1,655 pixels of width, 2.09% of the frame. The best corrections, at k1 = -0.15 and -0.18, brought that to 6.0 pixels, a drop of 83%. The mirror value, -0.25, left 27.5 pixels: it overshoots and reverses the bow at the ends instead of flattening it. That’s the trap in one line. A lens distortion correction isn’t the negative of the distortion, because the polynomial is evaluated on output coordinates, so you’re solving a different equation than the one that made the mess.

The still grid agreed: +0.25 corrected with -0.25 left a 27.5 pixel offset, where -0.20 left 4.0. Start near 80% of the mirror, then sweep in steps of 0.02 against a horizon.

The command I ran, and what it produced

This is the exact command, on a 5 second 1080p30 clip with AAC audio rather than a single frame. Correction first, then a 1.12x scale, then the crop back to 1920×1080.

ffmpeg -i distorted.mp4 -vf "lenscorrection=cx=0.5:cy=0.5:k1=-0.20:k2=0:i=bilinear,scale=2150:1210:flags=lanczos,crop=1920:1080" -c:v libx264 -crf 20 -preset medium -c:a copy fixed.mp4

It returned exit code 0, kept the audio through -c:a copy, and the delivered file measured 5.000 seconds with a 1920×1080 H.264 stream. Read the filter order, because it carries the lesson from the table above: lenscorrection, then scale, then crop. Reversing the first two leaves the bow at 33.62 pixels against 6.0 in the correct order, which is within a pixel of doing nothing. The scale target is 2150×1210 because 1920×1.12 is 2150.4 rounded to even numbers.

nearest vs bilinear, measured

The default interpolation is nearest, and the gap between the two modes isn’t cosmetic. I checked what each does with no warp at all, k1 = 0, where an ideal resampler should pass the frame through untouched. Nearest is a pixel-exact identity: zero pixels changed. Bilinear changed 15,120 pixels, shifted the whole frame half a pixel toward the top left (a line centred on column 240.0 came back at 239.5) and moved values by up to 64 levels at line edges. So a bilinear pass at zero strength already softens one-pixel features and nudges the frame.

On one-pixel lines the trade reverses. At k1 = -0.5, nearest kept every line at full 255 brightness but resampled them into uneven widths, while bilinear spread each line wider and dropped the dimmest peak to 135, with a mean of 215. Nearest protects thin highlights; bilinear protects smooth gradients. For a lens distortion pass on footage with fine detail, bilinear is the right default, and it costs 3.01 to 3.05 seconds per 300 frames of 1080p against 1.30 to 1.32 for nearest on a 2 CPU quota. Roughly 2.3x the filter time for the mode you want.

Fisheye is a different problem from lens distortion

Barrel distortion is a radial bend, and a polynomial can undo it. A fisheye is a projection: the geometry differs at every radius, and no lens distortion value turns it into a rectilinear frame. FFmpeg has a separate filter, v360, which converts between projections. The command needs d_fov:

ffmpeg -i gopro.mp4 -vf "v360=input=fisheye:output=flat:d_fov=120:w=1920:h=1080:interp=lanczos" -c:v libx264 -crf 20 -c:a copy defished.mp4

Set h_fov and v_fov together on the fisheye output and the frame collapses: on my test grid only the centre column of pixels survived. d_fov, the diagonal field of view, is the parameter that produces a real fisheye. If a defish gives you a blank frame, change that first.

Then the resolution news, which is worse than most guides admit. A 120° fisheye built from a 1920×1080 grid put its content in 1,652×827 pixels, not the full frame. Converting back to full rectilinear upscales about 0.5 megapixels of real detail into 2.07 megapixels of canvas, and the round trip measured 17.93 dB against the original. Defishing redistributes detail rather than restoring it.

Running a lens distortion polynomial on a fisheye frame confirms it can’t do the job. Across k1 from -0.6 to +0.6, the best match against the flat original sat at 18.61 dB at k1 = -0.4, with every other value between 10.8 and 18.5. The filter bends the frame; it never resolves the projection.

Which tool for which job

Picking a tool for lens distortion is picking a projection, and the cost column is the part that matters:

Problem Tool Cost What to set
Barrel from a wide lens lenscorrection 1.2x crop negative k1, 80% of the mirror
Corners only lenscorrection same crop small k2, k1 near zero
Fisheye (GoPro, DJI) v360 up to 2x upscale d_fov, interp=lanczos
Stacked fixes one combined pass one generation never chain two corrections

Two bilinear passes shift the frame a full pixel between them. Combine the values instead.

Common mistakes

Using the mirror value. Measured above: -0.25 against a +0.25 distortion left 27.5 pixels of bow where -0.20 left 4.0. A lens distortion correction isn’t symmetric because the polynomial runs on output coordinates.

Zooming before the filter. The fill stayed at 437,511 pixels at every zoom level from 1.0x to 1.4x. Correction comes first.

Leaving interpolation on nearest. It’s the default. On diagonals you get alternate-column shimmer that survives compression and looks like a codec problem.

Correcting before you cut. A lens distortion correction changes the framing, so cut first if you’re matching shots, or apply the same values to every angle.

FAQ

Does lens distortion correction reduce quality?

Yes, twice over. It resamples every pixel once, and cropping out the fill keeps 69% of the frame area at 1.2x, which is 1600×900 from a 1080p source.

Can I fix lens distortion without cropping?

Only if the correction shrinks instead of magnifying, which means positive k1 and a fill border. At k1 = +0.2 that border is 18.11% of a 1080p frame. You either crop or you keep it.

The short version

Lens distortion correction is a radial resample, and every number above came from measuring it rather than repeating a recipe. Negative k1 magnifies and costs field of view. Positive k1 shrinks and paints fill, up to 28% of the frame at +0.4. The correction goes before the zoom. The inverse sits near 80% of the mirror, not at it. A fisheye needs v360, because no polynomial turns a projection into a rectilinear frame.

If you take one thing away, take the ordering. Most “the filter did nothing” reports are a zoom on the wrong side of the filter, and it’s a one-word fix. The edge-darkening cousin of this problem behaves the same way: the vignette measurements show a default that looks gentle and a setting that quietly eats a seventh of the frame.

For reference, the lenscorrection filter page lists the options and the optics article explains why barrel and pincushion exist. If you’re resampling for delivery rather than repair, the upscaling guide covers what a 1.2x crop does to perceived sharpness, and the flip guide covers the other geometric transform that has to happen before the crop.