Lens Distortion the quick way

The Lens Distortion node in Nuke can be quite heavy as it comes with a host of features which although useful, are often unneeded. If you want a quick and dirty lens distortion, then here is a convenient alternative. Nothing flashy, just a slider for the amount and a choice between barrel or pincushion. Simple.

LensDistortionImage

Installing

Download from here.

To run, simply drop a Blink Script node in Nuke, navigate to where you placed the downloaded script, and then hit Load. In Kernel Parameters you can change the settings, or even publish the node into a gizmo. For the unfamiliar, you can’t simply copy and paste a Blink Script node from one computer to another. Each user will need to load the script themselves unless you convert it into a gizmo.

Code Breakdown

For this script we only need a few variables. We want to be able to control the amount of distortion and whether to barrel or pincushion, so we set these as user defined. We’ll also need the center of the image as well as the distance from the center to the corner, neither of which will change during the frame so we can store these as local variables which will save us calculating it on every pixel.

void init() {
  center = float2( src.bounds.x2 / 2, src.bounds.y2 / 2 );
  max_dist = length( center );
}

For center, we’re using the source image (declared as src previously) to get the x and y position halfway in the image bounds. As this is already the distance from the bottom left corner (0, 0) we can simply get the length of the vector.

void process( int2 pos ) {

  // d = u * ( 1 - k * pow( u, 2 ) );
  // u = d / ( 1 - k * pow( d, 2 ) );

  float2 pos_f = float2( pos.x, pos.y );
  float2 dir = center - pos_f;
  float dist = length( dir );
  float n_dist = dist / max_dist;

An important thing to note is that process can be called with int2 pos, which allows us to access the current pixels x and y position from the variable pos. The commented out code is simply the formula for distorting or undistorting an image, it’s that simple!

To work with the position, we need to convert it to a float2 instead of an int2, then we can subtract it from the center to get the direction, and get the length of this new vector to find the distance from the center. We want this distance normalised (meaning between 0 and 1), so we divide it by the maximum distance from the center (Which we calculated in the init function).

  float target_dist;

  if ( pincushion )
    target_dist = dist * ( 1 - lens * pow( n_dist, 2) );
  else
    target_dist = dist / ( 1 - lens * pow( n_dist, 2) );

Lens Distortion is simply stretching an image to or from the center, so now that we know the distance to the current pixel, we simply want to find the distance in the same direction that we want to push / pull it to. This is where the formulas come in. We just need to check which method we want (barrel or pincushion) and get the distance to the pixel that we want to copy from (That is, we’re pushing / pulling that pixel to this location).

  float2 undistort_pos = center - normalize( dir ) * target_dist;

  dst() = bilinear( src, undistort_pos.x, undistort_pos.y );

Now we simply multiply this distance by the normalised direction and add it to the center to find the x and y positions of the pixel we need. This is why we need to be careful about how we access pixels outside the image. For example, if the new pixel was not in the image bounds then it wouldn’t know what to do. We use eEdgeClamped, which means it continues to use the edge pixels values stretched out. If you wanted the output to just have black outside the distortion, then change eEdgeClamped to eEdgeNone.

Finally, we set the value of the current pixel. However, the x and y values we calculated are floats, meaning they have decimal places and are not an exact pixel location. To find the value we need, we use a built in function called bilinear. This averages the surrounding pixel values from the given image to give the most accurate result.

And that is that! Once again, a long winded explanation to a very simple procedure. Hopefully you find it useful, or at least learned a little about blink scripts. Enjoy!

 

Advertisement
Lens Distortion the quick way

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s