Straighten a tilted video by API: rotate, then crop by angle

Level a crooked horizon with Sume video filter: rotate in radians, crop out the corners with a factor per angle (0.97 at 1 degree), scale back. $0.02.

5 min readSume
All posts

To straighten a clip whose horizon slopes, send Sume's video filter a rotate by the opposite angle, then crop away the black corners the rotation exposes and scale back: rotate=a=-2*PI/180:fillcolor=black,crop=w=floor(iw*0.94/2)*2:h=floor(ih*0.94/2)*2,scale=w=floor(iw/0.94/2)*2:h=floor(ih/0.94/2)*2. For a 2 degree tilt the crop factor is 0.94; the table below gives the factor for other angles.

This is a different problem from perspective correction or a clip that plays sideways because of its rotation flag. Here the camera was simply held a few degrees off level, which is common with handheld phone footage. Video inspect tells you about the flag; your eyes tell you about the tilt.

Which way do I rotate, and how big is the angle?

Positive a turns the picture clockwise. A horizon that dips to the right is tilted clockwise, so you rotate counter-clockwise with a negative value. a=-2*PI/180 converts 2 degrees to radians inside the expression, and the filter accepts PI.

To measure the tilt, pull a still with video frames and read the angle off a straight edge, or use the thirds grid review described in another post. Start from a small angle; rotating further than 5 degrees costs a lot of frame.

How much must I crop?

Rotation leaves empty corners. The largest same-shaped rectangle that fits inside a rotated frame has a scale of min(w / (w cos t + h sin t), h / (w sin t + h cos t)). I computed it for three common shapes and rounded down to two decimals so the corners are always gone. I also ran the 2 degree, 0.94 case on a white 1080x1920 test frame with a local ffmpeg build and all four corner pixels stayed white.

  • The crop and scale use floor(.../2)*2 so both sides stay even, which a yuv420p encode requires.
  • The last scale returns to within a couple of pixels of the source size: 1080x1920 comes back as 1078x1918 with a 0.94 factor.
  • Zoom costs sharpness. If the clip is short on pixels, run the Sume video upscale afterwards rather than shipping a soft frame.
Crop factor after rotate, rounded down (computed 2026-10-11)
Tilt9:16 or 16:91:1
0.5 degrees0.980.99
1 degree0.970.98
2 degrees0.940.96
3 degrees0.910.95
5 degrees0.860.92

How do I run it?

Run the check route, read the compiled filter names (rotate, crop, scale), then submit the encode with an idempotency key. The graph contains no commas outside parentheses and no forbidden characters, so it passes the contract check.

The source must be a Sume-hosted clip of 300 seconds or less, and an HDR or non-YUV clip fails closed.

curl -X POST https://api.sume.com/v1/video-filter/check \
  -H "Authorization: Bearer $SUME_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "video_url": "https://media.sume.com/artifacts/artf_demo/clip.mp4",
    "filtergraph": "rotate=a=-2*PI/180:fillcolor=black,crop=w=floor(iw*0.94/2)*2:h=floor(ih*0.94/2)*2,scale=w=floor(iw/0.94/2)*2:h=floor(ih/0.94/2)*2"
  }'

What can't this fix?

A single fixed angle assumes the tilt is constant. If the camera rolls during the shot, a fixed rotation will correct one moment and worsen another; Sume has no stabiliser on the allowlist, so split the clip into ranges with video trim and give each its own angle.

Sources

Related posts

More in Media tools

All Media tools posts

Written by Sume