G'MIC exercises

I think I’ve fixed it, but it’s no less hard to debug. There were a series of errors which G’MIC wasn’t complaining about before and now I think they’re fixed.

Another new version of the layer cake script with an antialiasing parameter.

xc=0.5
yc=0.5
num=3
ang={2*pi/($num-1)}
aa=4
f "begin(ang=("$ang")%(2*pi);xoff=w*"$xc";yoff=h*"$yc";num="$num";aa="$aa");
vx=x-xoff+0.5;vy=y-yoff+0.5;
lnum=max((norm(vx,vy))/norm(w,h)*2*num-(0.5*aa/norm(w,h)),0);
lnumint=floor(lnum);
angle=(ang*lnumint);
pa=I(vx*cos(angle)+vy*sin(angle)+xoff-0.5,vy*cos(angle)-vx*sin(angle)+yoff-0.5,z,2,3);
pb=I(vx*cos(angle+ang)+vy*sin(angle+ang)+xoff-0.5,vy*cos(angle+ang)-vx*sin(angle+ang)+yoff-0.5,z,2,3);
func=min((lnumint+1-lnum)*norm(w,h)/aa,1);
I=(pa*(func)+pb*(1-func))"

@Joan_Rake1 What about layer option?

That will have to come much later. For now, here is what I have:

#@gui Layer Cake 2 : fx_layer_cake_2, fx_layer_cake_2_preview(1)
#@gui : Layer Density = float(4,1,32)
#@gui : Angle Value = float(360,-1440,1440)
#@gui : Angle Interpretation = choice("At End","Per Layer")
#@gui : Centre = point(50,50,0,1,255,255,255,175)
#@gui : Interpolation = choice(1,"None","Linear","Bicubic")
#@gui : Boundary = choice(3,"None","Nearest","Periodic","Mirror")
#@gui : Blur = float(2,0,100)
fx_layer_cake_2 :
xc=$4%
yc=$5%
num=$1
inter=$6
bound=$7
if $3
ang={$2*2*pi/360}
else
ang={$2*2*pi/(($num)*360)}
fi
aa={$8*norm(w,h)/100}
f "begin(ang=("$ang");xoff=w*"$xc";yoff=h*"$yc";num="$num";aa="$aa";inter="$inter";bound="$bound");
vx=x-xoff+0.5;vy=y-yoff+0.5;
lnum=max((norm(vx,vy))/norm(w,h)*2*num-(0.5*aa/norm(w,h)),0);
lnumint=floor(lnum);
angle=((ang*lnumint)%(2*pi));
pa=I(vx*cos(angle)+vy*sin(angle)+xoff-0.5,vy*cos(angle)-vx*sin(angle)+yoff-0.5,z,inter,bound);
pb=I(vx*cos(angle+ang)+vy*sin(angle+ang)+xoff-0.5,vy*cos(angle+ang)-vx*sin(angle+ang)+yoff-0.5,z,inter,bound);
func=min((lnumint+1-lnum)*norm(w,h)/aa,1);
I=(pa*(func)+pb*(1-func))"
fx_layer_cake_2_preview :
fx_layer_cake_2 $*

Been looking at this - Shaped gradient - my first plugin - Plugin Developer's Central - paint.net Forum

Problem: I would like to create a fast “droste frame” based filter that is based on the very same concept. That way, you can use anything instead of binary, and one channel. Right now, all I got to go on by is to use atan2. Any idea?

