Reptorian G'MIC Filters

I would go the crop, resize, then image with opacity mask route.

PS ENHANCE!

Can you show a example? I failed at this filter since there’s a bug with subsampling level:

Failed script
rep_zoomin_shape:
#$1=shape#
#$2=pos-x(%)#
#$3=pos-y(%)#
#$4=place-pos-x#
#$5=place-pos-y#
#$6=shape_ratio_to_image#
#$7=zoom_level#
#$8=zoom_interpolation#
#$9=line_thickness-size#
#$10=line_thickness=color#
#$11=style#
#$12=subpixel_level#
#$13=subsampling_mode#
#$14=fit_tile#
#$15--1=shape_options#

__use_prebuilt_shape={!${"is_image_arg $1"}}
__sub={abs($12)+1}
isub={1/$__sub*100}
__line_thickness={round(abs($9))}
__izf={max(1,abs($7))}
__zf={1/max(1,$__izf)}
__new_line_thickness={$__line_thickness*$__sub}
__line_expand_factor={ceil($__new_line_thickness/2)}

if $__line_thickness
else
 style={$11%3}
fi

command "rep_zoomin_shape_zoomimage:
 if abs($""1)
  f. \"begin(
    const cx=w/2;
    const cy=h/2;
    const zf=$""1;
   );
   ic=[x-cx,y-cy];
   nc=ic*zf;
   jc=nc-ic;
   J(jc[0],jc[1],0,$""2)\"
 fi"
 
command "rep_zoomin_shape_create_border:
 f i?!(j(-1,0)&&j(1,0)&&j(0,-1)&&j(0,1))
 dilate_circ. $__new_line_thickness,0,0"

hex2img $10
l. s y a c endl
store. __line_color

if $__use_prebuilt_shape

 __sid="$1"
 
 if isnum($1) if isint($1)
  __sid=${"-arg "1+$__sid"","australia,barbedwire,circle,crosshair,cupid,diamond,dragon,dragonfly,fern,flip,gear,gumleaf,heart,information,kookaburra,mail,mapleleaf,paint_splat,paw,phone,polygon,rooster,shopping_cart,snowflake,star"}
 fi fi
 
 if $#>14 __shape_arg=$shape_size,${15-1}
 else __shape_arg=$shape_size
 fi
 
