Search code examples
mathimage-processingdistortionskewradial-gradients

How do I skew a pixel-based radial gradient without artifacts?


Right now, I am having trouble skewing a radial gradient that is based on sqrt(x^2+y^2). What I would like is a smooth skewing much in the same way that Illustrator have, but for pixel image processing related to distortion.

My attempt to apply a skewed radial gradient for distortion can be seen below:

Description of filter - Use Spiral gradient for finding the x-location of image, and radial gradient for finding y-location. 
Then use the values that are found in order to distort the image.

Scripting Language - G'MIC-QT

x is x-location of pixel within for loop
y is y-location of pixel within for loop
w is width
h is height

foo:
r2dx 200%,3#Resize Image using linear interpolation. Used for subpixel processing#
f "begin(
    sd=max(w,h)/min(w,h); #Divide the biggest side by the smallest size.#
    sx=w>h?sd:1;          #Find x-scale to scale x-coordinate#
    sy=w>h?1:sd;          #Find y-scale to scale y-coordinate#
    ang=pi*(0/180);       #Convert angle to radian. 0 next to /180 is the function angle.#
    slx=2;                #Scale of x-coordinate#
    sly=2;                #Scale of y-coordinate#
    skew_x=.15;           #Offset x-skewing#
    skew_y=.15;           #Offset y-skewing#
    skew_ang=atan2(skew_y,skew_x)+pi/2;          #Find skew angle#
    skew_fact=sqrt(skew_x^2+skew_y^2);           #Find multiplier for skewing#
    srot_x(a,b)=a*cos(skew_ang)-b*sin(skew_ang); #Function for rotating the skewing function#
    srot_y(a,b)=a*sin(skew_ang)+b*cos(skew_ang); #Function for rotating the skewing function#
    rot_x(a,b)=a*cos(ang)-b*sin(ang);            #Distortion Angle Function#
    rot_y(a,b)=a*sin(ang)+b*cos(ang);            #Distortion Angle Function#
);
XX=(x/w-.5)*2*sx*slx;       #Convert x into -1,1 range if image is a square#
YY=(y/h-.5)*2*sy*sly;       #Convert y into -1,1 range if image is a square#
SXX=(x/w-.5)*2*sx*slx;      #Convert x into -1,1 range if image is a square. Used for skewing!#
SYY=(y/h-.5)*2*sy*sly;      #Convert y into -1,1 range if image is a square. Used for skewing!#
xx=rot_x(XX,YY);            #Rotation of function#
yy=rot_y(XX,YY);            #Rotation of function#
sxx=srot_x(SXX,SYY)*sx*slx; #Rotation of skewing function#
syy=srot_y(SXX,SYY)*sy*sly; #Rotation of skewing function#
skew_atan=atan2(abs(sxx),syy)*skew_fact*sqrt(sxx^2+syy^2);#Generate Skewing Function#
radial=sqrt(xx^2+yy^2)*1+skew_atan;                       #Combine radial gradient with skewing Function#
if(1,sur_atan=1-(atan2(xx,yy)+pi)/(2*pi);,sur_atan=(atan2(xx,yy)+pi)/(2*pi););#Determine direction of spiral#
es=(sur_atan+radial*1)*1;   #Part 1 of Spiral Gradient#
es=es-floor(es);            #Part 2 of Spiral#
if(0,es=(es>.5?1-es:es)*2;); #If true, then spiral is continuous, else spiral is non-continuous#
i((es^1)*w,radial*h,z,c,2,3);#i(x-location,y-location,z-location,channel_numbers,interpolation,boundary); The i means image.#
"
r2dx 50%,3 #Resize Image using linear interpolation. Used for subpixel processing#

Target Image

Picture of Earth used for testing distortion filter

The result using this code

Distortion Filter using the above code, and skewing applied

If anything isn't clear, let me know.


Solution

  • I have finally found my solution to the problem. What I did is to make functions to rotate x-coordinate,y-coordinate,boundary box size, and use x-coordinate and y-coordinate to influence the skew factor.

    Here's the current G'MIC-QT code for reference. It's hard to explain what I did though.

    r2dx 200%,3
    f "begin(
        sd=max(w,h)/min(w,h);
        sx=w>h?sd:1;
        sy=w>h?1:sd;
        ang=pi*(0/180);
        slx=10;
        sly=10;
        skew_x=.5;
        skew_y=.5;
        nw=abs(w*sin(ang))+abs(h*cos(ang));
        nh=abs(w*cos(ang))+abs(h*sin(ang));
        rot_x(a,b)=a*cos(ang)-b*sin(ang);
        rot_y(a,b)=a*sin(ang)+b*cos(ang);
    );
    xx=(x/w-.5)*sx;
    yy=(y/h-.5)*sy;
    mx=((rot_x(xx,yy)/sx)+.5)*w;
    my=((rot_y(xx,yy)/sy)+.5)*h;
    nx=mx-abs(skew_x)*rot_x(xx,yy)*(skew_x>0?nw-mx:mx);
    ny=my-abs(skew_y)*rot_y(xx,yy)*(skew_y>0?nh-my:my);
    xx=(nx/w-.5)*2*slx;
    yy=(ny/h-.5)*2*sly;
    radial=sqrt(xx^2+yy^2);
    if(1,sur_atan=1-(atan2(xx,yy)+pi)/(2*pi);,sur_atan=(atan2(xx,yy)+pi)/(2*pi););
    es=(sur_atan+radial*1)*1;
    es=es-floor(es);
    if(0,es=(es>.5?1-es:es)*2;);
    i((es^1)*w,radial*h,z,c,2,3);
    "
    r2dx 50%,3
    

    Here's the result:

    Solution