G'MIC exercises

Question, what to do about Default values section? Formulamode defines whether there are 4 or 6 variables next to it. It is like a switch. The last half of those additional variables use the first half when undefined.

@afre This is what I came up with. I’m not a fan of the output, but it’s readable.

#@cli rep_pfrac : eq. to 'rep_popcorn_fractal' : (+)
#@cli rep_popcorn_fractal: _pts_per_pixels>0,_density>0,_H,_K,_zoom,_rotation_angle,_origin_x,_origin_y,_formulamode,_formulafunc_1={ 0=sin | 1=cos | 2=tan | 3=atan},...
#@cli : Generates Pickover Popcorn Fractal. Code was adapted from Paul Bourke's c code, and extended for more possibilities. Fractal is attributed to Clifford Pickover.\n
#@cli : Default values: '_pts_per_pixels=50','_density=1','_H=.05','_K=3','_zoom=1','_rotation_angle=0','_origin_x=0','_origin_y=0','_formulamode=0','_formulafunc_1=0','_formulafunc_2=2','_formulafunc_3=_formulafunc_1','_formulafunc_4=_formulafunc_2'\n
#@cli : Note: When _formulamode is equal to 1, then default values for _formulafunc1... becomes: '_formulafunc_1=0','_formulafunc_2=1','_formulafunc_3=2','_formulafunc_4=_formulafunc_1','_formulafunc_5=_formulafunc_2','_formulafunc_6=_formulafunc_2'

Output

    rep_pfrac: Shortcut for command 'rep_popcorn_fractal'.

    rep_popcorn_fractal:
        _pts_per_pixels>0,_density>0,_H,_K,_zoom,_rotation_angle,_origin_x,_origin_y,\
         _formulamode,_formulafunc_1={ 0=sin | 1=cos | 2=tan | 3=atan},...

      Generates Pickover Popcorn Fractal. Code was adapted from Paul Bourke's c code, and extended
        for more possibilities. Fractal is attributed to Clifford Pickover.

      Default values: '_pts_per_pixels=50','_density=1','_H=.05','_K=3','_zoom=1','_rotation_angle=0',
        '_origin_x=0','_origin_y=0','_formulamode=0','_formulafunc_1=0','_formulafunc_2=2',
        '_formulafunc_3=_formulafunc_1','_formulafunc_4=_formulafunc_2'

      Note: When _formulamode is equal to 1, then default values for _formulafunc1... becomes:
        '_formulafunc_1=0','_formulafunc_2=1','_formulafunc_3=2','_formulafunc_4=_formulafunc_1',
        '_formulafunc_5=_formulafunc_2','_formulafunc_6=_formulafunc_2'

Sorry, that’s really hard to follow. I actually had to rewrite this post a few times because I realized that I misunderstood something each time. :confused::dizzy_face:

I stand by my advice and would add that you haven’t explained what _formulamode does in your description. (It is implied in the note but the user has to connect a few dots.)

Ok, here’s the full cli and output