else
 pass$1 0
 if s<=4&&s>1
  if s==3
   to_gray.
  else
   s. c,{if(s==4,-3,if(s==2,-1,-s))}
   to_gray..
   *[-2,-1]
  fi
 elif s==5
  s. c,-4 cmyk2rgb.. to_gray.. *[-2,-1]
 fi
 autocrop. 0
 hmv={avg(im#-1,iM#-1)}
 ge. $hmv
 store. __zoom_shape
fi

command "rep_zoomin_shape_create_zoom_shape:
 shape_size={max(max(w,h)*abs($6),4)}
 
 if $__use_prebuilt_shape
  shape_$__sid $__shape_arg
  autocrop. 0
 else
  $__zoom_shape
  ml={max(w,h)}
  sf={$shape_size>$ml?$shape_size/$ml:$ml/$shape_size}
  sf*=100
  r. $sf%,$sf%,1,1,1
 fi
 
 if $14
  if w#-2==h#-2 
   if w#-1>h#-1 r. {h#-1},100%,1,100%,1
   else r. 100%,{w#-1},1,100%,1
   fi 
  else
   ri={w#-1/h#-1}
   rs={w#-2/h#-2}
   if $rs>$ri
    r. {w#-1*$rs/$ri},{h#-1},100%,100%,1
   else 
    r. {h#-1*$ri/$rs},{w#-1},100%,100%,1
   fi
  fi
 fi
 
 ml={h>w}
 
 if $ml 
  ch={*abs($6)*h*$__zf}
  cw={w/h*$ch}
 else
  cw={abs($6)*w*$__zf}
  ch={h/w*$cw}
 fi
 
 max_posx={w#0-$cw-1}
 max_posy={h#0-$ch-1}
 posx={abs($2)*$max_posx}
 posy={abs($3)*$max_posy}
 endposx={$posx+$cw}
 endposy={$posy+$ch}
 __cropimage={round($posx)},{round($posy)},{round($endposx)},{round($endposy)}
 
 {w},{h},1,{s#0},\"begin(
  const ww=w-1;
  const hh=h-1;
  const posx=\"$posx\";
  const posy=\"$posy\";
  const endposx=\"$endposx\";
  const endposy=\"$endposy\";
 );
 I(#0,lerp(posx,endposx,x/ww),lerp(posy,endposy,y/hh),0,$8);
 \"
 
 if $__line_thickness
  expand_xy[-2,-1] $__line_expand_factor,0
  +rep_zoomin_shape_create_border..
  f[1] (i#-1||i)?(i#-1?1:2)
  $__line_color
  if s#0==1 to_gray.
  elif s#0==2 to_graya.
  elif s#0==3 to_rgb.
  elif s#0==4 to_rgba.
  fi
  rep_singular_channel_autocrop_xy_coordinates[1]
  crop[1,2] ${}
  f[1] \"begin(
   line_color=I(#-1,0,0,0);
  );
  i<2?(I(#2)=line_color;);i?1;\"
 fi
 "

repeat $! l[$>]
 alpha_condition={s==2||s>3}
 rep_zoomin_shape_create_zoom_shape
 if $__line_thickness
 else
 
  r[-2,-1] $isub%,$isub%,100%,100%,{abs($13)+1}
  
  if $style==0
  
   $__line_color
   
   if s#0==1 to_gray.
   elif s#0==2 to_graya.
   elif s#0==3 to_rgb.
   elif s#0==4 to_rgba.
   fi

   f[0] I(#-1,0,0,0);
   j[0] [-2],{$4}~,{$5}~,0,0,1,[-3]
   
  elif $style==1||!$alpha_condition
  
   j[0] [-1],{$4}~,{$5}~,0,0,1,[-2]
   
  else
  
   if s==1||s==3 {w},{h},1,1 f. 255 a[-2,-1] c fi
   sh. {s-1}
   *. ... 
   rm.
   {w#0},{h#0},1,{s#0}
   j[-1] [-2],{$4}~,{$5}~
   blend[0,-1] alpha
   
  fi
  
  k[0]
  
 fi
endl done

Looks simple to me: G'MIC - GREYC's Magic for Image Computing: A Full-Featured Open-Source Framework for Image Processing - Reference Documentation - image. Sorry, I don’t have the energy to review your code. The hardest part is doing the circular mask, frame and line, which shouldn’t be a challenge to you.

Those aren’t actually the hardest part. The hardest part is getting the scaling to work properly in context of subsampling level change. The rest is easy-peasy.

I realized that what doesn’t work is this:

if $#>14 __shape_arg=$shape_size,${15-1}
 else __shape_arg=$shape_size
 fi
....
shape_size={max(max(w,h)*abs($6),4)}
 shape_$__sid $__shape_arg

Changing $6 does nothing. So, now I can continue.

Always good to print your variables to check if they are in the right range and change when they are supposed to do so.

Question though, is it necessary to have checks for inputs?

I usually try to adjust my code to be adaptive i.e minimizing errors as much as possible with inputs. That’s why you don’t see check in my code anywhere. If a number is not supposed to be negative, I use abs. If it supposed to be in 0-1 range, I use cut.

shape_size={max(max(w,h)*abs($6),4)} looks like you would end up with 4 quite often.

Yes. 4 is the minimum shape size that’s err even a bit distinguishable. 1% of image size tends to be close to 4.

But you are using max(.,.)

PS Ha ha, (.,.) looks like a sad elephant. :stuck_out_tongue:

Yes, max can be used to set a variable to minimum possible number. If you want to have a variable that’s no less than 4, max is appropriate.

Oops, you are right. Like I said, I have no energy for this. Anyway, check your values again step by step and you will find out why nothing happens when you change $6.

1 Like

I started over on the script. Easier to manage this time.

The final step for me is to create a script that will allow me to create anti-aliased thickline, another script to combine the shapes together, and the main script will utilize several scripts.

New Script
# $ sp dog tic _rep_zoomin_shape_create_shape 10%,2,1 ("190^50^100") _rep_zoomin_shape_outborder[0-2] 2,[-1],1,2,2,${} toc #

_rep_zoomin_shape_create_shape:
skip ${4=2},${5=1},${6=circle},${7=50%},${8=50%},${9=}
#$1=shape/image ratio#
#$2=zoomlevel#
#$3=zoom_interpolation#
#$4=sublevel#
#$5=subpixel_interpolation#
#$6=shape#
#$7=posx#
#$8=posy#
#$9=additional arguments

if ${is_image_arg\ $1}
 shape_size={max(max(w,h)*$1*$4,4)}
 pass$1 0
 ri={w#-1/h#-1}
 rs={w#-2/h#-2}
 if $ri>$rs
  sf={$shape_size/w#-1*100}
  r. $sf%,$sf%,100%,100%,2
 else
  sf={$shape_size/h#-1*100}
  r. $sf%,$sf%,100%,100%,2
 fi
 thres={avg(im#-1,iM#-1)}
 ge. $threshold
else
 shape_size={max(max(w,h)*$1*$4,4)}
 shape_$6 $shape_size,${9--1}
fi

scale_factor={1/($2*$4)}
nw={w*$scale_factor}
nh={h*$scale_factor}

crop_width={w#0-$nw}
crop_height={h#0-$nh}
start_x={$7*$crop_width}
start_y={$8*$crop_height}
end_x={$start_x+$nw-1}
end_y={$start_y+$nh-1}

outcrop=$start_x,$start_y,$end_x,$end_y

u $outcrop

{w},{h},{d#0},{s#0},"begin(
  const ww=w-1;
  const hh=h-1;
  const start_x="$start_x";
  const start_y="$start_y";
  const end_x="$end_x";
  const end_y="$end_y";
  const interp=abs($3)+1;
  posx(a)=lerp(start_x,end_x,a);
  posy(a)=lerp(start_y,end_y,a);
 );
 I(#0,posx(x/ww),posy(y/hh),z,interp);"
 
_rep_zoomin_shape_outborder:
#$1=line_thickness#
#$2=color-image#
#$3=include_original_crop#
#$4=subpixel_level#
#$5=subpixel_interpolation#
#$6=start_x#
#$7=start_y#
#$8=end_x#
#$9=end_y#

isub={1/$4*100}

if $3 +store.. shape_image fi

hlt={ceil($1*$4/2)}

expand_xy[-2,-1] $hlt,0

+f.. i?(!(j(-1,0)&&j(1,0)&&j(0,-1)&&j(0,1))?1)

dilate_circ. {$1*$4},0

pass$2 0

convert_mode=${arg\ s#0,to_gray,to_graya,to_rgb,to_rgba}

$convert_mode.

f[-4] "begin(
  col=I(#-1,0,0,0);
 );
 i#-2?(
  I(#-3)=col;
  1;
 ):(
  !i?I(#-3)=col;
  i;
 );"

if $3
 start_x=$6
 start_y=$7
 end_x=$8
 end_y=$9

 start_x-=$hlt
 start_y-=$hlt
 end_x+=$hlt
 
 target_length={$end_x-$start_x}
 
 outcrop=$start_x,$start_y
 
 u $outcrop
 
 $shape_image
 
 diff_dimension={w#-1/$target_length}
 
 res_downscale={1/$diff_dimension*100}
 
 new_line_thickness={$1*$diff_dimension}
 
 hnlt={ceil($new_line_thickness/2)}
 
 +f. i?(!(j(-1,0)&&j(1,0)&&j(0,-1)&&j(0,1))?1)
 
 expand_xy[-2,-1] $hnlt,0
 
 dilate_circ[-2,-1] $new_line_thickness,0
 
 r[-2,-1] $res_downscale%,$res_downscale%,100%,100%,$5
 rm[-4]
 r[-5--4] $isub%,$isub%,100%,100%,$5
else
 rm[-2,-1]
 r[-2,-1] $isub%,$isub%,100%,100%,$5
fi

EDIT: Optimized Nebulous filter even further while keeping translatability.


Guess what am I making?


It’s Hedon Phase Diagram.

More WIP shot:

The only thing left to do is the GUI filter, and add xy displacement option, and I’ll be ready to go! If you’d still like the early code:

Hedon Phase Diagram
#@cli rep_hpd: eq. to 'rep_henon_phase_diagram' : (+)
rep_hpd:rep_henon_phase_diagram $*
#@cli rep_henon_phase_diagram: a,_scale>0,-180>=_rotation>=180,_lines>0,_pts_per_line,_start_x0,_end_x0,_steps_x0,_multiple_map
#@cli : Creates Henon Phase Diagram on existing image. Multiple Map option is used to make it easier to create more interesting image via coding.
#@cli :
#@cli : (eq. to 'rep_hpd')\n
rep_henon_phase_diagram:
skip ${2=1},${3=0},${4=600},${5=1750},${6=-.5},${7=.5},${8=8},${9=0}

if $2==0 error "$"2!=0==F fi

output_mode={$9%4}

if $1!=0

 if s#-1!=1&&d#-1!=1 100%,100%,1,1,-1
 else
  if !iv#-1&&iM#-1!=-1 f. -1 fi
 fi

 if ($3-360*floor($6/360))?1
  out_xi=rot_x(xi,yi)
  out_yi=rot_y(xi,yi)
 else
  out_xi=xi
  out_yi=yi
 fi

 steps={round((max(1,abs($8))-1))}
 lines={max(1,round(abs($4)))}
 
 if $output_mode==3 calc_out=i(#-1,cx,cy)=1
 else calc_out=cv=i(#-1,cx,cy);i(#-1,cx,cy)=max(cv,y)
 fi

 $steps,$lines,1,1,":begin_t(
   const a=$1;
   const c=cos(a);
   const s=sin(a);
   const pts=max(1,round(abs($5)));
   const hw=(w#-1-1)/2;
   const hh=(h#-1-1)/2;
   const dist=min(hw,hh)*abs($2);
   const dpi=2*pi;
   const start_x0=$6;
   const end_x0=$7;
   const ang=($3/180)*pi*-1;
   const cos_ang=cos(ang);
   const sin_ang=sin(ang);
   if(abs($8)
    ,const end_step=w-1;
    ,const end_step=1;
   );
   rot_x(a,b)=a*cos_ang-b*sin_ang;
   rot_y(a,b)=a*sin_ang+b*cos_ang;
  );
  t=lerp(start_x0,end_x0,x/end_step);
  xi=t;
  yi=y/h*dpi;
  for(ptn=0,ptn<pts,ptn++,
   m=xi;
   n=yi-sqr(xi);
   xn=xi*c-n*s;
   yn=xi*s+n*c;
   xi=xn;yi=yn;
   if(m!=t,
    cx=round(hw+"$out_xi"/2*dist);
    cy=round(hh-"$out_yi"/2*dist);
    "$calc_out";
   );
  );
  "

 rm.

 if $output_mode==2
  +eq. -1
  +negate.
 elif $output_mode==1
  +gt. -1
 fi

else

 f. 0

fi
2 Likes

Okay, stuck with something. I’d like to know if this is the fastest setting for this command:

inpaint_pde [?],0,0,0

You could time the command.

The code appears to resolve scales≥1 and iterations≥5, and Delaunay-guided doesn’t iterate.

I checked that. Turns out that inpaint_pde is a extremely slow command. What I wanted to do was (and did not want to create my own command to solve the problem):

1. Create a colored image, and alpha image.
2. The non-alpha should had extended color bleeds over the alpha.

Guess I will resort to using a custom command. Not really hard to do though.

Reminds me of my command that tried to remove scratches and dust spots. It depends on your problem. If you could share a sample image, that would be great. In the meantime, how about regular inpaint? It is faster than inpaint_pde, though not as good in my opinion.

EDIT: @afre After I have found out that the filter stops changing after a certain number of points, I limited it to 500. Now the filter works as it should. Fast, and usable. I will continue to fine-tune the filter.

I would if you could figure out the stopping conditions so that it doesn’t iterate more than it should but no less.

1 Like

Oh great, I will have to disable my filter because of bluescreen crashes. :confused:

I think it has to do with line 123-143 of reptorian.gmic.
Others seem to be fine.

@David_Tschumperle :
Could you take a look?

Maybe the crash has to do with using INF or nan on multiple thread. So, all I have to do is to add a if INF condition to break() to avoid crash. If not this, is there a way to limit memory usage? It certainly not with memory of my computer as it is fine.

EDIT: A research paper reveal that it can be unbounded and a test with if changes so far did seem to fix it. I may release the fix soon.

For those who wants the fix, this is what I added before xi=xn;yi=yn;:

if(xn==inf||yn==inf||xn==-inf||yn==-inf,break());

I also would like to limit memory usage to see if that is also a cause or does gmic does that? A test shows huge memory usage.


Looks like B&W No Alpha option is much, much faster than the other options. I must look into why, and see how I can optimize it. Also, more tests shows that the BSOD crash bug seem to be solved.

I’m just gonna drop this link here, just so that I can get back to it. - Borland C++ Builder - Fractals & Strange Attractors

It has source code and it involves chaos game fractal.

1 Like