G'MIC exercises

I can’t break it down, however everything after the extract line ends in two image. So, that’s the only relevant details, you don’t have to pay attention to anything before that.

‘mode’ is condition in which pixel are added to second image.
‘pt_eval’ is used to detect if surrounding cropped area contains at least one point in second image, and then point info within extract start moving.

The goal is to stimulate optimized multithreaded ‘Diffusion Limited Aggregation’ using extracted coordinates image, and a binary image.

EDIT: In theory, I may be able to use run(fill) inside eval of older code to speed it up.

EDIT: Actually no. I’m reading extract code to do this. It’s confusing though. The part of str puts me off.

What I’m doing now is to loop per coordinates image, then dar_insert into last image using the condition that cropped area of image meet pt_eval condition, and return the the value of coordinates image. Hard to explain. This way, I can filter out points to move making the filters much faster as I’m not applying multithread operation on every single points found in coordinate image.

The coordinates image is the #0 image, and those are coordinates of points.

EDIT: Now I understand how eval works even better. I think I can nail this.

A brief web search shows different approaches to the same problem. I do see one where the author uses do..whiles like you do. Just remember that G’MIC has lots of implicit loops, so you may be looping more than you intend. E.g. fill and eval loop xyzc and crop loops the neighbourhood. Like with math equations, you could probably bring some processes outside of certain loops to make things go faster.

This would defy that principle.

You just aren’t used to the syntax. David is merely concatenating the string. It is actually a smart way of organizing the code because only one part of it is conditional.

This sort of creativity in coding is needed for sanity. E.g. instead of dealing with variables, sometimes it may be easier to store coordinates as a pixel value in an image. The possibilities are endless as long as you solve the problem efficiently.

Yes. Hence the later no. I actually did managed to extract coordinates in which the coordinates are close to point of interest, process with extracted coordinates, and repeat. Let’s just say it didn’t work out.

I see it, I’m not quite a fan of the syntax (to be fair, you probably don’t like mine), but I can see that it works which is what matters. I prefer to go by concatenating string outside of eval/fill, and then use string within fill, eval. A lot of my code use defined string inside eval/fill as I know gmic converts it into interpreted code.

I am trying to figure out Octave again. The popular function [nn, xx] = hist (y, nbins) has two outputs. I can get nn using G’MIC’s histogram. Not sure about xx, which the manual describes as

With two output arguments, produce the values nn (numbers of elements) and xx (bin centers) such that bar (xx, nn) will plot the histogram.

Should be simple. I even looked at the code just now. Must be the insomnia. (Oh, I may also be using a much older version. This file seems to have received multiple changes since.)

https://hg.savannah.gnu.org/hgweb/octave/file/tip/scripts/plot/draw/hist.m

What is bincenters? I think you could do it with eval[image] regardless, and using dynamic array + resize akin to how extract works.

I think it is where the centres are located to plot the bars in a bar graph of the histogram, whereas nn represents the counts. I agree that the wording can lead to confusion.

Ok, I think that’s doable. I think this is what you want:

