v9.1.1
Menu

Rolling Shutter Correction

hardPROVideo StabilizationCVCV: Motion Estimation

Implement a rolling shutter correction algorithm to rectify distorted video frames using gyroscope data. This task involves compensating for the skew caused by camera rotation during the rolling shutter capture process, where each row is captured at a slightly different time.

The rolling shutter effect is a consequence of the way images are captured in most cameras, where the sensor reads out the pixel values row by row, rather than all at once. When the camera rotates during this process, it results in a skewed image, which can be modeled using affine transformations. The gyroscope data provides the per-row rotation, which can be used to apply an inverse transformation to correct the distortion.

To achieve this, the following steps are involved:

  1. Understand the rotation matrix and how it relates to the gyroscope data.
  2. Apply the inverse rotation to each row of the image.
  3. Resample: each output pixel copies a pixel from the same row of the input, at the (generally non-integer) source column rounded down.
(x′y′)=(cos⁡(θ)−sin⁡(θ)sin⁡(θ)cos⁡(θ))(xy)\begin{pmatrix} x' \\ y' \end{pmatrix} = \begin{pmatrix} \cos(\theta) & -\sin(\theta) \\ \sin(\theta) & \cos(\theta) \end{pmatrix} \begin{pmatrix} x \\ y \end{pmatrix}

Exact mapping

For a frame of height HH and width WW, let cx=W/2c_x = W/2, cy=H/2c_y = H/2 and θy=−ry\theta_y = -r_y, the inverse of row yy's rotation ryr_y. Output pixel (x,y)(x, y) takes its value from input row yy, column ⌊xs⌋\lfloor x_s \rfloor, where

xs=cx+(x−cx)cos⁡θy−(y−cy)sin⁡θyx_s = c_x + (x - c_x)\cos\theta_y - (y - c_y)\sin\theta_y

(the first row of the rotation above, applied about the image centre). If xs<0x_s < 0 or xs≥Wx_s \ge W, the output pixel is 00. For RGB frames all three channels are copied together. Return an 8-bit unsigned integer array with the same shape as the input.

This technique is widely used in video stabilization applications.

Example

Input
Frame and rotation per row
Output
Corrected frame
Reasoning
  • Inputs: a 4×44\times4 grayscale frame with rows [10,20,30,40][10,20,30,40], [50,60,70,80][50,60,70,80], [90,100,110,120][90,100,110,120], [130,140,150,160][130,140,150,160], and one angle per row, [0.3,0,0.2,1.0][0.3, 0, 0.2, 1.0] radians. The centre is cx=cy=2c_x=c_y=2.
  • Row 1 has angle 00, so xs=xx_s=x and it is copied unchanged: [50,60,70,80][50,60,70,80].
  • Row 2 lies on the centre line (y−cy=0y-c_y=0), so only the cosine acts: xs=2+(x−2)cos⁡0.2x_s=2+(x-2)\cos 0.2 gives 0.04,1.02,2,2.980.04, 1.02, 2, 2.98. The last pixel reads column 2: [90,100,110,110][90,100,110,110].
  • Row 0 (y−cy=−2y-c_y=-2, θ=−0.3\theta=-0.3): xs=2+0.955(x−2)−0.591x_s=2+0.955(x-2)-0.591 gives −0.50,0.45,1.41,2.36-0.50, 0.45, 1.41, 2.36. The first falls off the left edge, so the row becomes [0,10,20,30][0,10,20,30].
  • Row 3 (y−cy=1y-c_y=1, θ=−1.0\theta=-1.0): xs=2+0.540(x−2)+0.841x_s=2+0.540(x-2)+0.841 gives 1.76,2.30,2.84,3.381.76, 2.30, 2.84, 3.38, so [140,150,150,160][140,150,150,160].
  • Output: the corrected frame, a 4×44\times4 array of 8-bit integers. Notice that rows only shift and stretch sideways, and the shift grows with both the angle and the row's distance from the centre.

Constraints

  • Input parameters: image (2D numpy array, grayscale or RGB), rotation_per_row (1D numpy array of angles in radians)
  • Valid ranges: Pixel values in [0, 255], rotation angles in [-π, π]
  • Output format: Return the corrected frame as a 2D numpy array (same shape and type as input image)
  • Special conditions: Assume the input image has a height of at least 2 rows, and the rotation_per_row array has the same length as the number of rows in the image

Learn this in

More from CV: Motion Estimation

PRO

Editor locked

The code editor is locked for Pro problems. It is only available for free problems. Please upgrade to gain access to the code editor for all problems.

solution.py

Test results

Sign in to run your code against the test cases.