Reptorian G'MIC Filters

Nice. Your designs are looking cleaner than when you started.

8/18:

Yes, they are. I still think that some of the earlier design could be option for the regular popcorn fractal. That being said, I had pushed Complex Popcorn Fractal as a CLI filter. I hope the help documentation for rep_c_pfrac is useful.

This is the documentation:

rep_c_pfrac help documentation
  rep_c_pfrac (+):
      Shortcut for command 'rep_complex_popcorn_fractal'.

  rep_complex_popcorn_fractal:
      _points>0,_density>0,_H,_K,_zoom,_rotation_angle,_origin_x,_origin_y,
        set_arg_a,set_arg_b

    Generates Pickover Popcorn Fractal utilizing complex-plane functions.
    Discovered by T.Gangopadhyay at XLRI in C.H.Area(E),Jamshedpur,India in
    2012.

    Source: International Journal of Computer Applications(0975-8887) Volume
    50-No.8, July 2012.

    _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(a,b) 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.
    _set_arg defines complex trigometric functions to utilize to define the
    complex popcorn fractal. There is at least three different set of argument
    to use. Use the example formula to avoid needing to manually type these
    arguments.

    Note: See below note for more details on _set_arg

    ---- Set of arguments for each _set_arg -----

     if _set_arg_n_1==0: 0,_complex_function

      _complex_function={0=csin|1=csinh|2=ccos|3=ccosh|4=ctan|5=ctanh}

     elif _set_arg_n_1==1: 1,_complex_function_a,_complex_function_b

      _complex_function_a={0=v|1=csin|2=csinh|3=ccos|4=ccosh|5=ctan|6=ctanh}
      _complex_function_b={0=v|1=csin|2=csinh|3=ccos|4=ccosh|5=ctan|6=ctanh}

     elif _set_arg_n_1==2: 2,_complex_function_a,_complex_function_b,_include_v

      _complex_function_a={0=csin|1=csinh|2=ccos|3=ccosh|4=ctan|5=ctanh}
      _complex_function_b={0=csin|1=csinh|2=ccos|3=ccosh|4=ctan|5=ctanh}
      _include_v={0=FALSE|1=TRUE}

     fi

    ---- End ----

    Author: Reptorian.

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

    Example:
      [#1] set_arg_a=0,0 set_arg_b=0,4 512,512 rep_complex_popcorn_fractal 50,
       2,.05,3,.5,45,0,0,$set_arg_a,$set_arg_b cut 0,5000
      [#2] set_arg_a=2,1,4,, set_arg_b=1,4,2 512,512
       rep_complex_popcorn_fractal 50,2,.05,3,.5,45,0,0,$set_arg_a,
       $set_arg_b cut 0,1000

I have released Complex Popcorn Fractal, but that’s a misnomer because it doesn’t actually use imaginary. I would have to address that, and it’s going to be renamed to Transformative Popcorn Fractal. So, if you see it gone, it’s just renamed after I have fixed code to make it much faster. It’s extremely slow now.

Now, it is changed to Transformative Popcorn Fractal. See this for details - Changes to the new filter · dtschump/gmic-community@2cf7aaf · GitHub


Even yet another variation of Popcorn Fractal incoming. This version has H, and K as complex number, and a initial starting imaginary number.

image


8/19 Update:

New Filter! - Complexion Burst

It’s the last picture to demonstrate.


8/20:

After testing out Complexion Burst, I finally realized why it’s so hard to work with compared to the normal version. For better shading, one need to work on using float precision, and post-processing using s-shaded curve and a upward curve bulge, and a very large surface. The reason is that Complexion Burst frequently hits localized areas, and the more you zoom in, the more you lose curves found with zoomed-out images. It seem that I can only address the post-processing shading problem. I believe @afre talked about this before (S-Curves shading)

1 Like

Now, I created a new generic cli filter. I think @afre would find it useful, and I do plan to put it into Popcorn Fractal and variants that I have submitted. That way, I can dodge the need to create color functions to them.

The new cli filter is named rep_exp_sig_adj. Basically, combines sigmoid curve adjustment with exponential curve adjustment. I will plan to improve it by separating positive/negative value influence within sigmoid function.

Here’s a picture:
image

Also, I do have news that I might be working, so G’MIC activity will be reduced. Wish me luck.

EDIT: And no luck on finding a job. :confused:


I have made large number of changes to reptorian.gmic. Particularly on restructuring code so that it is easier to read.

Also, I found this bug. @David_Tschumperle

D:\Programs\G'MIC\gmic-community>gmic 500,500 u {\"const m=norm(w,h);m;\"} rm. echo ${}
[gmic]-0./ Start G'MIC interpreter.
[gmic]-0./ Input black image at position 0 (1 image 500x500x1x1).
[gmic]-1./ *** Error *** Item substitution '{const m=norm(w,h);m;}': Operator '=': Second argument (of type 'scalar') is not a constant, in expression 'const m=norm(w,h);m...'

There is also another bug related.

D:\Programs\G'MIC\gmic-community>gmic u {\"const m=(v=4;v^2+v-1;);\"}
[gmic]-0./ Start G'MIC interpreter.
[gmic]-0./ *** Error *** Item substitution '{const m=(v=4;v^2+v-1;);}': Operator '=': Second argument (of type 'scalar') is not a constant, in expression 'const m=(v=4;v^2+v-1;)'.

Which begs me to wonder. Why not evaluate the entire expression before inserting it as a constant?

1 Like

Some of you may noticed bugs that are cropping up. Please do not be alarmed, I’m in the process of refactoring code.

For non-programmers, this means making code easier to comprehend, and reducing reductive lines.

So, these bugs will be fixed, but I do need cooperation. If you can find bugs, do tell them to me, and they will be addressed.

EDIT: I might be finished with refactoring. Please refresh and don’t be afraid to pester me on bugs because I think there are even after refactoring.


9/12/2021 Update:

I think that I am done with making code easier to read. I did git diff from two different commits, checked many times and have found all issues might have been resolved. I may be wrong though, but I believe it has been resolved.

So, my code should be much easier to read now that it has been refactored for that purpose, and the file size has been trimmed significantly. As for OOBS, and Vibrato, again no plans to touch these.

This is not much, but it’ll be a new filter:

Based off Ellsworth Kelly’s work. If you pay attention closely, you will notice that there are no two colors that are neighbor that are the same.

The white ?

That’s background color, so it doesn’t count.

How many different colors do you consider ?

5 at the minimum because if all 4 surrounding neighbors (top, bottom, left, right) are filled with different colors, then it cannot find a color which will be a unique color from the existing palette. I tested it with pal bw_rgb or pal 3. Works with 5, but 4 almost always throws a error.

Here’s the current source code:

Ellsworth Kelly Grid
#@cli rep_ekscg: eq. to 'rep_ellsworth_kelly_color_grid' : (+)
rep_ekscg: rep_ellsworth_kelly_color_grid $*
#@cli rep_ellsworth_kelly_color_grid: sqr_size,_border_size[%],_border_value[%],_distribution,_{pal_id,[image]},_background_hex,fit_mode,_color_space
#@cli : Outputs a color grid based on colored square tiles art made by Ellsworth Kelly with transparent areas.
#@cli : sqr_size defines the painted square size.
#@cli : _border_size defines the size of border. Negative number will take away areas from the painted squares. Positive number will separate painted areas by this amount.
#@cli : _border_value defines the gray level of border.
#@cli : _distribution defines the probability of a square to be painted.
#@cli : _{pal_id,[image]} defines the color. If you choose a name of a existing palette, then this will be the base of the colors of the square. Otherwise, it will be based off the palette.
#@cli : _background_hex defines the background color
#@cli : _fit_mode defines whether the resulting grid should exceed the size of the original image.
#@cli : _color_space defines the color space of the grid.
#@cli : Default values: '_border_size=10%','_border_value=50%','_distribution=10%','{pal_id,[image]}=120','_background_hex=n/a',_fit_mode=0,_color_space=0
#@cli :
#@cli : Author: Reptorian
rep_ellsworth_kelly_color_grid:
skip "${2=10%},${3=50%},${4=50%},${5=120},${6=},${7=0},${8=0}"

check "($1==int(abs($1)))&&(int(abs($1))>=1)"

convert_colors_fwd=${arg\ $8+1,,rgb2ryb,rgb2cmy,rgb2cmyk,rgb2hcy,rgb2hsi,rgb2hsl,rgb2hsv,rgb2ycbcr,rgb2ycbcrglic,rgb2yiq,rgb2yuv,rgb2xyz,rgb2yes}
convert_colors_bwd=${arg\ $8+1,,ryb2rgb,cmy2rgb,cmyk2rgb,hcy2rgb,hsi2rgb,hsl2rgb,hsv2rgb,ycbcr2rgb,ycbcrglic2rgb,yiq2rgb,yuv2rgb,xyz2rgb,yes2rgb}

ref_sqr_size={abs($1)}

mode=1

border_direction={$2>=0}

('$2')

if i(#-1,w-1)==37 use_percent=1 else use_percent=0 fi

rm.
 
if $border_direction&&$ref_sqr_size>1

 if $use_percent border_size={round(($ref_sqr_size)*abs($2))}
 else border_size={round(abs($2))-1}
 fi
 
 if $border_size>0
  sqr_size={$ref_sqr_size+$border_size}
 else
  sqr_size=$ref_sqr_size
 fi
 
elif !$border_direction||$ref_sqr_size==1

 if $use_percent border_size={round(($ref_sqr_size-1)*abs($2))}
 else border_size={min(round(abs($2)),$ref_sqr_size-1)}
 fi
 sqr_size=$ref_sqr_size
 
else
 border_size=0
 sqr_size=$ref_sqr_size
fi

border_value={cut($3,0,1)}

if ${is_image_arg\ $5}

 pass$5 0
 
 if !((w>1&&h==1)||(w==1&&h>1)) error dim_inv fi
 
 l.
  if w>h
   s x
  else
   s y
  fi
  remove_duplicates
  a x
 endl
 
 cs=$8
 
else

 pal $5
 cs=0
 
fi

if w#-1<5 error min_cols>=5==F fi

if $cs<2 init_border_color={vector3($border_value*255)}
elif $cs==2 init_border_color=0,0,{$border_value*255}
elif $cs==3 init_border_color=0,0,0,{$border_value*255}
elif $cs>=4&&$cs<=7 init_border_color=0,0,{$border_value}
elif $cs>=8&&$cs<=13||$cs==15 init_border_color={$border_value*255},0,0
elif $cs==14 init_border_color={$border_value*255},{$border_value*255},{$border_value*255}
fi

if narg($6)
 bg_color=${rep_hex2int8\ $6}
 1,1,1,{s},"vectors("$bg_color")"
 if $8 $convert_colors_fwd. fi
 eval.. "begin(test_color=I(#-1,0,0,0););if(I==test_color,run('error inval_bant'));"
 empty_color=[{[crop(#-1),255]}]
 rm.
else
 empty_color=vector(#s,0)
fi

if $border_size
 condition_text=condition=(nx>border_size)&&(ny>border_size);
 result=condition?color:border_color;
else
 result=color;
fi

repeat $!-1 l[$>,-1]

 if $7
  mini_w={ceil(w#0/$sqr_size)}
  mini_h={ceil(h#0/$sqr_size)}
 else
  mini_w={int(w#0/$sqr_size)}
  mini_h={int(h#0/$sqr_size)}
 fi
 
 large_w={$mini_w*$sqr_size+($border_size+1)}
 large_h={$mini_h*$sqr_size+($border_size+1)}
 
 if $7
  if ($large_w-$sqr_size)>w#0 
   large_w-=$sqr_size 
   mini_w-=1
  fi
  if ($large_h-$sqr_size)>h#0  
   large_h-=$sqr_size 
   mini_h-=1
  fi
 else
  if $large_w>w#0 
   large_w-=$sqr_size 
   mini_w-=1
  fi
  if $large_h>h#0 
   large_h-=$sqr_size 
   mini_h-=1
  fi
 fi
 
 $mini_w,$mini_h,1,1,"begin(
   const probability=cut($4,0,1);
   if(probability==1,
    calc_result()=int(u(w#-1));,
    calc_result()=u(1)<probability?int(u(w#-1)):-1;
   );
  );
  calc_result();
  "
  
 f. >"begin(
   const num_of_colors=w#-2;
   const mx=w-1;
   const my=h-1;
   find_new_color()=(
    if(sum(cols)==num_of_colors,run('error cols_option_filled'));
    new_col_id=int(u(num_of_colors));
    do(
     new_col_id++;
    ,cols[new_col_id%num_of_colors]
    );
    new_col_id%num_of_colors;
   );
  );
  cols=vector(#num_of_colors,0);
  (i+1)?(
   (x==0&&y==0)?(
    (j(1,0)+1)?cols[j(1,0)]=1;
    (j(0,1)+1)?cols[j(0,1)]=1;
    find_new_color();
   ):
   (x==mx&&y==0)?(
    (j(-1,0)+1)?cols[j(-1,0)]=1;
    (j(0,1)+1)?cols[j(0,1)]=1;
    find_new_color();
   ):
   (x==0&&y==my)?(
    (j(1,0)+1)?cols[j(1,0)]=1;
    (j(0,-1)+1)?cols[j(0,-1)]=1;
    find_new_color();
   ):
   (x==mx&&y==my)?(
    (j(-1,0)+1)?cols[j(-1,0)]=1;
    (j(0,-1)+1)?cols[j(0,-1)]=1;
    find_new_color();
   ):
   (x==0)?(
    (j(1,0)+1)?cols[j(1,0)]=1;
    (j(0,1)+1)?cols[j(0,1)]=1;
    (j(0,-1)+1)?cols[j(0,-1)]=1;
    find_new_color();
   ):
   (x==mx)?(
    (j(-1,0)+1)?cols[j(-1,0)]=1;
    (j(0,1)+1)?cols[j(0,1)]=1;
    (j(0,-1)+1)?cols[j(0,-1)]=1;
    find_new_color();
   ):
   (y==0)?(
    (j(0,1)+1)?cols[j(0,1)]=1;
    (j(1,0)+1)?cols[j(1,0)]=1;
    (j(-1,0)+1)?cols[j(-1,0)]=1;
    find_new_color();
   ):
   (y==my)?(
    (j(0,-1)+1)?cols[j(0,-1)]=1;
    (j(1,0)+1)?cols[j(1,0)]=1;
    (j(-1,0)+1)?cols[j(-1,0)]=1;
    find_new_color();
   ):(
    (j(1,0)+1)?cols[j(1,0)]=1;
    (j(-1,0)+1)?cols[j(-1,0)]=1;
    (j(0,1)+1)?cols[j(0,1)]=1;
    (j(0,-1)+1)?cols[j(0,-1)]=1;
    find_new_color();
   );
  ):-1"
  
  $large_w,$large_h,1,{s#-2+1},*"begin(
   const col_s=s#-2;
   const border_size=$border_size;
   modv(a)=a-int(a/$sqr_size)*$sqr_size;
   mini(a)=int(a/$sqr_size);
   const gv=$border_value*255;
   border_color=["$init_border_color",255];
   empty_color="$empty_color";
  );
  nx=modv(x);
  ny=modv(y);
  mx=mini(x);
  my=mini(y);
  "$condition_text"
  color_pos=i(#-1,mx,my,0,0);
  color=(color_pos+1)?[I(#-2,color_pos,0,0),255]:empty_color;
  "$result"
  "
  
  if $8 
   if $8!=3 $convert_colors_bwd. 
   else 
    if s==5 s. c,-2 cmyk2rgb.. a[-2,-1] c
    else cmyk2rgb.
    fi
   fi
  fi
  
  if $7 rv[0,-1] rm[-2,-1]
  else
   if s#0!=s#-1 
    if s#-1==4 to_rgba[0] elif s#==2 to_graya[0] fi
   fi
   if narg($6) j[0] [-1],.5~,.5~ rm[-2,-1]
   else sh. 0,{s-2} sh.. {s} j[0] [-2],.5~,.5~,0,0,1,[-1],255 rm[-4--1]
   fi
  fi
  
endl done

rm.

New filter! Ellsworth Kelly Board

The above was created with the GUI filter.

2 Likes

Now that the Ellsworth Kelly Board is fully functional, I decided to rewrite fibonacci. Made a clever new solution too. The older version looks like a mess compared to this solution. This would be the base.

New Fibonacci
rep_fibonacci_fill_new:
skip "${6=}"
check $!>0

r 100%,100%,100%,1,-1

timg={$!}

+rep_fibonacci ${1-4}

fibo_id={$!-1}

if $4
 if $2
 else
 fi
else
 if $2
  f[^-1] "begin(
    const ww=w-1;
    const hh=h-1;
    const ox=(1+cut($5,0,1))/2;
    const oy=(1+cut($6,0,1))/2;
    const px=int(xm#-1-ww*ox);
    const py=int(ym#-1-hh*oy);
   );
   i(#-1,px+x,py+y,z,0);"
 else
  if $1==0   j[^-1] [-1],0~,0~
  elif $1==1 j[^-1] [-1],1~,0~
  elif $1==2 j[^-1] [-1],0,1~
  else       j[^-1] [-1],1~,1~
  fi
 fi
 if narg($5)
  if ${is_image_arg\ $5}
   #-1#
   pass$5 0
   #-2#
   l.
    if w>h s x remove_duplicates a x
    else s y remove_duplicates a x
    fi
   endl
   {w#-1},1,1,100%,"begin(if(narg($6),srand($6)););u"
   pixelsort.. +,x,[-1]
   map[0--3] [-1]
   rm[-3--1]
  else error \$\5!=img_arg
  fi
 fi
fi
+rep_fibonacci:
# _direction=={ 0= top left | 1= top right | 2= bottom left | 3= bottom right }
# _spiral_mode={ 0= non-spiral | 1= spiral_fill }
# _start_pos
# _iteration

dir={$1%4}

if $4==1 1 return fi

use_dim_lim={!$4}

if $4
 iter_lim=$4
else
 iter_lim=inf
 mw=${-max_w}
 mh=${-max_h}
fi

__size_n=2
size_1=1
size_2=2

__iter=2

m "swap: rv[-2,-1]"
m "join: a[-2,-1] $""1"
m "ins_north: $__size_n,$__size_n,1,1,$__iter swap join y"
m "ins_south: $__size_n,$__size_n,1,1,$__iter join y"
m "ins_west: $__size_n,$__size_n,1,1,$__iter swap join x"
m "ins_east: $__size_n,$__size_n,1,1,$__iter join x"

na={$2?4:2}

if $3
 if $2 #Spiral Mode#
  if $1%2 1,2,1,1,1-y
  else    1,2,1,1,y
  fi
  if $dir==0   ins_arg=ins_west,ins_south,ins_east,ins_north
  elif $dir==1 ins_arg=ins_west,ins_north,ins_east,ins_south
  elif $dir==2 ins_arg=ins_east,ins_south,ins_west,ins_north
  else         ins_arg=ins_east,ins_north,ins_west,ins_south
  fi
 else #Corner Mode#
  if $dir<2 1,2,1,1,y
  else      1,2,1,1,1-y
  fi
  if $dir==0   ins_arg=ins_east,ins_south
  elif $dir==1 ins_arg=ins_west,ins_south
  elif $dir==2 ins_arg=ins_east,ins_north
  else         ins_arg=ins_west,ins_north
  fi
 fi
else
 if $2 #Spiral Mode#
  if $1%2 2,1,1,1,x
  else    2,1,1,1,1-x
  fi
  if $dir==0   ins_arg=ins_north,ins_west,ins_south,ins_east
  elif $dir==1 ins_arg=ins_north,ins_east,ins_south,ins_west
  elif $dir==2 ins_arg=ins_south,ins_west,ins_north,ins_east
  else         ins_arg=ins_south,ins_east,ins_north,ins_west
  fi
 else #Corner Mode#
  if $1%2 2,1,1,1,1-x
  else      2,1,1,1,x
  fi
  if $dir==0   ins_arg=ins_south,ins_east
  elif $dir==1 ins_arg=ins_south,ins_west
  elif $dir==2 ins_arg=ins_north,ins_east
  else         ins_arg=ins_north,ins_west
  fi
 fi
fi

do
 if $__iter==$iter_lim break fi

 if $use_dim_lim
  if (w#-1>$mw)&&(h#-1>$mh) 
   if $2
    iter_lim=$__iter+3
    use_dim_lim=0
   else break
   fi
  fi
 fi
 
 ${arg\ ($__iter%$na)+1,$ins_arg}
 
 __size_n={$size_1+$size_2}
 size_1=$size_2
 size_2=$__size_n
 
 __iter+=1
while $__iter<$iter_lim

um swap,join,ins_north,ins_south,ins_west,ins_east

EDIT: Saving this for later as I will be away from my main PC again.

EDIT: Back to main pc.

Finally, I successfully refactored Fibonacci! Fibonacci Texture has been changed to Fibonacci.


@KaRo Since I cannot PM you, I got a question for you. Is there a version of map with negative palette as option in Pink library? I asked because I don’t want to use the image command as opposed to map because it is like 10 times slower which is why I asked. Negative palette involves just adding a image argument as base for negative values.

Hi, as far as I see no. In pink there are only three look-up-table related routines using all pgm byte images and lut-files with pgm/ppm byte output. The color related things are seemingly in pink quite poor. Still look by yourself Pink: Main Page.

The routines I mentioned are pgm2ppm, genlut and colorize

Got it. One more thing, where can one download Pink Library? (Source Code and Binary package) The download link is dead. Wayback Machine doesn’t have it.

EDIT: Found it here - Pinkimage - Browse Files at SourceForge.net

Do add a note to download the library from there.

I am using a link I got from Michel Couprie : > > http://www.esiee.fr/~coupriem/pink.tgz

Binaries are a problem, I have build them for my Mac and some/many years ago under Windows and linux. I think you have to go through that too!

I found the pink library installed right here - C:\Users\User\AppData\Local\Programs\Python\Python38\Lib\site-packages\pink. I just put that under path to get it to work on G’MIC?

I really don’t think you need to install PINK for that!
Writing a map2 command that takes two palettes as arguments (one for the negative values, the other for the positive values) seems simple enough:

#@cli map2 : [palette_negative],[palette_positive],_boundary_conditions
map2 :
  pass$1 0 mirror. x off={w}
  pass$2 0 to_colormode[-2,-1] 0
  a[-2,-1] x
  repeat $!-1 +[$>] $off map[$>] . done
  rm.

test_map2 :
  sp lena luminance n -255,255 round  # Image with negative/positive values
  palette 4 # 'Negative' palette
  palette 3 # 'Positive' palette

  map2[-3] [-2],[-1]
1 Like

Here’s my concern with that, if the positive value exceed the size of combined palette, then I will see negative palette mapped on positive values.

Also, I mentioned that you can map into Nan and inf value which shouldn’t happen. In the case of Fibonacci, if that wasn’t the case, I would be able to dodge the need of negative palette on map to retain almost the same computational speed.

No, if the positive values go outside the positive palette, it just does the same as with the classical map (except if you chose boundary_conditions=2).

Never a good idea to use map on an image containing inf or nan.
Commands replace_inf, replace_nan and replace_naninf may be useful in that case.

Also, if you have a very specific need for a custom map command, remember you can always use a personalized expression in conjunction with fill to control what you want to do precisely.

@David_Tschumperle I got my solution, but I’d imagine it would be 2 times slower than a c++ map disabling mapping on inf/nan, and c++ map just on inf/nan. Maybe I’ll try on that later, but barely know C++.

$ 500,500,1,1,norm((x-(w/2))/(w/2),(y-(h/2))/(h/2)); f. i"<"1?i*10:inf pal 140 tic +store.. base map.. . $base eval. isinf(i)?I(#-3)=[50,250,50] rm[-2,-1] toc

The line between tic toc is what I’m thinking of as in inf get replaced with a color.