Implementation of "Optics Compensation" effect

87 views Asked by At

I'm trying to replicate effect from Adobe After Effects called "Optics Compensation". I think it is similar to Lens Distortion. But the formulas that are used there do not fit. This effect have a few options to manipulate.This effect has several parameters to change.

  1. Center
  2. FOV. aka Field Of View. Value from 0 to 180 degrees.
  3. FOV Orientation (Horizontal, Vertical, Diagonal)

In this video i animated the FOV value from 0 to 180 degrees; Center = 540,960

Also image example:

enter image description here

It's looks like Barrel distortion or Fisheye distortion.

I tried different formulas. For example "Lens correction model"

enter image description here

But I don't understand how to calculate all these parameters with only FOV and center value.

Does anyone know how to achieve this effect? What formulas should be used? Everywhere it is described how to fix "Lens Distortion". But how to apply such an effect on the picture?

After some Research I found Mathworks implementation for Barrel Transformation. enter image description here

Code

[xi,yi] = meshgrid(1:ncols,1:nrows);
xt = xi - ncols/2;
yt = yi - nrows/2;

[theta,r] = cart2pol(xt,yt);
a = 1; % Try varying the amplitude of the cubic term.
rmax = max(r(:));

s1 = r + r.^3*(a/rmax.^2);
[ut,vt] = pol2cart(theta,s1);
ui = ut + ncols/2;
vi = vt + nrows/2;
ifcn = @(c) [ui(:) vi(:)];
tform = geometricTransform2d(ifcn);
I_barrel = imwarp(I,tform,FillValues=fill);
imshow(I_barrel)

My implementation in apple metal

fragment float4 opticsCompensationFragment(metalpetal::VertexOut vertexIn [[ stage_in ]],
                                           texture2d<float, access::sample> inputTexture [[ texture(0) ]],
                                           sampler inputTextureSampler [[ sampler(0) ]]) {
    
    float2 center = float2(0.5, 0.5);
    
    // Shift the origin to the center of the image
    float2 st = vertexIn.textureCoordinate - center;
    
    // Convert the Cartesian x- and y-coordinates to cylindrical angle (theta) and radius (r) coordinates
    float theta = sqrt(st.x * st.x + st.y * st.y);
    float r     = atan2(st.y, st.x);
    
    // Try varying the amplitude of the cubic term.
    float a  = 0.1;
    
    //  add a cubic term to r so that r changes nonlinearly with distance from the center pixel.
    float s1 = r + (r*r*r)*(a/(r*r));
    
    // Convert back to the Cartesian coordinate system. Shift the origin back
    float ut = theta * cos(s1) + center.x;
    float vt = theta * sin(s1) + center.y;
    
    
    return inputTexture.sample(inputTextureSampler, float2(ut, vt));
}

but my result is not like this.

enter image description here

The only difference is that in the code in Mathworks they use meshwarp, but i am trying to implement this using only fragment shader. What could be wrong in my code?

0

There are 0 answers