#@cli rep_pfrac : eq. to 'rep_popcorn_fractal' : (+)
#@cli rep_popcorn_fractal: _pts_per_pixels>0,_density>0,_H,_K,_zoom,_rotation_angle,_origin_x,_origin_y,_formulamode,_formulafunc_1={ 0=sin | 1=cos | 2=tan | 3=atan},...
#@cli : Generates Pickover Popcorn Fractal. Code was adapted from Paul Bourke's c code, and extended for more possibilities. Fractal is attributed to Clifford Pickover.\n
#@cli : _pts_per_pixels defines the maximum number of points to be added on image based on pixel location.
#@cli : _density defines the frequency of points to be added along row and height of image. A value of one implies n points to be added per pixel. 
#@cli : _H is the function multiplier used to subtract from the new found values from each iteration.
#@cli : _K is the inner multiplier for the inside function. See popcorn_x(a,b), and popcorn_y embedded within the code of rep_popcorn_fractal for more information.
#@cli : _zoom defines the magnification of image. A negative value will "shrink" the structure of generated fractal.
#@cli : _rotation_angle defines the function angle of fractal.
#@cli : _origin_x defines the position of fractal. Center of image row will be treated as zero, and the ranges for image row are treated as -1,1.
#@cli : _origin_y defines the position of fractal. Center of image column will be treated as zero, and the ranges for image column are treated as -1,1.
#@cli : _formulamode defines whether to use 4 trigometric functions or 6 trigometric functions.
#@cli : _formulafunc_n defines the individual trigometric function to be used. The last half use the function on first half unless the user defines the trigometric function.\n
#@cli : Default values: '_pts_per_pixels=50','_density=1','_H=.05','_K=3','_zoom=1','_rotation_angle=0','_origin_x=0','_origin_y=0','_formulamode=0','_formulafunc_1=0','_formulafunc_2=2','_formulafunc_3=_formulafunc_1','_formulafunc_4=_formulafunc_2'\n
#@cli : Note: When _formulamode is equal to 1, then default values for _formulafunc1... becomes: '_formulafunc_1=0','_formulafunc_2=1','_formulafunc_3=2','_formulafunc_4=_formulafunc_1','_formulafunc_5=_formulafunc_2','_formulafunc_6=_formulafunc_3'
    rep_pfrac: Shortcut for command 'rep_popcorn_fractal'.

    rep_popcorn_fractal:
        _pts_per_pixels>0,_density>0,_H,_K,_zoom,_rotation_angle,_origin_x,_origin_y,\
         _formulamode,_formulafunc_1={ 0=sin | 1=cos | 2=tan | 3=atan},...

      Generates Pickover Popcorn Fractal. Code was adapted from Paul Bourke's c code, and extended
        for more possibilities. Fractal is attributed to Clifford Pickover.

      _pts_per_pixels defines the maximum number of points to be added on image based on pixel location.
      _density defines the frequency of points to be added along row and height of image. A value of
        one implies n points to be added per pixel.
      _H is the function multiplier used to subtract from the new found values from each iteration.
      _K is the inner multiplier for the inside function. See popcorn_x(a,b), and popcorn_y embedded
        within the code of rep_popcorn_fractal for more information.
      _zoom defines the magnification of image. A negative value will "shrink" the structure of
        generated fractal.
      _rotation_angle defines the function angle of fractal.
      _origin_x defines the position of fractal. Center of image will be treated as zero, and x-axis+
        y-axis are both treated as -1,1 range.
      _origin_y defines the position of fractal. Center of image will be treated as zero, and x-axis+
        y-axis are both treated as -1,1 range.
      _formulamode defines whether to use 4 trigometric functions or 6 trigometric functions.
      _formulafunc_n defines the individual trigometric function to be used. The last half use the
        function on first half unless the user defines the trigometric function.

      Default values: '_pts_per_pixels=50','_density=1','_H=.05','_K=3','_zoom=1','_rotation_angle=0',
        '_origin_x=0','_origin_y=0','_formulamode=0','_formulafunc_1=0','_formulafunc_2=2',
        '_formulafunc_3=_formulafunc_1','_formulafunc_4=_formulafunc_2'

      Note: When _formulamode is equal to 1, then default values for _formulafunc1... becomes:
        '_formulafunc_1=0','_formulafunc_2=1','_formulafunc_3=2','_formulafunc_4=_formulafunc_1',
        '_formulafunc_5=_formulafunc_2','_formulafunc_6=_formulafunc_3'

Note: Each halves of formulafunc series are used in different-axis formulas. Yes, they’re part of popcorn_x(a,b), and popcorn_y(a,b) macro.

Make it more readable.

1 Only prepend _s on the line the parameters first appear, where they serve a purpose.

2 Reduce the amount of text.

3 Add spaces after ,s.

I suggest you replace “default values” and “note” with this (and put it above the parameters’ description).

Default values:

  If mode=0: 'points=50', 'density=1', 'H=.05', 'K=3', 'zoom=1', 'angle=0', 'origin_x=0',
    'origin_y=0', 'mode=0', 'fn1=fn3=0' and 'fn2=fn4=2'.

  If mode=1: 'points=50', 'density=1', 'H=.05', 'K=3', 'zoom=1', 'angle=0', 'origin_x=0',
    'origin_y=0', 'mode=1', 'fn1=fn4=0', 'fn2=fn5=1' and 'fn3=fn6=2'.
1 Like

That’s actually what I was looking for. Thank you so much! I don’t get the 3 part though.