Is it possible for me to use “I(#variable)” in an eval block or something like it? It doesn’t seem to work, and I don’t know how to use ext() to work around this.

Seems to work OK for me with gmic sp rooster +mirror x f. "X=u>0.5;i(#X,x,y)"
Do you mean an external variable?
Usually have to break the quotes for that, like f. "i(#"$X",x,y)". If you want to set an external variable during the loop it gets more tricky probably, although I’m not sure it would be useful anyway…

@Reptorian are you able to make some kind of example output?

I’ll pick that up again later and see what happens, thanks for the info. Right now I have two kaleidoscope commands which both use this:

#@cli symmetrize_jr : _x[%],_y[%],_angle,_boundary_conditions={ 0=dirichlet | 1=neumann | 2=periodic | 3=mirror },_is_antisymmetry={ 0 | 1 },_swap_sides={ 0 | 1 },_interpolation={ 0=none | 1=linear | 2=bicubic }
#@cli : Symmetrize selected images regarding specified axis.
#@cli : Default values: 'x=y=50%', 'angle=90', 'boundary_conditions=3', 'is_antisymmetry=0', 'swap_sides=0' and 'interpolation=1'.
#@cli : $ image.jpg +symmetrize 50%,50%,45 +symmetrize[-1] 50%,50%,-45
symmetrize_jr : skip ${1=50%},${2=50%},${3=90},${4=3},${5=0},${6=0},${7=1}
e[^-1] "Symmetrize image$?, regarding axis ($1,$2,$3 deg.)."
v -
theta={$3*pi/180} u={cos($theta)} v={sin($theta)}
if $6 symmetry_cond=A<0 else symmetry_cond=A>0 fi
repeat $! l[$>]
x0={if(${is_percent\ $1},w*$1,$1)}
y0={if(${is_percent\ $2},h*$2,$2)}
if $5 f 'A=($y0-y)*$u-($x0-x)*$v;X=x+2*($x0-x);Y=y+2*($y0-y);if($symmetry_cond,i(X,Y,z,c,$7,$4),i)'
else f 'A=($y0-y)*$u-($x0-x)*$v;X=x-2*$v*A;Y=y+2*$u*A;if($symmetry_cond,i(X,Y,z,c,$7,$4),i)'
fi
endl done

This first one is one that I’ve made myself and it’s quite fast but has a flawed design as can be seen in the image that comes after this:

#@gui : Number = int(6,2,32)
#@gui : Mirror Rotation = float(0,-180,180)
#@gui : Center (%) = point(50,50,0,1)
fx_jr_kaleidoscope:
num=$1
rrot={$2/180*pi}
cx=$3*w/100
cy=$4*h/100
symmetrize_jr $cx,$cy,(-180/$num+$2),3,0,0,0
f "begin(rrot="$rrot";cx="$cx";cy="$cy");
vx=x-cx+0.5;vy=y-cy+0.5;num="$num";
amult=round(atan2(vy,vx)-rrot,2*pi/num,1);ang=(amult)%(pi*2);
xwarp=vx*cos(ang)+vy*sin(ang)+cx;
ywarp=vy*cos(ang)-vx*sin(ang)+cy;
I=I(xwarp,ywarp,z,0,3)"
fx_jr_kaleidoscope_preview:
fx_jr_kaleidoscope $*

(using Imgur since I get ‘permission denied’ errors when I upload any image)

This alternative command is slower but it does not have this defect:

#@gui Kaleidoscope [Polar] : fx_kaleidoscope, fx_kaleidoscope(1)
#@gui : Center (%) = point(50,50)
#@gui : X-Offset (%) = float(0,0,100)
#@gui : Y-Offset (%) = float(0,0,100)
#@gui : Radius Cut = float(100,0,100)
#@gui : Angle Cut = float(10,0,100)
#@gui : Boundary = choice(3,"Transparent","Nearest","Periodic","Mirror")
#@gui : sep = separator()
#@gui : note = note("<small>Author: <i><a href="http://bit.ly/2CmhX65">David Tschumperl&#233;</a></i>.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
#@gui : Latest Update: <i>2010/29/12</i>.</small>")
fx_kaleidoscope :
if !$7 to_a fi
shift $3%,$4%,0,0,2 kaleidoscope $1%,$2%,$5,$6,$7
#@gui Kaleidoscope [Symmetry] : fx_symmetrizoscope, fx_symmetrizoscope(1)
#@gui : Iterations = int(4,1,32)
#@gui : Angle = float(0,0,360)
#@gui : Boundary = choice(3,"Transparent","Nearest","Periodic","Mirror")
#@gui : Symmetry Sides = choice("Backward","Forward","Swap")
#@gui : Center (%) = point(50,50,0,1)
#@gui : Rotation = float(0,0,360)
#@gui : sep = separator()
#@gui : note = note("<small>Author: <i><a href="http://bit.ly/2CmhX65">David Tschumperl&#233;</a></i>.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
#@gui : Latest Update: <i>2013/07/01</i>.</small>")
fx_symmetrizoscope :
if !$3 to_a fi
repeat $1
ang={$2+180*$>/max(1,$1-1)}
symmetrize_jr $5%,$6%,$ang,$3,0,{if($4!=2,$4,$>%2)},0
done

I want to be able to duplicate the functionality of the GEGL script but I have no idea as to how I’d apply a final rotation on the whole thing and do other things like zooming out through the use of formulae and conditions in the mathematical parser which would make it sweet and fast.

For me to do that, I’d have to find a code that can use any colors as base for processing. In my head, I am thinking of extrusion where the lower layer point is at 0 width. I may have to look at this and see how I can change the original code.

For now, I went to replicating Stitch Paint.NET plugin since it is easier to figure out.

repeat $! l[$>]
Sublevel=1
Angle_Stitch=55
Thickness=3
Interpolation=3
Intensity=50
Boundary=3
iw={w}
ih={h}
ang={pi*($Angle_Stitch/180)}
ang2={pi*(($Angle_Stitch+90)/180)}
r {($Sublevel+1)*100}%,{($Sublevel+1)*100}%,100%,100%,1
{w},{h},1,1,sur=x*cos($ang)+y*sin($ang);floor(sur/($Thickness*($Sublevel+1)))
{max(1,round(iM,1,1))},1,1,1,u(1) round. map.. . rm. -. {iM/2} f. i<0?-1:1
f.. "sx="$Intensity"*cos("$ang2")*i(#1,x,y,z,c);sy="$Intensity"*sin("$ang2")*i(#1,x,y,z,c);sx+=x;sy+=y;i(sx,sy,z,c,"$Interpolation","$Boundary")"
endl
done
channels 0

Check channels, it works only on first channel. How come?

I think I’ll do shared approach here.

EDIT:

repeat $! l[$>]
Sublevel=1
Angle_Stitch=75
Thickness=1
Interpolation=3
Intensity=100
Boundary=1
iw={w}
ih={h}
ang={pi*($Angle_Stitch/180)}
ang2={pi*(($Angle_Stitch+90)/180)}
r {($Sublevel+1)*100}%,{($Sublevel+1)*100}%,100%,100%,1
{w},{h},1,1,sur=x*cos($ang)+y*sin($ang);floor(sur/($Thickness*($Sublevel+1)))
{max(1,round(iM,1,1))},1,1,1,u(1) round. map.. . rm. -. {iM/2} f. i<0?-1:1
repeat s#0 sh[0] $>
f. "sx="$Intensity"*cos("$ang2")*i#1;sy="$Intensity"*sin("$ang2")*i#1;sx+=x;sy+=y;i(sx,sy,z,c,"$Interpolation","$Boundary")" rm. done rm.
r {$iw},{$ih},100%,100%,{$Interpolation}
endl
done

That’s the shared approach. Speed shouldn’t be a issue here I guess. I’ll figure making shift factor much more random as it’s now uniform. After that, I’ll replicate the Paint.NET Stitch filter with more options.

I’m completely stumped regarding the GEGL kaleidoscope remake so I’ll have to focus on the layer cake script; I have to hold my hands up and say it’s too difficult for me to understand how to do it. I’ll focus on the layer cake script, but my focus was on trying to merge the layer cake and kaleidoscope scripts without any of the artefacts from the kaleidoscope thing going wrong.

Merging the Kaleidoscope and Layer Cake? That’s a interesting idea. If you’re going to extend the Layer Cake, may I suggest to add color overlay or treating each circles as blending mode layers?

What is a good way to find the median disregarding certain values? E.g., ignore the 0s.

11 11 12
21 21 22
 0  0 32

I.e., using fill and N = crop(). med(N) will find the median of this matrix.

Could you pixel_sort, and then find the med using N utilizing crop? That is what I would do. I would probably try a repeat loop to test variable to find if 0 exist, and use that for crop info.

You are suggesting that I do it outside of fill, though I don’t know how to make a median filter using builtin commands ATM. (Brain still melting. Maybe at 5%. I should rest.)

In fill, I was thinking: for each N neighbourhood, remove all 0s (or another arbitrary value); then find the median and filter the pixel.

Then in that case, then you would have to do a while loop within fill, and I believe med would work here. I’m just not sure how to do that.


Any idea of how to extract rgb from the command @David_Tschumperle made to check if all RGB8 info? I feel that it’s the answer to find colors that does not exist as well as colors that does exist. I know that each z represent blue, and the x, y represent red,green. So, the light area imply it exists. So, I need to find a way to convert that to 4096,4096.

I imagine that each z are blocks which are 16x16 big blocks where one of those block is 256x256 px. That’s as far as I can go. The real trouble is finding a code that does that and to convert cube to 4096,4096,1,3.

Here’s a brief code

256,256,256 eval.. "++i(#-1,R,G,B)"
k.
s z
repeat 16 l[$>-{$>+15}] a x endl done
a y

I see where the colors are on the preview. Those little dots imply that these colors exist here and there.


SOLVED!

nk=0
nk_1={$nk?255:0}
nk_2={$nk?0:255}
repeat $! l[$>]
    256,256,256 eval.. "++i(#-1,R,G,B)" k.
    4096,4096,1,4,[x%256,y%256,floor(x/256)+(floor(y/256)*16),i(#-1,x%256,y%256,floor(x/256)+(floor(y/256)*16))?$nk_1:$nk_2] k.
endl done

The above tells me that if color exists, then it’s opaque, else it’s not.

In Octave, I could do

octave:1> N=[0,1,2]
N = 0 1 2

octave:2> med=median(N(N!=0))
med = 1.5000

That octave format seem easier to understand.

On that note : Does octave has a mode function (Get all the colors, then grab all the most frequent colors, the cube code is fast enough to base things on)? After looking more at what check_rgb8, I realized g’mic could benefit from having mode function to it.

I don’t feel like calling @David_Tschumperle as he’s busy, but it’s a interesting idea to add option for conditionals. I think it’s time to hear what he has to say about this.

ic#(#-1(N!=0)) #Does this look ok?#

This is what I have so far. I am able to loop and replace the 0 with a 9.

med0_:
  eval "
    N=[0,1,2];
    A=vector3();
    for(k=0,k<size(N),++k,
      if(
        N[k]==0,
        A[k]=9,
        A[k]=N[k];
      );
    );
    print(N);
    print(A);
  "
[gmic_math_parser] N = [ 0,1,2 ] (size: 3)
[gmic_math_parser] A = [ 9,1,2 ] (size: 3)

Now, I have 2 problems.

1 I don’t know how to replace vector3 with size(N).

2 I don’t know how to use dar_remove (or something to that effect) to obtain A = [ 1,2 ].

I tried coding in is_prime

1,1,1,1,6 k.
f "isP=1;
for(in=2,in<=int(i)/2,++in,isP=i%in==0?0:1;if(isP==0,break()));
isP;
"

EDIT : Solved!