0
$\begingroup$

I am attempting to generate a effect that allows me to use original color of image, but also mimic a pinched extruded 3d surface from orthographic view. To do this, I used the G'MIC-QT scripting language. Explanation are between ##. This can be pasted into code[local] or code[global] of G'MIC QT plugin for Krita or as a plugin for GIMP. Paint.NET is also accepted.

My question is that if there's another solution that doesn't have the problem of using multiple resized images.

isophotes 4            #Create edges of image for testing purpose#
ww={w}                 #Rescale to original#
sh 0,{s-2}             #Create a layer that share info from 1st image#
sh.. {s}               #See above, but for last channel#
max_alpha={iM-1}       #Unused code to use alpha channel#
{w},{h},1,1,i#-1?0:1   #Create new layer that use shared alpha to create inpaint area#
inpaint_pde[1] [-1]    #Inpaint fills missing info with existing colors#
k[0]                   #Erase Additional layer and keep only original image.Edited shared image will affect [0]#
r2dx 125%,1            #Rescale to 125% size using nearest interpolation#
if w>h                 #Evaluate if width is greater than height#
    dx_a={.125*w}      #Assign value using 12.5% of image width#
    dx_b={w-$dx_a}     #Invert the value#
    dp={1/(max($dx_a,$dx_b)-1)} #Find maximum of the two#
else
    dy_a={.5*w}       #Same as above, but for height#
    dy_b={h-$dy_a}    #Invert the value# 
    dp={1/(max($dy_a,$dy_b)-1)} #Find the maximum of two#