Ok, I think I’ll settle for this. Though, I have a concern that it might be confusing. I did left a little note though pointing that fx_n comes before fy_n. I guess I shouldn’t use fx_n, or fy_n.

    rep_pfrac: Shortcut for command 'rep_popcorn_fractal'.

    rep_popcorn_fractal:
        _points>0,_density>0,_H,_K,_zoom,_rotation_angle,_origin_x,_origin_y,_mode,\
         _fx_1={ 0=sin | 1=cos | 2=tan | 3=atan},...,_fy_1={ 0=sin | 1=cos | 2=tan | \
         3=atan},...

      Generates Pickover Popcorn Fractal. Code was adapted from Paul Bourke's c code, and extended
        for more possibilities. Fractal is attributed to Clifford Pickover.

      _points defines the maximum number of points to be added on image based on pixel location.
      _density defines the frequency of points to be added along row and height of image. A value of
        one implies n points to be added per pixel.
      _H is the function multiplier used to subtract from the new found values from each iteration.
      _K is the inner multiplier for the inside function. See popcorn_x(a,b), and popcorn_y embedded
        within the code of rep_popcorn_fractal for more information.
      _zoom defines the magnification of image. A negative value will "shrink" the structure of
        generated fractal.
      _rotation_angle defines the function angle of fractal.
      _origin_x defines the position of fractal. Center of image row will be treated as zero, and the
        ranges for image row are treated as -1,1.
      _origin_y defines the position of fractal. Center of image column will be treated as zero, and
        the ranges for image column are treated as -1,1.
      _mode defines whether to use 4 trigometric functions or 6 trigometric functions. Each halves of
        functions are used on 2 functions used by different axis.
      _fx_n defines individual function used for x-axis function.
      _fy_n defines individual function used for y-axis function.

      Default values: '_points=50','density=1','H=.05','_K=3','_rotation_angle','_origin_x=0',
        '_origin_y=0','_mode=0',...

          If _mode=0: ... : '_fx_1=_fy_1=0','_fx_2=_fy_2=2'
          If _mode=1: ... : '_fx_1=_fy_1=0','_fx_2=_fy_2=1','_fx_3=_fy_3=1'

@David_Tschumperle It has been a year but I still haven’t figured out how to use search_dichotomic in math_lib form. An example would be nice. :crossed_fingers:

@Reptorian You could chime in if you wish using the example from post #131.

Did you try eval ${-math_lib}"". I think to do it, you need to make a for x, for y loop. It’s possible multiple loops would be needed though.

I can do post #126 in eval form.

foo_search :
  eval ${-math_lib}"
    search_dichotomic(1/(1+exp(-x)),.15)
  "
  e[] ${}

Having trouble doing post #131, which is an application of post #126: apply a sigmoid function with a parameter value that outputs an image with an average intensity of 0.5.


Other Questions
1 Would like to know how to process image with colour kernel (instead of per channel); e.g. vector mode, mean or median filtering. I.e. fill and eval generally cycle through c; so does crop().

Here’s what could possibly be the beginning of something really nice…

ciecam02_adjustment :
#model properties: reference white, reference illuminant, background luminance
to_rgb rgb2xyz
(100,100,100) # reference white w
(100,100,100) # reference illuminant wr
backlum=1 # background/surround luminance
(0.7328,0.4296,-0.1624;-0.7036,1.6975,0.0061;0.003,0.0136,0.9384) +invert. # cat02 matrix and its inverse
mix_channels[0] [-2]

@afre I()will return vectors of the values for each channel of a pixel. You can use averages and perhaps dot products to get what you want.

Edit: so far I’ve completed everything up to the post-adaptation for this CIECAM02 adjustment command. I’ll need to make a reverse procedure for that.

ciecam02_adjustment :
# model properties: reference white, reference illuminant, surround ratio, adapting field luminance
# reference white in XYZ
wx=95.047
wy=100
wz=108.883
# reference illuminant wr in XYZ
wrx=95.047
wry=100
wrz=108.883
# surround ratio
sr=0.2
# adapting field luminance
la={10^2}
# relative background luminance
yb=1

