Reptorian G'MIC Filters

Very good and efficient. There should be an “unserialize” anywhere! (befor keep)

Hmm, I would have to test that once I am able to update G’MIC again.

Meanwhile, I released a new command that would make importing file with the use of ‘it’ command easier. This is similar to python_string.split(“var”)

See results of the new command:

# Default value for rep_split_it is \n or newline.
C:\Users\User\Downloads>gmic it test.txt rep_split_it , foreach echo {t} done rm
[gmic]-0./ Start G'MIC interpreter.
[gmic]-0./ Input text-data file 'test.txt'.
[gmic]-1./*foreach/ ; paint.net Palette File: Rainbow
[gmic]-1./*foreach/ ; Made by: BoltBait
[gmic]-1./*foreach/ FFFFD8D8
[gmic]-1./*foreach/ FFFFA8A8
[gmic]-1./*foreach/ FFFF7777
[gmic]-1./*foreach/ FFFF3A3A
[gmic]-1./*foreach/ FFFF0000
[gmic]-1./*foreach/ FFC10000
[gmic]-1./*foreach/ FF890000
[gmic]-1./*foreach/ FF4C0000
[gmic]-1./*foreach/ FFFFD8FF
[gmic]-1./*foreach/ FFFFA8FF
[gmic]-1./*foreach/ FFFF77FF
[gmic]-1./*foreach/ FFFF3AFF
[gmic]-1./*foreach/ FFFF00FF
[gmic]-1./*foreach/ FFBC00BC
[gmic]-1./*foreach/ FF840084
[gmic]-1./*foreach/ FF4F004F
[gmic]-1./*foreach/ FFD8FFDF
[gmic]-1./*foreach/ FFA8FFB8
[gmic]-1./*foreach/ FF77FF90
[gmic]-1./*foreach/ FF3AFF5E
[gmic]-1./*foreach/ FF00FF00
[gmic]-1./*foreach/ FF00BF23
[gmic]-1./*foreach/ FF008718
[gmic]-1./*foreach/ FF00510E
[gmic]-1./*foreach/ FFD8D8FF
[gmic]-1./*foreach/ FFA8A8FF
[gmic]-1./*foreach/ FF7777FF
[gmic]-1./*foreach/ FF3A3AFF
[gmic]-1./*foreach/ FF0000FF
[gmic]-1./*foreach/ FF0000BF
[gmic]-1./*foreach/ FF000087
[gmic]-1./*foreach/ FF000051
[gmic]-1./*foreach/ FFF7FFD8
[gmic]-1./*foreach/ FFEDFFA8
[gmic]-1./*foreach/ FFE3FF77
[gmic]-1./*foreach/ FFD7FF3A
[gmic]-1./*foreach/ FFCCFF00
[gmic]-1./*foreach/ FF96BC00
[gmic]-1./*foreach/ FF6A8400
[gmic]-1./*foreach/ FF3F4F00
[gmic]-1./*foreach/ FFD8F1FF
[gmic]-1./*foreach/ FFA8E0FF
[gmic]-1./*foreach/ FF77CFFF
[gmic]-1./*foreach/ FF3ABAFF
[gmic]-1./*foreach/ FF00A5FF
[gmic]-1./*foreach/ FF0077B7
[gmic]-1./*foreach/ FF00527F
[gmic]-1./*foreach/ FF002F47
[gmic]-1./*foreach/ FFFFFFD8
[gmic]-1./*foreach/ FFFFFFA8
[gmic]-1./*foreach/ FFFFFF77
[gmic]-1./*foreach/ FFFFFF3A
[gmic]-1./*foreach/ FFFFFF00
[gmic]-1./*foreach/ FFBCBC00
[gmic]-1./*foreach/ FF848400
[gmic]-1./*foreach/ FF4F4F00
[gmic]-1./*foreach/ FFD8FFFF
[gmic]-1./*foreach/ FFA8FFFF
[gmic]-1./*foreach/ FF77FFFF
[gmic]-1./*foreach/ FF3AFFFF
[gmic]-1./*foreach/ FF00FFFF
[gmic]-1./*foreach/ FF00BABA
[gmic]-1./*foreach/ FF008282
[gmic]-1./*foreach/ FF004444
[gmic]-1./*foreach/ FFFFF3CC
[gmic]-1./*foreach/ FFFFE89E
[gmic]-1./*foreach/ FFFFDB66
[gmic]-1./*foreach/ FFFFCE30
[gmic]-1./*foreach/ FFFFC300
[gmic]-1./*foreach/ FFE0AC00
[gmic]-1./*foreach/ FFB78C00
[gmic]-1./*foreach/ FF876700
[gmic]-1./*foreach/ FFFAF3EC
[gmic]-1./*foreach/ FFF6E0DA
[gmic]-1./*foreach/ FFF0D4C5
[gmic]-1./*foreach/ FFEDC7BD
[gmic]-1./*foreach/ FFEBB9AF
[gmic]-1./*foreach/ FFD09385
[gmic]-1./*foreach/ FFC5887D
[gmic]-1./*foreach/ FFAA6D64
[gmic]-1./*foreach/ FFFFE2CC
[gmic]-1./*foreach/ FFFFD0A8
[gmic]-1./*foreach/ FFFFB677
[gmic]-1./*foreach/ FFFF9D47
[gmic]-1./*foreach/ FFFF7700
[gmic]-1./*foreach/ FFBF5900
[gmic]-1./*foreach/ FF7F3B00
[gmic]-1./*foreach/ FF492100
[gmic]-1./*foreach/ FFE0E0E0
[gmic]-1./*foreach/ FFC0C0C0
[gmic]-1./*foreach/ FFA0A0A0
[gmic]-1./*foreach/ FF808080
[gmic]-1./*foreach/ FF606060
[gmic]-1./*foreach/ FF404040
[gmic]-1./*foreach/ FF202020
[gmic]-1./*foreach/ FF000000
C:\Users\User\Downloads>gmic ('"Hi, I am Reptorian\nLove GMIC."') rep_split_it "m " foreach echo {t} done rm
[gmic]-0./ Start G'MIC interpreter. (1 image 29x1x1x1).
[gmic]-1./*foreach/ Hi, I a
[gmic]-1./*foreach/ Reptorian
Love GMIC.

Not sure if you know this already, but command split has a special mode to split an image according to a sequence of values specified as a separator. That’s actually very useful to process text buffers.
For instance:

foo :
  ('"Hello my friends\nHow are you today?\nI like the \'split\' command\n"')
  split. -,{'\n'}
  repeat $! echo {$>,t} done
~~~
gives:
~~~
$ gmic foo
[gmic]-0./ Start G'MIC interpreter.
[gmic]-3./foo/*repeat#152/ Hello my friends
[gmic]-3./foo/*repeat#152/ How are you today?
[gmic]-3./foo/*repeat#152/ I like the 'split' command
~~~
1 Like

EDIT: Checked the license of original code, and it came from Unreal Engine 4. Looks like I’ll have to remove this for obvious reason.

Not really much of news:

I pushed the combinations version of the permutations commands I made. Before that, I made a importer for Paint.NET palette files. The import is slow, but it works for the vast majority of cases.

Bad news is that I’m still stuck on cubic spline, but I think for length, I will go for a naive approach as it seems the two non-naive approach has their problems (one of them has the problem of being part of UE4 code).

That being said, I released a command which shows a usage of rep_full_combinations (I added a option to it recently, so that will show up when the new command shows up on update). Here’s the output of a new command:

You see what’s going there? These are symbols used for the Wii U. I wanted to figure out if I can enter symbol-password without having connection to TV. There are 256 possible combination. The video showcase these possible entries.

1 Like

Another update. I pushed nCr combinations version of the combinations/permutations command. I will figure out implementing this algorithm for the final part of nCr → Revisions to Fast way to get a position of combination (without repetitions) - Mathematics Stack Exchange . That being said, this is the first time built-in permut() is being used.

EDIT: This didn’t work for the last nCr command I pushed. I will have to find another solution before resorting to finding my own (which I did for first time)

EDIT: Maybe this will work - indexing - Find the index of a given combination (of natural numbers) among those returned by `itertools` Python module - Stack Overflow

I see you have been busy learning math and programming. How industrious of you. :slight_smile:

1 Like

Yes, that code worked. I think I can conclude that my nCr combinations,full combinations, and permutation tools work. Wait 6 hours or so before updating. Now, the update for gmic is now here. You can get lexicographic index of combination and find the set of number at index p for all of them. Feels like implementing pyitertools for G’MIC.

Now, I’m working on the Transfer Colors [Reduced Colors] again. This time, I figured out a few thing, so therefore I can continue on this. It will be extended at some point soon, that’s for sure.

Also, see here, it seem like progress:

It’s not actually that dark:

image

Edit: Hmm, I noticed a difference in computer monitor and phone screen. Interesting… This is better on my computer monitor and the other one is better on mg phone screen. Hmm… What do I do now?

Edit: Yes, calibrate computer monitor. Or find a compromise value.

Well, I found the compromise value. That being said, that’s not what I’m here for.

I’m more here to ask a question about #@gui. Now that G’MIC supports #@gui:Variable=type() instead of just #@gui :Variable=type(), I feel the urge to replace every one of them with the former.

Not sure if this’ll be a problem right now… But, after Krita gets the updated G’MIC, it’ll be fine to make the move to it.

EDIT: Not that anyone use this filter much, but Color Harmonies gets a slight upgrade. It now use $_persistent. So, it should be slightly more responsive. Still a bit slow, but it is what it is, and honestly speed is not relevant in this case as it’s responsive enough. I also fixed a few bugs with this that of course, no one reported.

Ok, not exactly a new filter, but a tool again. - Image Dimensions Factors

This gives quite informative information about factors of images.

Here’s the copied output:

Image Width: 900
Image Height: 1200
Image Dimensions: 900x1200

Factor(s) of Width: 1,2,3,4,5,6,9,10,12,15,18,20,25,30,36,45,50,60,75,90,100,150,180,225,300,450,900
Factor(s) of Height: 1,2,3,4,5,6,8,10,12,15,16,20,24,25,30,40,48,50,60,75,80,100,120,150,200,240,300,400,600,1200
Factor(s) of Width and Height: 1,2,3,4,5,6,10,12,15,20,25,30,50,60,75,100,150,300

Bad news on the new version of Transfer Color[Reduced Color] filter. I have stumbled upon a error that confuses me.

Wall of Code
#@cli rep_transfer_color_reduced: [palette],0<=_dither<=1,_pixel_ratio_w>=0,_pixel_ratio_h>=0,_windows_width>=0,_window_height>=0,_color_restriction_per_window>=0,_color_restriction_per_whole>=0,_number_of_alpha>=0,_alpha_dithering>=0,_alpha_mode={ 0=index | 1=window-index | 2=ordered },_alpha_restrict>=0 : { bit_depth | bit_a:...:bit_z | :[palette] },0<=_dither<=1,_pixel_ratio_w>=0,_pixel_ratio_h>=0,_color_restriction_per_whole>=0,_number_of_alpha>=0,_alpha_dithering>=0
#@cli : Change images to look as if it was reduced. Can be used to emulate old hardware.
rep_transfer_color_reduced:
skip ${3=1},${4=1},${5=1},${6=},${7=},${8=},${9=},${10=},${11=},${12=},${13=},${14=},${15=}

# $1  = [palette] = $1                                              | $1 = { bit_depth | bit_a:...:bit_z | :[palette] } = $1
# $2  = 0<=_dither<=1 = $2                                          | $2 = 0<=_dither<=1 = $2
# $3  = _pixel_ratio_w>=0 = $3                                      | $3 = _pixel_ratio_w>=0 = $3
# $4  = _pixel_ratio_h>=0 = $4                                      | $4 = _pixel_ratio_h>=0 = $4
# $5  = _windows_width>=0 = $5                                      | $5 = _threshold_map = $5
# $6  = _window_height>=0 = $6                                      | $6 = _color_restriction_per_whole>=0 = $6
# $7  = _color_restriction_per_window>=0 = $7                       | $7 = _number_of_alpha>=0 = $7
# $8  = _color_restriction_per_whole>=0 = $8                        | $8 = _alpha_dithering>=0 = $8
# $9  = _number_of_alpha>=0 = $9                                    | $9  =_alpha_mode={ 0=index | 1=ordered } = $9
# $10 = _alpha_dithering>=0 = $10                                   | $10 = _return_index_values={ 0=color | 1=index_value | 2=index_value_without_rescale } = $10
# $11 = _alpha_mode={ 0=index | 1=window-index | 2=ordered } = $11
# $12 = _alpha_restrict>=0                                   = $12
# $13 = _alpha_threshold_map                                 = $13
# $14 = _return_index_values={ 0=color | 1=index_value | 2=index_value_without_rescale } = $14

mode={(find('$1',':',0,1)!=-1)||isint($1)}

if $mode

  location_of_bracket={find('$1','[',0,1)}
  
  if $location_of_bracket!=-1
    ('$1')
    crop. $location_of_bracket,{w#-1-1}
    img_arg={t}
    rm.
    pass$img_arg 0
    _rep_transfer_color_reduced[^-1] $mode,[-1],$2,$3,$4,$5,$6,$7,$8,$9,$10
    rm.
  else _rep_transfer_color_reduced $mode,${1-10}
  fi
  
else

  pass$1 0
  _rep_transfer_color_reduced[^-1] $mode,[-1],${1-14}
  rm.
  
fi
_rep_transfer_color_reduced:
skip ${3=1},${4=1},${5=1},${6=},${7=},${8=},${9=},${10=},${11=},${12=},${13=},${14=},${15=}

# Indexed                                                           | Ordered
# $1  = mode      = $1                                              | $1 = mode
# $2  = [palette] = $2                                              | $2 = { bit_depth | bit_a:...:bit_z | :[palette] } = $2
# $3  = 0<=_dither<=1 = $3                                          | $3 = 0<=_dither<=1     = $3
# $4  = _pixel_ratio_w>=0 = $4                                      | $4 = _pixel_ratio_w>=0 = $4
# $5  = _pixel_ratio_h>=0 = $5                                      | $5 = _pixel_ratio_h>=0 = $5
# $6  = _windows_width>=0 = $6                                      | $6 = _threshold_map = $6
# $7  = _window_height>=0 = $7                                      | $7 = _color_restriction_per_whole>=0 = $7
# $8  = _color_restriction_per_window>=0 = $8                       | $8 = _number_of_alpha>=0 = $8
# $9  = _color_restriction_per_whole>=0  = $9                       | $9 = _alpha_dithering>=0 = $9
# $10 = _number_of_alpha>=0  = $10                                  | $10  =_alpha_mode={ 0=index | 1=ordered } = $10
# $11 = _alpha_dithering>=0  = $11                                  | $11 = _return_index_values={ 0=color | 1=index_value | 2=index_value_without_rescale } = $11
# $12 = _alpha_mode={ 0=index | 1=window-index | 2=ordered } = $12
# $13 = _alpha_restrict>=0                                   = $13
# $14 = _alpha_threshold_map                                 = $14
# $15 = _return_index_values={ 0=color | 1=index_value | 2=index_value_without_rescale } = $15

# mode == 0 => indexed
# mode == 1 => ordered

#################
# TODO : Finish up the Code. 
#################

num_of_images={$!}

mode,dither={[$1?1,cut($3,0,1)]}
pixel_ratio_w,pixel_ratio_h,rescale_back_w,rescale_back_h={pixel_ratio=vmax([1,1],int(abs([$4,$5])));[pixel_ratio,pixel_ratio*100]}
return_index_values={$mode?(narg($11)?$11%3:0):(narg($15)?$15%3:0)}

number_of_alpha,alpha_dithering={$mode?(narg($8)?int(abs($8))):(narg($10)?int(abs($10)))},{$mode?(narg($10)?cut($10,0,1)):(narg($12)?cut($12,0,1))}
alpha_mode={$number_of_alpha?($mode?($10&1)*2+1:$12%2+1)}

color_restriction_per_window,color_restriction_whole={!$mode?(narg($8)?$8)},{$mode?(narg($7)?int(abs($7))):(narg($9)?int(abs($9)))}

if !$mode&&($color_restriction_per_window<=$color_restriction_whole) color_restriction_per_window=0 fi

decrement_color_restriction_whole={$color_restriction_whole-1}

pixel_ratio_gcd={gcd($pixel_ratio_w,$pixel_ratio_h)}
if $pixel_ratio_gcd>1 pixel_ratio_w,pixel_ratio_h/=$pixel_ratio_gcd fi

if $pixel_ratio_w==1||$pixel_ratio_h==1
  initial_rescale_w,initial_rescale_h={bd=max($pixel_ratio_w,$pixel_ratio_h);100*($pixel_ratio_w>$pixel_ratio_h?vector(#2,1)/[bd,1]:vector(#2,1)/[1,bd])}
else
  min_dimension,max_dimension={min($pixel_ratio_w,$pixel_ratio_h)},{max($pixel_ratio_w,$pixel_ratio_h)}
  recip_rd={1/($max_dimension/$min_dimension)}
  initial_rescale_w,initial_rescale_h={100*($pixel_ratio_w>$pixel_ratio_h?[$recip_rd,1]:[1,$recip_rd])}
fi

if $mode
 threshold_map_level,alpha_restrict={narg($6)?$6:3},$number_of_alpha
else
  window_width,window_height,alpha_restrict,alpha_threshold_map={int(abs([narg($6)?int(abs($6)),narg($7)?int(abs($7))]))},{narg($13)?int(abs($13))},{narg($14)?$14)}
  if $window_width&&!$window_height window_height+=1 fi
  if $window_height&&!$window_width window_width+=1 fi
fi

use_images=0

if ${is_image_arg\ $2}

  pass$2 0 => palette
  
  if !(s%2) error pal_cont_alp fi
  
  if h#-1>1&&d#-1==1 rotate. -90
  elif h#-1>1&&d#-1>1 colormap. 0,,0
  fi
  
  store. img_palette
  use_images+=1

fi

if $alpha_mode%($mode?2:3)

  $number_of_alpha,1,1,1,"begin(
      const dividier=(w-1)/255;
    );
    x/dividier;"
  
  => alpha
  
  use_images+=1
fi

if $use_images==2

  images="$>",-1
  v_col_info,v_alpha=[palette],[alpha]
  
elif $use_images==1 

  images="$>",-1
  
  if ${is_image_arg\ $2}
    v_col_info,v_alpha=[palette],$number_of_alpha
  else
    v_col_info,v_alpha=$2,[alpha]
  fi
  
else 

  images="$>"
  v_col_info,v_alpha=$2,$number_of_alpha
  
fi

contain_pal=${is_image_arg\ $v_col_info}


repeat $num_of_images
  local[{"$images"}] {
  
    if s#0>4||!s#0 continue fi
    
    targ_img_alp,con_img_palette={!(s#0%2)},0
    
    resize[0] $initial_rescale_w%,$initial_rescale_h%,100%,100%,3
    
    if $contain_pal
    
      $img_palette
      
      con_img_palette=1
      
      use_color_space_conversion,min_col_pos={s0=s#0;s0-=!(s0%2);csc=s0!=s#-1;s#-1>s0?[csc,-1]:[csc,0];}
      
      if $use_color_space_conversion
        if $min_col_pos==-1 to_gray[-1]
        else
          cs_convert=${arg\ s#0-1,to_gray,to_graya,to_rgb}
          $cs_convert[0]
        fi
      fi
      
    fi
    
    if $targ_img_alp?!$return_index_values
    
      sh[0] 0,{s#0-2}
        
      if $color_restriction_whole&&$con_img_palette
        
        +index[-1] [palette],1,0
        histogram. 100%
        w,1,1,1,x
        pixelsort. -,x,..
        crop 0,0,$decrement_color_restriction_whole,0
        map. [palette]
          
        if $mode rep_ordered_dithering[-3] [-1],$dither,$threshold_map_level
        else rep_index_by_window_and_color_restriction[-3] [-1],$dither,$color_restriction_per_window,$window_width,$window_height,1,!$return_index_values
        fi
          
        rm[-2,-1]
        
      else
      
        if $mode rep_ordered_dithering[-1] $v_col_info,$dither,$threshold_map_level
        else rep_index_by_window_and_color_restriction[-1] $v_col_info,$dither,$color_restriction_per_window,$window_width,$window_height,1,!$return_index_values
        fi
        
      fi
        
      rm.
      
      if $alpha_mode
        
        sh[0] {s#0-1}
          
        if $alpha_mode==3 rep_ordered_dithering[-1] $v_alpha,$alpha_dithering,$threshold_map_iteration
        elif $alpha_mode==2 rep_index_by_window_and_color_restriction[-1] $v_alpha,$alpha_dithering,$alpha_restrict,$window_width,$window_height,1,!$return_index_values
        else index[-1] $v_alpha,$alpha_dithering,1
        fi
          
        rm.
          
      fi
      
    else
    
      if $targ_img_alp split_opacity[0,1] fi
      
      if $mode rep_ordered_dithering[0] $v_col_info,$dither,$threshold_map_level,!$return_index_values
      else rep_index_by_window_and_color_restriction[0] $v_col_info,$dither,$color_restriction_per_window,$window_width,$window_height,1,!$return_index_values
      fi
      
      if $targ_img_alp
        if $return_index_values
          if $alpha_mode==3 rep_ordered_dithering[1] $v_alpha,$alpha_dithering,$threshold_map_level,!$return_index_values
          elif $alpha_mode==2 rep_index_by_window_and_color_restriction[1] $v_alpha,$alpha_dithering,$alpha_restrict,$window_width,$window_height,1,!$return_index_values
          else index[1] $v_alpha,$alpha_dithering,!$return_index_values
          fi
        else rm[1]
        fi
      fi
      
    fi
    
    if $con_img_palette rm[palette] fi
   
    if $return_index_values!=2 resize[0] $rescale_back_w%,rescale_back_h%,100%,100%,1 fi
  }
  
done
#@cli rep_index_by_window_and_color_restriction:[palette],0<=_dithering<=1,_color_restriction>2,_window_width,_window_height,_window_depth,_map_palette={ 0 | 1 }
#@cli : Index images per window
rep_index_by_window_and_color_restriction:
skip ${2=1},${3=},${4=1},${5=1},${6=1},${7=1}
dithering,wi_w,wi_h,wi_d,map_palette,timg={cut($2,0,1)},{vmax(vector(#3,1),int(abs([${4-6}])))},{$7%2},{$!}


pass$1 1

if h#-1>1&&d#-1==1
 rm. pass$1 0
 rotate. -90
elif h#-1>1&&d#-1>1
 rm. pass$1 0
 colormap. 0,,0
fi

col_res={narg($3)?cut(int(abs($3)),2,w#-1):w#-1}
dec_col_res={$col_res-1}

if $dithering
 
 # Jarvis, Judice, and Ninke dithering Array
  jjn_1R0D,jjn_2R0D,\
  jjn_2L1D,jjn_1L1D,jjn_M01D,jjn_1R1D,jjn_2R1D,\
  jjn_2L2D,jjn_1L2D,jjn_M02D,jjn_1R2D,jjn_2R2D\
  ={([7,5,3,5,7,5,3,1,3,5,3,1]/48)*$dithering}
 
fi

eval "
  const spectrum_size=s#-1;
  const rf=$timg;
  valid_spec=1;
  repeat(rf,id,
   if(s#id!=spectrum_size,valid_spec=0;break(););
  );
  valid_spec;
 "
 
if !${} error incompatible_img_pal fi

if $col_res>=w#-1
 index[^-1] [-1],$dithering,$map_palette
 rm.
 return
fi

repeat $timg local[$>,-1] 
 {
 
  ow,oh,od,tw,th,td,nw,nh,nd={od=[w#0,h#0,d#0];wd=vmin([w#0,h#0,d#0],[$wi_w,$wi_h,$wi_d]);td=ceil(od/wd);nd=td*wd;[od,td,nd]}

  
  if [$tw,$th,$td]==vector(#3,1)
   +index[0] [1],1,0
   histogram. 100%
   {w},1,1,1,x
   pixelsort. -,x,..
   crop. 0,0,$dec_col_res,0
   map. ...
   index[0] .,$dithering,$map_palette
  else
  
   r[0] $nw,$nh,$nd,100%,0,3,.5,.5,.5
  
   +index[0] [1],{$dithering?.75},0
  
   $tw,$th,$td,1,*"begin(
     const nb_cols=w#1;
    
     const spectrum_size=s#1;
     const inc_spectrum_size=spectrum_size+1;
    
     const nb_restrict=$col_res;
     const dec_nb_restrict=nb_restrict-1;
    
     const res_y_spec=nb_restrict*spectrum_size;
    
     const wi_w=$wi_w;
     const wi_h=$wi_h;
     const wi_d=$wi_d;
    
     const dec_wi_w=wi_w-1;
     const dec_wi_h=wi_h-1;
     const dec_wi_d=wi_d-1;
    
     const box_dim=wi_w*wi_h*wi_d;
    
     init_freq_y_ind=expr('(x%2)?int(x/2);',nb_cols*2);
     init_sel_res_pal_dist_arr=vector(#nb_restrict,0);
    
     const dithering_mode=$dithering;
     const map_palette=$map_palette;
    
     dithering_mode?(
    
      #                            jjn_1R0D jjn_2R0D
      # jjn_2L1D jjn_1L1D jjn_M01D jjn_1R1D jjn_2R1D
      # jjn_2L2D jjn_1L2D jjn_M02D jjn_1R2D jjn_2R2D
     
      const jjn_1R0D=$jjn_1R0D;
      const jjn_2R0D=$jjn_2R0D;
      const jjn_2L1D=$jjn_2L1D;
      const jjn_1L1D=$jjn_1L1D;
      const jjn_M01D=$jjn_M01D;
      const jjn_1R1D=$jjn_1R1D;
      const jjn_2R1D=$jjn_2R1D;
      const jjn_2L2D=$jjn_2L2D;
      const jjn_1L2D=$jjn_1L2D;
      const jjn_M02D=$jjn_M02D;
      const jjn_1R2D=$jjn_1R2D;
      const jjn_2R2D=$jjn_2R2D;
     
      v_col()=I(#2,pos_x,pos_y,pos_z);
     
      # gen_res_pal_col();
     
      map_palette?(
       result_img_part()=(
        old_color=I(#0,pos_x,pos_y,pos_z);
        new_color=I(#1,res_col_id[argmin(sqrt(res_color_sum))],0,0);
      
        I(#0,pos_x,pos_y,pos_z)=new_color;
       );
      ):(
       result_img_part()=(
        old_color=I(#0,pos_x,pos_y,pos_z);
        new_color_pos=res_col_id[argmin(sqrt(res_color_sum))];
        new_color=I(#1,new_color_pos,0,0);
      
        i(#0,pos_x,pos_y,pos_z,0)=new_color_pos;
       );
      );
     
      result_img()=(
       result_img_part();
       diff_color=old_color-new_color;
      
       use_strip_1D=(pos_y+1)<min_out_of_boundary_offset_pos[2];
       use_strip_2D=(pos_y+2)<min_out_of_boundary_offset_pos[2];
      
       use_strip_1D?(
        I(#0,pos_x,pos_y+1,pos_z)+=diff_color*jjn_M01D;
       );
      
       use_strip_2D?(
        I(#0,pos_x,pos_y+2,pos_z)+=diff_color*jjn_M02D;
       );
      
       (pos_x-2)>min_out_of_boundary_offset_pos[0]?(
        use_strip_1D?(
         I(#0,pos_x-2,pos_y+1,pos_z)+=diff_color*jjn_2L1D;
        );
        use_strip_2D?(
         I(#0,pos_x-2,pos_y+2,pos_z)+=diff_color*jjn_2L2D;
        );
       );
      
       (pos_x-1)>min_out_of_boundary_offset_pos[0]?(
        use_strip_1D?(
         I(#0,pos_x-1,pos_y+1,pos_z)+=diff_color*jjn_1L1D;
        );
        use_strip_2D?(
         I(#0,pos_x-1,pos_y+2,pos_z)+=diff_color*jjn_1L2D;
        );
       );
      
       (pos_x+1)<min_out_of_boundary_offset_pos[1]?(
        I(#0,pos_x+1,pos_y,pos_z)+=diff_color*jjn_1R0D;
        use_strip_1D?(
         I(#0,pos_x+1,pos_y+1,pos_z)+=diff_color*jjn_1R1D;
        );
        use_strip_2D?(
         I(#0,pos_x+1,pos_y+2,pos_z)+=diff_color*jjn_1R2D;
        );
       );
       
       (pos_x+2)<min_out_of_boundary_offset_pos[1]?(
        I(#0,pos_x+2,pos_y,pos_z)+=diff_color*jjn_2R0D;
        use_strip_1D?(
         I(#0,pos_x+2,pos_y+1,pos_z)+=diff_color*jjn_2R1D;
        );
        use_strip_2D?(
         I(#0,pos_x+2,pos_y+2,pos_z)+=diff_color*jjn_2R2D;
        );
       ); 
       
      );
     
     ):(
    
      v_col()=I(#0,pos_x,pos_y,pos_z);
     
      # gen_res_pal_col();
      
      map_palette?(
       result_img()=(
        I(#0,pos_x,pos_y,pos_z)=I(#1,res_col_id[argmin(sqrt(res_color_sum))],0,0);
       );
      ):(
       result_img()=(
        i(#0,pos_x,pos_y,pos_z,0)=res_col_id[argmin(sqrt(res_color_sum))];
       );
      );
     );
    
    
    );
   
    c_xp=x*wi_w;
    c_yp=y*wi_h;
    c_zp=z*wi_d;
   
    min_out_of_boundary_offset_pos=[c_xp,c_xp,c_yp]+[-1,wi_w,wi_h];
   
    freq_y_ind=init_freq_y_ind;
    
    tv=crop(#2,c_xp,c_yp,c_zp,0,wi_w,wi_h,wi_d,1);
    
    repeat(box_dim,k,
     ++freq_y_ind[tv[k]*2];
    );
   
    freq_y_ind=sort(freq_y_ind,0,nb_cols,2);
    res_col_id=(freq_y_ind)[1,nb_restrict,2];
   
    res_pal=vector(#res_y_spec,0);
    
    repeat(nb_restrict,p,
     res_pal_col=I(#1,res_col_id[p],0,0);
     repeat(spectrum_size,q,
      res_pal[q*nb_restrict+p]=res_pal_col[q];
     );
    );
   
    repeat(wi_d,oz,
     pos_z=c_zp+oz;
    
     repeat(wi_h,oy,
      pos_y=c_yp+oy;
     
      repeat(wi_w,ox,  
       pos_x=c_xp+ox;
      
       res_color_sum=init_sel_res_pal_dist_arr;
       v_col=I(#0,pos_x,pos_y,pos_z);
      
       repeat(spectrum_size,k,
        res_color_sum+=sqr((res_pal)[k*nb_restrict,nb_restrict]-v_col[k]);
       );
      
       result_img();
       
      );
     );
    );
    0;
    "
   
   if !$map_palette channels[0] 0 fi
   
   crop[0] {od=[$ow,$oh,$od];op=[$nw,$nh,$nd]-od;[op,vsum(od,op)-1];}
  fi
  
  k[0,1]
 }
done

rm.
#@cli rep_ordered_dithering: bit_depth>0,0<=dithering<=1,threshold_map_iteration>0 : 
#@cli : bit_depth_a>0:...:bit_depth_z>0,0<=dithering<=1,threshold_map_iteration>0 :
#@cli : [palette],0<=dithering<=1,threshold_map_iteration>0,map_palette={ 0 | 1 } :
#@cli : bit_depth<0,0<=dithering<=1,threshold_map_iteration>0,spread
#@cli : Apply ordered dithering effect onto image.
#@cli : Note: bit_depth_a:...:bit_depth_z implies that the first argument is a set of arguments joined by the ':' char. This is used for separating bit depth channels. 
#@cli : Note: Negative value is used to alter values of images without indexing, and that is useful for generating windows-based ordered-dithering.
rep_ordered_dithering:
skip ${4=1}
check "($2?($2>=0&&$3>0):1)"

dithering,iteration={cut(abs($2),0,1)},{int(abs($3))}

if ${is_image_arg\ $1} use_pal_image=1
else use_pal_image=0
fi

m "convert_first_arg_to_mul_args :

  ('$1')

  local[-1] {
   split. -,{':'}
   foreach[^-1] {
    (',')
    a y
   }
   a y
  }

  _bit_depths={t} rm.

  u $_bit_depths"
  
m "index_from_bitmaps :

  t_bit_depths:=[$_bit_depths]+1

  foreach {

   if s>$_narg_bit_depths 
    sh. 0,{$_narg_bit_depths-1}
   fi

   if s==3 
    dims:=vector3($t_bit_depths,1,1)
    $dims,{s},:\"begin(
      const mxi=w-1;
      const myi=h-1;
      const mzi=d-1
     );
     [x/mxi,y/myi,z/mzi]*255;\"
   elif s==2 
    dims:=vector3(vector2($t_bit_depths),1,1)
    $dims,{s},:\"begin(
      const mxi=w-1;
      const myi=h-1;
     );
     [x/mxi,y/myi]*255;\"
   else 
    dims:=vector1(vector2($t_bit_depths),1,1)
    $dims,{s},\"begin(
      const mxi=w-1;
     );
     x/mxi*255;\"
   fi

   index[-2] [-1],0,1

   k[0]

  }"
  
if isnum($1)?$1<0

 if $#!=4 error inv_arg_cnt fi
 if $-1==0 error inv_spr fi
 
 +rep_bayer_threshold_map $iteration
 
 f[^-1] "begin(
   const n=w#-1-1;
   const dithering=$dithering*abs($-1);
  );
  thres_x=x&n;
  thres_y=y&n;
  threshold_map=i(#-1,thres_x,thres_y,0,0);
  new_color=(I+threshold_map*dithering);"
 rm.
 
 return
 
fi

if $use_pal_image

 pass$1 0

 +rep_bayer_threshold_map $iteration

 repeat $!-2 {
  local[$>,-2,-1] {
  
   {w#0},{h#0},100%,1,"
     v_col=I#0;
     color_sum=vector(#w#-2,0);
     repeat(s#-2,k,
      color_sum+=sqr(crop(#-2,0,0,0,k,w#-2,1,1,1)-v_col[k]);
     );
     color_sum=sqrt(color_sum);
     p=argmin(color_sum);
     color_sum[p];
     "
   spread:=ic#-1*2
   
   rm.
   
   if $spread
   
    f[0] "begin(
      const n=w#-1-1;
      const scale=$dithering*$spread;
     );
     thres_x=x&n;
     thres_y=y&n;
     threshold_map=i(#-1,thres_x,thres_y,0,0);
     v_col=cut((I+threshold_map*scale),0,255);"
     
    index[0] [1],0,$4
    
   fi
   
  }
 }
 
 rm[-2,-1]

else

 if $dithering

  if isint($1)

   +rep_bayer_threshold_map $iteration

   f[^-1] "begin(
     const n=w#-1-1;
     const bit_depth=max(1,int(abs($1)));
     const scale=255/bit_depth;
     const dithering=$dithering;
     const internal_scale=scale*dithering;
     const power_level=s>1?2^(1/(bit_depth+.5)):1;
    );
    thres_x=x&n;
    thres_y=y&n;
    threshold_map=i(#-1,thres_x,thres_y,0,0);
    new_color=(I+internal_scale*threshold_map)/scale;
    inew_color=int(new_color);
    exp_dist_from_inew_color=abs(new_color-inew_color)^power_level;
    cut(round(lerp(new_color,exp_dist_from_inew_color+inew_color,dithering))*scale,0,255);"

   rm.

  else

   _bit_depths=${-convert_first_arg_to_mul_args}
   _narg_bit_depths:=narg($_bit_depths)
   if $_narg_bit_depths>3 error excess_args fi

   +rep_bayer_threshold_map $iteration

   f[^-1] "begin(
     const n=w#-1-1;
     const dithering=$dithering;
     _bit_depths=vector(#s,"$_bit_depths");
     scale=255/_bit_depths;
     internal_scale=scale*dithering;
     power_level=2^(1/_bit_depths);
    );
    thres_x=x&n;
    thres_y=y&n;
    threshold_map=i(#-1,thres_x,thres_y,0,0);
    new_color=(I+internal_scale*threshold_map*dithering);"

   rm.

   index_from_bitmaps

  fi

 else

  if isint($1)

   f "begin(
     const bit_depth=max(1,int(abs($1)));
     const scale=255/bit_depth;
    );
    round(I/scale)*scale;"

  else

   _bit_depths=${-convert_first_arg_to_mul_args}
   _narg_bit_depths:=narg($_bit_depths)
   if $_narg_bit_depths>3 error excess_args fi

   index_from_bitmaps

  fi

 fi

fi

um convert_first_arg_to_mul_args,index_from_bitmaps
#@cli +rep_bayer_threshold_map: iteration,_normalize
#@cli : Create Bayer Threshold Map
+rep_bayer_threshold_map:
skip ${2=1}

ws=2

(0,2;3,1)
+store. initial_map

repeat $1 {

 ws*=2
 
 $initial_map
 
 $ws,$ws
 
 eval[-2] "begin(
   const ws=$ws;
   const half_ws=ws>>1;
   initial=crop(#-3);
  );
  M_Surface=initial*4;
  M_Surface+=i;
  draw(#-1,M_Surface,x*half_ws,y*half_ws,0,0,half_ws,half_ws,1,1);
  "
 
 rm[-3,-2]
 
}

if $2

 +. 1
 /. {4^($1+1)}
 -. {ia#-1}
 
fi

Running the above code with $ sp cat +pal 23 rep_transfer_color_reduced[0] :[-1],.5,2,1,3,0 gives me this:

[snip]
<gmic>-1./rep_transfer_color_reduced/*if#71/*if#75/_rep_transfer_color_reduced/*repeat/*local#216/*if#242/*if#288/rep_ordered_dithering/*if#687/*repeat#693/*local#694/*if#710/index/+palette/ Item[13]: 'e[^-1]', selections [0,1,2,(...),12,13,14].
<gmic>-1./rep_transfer_color_reduced/*if#71/*if#75/_rep_transfer_color_reduced/*repeat/*local#216/*if#242/*if#288/rep_ordered_dithering/*if#687/*repeat#693/*local#694/*if#710/index/+palette/ Command 'echo': arguments = 'Input color palette '$name'.' -> 'Input color palette '[1]'.'.
[gmic]-1./rep_transfer_color_reduced/*if#71/*if#75/(...)/*repeat#693/*local#694/*if#710/index/ Input color palette '[1]'.
[gmic]./rep_transfer_color_reduced/*if#71/*if#75/(...)/*local#694/*if#710/index/+palette/ *** Error *** Command '_palette_': Invalid selection [1] (contains index 1, not in range -1...0).
[gmic] *** Error in ./rep_transfer_color_reduced/*if#71/*if#75/(...)/*local#694/*if#710/index/+palette/ (file 'C:\Users\User\AppData\Roaming\user.gmic', call from line #720) *** Command '_palette_': Invalid selection [1] (contains index 1, not in range -1...0).

It tells me there isn’t 3 images. The thing is, there is indeed 3 images. So [1] is valid. But it’s not detected as valid. I will try to see if I can replicate it with a smaller code.

EDIT: I fixed it now. Now I see what’s going on. Instead of !$return_index_values, I used $out_color where out_color={!$return_index_values}.

EDIT: I’m at a point where alpha condition needs to be factored in part, and the new GUI filter. Not too far off even though the road is difficult.

EDIT as of 7/12/2022: Finished the cli version of rep_transfer_color_reduced after many tests and fixes. I will finish up the GUI version before it’s released. Finally.

I had made my code a bit more readable in gmic-community.

@afre Since you pointed to where I can improve before, I’d like to know if it is better now.

Just looking at the vibrance code, it is very readable. Congrats: it is like you are another person. :slight_smile:

My feedback would be to reduce the amount of empty newlines within commands and ensure newlines are between commands and sections of commands. Currently, this is not there or very consistent. Same could be said for end quotes or braces: sometimes they are on a new lines and other times at the end. Minor quibbles but over time these can add up or interfere with Python interventions or code cleanup.

Overall, great to see. I can actually read the code without confusion or tiredness. As with all code, the more comments and references (papers, links) the better. None of us are good at that.

1 Like

And the most difficult filter so far for me is now getting closer:

Still more things to do and test though, it is quite involved.

To get a idea of how difficult this is: It’s not the algorithm behind the effect that’s hard. It’s the conditionals. The reason is it hard is that I made two different effects with many options, and decided to combine them both which means using many different conditionals, and seeing how they relate to each other. This also forces me to actually code the whole thing and then test, then debug rather than code and debug.

Overall 2600+ Lines of Code, and most of them involves conditionals.

From the brief test, it is much more accurate than previous iteration which seem to have precision option, and it is so much more responsive. The precision option will be removed in favor of response speed, and accuracy as it is to be assumed nearly 100% precise.

Major upgrade to Transfer Color [Reduced Colors] has been released.

A new filter is on work. Based on @weightt_an Python Code. Horrendously slow when using multiple translated set-based operations as G’MIC has no concept of set, nor the operations based on set could be optimized all that much, and G’MIC doesn’t offer having images with varying channel size (could be a wish for G’MIC 4.0, not sure).

weightt_an Python Code given on discord/generative
from itertools import chain, combinations

def m_show(m, size = 4, cmap = 'copper'):
    import matplotlib.pyplot as plt
    from numpy import array
    cmaps =  ['binary', 'gist_yarg', 'gist_gray', 'gray', 'bone',
                'pink', 'spring', 'summer', 'autumn', 'winter', 'cool',
                'Wistia', 'hot', 'afmhot', 'gist_heat', 'copper']
    plt.figure(num = None, figsize=(size, size), dpi=300)
    plt.axis('off')
    plot = plt.imshow(array(m), cmap = cmap) #, interpolation='bicubic' )
    plt.show()
    plt.close()

def print_m(M):
    print('[' + ',\n '.join(map(str, M)) + ']\n' )

def powerset(iterable):
    "powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
    s = list(iterable)
    return chain.from_iterable(combinations(s, r) for r in range(1, len(s)+1 ))

def get_matrix(s):
    n = len(s)
    print(n)
    print(n)
    mat =  [[0]*n for i in range(n)]
    for x in range(0, n):
        for y in range(0, n):
            mat[x][y] = len(set(s[x]) ^ set(s[y]))
    return mat

big_n = 8
pows = list(powerset(range(1, big_n+1)))
adj_m = get_matrix(pows)

m_show(adj_m)
G'MIC translated Code
$ rep_lavander_binary_map 8
rep_lavander_binary_map:
check "$1>0&&($1==int($1))"

repeat $1 {
  k={$>+1}
  +rep_ncr_combinations $1,$k
  {w},1,1,1,$k
  rv[-2,-1]
  a[-2,-1] c
}

local[-$1--1] {
  total_length={sum(expr('w#x',$!))}
  max_spectrum_count=${-max_s}
  
  $total_length,1,1,$max_spectrum_count
  
  p=0
  
  repeat $1 {
    j[-1] [$>],$p
    p+={w#$>}
  }
  
  keep[-1]
}

local[-1] {
  square_size={w#-1}
  
  $square_size,$square_size,1,1,:"begin(
     const max_index=$1;
     
     p(pos)=I(#-1,pos,0,0);
     empty_set=vector(#s#-1,0);
     
     and_set(v0,v1)=(
       new_set=empty_set;
       ins_to_new_set=1;
       
       repeat(v0[0],v0_ip,
         v0_p=v0_ip+1;
         repeat(v1[0],v1_ip,
           v1_p=v1_ip+1;
           if(v0[v0_p]==v1[v1_p],          
             new_set[ins_to_new_set]=v0[v0_p];
             ++new_set[0];
             ++ins_to_new_set;
           );
         );
       );
       
       new_set;
       
     );
     
     or_set(v0,v1)=(
       new_set=empty_set-1;
       new_set[0]=0;
       
       ins_to_new_set=1;
       
       repeat(v0[0],v0_ip,
         v0_p=v0_ip+1;
         v=v0[v0_p];
         search_result=find(new_set,v,1,1);
         if(search_result==-1,
           new_set[ins_to_new_set]=v;
           ++new_set[0];
           ++ins_to_new_set;
         );
       );

       repeat(v1[0],v1_ip,
         v1_p=v1_ip+1;
         v=v1[v1_p];
         search_result=find(new_set,v,1,1);
         if(search_result==-1,
           new_set[ins_to_new_set]=v;
           ++new_set[0];
           ++ins_to_new_set;
         );
       );
       
       new_set;
       
     );
     
     diff_set(v0,v1)=(
       new_set=empty_set;
       ins_to_new_set=1;
       
       repeat(v1[0],v1_ip,
         v1_p=v1_ip+1;
         v=v1[v1_p];
         found=0;
         
         repeat(v0[0],v0_ip,
           v0_p=v0[v0_ip+1];
           if(v==v0_p,
             found=1;
             break();
           );
         );
         
         if(!found,
           new_set[ins_to_new_set]=v;
           ++new_set[0];
           ++ins_to_new_set;
         );
         
       );
       
       new_set;
       
     );
     
     xor_set(v0,v1)=(
       new_set=empty_set;
       ins_to_new_set=1;
       
       repeat(v1[0],v1_ip,
         v1_p=v1_ip+1;
         v=v1[v1_p];
         found=0;
         
         repeat(v0[0],v0_ip,
           v0_p=v0[v0_ip+1];
           if(v==v0_p,
             found=1;
             break();
           );
         );
         
         if(!found,
           new_set[ins_to_new_set]=v;
           ++new_set[0];
           ++ins_to_new_set;
         );
         
       );
       
       repeat(v0[0],v0_ip,
         v0_p=v0_ip+1;
         v=v0[v0_p];
         found=0;
         
         repeat(v1[0],v1_ip,
           v1_p=v1[v1_ip+1];
           if(v==v1_p,
             found=1;
             break();
           );
         );
         
         if(!found,
           new_set[ins_to_new_set]=v;
           ++new_set[0];
           ++ins_to_new_set;
         );
         
       );
       
       new_set;
     );
     
   );
   out=xor_set(p(x),p(y));
   out[0];"
}

rm..

Side by Side Compare:

Left: @weightt_an Python Code
Right: @Reptorian G’MIC Code

Result when using multiple translated set operation Turns out there’s a bug: https://github.com/dtschump/gmic/issues/409

dynamic arrays (with functions da_*()) have been introduced specifically for this purpose.
If you want to manipulate sets of numbers or vectors, you’d probably use them.

I’m not sure I get the idea here. G’MIC does manage images with arbitrary number of channels (that’s even one of its strength). Could you please describe the “missing” feature you’d like to see introduced in future releases of G’MIC?

Let me clarify, what I want to see in G’MIC is images where two pixels can have two different numbers of channels. In my case with the translated code, it would be really tedious to find a way to perform multi-threaded operation on different dynamic arrays and then copying it back, and so it was easier to try to make macros to stimulate Python set operation ( union , intersection, difference, and symmetric difference )(that comes with the problem when assuming function is the same as macro). Of course, that means inserting images into a new image that fit channel size + 1, and the additional is for representing the size of array.

For reference, a set in Python is the same as a vector, but in Python, you can have different-sized array in a single array. Having different sized pixel is a image is not possible in G’MIC now. And this requires specialized functions too and I imagine a new image type of avoid conflicts.

It won’t be an image anymore. I think I’ve never seen images like this.
In any case, the structure of images in G’MIC does not allow this (and it won’t).

I understand that Python proposes a set structure that allows this, but converting a Python code that uses this is probably feasible without managing so much degrees of liberty.
Most often, you can have an idea about the maximal dimension M, then work with an image with M channels (and put 0 in the channels that are not used).
Otherwise, you can manage a dynamic array where you push elements of various sizes, and use a second dynamic array to push the size of each element. This way, it’s easy to retrieve element #N.