fi
iter=1
do                                   #Do while start#
    rx={round((1-($iter*$dp))*w#0)}  #Find the next width#
    rx={$rx<1?1:$rx} 
    ry={round((1-($iter*$dp))*h#0)}  #Find the next height#
    ry={$ry<1?1:$ry}
    +r[0] $rx,$ry,100%,100%,6        #Create image resized to vector rx,ry using Lanczos Interpolation#
    iter+=1                          #Add 1 to iteration#
while w!=1&&h!=1                     #End condition for do while loop#
ti={$!-2}
r[^0] {w#0},{h#0},100%,100%,0,0,.125,.5 #Resize canvas, and the last two numbers determine anchor placement#
rv blend alpha  #Create the shaped gradient#
r2dx $ww,2      #Resize to original#
. blend alpha   #Fill missing alpha#

Using Mona Lisa Painting, and isophotes 3 instead of isophotes 4

  • Result - enter image description here

The problem is clear. The result is not smooth with the above code.


EDIT as of 11/30/2019:

It seems possible to do the effect with transformation. In between transformation, you can create vertical lines, and after transformation is finished, the effect is like the first image in this post.

EDIT: I have finished with transformations for the benefit of other users. The solution is near in sight.

#@cli rep_polrectrans_inv : eq. to 'rep_polar_rectangular_transform_inverse'. : (+)
rep_polrectrans_inv: rep_polar_rectangular_transform_inverse $*
#@cli rep_polar_rectangular_transform_inverse : -1>=_xpos<=1,-1>=_ypos<=1,_from_preserved_details={ 0=false | 1=true }
#@cli : Transform rectangular polar images into cartesian coordinates.
#@cli : (eq. to 'rep_polrectrans_inv').\n
#@cli : Warning: Without preservation of details, artifacts is a lot more visible.
#@cli : Default values: '_xpos=0','_ypos=0','_preserve_details=1'
rep_polar_rectangular_transform_inverse:
skip ${1=0},${2=0},${3=1}
if $1<-1||$1>1 error "($1>=-1&&$1<=1)=0" fi
if $2<-1||$2>1 error "($2>=-1&&$2<=1)=0" fi
if $3
    repeat $! l[$>]
        ov={[im,iM]}
        {w/2-h/2},{h/2},{d},{s},"
        begin(
            ww=w#0;
            hh=h#0;
            ox=ww/2-hh/2;
            oy=hh/2;
            sd=max(ww,hh)/min(ww,hh);
            sxf=ox<oy?sd:1;
            syf=ox<oy?1:sd;
            cx=.5+$1*.5;
            cy=.5+$2*.5;
            px=cx*ww;
            py=(1-cy)*hh;
            sxl=(ww/2)/px;
            sxr=(ww/2)/(ww-px);
            syt=(hh/2)/py;
            syb=(hh/2)/(hh-py);
        );
        xx=(x/(w-1))*ww;xx+=(xx/(ww-1)-.5)*-1;
        yy=(y/h)*hh;
        xl=-1+(xx/ww)*2*sxl;
        xr=1-(1-xx/(ww-1))*2*sxr;
        yt=-1+(yy/hh)*2*syt;
        yb=1-(1-yy/(hh-1))*2*syb;
        nxx=xx>px?xr:xl;
        nyy=yy>py?yb:yt;
        ay=max(abs(nxx),abs(nyy));
        ax=(atan2((yy/hh-(1-cy))*syf,(xx/ww-cx)*sxf)+pi)/(2*pi);
        i(#0,ax*ww,ay*hh,z,c,1,1);
        "
        n $ov
        k.
    endl done
else
    ov={[im,iM]}
    f "
    begin(
        sd=(max(w,h)/min(w,h));
        sx=w>h?sd:1;
        sy=w>h?1:sd;
        ww=w-1;
        hh=h-1;
        cx=.5+$1*.5;
        cy=.5+$2*.5;
        px=cx*w;
        py=(1-cy)*h;
        sxl=(w/2)/px;
        sxr=(w/2)/(w-px);
        syt=(h/2)/py;
        syb=(h/2)/(h-py);
    );
    xl=-1+(x/w)*2*sxl;
    xr=1-(1-x/w)*2*sxr;
    yt=-1+(y/h)*2*syt;
    yb=1-(1-y/h)*2*syb;
    xx=x>px?xr:xl;
    yy=y>py?yb:yt;
    ay=max(abs(xx),abs(yy));
    xx=(x/w)-cx;
    yy=(y/h)-(1-cy);
    ax=(atan2(yy*sy,xx*sx)+pi)/(2*pi);
    i(ax*ww,ay*hh,z,c,2,1);
    "
    n $ov
fi
#@cli rep_polrectrans : eq. to 'rep_polar_rectangular_transform'. : (+)
rep_polrectrans: rep_polar_rectangular_transform $*
#@cli rep_polar_rectangular_transform : -1>=_xpos<=1,-1>=_ypos<=1,_preserve_details={ 0=false | 1=true }
#@cli : Transform image into rectangular polar coordinates.
#@cli : (eq. to 'rep_polrectrans').\n
#@cli : Default values: '_xpos=0','_ypos=0','_preserve_details=1'
rep_polar_rectangular_transform:
skip ${1=0},${2=0},${3=1}
if $1<-1||$1>1 error "($1>=-1&&$1<=1)=0" fi
if $2<-1||$2>1 error "($2>=-1&&$2<=1)=0" fi
repeat $! l[$>]
    ov={[im,iM]}
    if $3 r {(w+h)*2},200%,100%,100%,1 fi #Resize to perimeter for width and double the height for height to preserve all the details in the original image using nearest-neighbor#
    f "
    begin(
        point_x=(($1*-1)*.5+.5)*w;
        point_y=($2*.5+.5)*h;
        inv_point_x=w-point_x;
        inv_point_y=h-point_y;
        cut_ang_s0=abs(atan2(inv_point_y,inv_point_x)*180/pi); #Find angle requirement to meet side#
        cut_ang_s1=180-abs(atan2(inv_point_y,point_x)*180/pi); #Find angle requirement to meet side#
        cut_ang_s2=180+abs(atan2(point_y,point_x)*180/pi);     #Find angle requirement to meet side#
        cut_ang_s3=360-abs(atan2(point_y,inv_point_x)*180/pi); #Find angle requirement to meet side#
        distanceaway(value)=(
            if(value==0,w-point_x, #Left#
            if(value==1,h-point_y, #Top#
            if(value==2,point_x,   #Right#
            if(value==3,point_y    #Bottom#
            );
            );
            );
            );
        );
    );
    surface_angle=(x/w)*360; #Convert into angle surface using x-coordinate#
    if(surface_angle>cut_ang_s0&&surface_angle<=cut_ang_s1,side=1, #Top#
    if(surface_angle>cut_ang_s1&&surface_angle<=cut_ang_s2,side=2, #Right#
    if(surface_angle>cut_ang_s2&&surface_angle<=cut_ang_s3,side=3, #Bottom#
                                                           side=0; #Left#
                                                                );
                                                                );
                                                                );
    mdist=abs(side%2?1/sin((surface_angle/180)*pi):1/cos((surface_angle/180)*pi));    #Find multiplier to distance based on angle to edge boundary#
    dix=(point_x+cos((surface_angle/180)*pi)*distanceaway(side)*mdist*y/h)*((w-1)/w); #x-coordinate#
    diy=(point_y+sin((surface_angle/180)*pi)*distanceaway(side)*mdist*y/h)*((h-1)/h); #y-coordinate#
    i(w-(dix+1),h-(diy+1),z,c,2); #Output using pixel coordinate with linear interpolation#
    "
    cut $ov
endl done
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.