On the road to 3.0

Even though gcd_boxfilter_local streaks, [Edit See (1) at footer.] it is still more stable than the generic SAT driven box filter. I am not sure what @garagecoder is doing that makes it behave better. I.e., substituting his box filter in my guided filter doesn’t cause range disparities (impulse noise). Mine does, even though it is a simple 2D SAT driven box filter injected into afre_gui0.

afre_box0 : check ${1=1}>=1
  repeat $! l[$>]
    b={$1*2+2} r {[w,h]+$b},100%,100%,0,1,0.5,0.5
    cumulate xy
    f "begin(const boundary=1; const R=$1; const S=-R-1;
      const A=sqr(R*2+1)); (j(R,R)+j(S,S)-j(S,R)-j(R,S))/A
    " r {[w,h]-$b},100%,100%,0,0,0.5,0.5
  endl done

afre_gui0 with changes in smoothing: original, 1e-2, 1e-1, 1e0 and 1e1. The latter two have peaks only in the whiskers.

gmic sp tiger repeat 4 +Agui0[0] 1,1e{$^>-2} done c 0,255 a z xz s z a y o tigers.png

tigers

Note that boxfilter, blur and my custom convolve driven methods don’t exhibit such artifacts.


Edit (1) Correction: the command that works error free for me is gcd_satboxfilter, the precursor of gcd_boxfilter_local.

Not surprising at all. Usually, when smoothing an image, it’s good to have a smoothing geometry that is smooth itself, to avoid the apparition of artefacts (mostly discontinuities that are too contrasted).
I would suggest you store the smoothing “radius” of each pixel in an image, then blur it (with gaussian blur) before using the smothed radii to actually filter the image.

Something like this:

