Reptorian G'MIC Filters

Have a look at this sweet new code for rep_diffusion_limited_aggregation. Note there is a ‘_new’ next to command name, so it won’t interfere with current version. This will replace current version when I add a feature to randomly insert points via probability around appended points, and this will create thickening.

I say the code is sweet because it is easier to understand what’s going on and easier to add features or base new code off from. It’s faster too for all cases.

Also, I note that there is Laplacian Growth version, but I never was able to find code for it. Laplacian Growth is a much faster version for DLA.

image

The New Diffusion Limited Aggregation Code
$ {vector2(300)}  rep_diffusion_limited_aggregation_new 100,2,0,0,0,0
#@cli rep_dla : eq. to 'rep_diffusion_limited_aggregation' : (+)
rep_dla_new: rep_diffusion_limited_aggregation_new $*
#@cli rep_diffusion_limited_aggregation: _escape,_mode,_stem_color={ 0=dark | 1=light },_border,_initial_point_mode={ 0=less_dense | 1=more_dense },_preserve_binary_image={ 0=maskless | 1=mask }
#@cli : Generate Diffusion Limited Aggregation
#@cli : (eq. to 'rep_dla').
#@cli :
#@cli : '_escape' defines how much attempts on filling the aggregation form before finishing.
#@cli : '_mode' defines how particles aggregate on the aggregation form.
#@cli : '_stem_color' defines where the aggregation form will fill on.
#@cli : '_border' is only applicable if there is a planting seed map. It is used to limit particles based on proximity away from existing structure.
#@cli : '_initial_point_mode' defines whether to use less dense or more dense point coordinates map.
#@cli : '_preserve_binary_image' is only applicable on images with variance.
#@cli :
#@cli : Author: Reptorian.
#@cli : Default values: '_escape=10','_mode=1','_stem_color=1','_border=0','_keep_erase_mask=1','_initial_point_mode=1','_preserve_binary_image=1'
rep_diffusion_limited_aggregation_new:
skip ${1=100},${2=0},${3=0},${4=0},${5=1},${6=1}

maximum_iterations,pixel_detection_mode,stem_color,border_size,initial_coordinates_map_mode,preserve_silhouette_mode={[abs($1),int($2)%4,!$3,round(abs($4)),$5?1,$6?1]}
inv_stem_color,use_altern_text,n_threads={[!$stem_color,$pixel_detection_mode==3]},$_cpus

m "dla_target_1s:
   ge {avg(iM,im)}
  "
m "dla_target_2s:
    normalize 0,1
    split[-1] c *
    ge {avg(iM,im)}
  "
m "dla_target_3s:
    normalize 0,1
    split c
    add / 3
    ge {avg(iM,im)}
  "
m "dla_target_4s:
    normalize 0,1
    ts={s-1}
    split c
    add[^-1]
    /[-1] $ts *
    ge {avg(iM,im)}
  "
m "dla_target:
    if s==1   dla_target_1s
    elif s==2 dla_target_2s
    elif s==3 dla_target_3s
    else      dla_target_4s
    fi
  "