rep_bin_size:
#$1=histogram max size#
#$2=bar_size#
bars={int($1/$2)}
repeat $! l[$>]
 $bars,1,1,100%
 eval.. "
 i(#-1,int(i/$2),0,0,c)++;
 "
endl done

Not really sure though.

Do note that instead of histogram for individual values, what the command does is basically determines the number of pixel values that hit within ranges of bars. I don’t think it’s what you want though.

Here’s a pic:

image

After updating Octave, the results finally match. Look how large Octave is! Took a while to decompress and move.

image


Figuring out this now: Function Reference: interp1.

yi = interp1 (x, y, xi, 'linear', 'extrap')

To my understanding, (x,y) transforms xi into yi with interpolation and boundary type linear and extrap. In my exercise, (x,y) are CDFs that form a two-column LUT. Before, @garagecoder helped me with the single ramp scenario using

[image] [ramp] f.. i[#1,i#0]

Now, we are dealing with 2 ramps. Use warp? Doesn’t look like what warp does…

No indeed, warp is most easily used for interp in the case where the input points are at evenly spread locations. It won’t do extrapolation in the same manner either. I’m not certain of the best way to handle arbitrary input locations (I have some ideas though).

Could you give an example showing input and desired output possibly (as small as possible)? I’m just wondering which parts of that you actually need for your goal.

xi =

   0.1165   0.1169   0.1160   0.1163   0.1090
   0.1111   0.1000   0.1088   0.1102   0.1043
   0.1116   0.1125   0.1097   0.1133   0.1123
x =

   0.3248   0.1009   0.1026   0.1042   0.1059   0.1076   0.1093   0.1110   0.1127   0.1143   0.4931

y =

        0
   0.0667
   0.0667
   0.1333
   0.1333
   0.1333
   0.3333
   0.5333
   0.7333
   0.7333
   1.0000
yi =

   0.725957   0.724533   0.727663   0.726599   0.295726
   0.553218   0.066667   0.273784   0.445536   0.133333
   0.603867   0.709664   0.379286   0.733333   0.690269

Let’s say I am using I(#0,px,py,z,2) and I want to cut the value by min/max of all vector used by bicubic interpolation, how would I do it? I know cut() exists, but I just don’t know how to do it with cubic.

Aren’t cut() points hard? Interpolation isn’t necessary… Give us an example.

The recpoltrans I’m working on. Interpolation is necessary there as I want to use it for upgraded version of perspective streak. Right now, the output shows only the value of pixels are off, and the coordinates of translated pixels doesn’t seem to be off except for very few pixels.

How would this play out differently with interpolation? cut() makes all values below and above min and max min and max respectively.

(10,11,15,568,-10) f cut(i,4.5,14.5)    # (10,11,14.5,14.5,4.5)

The values are blended (This is why I need interpolation), and bicubic sampling works effectively with the problem of values exceeding original min/max of vectors used for bicubic sampling. My goal is to perform axis streak, and the values should be interpolated when transforming from rectangular-polar to cartesian format.

I am getting an inkling of what you mean. More questions: Is this an actual cut() or are you nudging a value like it is a key point and interpolating its neighbours? When is this interpolation taking place? Before, during or after the transformation? Or between the original and the problematic result? As I said, an example (numerical or graphic) would definitely clear things up.

It should be taking place during the transformation. To clarify with example of my problem, I will post the output of the difference from original to images applied with transformations

Code used:

new_rep_recpoltrans
$ sp monalisa +new_rep_recpoltrans 0,0,1 new_rep_recpoltrans. 0,0,0,1 a z
new_rep_recpoltrans:
skip ${1=0},${2=0},${3=0},${4=}
if $1<-1||$1>1 error ($1>=-1&&$1<=1)=0 fi
if $2<-1||$2>1 error ($2>=-1&&$2<=1)=0 fi

repeat $! l[$>]
 if $3>0
 
  if abs($1)==1&&abs($2)==1
  
   maxlength={max(w,h)*2}
   perimeter={(w+h)*2}
   
   if $1==1 x_coord=round(ww-dix)
   else x_coord=round(dix)
   fi
   
   if $2==1 y_coord=round(hh-diy)
   else y_coord=round(diy)
   fi
   
   {$perimeter},{$maxlength},{d},{s},":begin(
     if($1==$2
      ,surface=expr('begin(const hpi=acos(0););hpi-x/w*hpi;',w);
      ,surface=expr('begin(const hpi=acos(0););(x/w)*hpi;',w);
     );
     const hpi=acos(0);
     const ww=w#0-1;
     const hh=h#0-1;
     const ihh=h-1;
     const cut_ang=atan2(hh,ww);
     distanceaway=[ww,hh];
    );
    surface_angle=surface[x];
    surface_angle<cut_ang?side=0:side=1;
    mdist=side%2?abs(1/sin(surface_angle)):abs(1/cos(surface_angle));
    dix=cos(surface_angle)*distanceaway[side]*mdist*y/ihh;
    diy=sin(surface_angle)*distanceaway[side]*mdist*y/ihh;
    I(#0,"$x_coord","$y_coord",z);"
    
  else
   
   maxlength={max(w,h)*2}
   perimeter={(w+h)*4}
   
   {$perimeter},{$maxlength},{d},{s},":begin(
     surface=expr('begin(const dpi=2*pi;);(x/w)*dpi;',w);
     const dpi=pi*2;
     const ww=w#0-1;
     const hh=h#0-1;
     const ihh=h-1;
     const point_x=(($1*-1)*.5+.5)*ww;
     const point_y=($2*.5+.5)*hh;
     const inv_point_x=ww-point_x;
     const inv_point_y=hh-point_y;
     const cut_ang_s0=abs(atan2(inv_point_y,inv_point_x));
     const cut_ang_s1=pi-abs(atan2(inv_point_y,point_x));
     const cut_ang_s2=pi+abs(atan2(point_y,point_x));
     const cut_ang_s3=dpi-abs(atan2(point_y,inv_point_x));
     distanceaway=[ww-point_x,hh-point_y,point_x,point_y];
    );
    surface_angle=surface[x];
    surface_angle>cut_ang_s0&&surface_angle<=cut_ang_s1?side=1:
    surface_angle>cut_ang_s1&&surface_angle<=cut_ang_s2?side=2:
    surface_angle>cut_ang_s2&&surface_angle<=cut_ang_s3?side=3:
    side=0;
    mdist=abs(side%2?1/sin(surface_angle):1/cos(surface_angle));
    dix=point_x+cos(surface_angle)*distanceaway[side]*mdist*y/ihh;
    diy=point_y+sin(surface_angle)*distanceaway[side]*mdist*y/ihh;
    I(#0,round(ww-dix),round(diy),z);"  
   
  fi

 else
 
  $=val
  orientation=${val{$>+4}}
  perimeter={w}
  
  if abs($1)==1&&abs($2)==1
   length_1={$perimeter-h}
   length_2={$perimeter-$length_1}
  else
   length_1={$perimeter-h*2}
   length_2={$perimeter-$length_1}
  fi
  
  if $orientation
   width={min($length_1,$length_2)}
   height={max($length_1,$length_2)}
  else
   width={max($length_1,$length_2)}
   height={min($length_1,$length_2)}
  fi

  if abs($1)==1&&abs($2)==1
  
   if $1==1 surface_x=x-nw
   else surface_x=x
   fi
   if $2==1 surface_y=y-nh
   else surface_y=y
   fi
  
   if [$1,$2]==[-1,-1] calc_ay=(atan2(-ypos,xpos)+hpi)/hpi
   elif [$1,$2]==[1,1] calc_ay=y!=nh?atan2(-ypos,xpos)/pi:1
   elif [$1,$2]==[-1,1] calc_ay=atan2(-ypos,xpos)/hpi
   elif [$1,$2]==[1,-1] calc_ay=ypos?(atan2(-ypos,xpos)+pi)/hpi
   else error invalid_inp("$"1,"$"2) fi
   
   {$width/2},{$height/2},{d},{s},"begin(
     const ww=w#0-1;
     const hh=h#0-1;
     const nw=w-1;
     const nh=h-1;
     const hpi=acos(0);
    );
    xpos="$surface_x";
    ypos="$surface_y";
    ay=max(abs(xpos/nw),abs(ypos/nh));
    ax="$calc_ay";
    I(#0,ax*ww,ay*hh,z,2,1);
    "
  else
   {$width/4},{$height/4},{d},{s},":begin(
     const ww=w#0-1;
     const hh=h#0-1;
     const nw=w-1;
     const nh=h-1;
     const dpi=2*pi;
     const cx=.5+$1*.5;
     const cy=.5+$2*.5;
     const px=cx*nw;
     const py=cy*nh;
     const rpx=nw-px;
     const rpy=nh-py;
    );
    xpos=x-px;
    ypos=y-py;
    ax=1-(atan2(ypos,xpos)+pi)/dpi;
    ay_x=x>px?(rpx-(nw-x))/rpx:(px-x)/px;
    ay_y=y>py?(rpy-(nh-y))/rpy:(py-y)/py;
    ay=max(ay_x,ay_y);
    I(#0,ax*ww+(ax*ay),ay*hh,z,2,1);
    "
   fi
 fi
 k.
endl done

Difference analysis:

Note how most of the image is black? That is the result I want to see. The minimum difference possible. Now, it seems that there are localized error. Let’s zoom in that area and check what happens.

Before:

image

After:

image

They look almost the same. The thing is that only the value is off, not the internal coordinates used for transformation, and even if that were off, it’s pretty minor.

So, that’s why I want cut value using capital I(#n) as input, and to cut values found in each channel. Should be done during transformations.

Is that not just something like cut(I,50,100)?

No. The 2nd and 3rd input must be based on min/max of pixels utilized by bicubic interpolation. As you can see the difference analysis, the problem mostly is local.