foo : check "${1=2}>0"
  repeat $! l[$>]

    # Determine pixelwise smoothing radius.
    +b. 2 gradient_norm. f. "$1/(1+i^0.5)"

    # Iterate adaptive box filter.
    repeat 2
      +cumulate[0] xy
      f[0] "
        const boundary = 1;
        const interpolation = 1; # R is float-valued
        R = i(#1,x,y,0,0);
        R2p1 = R*2 + 1;
        R>0?(
          x0 = x - R - 1;
          y0 = y - R - 1;
          x1 = x + R;
          y1 = y + R;
          (i(#-1,x1,y1) + i(#-1,x0,y0) - i(#-1,x1,y0) - i(#-1,x0,y1))/R2p1^2;
        ):i"
      rm.
    done
    k[0]
    c 0,255
  endl done

Yes, that’s my point exactly - not surprising, because it’s mathematically not separable when the window sizes are arbitrary. With 2D summed area the problem goes away - so I’ll work on that approach later. It’s easy, but boundary handling is the main issue there (also an issue for separated, but my 1D filter handles it). An approximate separated method is still useful, but I’d like a correct reference version too!

Edit: thanks for the 2D version to use as a starting point. If the reference/guidance image (the gradient part) is replaced by +f 10 to simulate a normal box filter, the edges problem will be visible (it’s also apparent mathematically).

Edit2: after some scribbled drawings, it’s definitely possible to handle boundaries in 2D summed area (without a horrible extend-the-image hack). Mostly just finding edge sums and multiplying by distance and sign(x*y). It’s tricky but hopefully reducable. Not sure if I’ll complete it before next weekend though.

I think I’ve got a working reference which properly handles boundaries:

gcd_boxfilter_local : check ${"is_image_arg $1"}
  pass$1 0 max. 1
  repeat $!-1 l[$>,-1]
    cumulate.. xy
    f.. "
    begin(
      const boundary=1;
      const interpolation=1;
      const W=w-1; const H=h-1;
      T(X,Y)=Y>1?i(X,Y-1):Y*i(X,0);
      B(X,Y)=Y<H?i(X,Y):(1+Y-H)*i(X,H)-(Y-H)*i(X,H-1);
      C(X,Y)=X<W?B(X,Y):(1+X-W)*B(W,Y)-(X-W)*B(W-1,Y);
      D(X,Y)=X>1?T(X-1,Y):X*T(0,Y);
      E(X,Y)=X<W?T(X,Y):(1+X-W)*T(W,Y)-(X-W)*T(W-1,Y);
      F(X,Y)=X>1?B(X-1,Y):X*B(0,Y);
    );
    R=i#1; S=R*R; K=(R-1)/2;
    x0 = x - K;
    y0 = y - K;
    x1 = x + K;
    y1 = y + K;
    (C(x1,y1) + D(x0,y0) - E(x1,y0) - F(x0,y1))/S"
  endl done rm.

It’s already quite fast. Boundary check:
boundarycheck
Accuracy check:
accuracycheck

Edit: some extra info about how it works.

The starting point is to define two functions T(x,y) and B(x,y) which can extrapolate the summed area past the top and bottom boundaries respectively (but not left and right edges). Then we use knowledge of which boundaries each of the four areas can pass, to define and extrapolate each of those (to minimise number of comparisons per function). Those are C = bottom right, D = top left, E = top right, F = bottom left.

2 Likes

@David_Tschumperle any plans to add 64bit image support?

Each image pixel takes then 32bits/channel (except if double-precision buffers have been enabled during the compilation of the software, in which case 64bits/channel can be the default).


@David_Tschumperle The PDF version is 2.9.4, two versions behind. Another thing I noticed was that it is quite large. Could you make a low-fi version?

Request for making a knots paterns

Is it possible to create GMIC patterns similar to celtic knots ?

@hover

In theory, it is possible, but time-consuming. I think you are much better off learning gmic coding.

There is on my mac with gmic from git built a minor problem with “display”
Displaying some rel. large images and selecting e.g. the second, selecting a subregion, clicking left to leave it, and clicking left again to return to display of all images does not return to initial display, only <esc> helps, closing the window completely.

Aah, I just found that zooming out by mouse wheel and than clicking left helps. Seemingly there is a remaining zoom.

I think it is a problem of calculating/rounding coordinates!
Example: (it is a 24 MB file! with two images (1996,2698,1,3)) http://karo03.bplaced.net/Test/gmic_0000.cimgz

By the way, my screen #0:
dimensions: 2560x1416 pixels (677x375 millimeters)

Hello Karsten. Just tested here with your sample image, and it works for me :frowning:
My screen is 1920 x 1080.
I don’t know what I can do if I can’t reproduce the bug unfortunately. I’ll check how the test of the single click is done, maybe I can find something wrong there.

:thinking: I may have reported it before. It has been a while, so it may have been a different issue; but this sounds vaguely familiar.

Thank you for the quick response, David.

Left clicking shows instead of going back to initial display shortly a very small rectangle in the upper left of the cross hair!

I thought the problem was happening when left-clicking from the “image list” display modules, not the “image” display module ? In the “image list” module, there is no cross hair.
Could you tell me exactly where it occurs. It’s not the same code to inspect.

It is in the “image” module, with the cross hair cursor. The small white box, perhaps 1 px, appears in the cross upper left . from there I cannot return to “image list” module.

Clicking left does change slightly the display seemingly a zoom recalculation and sometimes a very small piece is zoomed and displayed as subregion!

With
gmic gmic_0000.cimgz luminance. gt. 40 dilate_oct. 3 r 50%,50%,50%
the problem does not occur! As well as with “r 200%,200%,200%” no problem!

Here are snapshots with my camera from the situation

unpressed

pressed

You see the different thickness of some lines?

Could you try to update with $ gmic up ?
I’ve tried something, but as everything works for me, I’m not sure it really fixes your issue.

No change, or even worse. zooming does not help anymore. By chance sometimes it returned to list mode.
Still the change in display by pressing! A very special “refreshing”!

Ha, closing the image window (via window decoration) let appear the image list window. I think earlier the display mode terminated completely by closing the window.

By the way

“fitscreen .” returns 891,1204 for my display.
Perhaps a problem with odd window sizes?

AND

gmic gmic_0000.cimgz r {w+1},100%,100%,100%

let’s disappear the problem!

Ok, I have found something:
the problem mentioned appears only on my external monitor, optimized for the external monitor. If I optimize the external monitor for the internal monitor (from my laptop) the problem does not appear.

Hence, although I have the latest OS and the latest XQuartz version, there is still the problem of X11 server with second monitors on Mac.

Thank you for your responses, David