m "dla_check_variance:
    tv=0

    repeat s {
     shared $>
     tv+={iv#-1}
     rm.

     if $tv
      break
     fi
    }

    status {$tv?1:0}
  "
m "dla_clear_image:
   {w#0},{h#0},1,1,"$stem_color"
   rv[-1,0]
   rm.
  "

if $use_altern_text
 altern_text_a=altern=int(u(0,2))
 altern_text_b=altern=++altern%2
fi

foreach

 if s>4||d#0>1 continue fi

 +dla_create_coordinate_map $initial_coordinates_map_mode
 gcd_shuffle.

 use_dla_map=${dla_check_variance[0]}

 if $use_dla_map

  dla_target[0]

  if $border_size
   +distance.. $inv_stem_color,2
   1,{h#-2},1,1,v=i(#-1,I(#-2));v?(v<=$border_size?y:-1):-1
   discard. -1
   map. ...
   1,100%,1,1,i(#2,I(#-1))
   rm[-4,-3]
   pixelsort.. +,y,.
   rm.
   1,100%,1,1,:"begin_t(const n_threads=$n_threads;n=t;);v=n;n+=n_threads;v;"
   map. ..
   rm..

   if !$preserve_silhouette_mode
    if $stem_color
	 replace[0] 0,.999
    else
     *[0] .001
    fi
   fi

  else
   if $stem_color val_check=>.999
   else  val_check=<.001
   fi

   1,{h},1,1,y
   eval.. :if(!(i(#0,I)$val_check),i(#-1,0,y)=-1;);I;
   discard. -1
   map. ..
   rm..

   +distance[-2] $inv_stem_color,2
   1,{h#-2},1,1,i(#-1,I(#-2))
   rm[-2]
   pixelsort[-2] +,y,[-1]
   rm[-1]
   1,100%,1,1,:"begin_t(const n_threads=$n_threads;n=t;);v=n;n+=n_threads;v;"
   map. ..
   rm..

   if !$preserve_silhouette_mode
    if $stem_color
	 replace[0] 0,.999
    else
     *[0] .001
    fi
   fi

  fi

 else

  center_x,center_y={[(w#0-1)>>1,(h#0-1)>>1]}
  minimum_circle_radius={norm($center_x,$center_y)}

  1,{h},1,2,"begin(
    const sqrt_of_two=sqrt(2);
    const minimum_circle_radius=$minimum_circle_radius;
    const center_x=$center_x;
    const center_y=$center_y;
   );
   distance_from_center=norm(I#-1-[$center_x,$center_y]);
   distance_from_center<=minimum_circle_radius?(
    relative_position=distance_from_center/minimum_circle_radius;
    valid_point=lerp(1,u^.625,relative_position)>=relative_position?y:-1;
   ):(
    valid_point=-1;
   );
   [distance_from_center,valid_point];
   "

  split[-1] c
  discard[-1] -1
  [-1]
  repeat 2 { map[{$>-2}] [{$>-4}] }
  remove[-4,-3]
  pixelsort[-2] +,y,[-1]
  remove[-1]
  1,100%,1,1,:"begin_t(const n_threads=$n_threads;n=t;);v=n;n+=n_threads;v;"
  map[-1] [-2]
  remove[-2]

  dla_clear_image
  set[0] $inv_stem_color,50%,50%
 fi

 a[^0] y

 eval[1] :"begin_t(
   const width=w#0;
   const height=h#0;

   const limit_of_attempts=$maximum_iterations;
   const pixel_detection_mode=$pixel_detection_mode;
   const target_mode=$inv_stem_color;

   new_pos_x=[-1, 0, 1,
              -1,    1,
              -1, 0, 1];
   new_pos_y=[-1,-1,-1,
               0,    0,
               1, 1, 1];

   if(!target_mode
   ,det_px(pixel)=pixel<1;
   ,det_px(pixel)=pixel;
   );

   pixel_detection_mode==3?(
    pixel_detected()=
     altern?(
      det_px(i(#0,xp-1,yp-1,0,0,0,2))||
      det_px(i(#0,xp-1,yp+1,0,0,0,2))||
      det_px(i(#0,xp+1,yp-1,0,0,0,2))||
      det_px(i(#0,xp+1,yp+1,0,0,0,2))
     ):(
      det_px(i(#0,xp-1,yp,0,0,0,2))||
      det_px(i(#0,xp+1,yp,0,0,0,2))||
      det_px(i(#0,xp,yp-1,0,0,0,2))||
      det_px(i(#0,xp,yp+1,0,0,0,2))
     );
    ):
   pixel_detection_mode==2?(
    pixel_detected()=
     det_px(i(#0,xp-1,yp-1,0,0,0,2))||
     det_px(i(#0,xp-1,yp+1,0,0,0,2))||
     det_px(i(#0,xp+1,yp-1,0,0,0,2))||
     det_px(i(#0,xp+1,yp+1,0,0,0,2))||
     det_px(i(#0,xp-1,yp,0,0,0,2))||
     det_px(i(#0,xp+1,yp,0,0,0,2))||
     det_px(i(#0,xp,yp-1,0,0,0,2))||
     det_px(i(#0,xp,yp+1,0,0,0,2));
   ):
   pixel_detection_mode==1?(
    pixel_detected()=
     det_px(i(#0,xp-1,yp,0,0,0,2))||
     det_px(i(#0,xp+1,yp,0,0,0,2))||
     det_px(i(#0,xp,yp-1,0,0,0,2))||
     det_px(i(#0,xp,yp+1,0,0,0,2));
   ):(
    pixel_detected()=
     det_px(i(#0,xp-1,yp-1,0,0,0,2))||
     det_px(i(#0,xp-1,yp+1,0,0,0,2))||
     det_px(i(#0,xp+1,yp-1,0,0,0,2))||
     det_px(i(#0,xp+1,yp+1,0,0,0,2));
   );

   "$altern_text_a"
  );

  temp_vec=I;

  xp=temp_vec[0];
  yp=temp_vec[1];

  repeat(limit_of_attempts,
   pv=int(u(0,8));

   xp+=new_pos_x[pv];
   yp+=new_pos_y[pv];
   xp%=width;
   yp%=height;

   if(pixel_detected(),
    i(#0,xp,yp)=target_mode;
    break();
   );

   "$altern_text_b"
  );

  I;
  "

 k[0]

 if $use_dla_map&&!$preserve_silhouette_mode round fi

done

um dla_target,dla_target_1s,dla_target_2s,dla_target_3s,dla_target_4s,dla_check_variance,dla_clear_image
+dla_create_coordinate_map:
if $1
 row_a={ceil(h/2)}
 row_b={h-$row_a}
 counts_per_row_a,counts_per_row_b={[w,w+1]>>1}

 1,{$row_a*$counts_per_row_a+$row_b*$counts_per_row_b},1,2,:"begin(
   const row_length=w#-1;
   const half_row_length=row_length>>1;
  );
  pos_y=int(y/half_row_length);
  ny=y<<1;
  pos_x=pos_y&1?(ny%row_length):((ny+1)%row_length);
  [pos_x,pos_y];
  "
else
 1,{(w>>1)*(ceil(h/2))},1,2,:"begin(
   const row_length=w#-1;
   const half_row_length=row_length>>1;
  );
  y_pos=int(y/half_row_length)<<1;
  [(y<<1)%row_length,y_pos];
  "
fi

EDIT: I realized my algorithm fails in one way. It seems that there isn’t as much perpendicular stem at all, and that is needed in case of empty image. Hmm, that needs to be addressed. I don’t know, but smaller images doesn’t have that problem:

image