factor={min((0.8+$sr),1)}
adapt=$factor*(1-(exp(-($la+42)/92))/3.6)
to_rgb rgb2xyz 1 f "i/[0.95047,1,1.08883]"
1,1,1,3,"["$wx","$wy","$wz"]*0.01"
1,1,1,3,"["$wrx","$wry","$wrz"]*0.01"
(0.7328,0.4296,-0.1624;-0.7036,1.6975,0.0061;0.003,0.0136,0.9384) +invert. # cat02 matrix and its inverse
mix_channels[0] [-2]
+mix_channels[-4,-3] [-1]
lumcorr={i(#-6,0,0,0,1)/i(#-5,0,0,0,1)}
lmult={i(#-1,0,0,0,0)/i(#-2,0,0,0,0)}
mmult={i(#-1,0,0,0,1)/i(#-2,0,0,0,1)}
smult={i(#-1,0,0,0,2)/i(#-2,0,0,0,2)}
rm[-2,-1]
f[0] "begin(n=("$lumcorr"*["$lmult","$mmult","$smult"]*"$adapt")+1-"$adapt");
n*I"
mix_channels[0] [-1]
(0.38971,0.68898,-0.07868;-0.22981,1.1834,0.04641;0,0,1)
mix_channels[0] [-1]
rm.
kmm=1/((5*$la)+1)
flmm=$kmm^4*$la+0.1*(1-$kmm^4)^2*(5*$la)^1/3
f[0] "(400*("$flmm"*I)^0.42)/(27.13+("$flmm"*I)^0.42)+0.1"
rm[^0]

@Joan_Rake1 Hope it is fast. A couple of months ago, I wrote a xyz2jzazbz and inverse for fun and it was miserably slow. I asked @garagecoder and he wrote one that was magnitudes faster. Still not satisfied with the outcome; hence, no talk about it.

Anyway, G’MIC needs more colour stuff. Unfortunately, it may never (or for the foreseeable future) have CMS support.

Not sure what the benchmarks should be but this one is quite fast.

As usual, unless I complain I’ll never get it to work. These commands should be invertible but they’re not.

rgb2lms :
# model properties: reference white, reference illuminant, surround ratio, adapting field luminance
# reference white in XYZ
wx=95.047
wy=100
wz=108.883
# reference illuminant wr in XYZ
wrx=95.047
wry=100
wrz=108.883
# surround ratio
sr=0.2
# adapting field luminance
la={10^2}
# relative background luminance
yb=1


factor={min((0.8+$sr),1)}
adapt=$factor*(1-(exp(-($la+42)/92))/3.6)
kmm=1/((5*$la)+1)
flmm=$kmm^4*$la+0.1*(1-$kmm^4)^2*(5*$la)^1/3
1,1,1,3,"["$wx","$wy","$wz"]*0.01"
1,1,1,3,"["$wrx","$wry","$wrz"]*0.01"
(0.7328,0.4296,-0.1624;-0.7036,1.6975,0.0061;0.003,0.0136,0.9384) +invert. # cat02 matrix and its inverse
+mix_channels[-4,-3] [-1]
lumcorr={i(#-6,0,0,0,1)/i(#-5,0,0,0,1)}
lmult={i(#-1,0,0,0,0)/i(#-2,0,0,0,0)}
mmult={i(#-1,0,0,0,1)/i(#-2,0,0,0,1)}
smult={i(#-1,0,0,0,2)/i(#-2,0,0,0,2)}
rm[-2,-1]

to_rgb[0] rgb2xyz[0] 1 f[0] "I/[0.95047,1,1.08883]"
mix_channels[0] [-2]
f[0] "begin(n=("$lumcorr"*["$lmult","$mmult","$smult"]*"$adapt")+1-"$adapt");n*I"
mix_channels[0] [-1]

(0.38971,0.68898,-0.07868;-0.22981,1.1834,0.04641;0,0,1)
mix_channels[0] [-1]
rm.

f[0] "(400*("$flmm"*I)^0.42)/(27.13+("$flmm"*I)^0.42)+0.1"

rm[^0]

lms2rgb :
# model properties: reference white, reference illuminant, surround ratio, adapting field luminance
# reference white in XYZ
wx=95.047
wy=100
wz=108.883
# reference illuminant wr in XYZ
wrx=95.047
wry=100
wrz=108.883
# surround ratio
sr=0.2
# adapting field luminance
la={10^2}
# relative background luminance
yb=1


factor={min((0.8+$sr),1)}
adapt=$factor*(1-(exp(-($la+42)/92))/3.6)
kmm=1/((5*$la)+1)
flmm=$kmm^4*$la+0.1*(1-$kmm^4)^2*(5*$la)^1/3
1,1,1,3,"["$wx","$wy","$wz"]*0.01"
1,1,1,3,"["$wrx","$wry","$wrz"]*0.01"
(0.7328,0.4296,-0.1624;-0.7036,1.6975,0.0061;0.003,0.0136,0.9384) +invert. # cat02 matrix and its inverse
+mix_channels[-4,-3] [-1]
lumcorr={i(#-6,0,0,0,1)/i(#-5,0,0,0,1)}
lmult={i(#-1,0,0,0,0)/i(#-2,0,0,0,0)}
mmult={i(#-1,0,0,0,1)/i(#-2,0,0,0,1)}
smult={i(#-1,0,0,0,2)/i(#-2,0,0,0,2)}
rm[-2,-1]


f[0] "((2713-27130*I)^(50/21))/("$flmm"*(-400100+1000*I)^(50/21))"
(0.38971,0.68898,-0.07868;-0.22981,1.1834,0.04641;0,0,1) invert.
mix_channels[0] [-1]
rm.
mix_channels[0] [-2]
f[0] "begin(n=("$lumcorr"*["$lmult","$mmult","$smult"]*"$adapt")+1-"$adapt");I/n"
mix_channels[0] [-1]
f[0] "I*[0.95047,1,1.08883]" xyz2rgb[0] 1 
rm[^0]

In particular I need to find an inverse to this: f[0] "(400*("$flmm"*I)^0.42)/(27.13+("$flmm"*I)^0.42)+0.1" but I can’t since my manual tries failed and so did a symbolic calculus thing I found online. It’s the last piece of this puzzle but I’ll never be able to solve it.

Edit: so I found some equations from colorspacious/ciecam02.py at master · njsmith/colorspacious · GitHub but they still don’t work for me. If I try the compression formula and then its inverse, the result is the original image but multiplied by a constant factor that varies with $la's value. When it’s 100 the factor is 2.77778, and when it’s 10 the factor is 0.0277803.

to_rgb
la=10^2
kmm=1/((5*$la)+1)
flmm=$kmm^4*$la+0.1*(1-$kmm^4)^2*(5*$la)^1/3
[0]
f[1] "temp=("$flmm"*abs(I)*0.01)^0.42;
sign(I)*400*(temp/(temp+27.13))+0.1"
f[1] "(sign(I-0.1)*(100/"$flmm")*((27.13*abs(I-0.1))/(400-abs(I-0.1)))^(1/0.42))"
f[1] "i/i(#0)"
display

@Joan_Rake1 Tried inverting by hand. I do not think it is correct.

val=((-397.187/I-27.13)^(1/.42))/F

EDIT: Try ((2713-27130*I)/(flmm*(1000*I-4001000)))^2.3809523809523809523809523809524 That’s correct.

I’ve found the factor that’s giving me problems. When I eliminate $flmm from the formulae or set it to 1 it suddenly works!

$flmm is a variable model parameter which ultimately depends on $la. Within the fill block it should be treated as a constant, so I could try that.

Edit: it was to do with the way the variable’s substituted. I haven’t used the mathematical parser when setting $flmm's value so it’s treating it as a string, and the order of operations in the inverse function is different. So really all I needed to do was add brackets:

la=(10^2)

kmm=(1/((5*$la)+1))
flmm=($kmm^4*$la+0.1*(1-$kmm^4)^2*(5*$la)^1/3)

@Joan_Rake1 Any idea why inverse channel selection does not work? Inverse is supposed to be going from Blue → Green → Red. Not Blue → Red → Green.

EDIT: I can fix it by doing sh. 0,1 mirror. c operation though. Not convenient, but it works.

Code for channel per lines
$1 == Thickness of Line
$2 ==Axis
rep_linechan:
repeat $! l[$>]

 sh. 0,2
 
 if $1>=0
  if $2 chansel="int(y/thickness)%3"
  else  chansel="int(x/thickness)%3"
  fi
 else
  if $2 chansel="2-(int(y/thickness)%3)"
  else  chansel="2-(int(x/thickness)%3)"
  fi
 fi
 
 f. "begin(
  imgvec=vector3(0);
  const thickness=abs($1)>=1?round($1):1;
  chansel()="$chansel";
 );
 imgvec*=0;
 imgvec[chansel()]=i(x,y,z,chansel());
 imgvec;
 "
 rm.
endl done

Also, this works great with RGB, and RYB images, and XYZ.

@afre
I don’t think I can bring new elements

jacques

@jdc No problem. Turns out it was a coding issue.