On the road to G'MIC 3.4

Qt does support 16 bit and float RGBX, but not sure about Qt-widget specifically… that would be neat though.

  • Added new cli command gcd_inpaint_flat

This is a very basic and relatively fast inpaint which “flat” fills using average of connected edges. It’s intended for building more complex filters, rather than directly for inpainting (obviously the restoration isn’t very suitable for that).

The algorithm is very simple:

  • inpaint masked areas by 1px using a 3x3 weighted average
  • label the segments and take a histogram of the inpaints
  • map the averaged colours back to the segments

I would recommend starting your own thread, so that we can see updates on your filters.

In case you might consider it (no harm in asking!)… a possible optimisation which could be used for a few things: native guided histogram (histogram which accepts a mask), or equivalently, additive forward warp.

Yes, this can be done with a simple math equivalent such as eval[mask] "I[#-1,i]+=I#0" but I would guess this could be an order of magnitude faster as a native command (especially for large images such as raw). It has general usage for weighted sums.

I understand the concept of masked histogram, but what you mean by additive forward mask ?

With warp in “forward” mode, your mask holds the [x,y,z] location to draw a pixel to, so the idea could be rather than simply draw/overwrite it would add. As I say, pretty much the same thing.

But cannot be this already done with sth as +warp[img] [warp_field] +[img,-1] ?

I don’t think so no, seems like the last pixel wins (I’m talking here about multiple source pixels going to the same output pixel). Example, write all inputs to the same output position:

gmic "(1,2,3,4)" "(0,0,0,0)" warp.. .,2

data = (4,0,0,0)

Ah OK, I got it.
It would be like using opacity=-1 in the drawing functions.

Sorry, yes that’s the easiest way to state it!

Edit: I did some tests based on existing speed of warp and it’s not as big a gain as I’d hoped, but still significant: roughly about 1/4 time taken vs using eval. Also surprised that nn interp appears slower than linear or cubic.

How about this:

#@cli masked_histogram : [mask],nb_levels>0[%],_min_value[%],_max_value[%]
#@cli : Compute the masked histogram of selected images.
#@cli : Default values: 'min_value=0%' and 'max_value=100%'.
masked_histogram : check ${"is_image_arg $1"}" && isint($2) && $2>0" skip ${3=0%},${4=100%}
  e[^-1] "Compute histogram of image$?, with mask $1, $2 levels in range [$3,$4]."
  foreach[^-1] {
    vmin,vmax:="ispercentage($3)?(1 + $3):1 + ($3 - im)/(iM - im),"\
               "ispercentage($4)?(1 + $4):1 + ($4 - im)/(iM - im)"
    n 1,2 pass$1 !=. 0 * discard 0 histogram $2,$vmin,$vmax

A bit tricky, but seems to work (unfortunately probably not with images having inf or NaN values…).

OK this is useful as well (thanks!), but… this is masking away certain pixels/values from being included in the histogram.

What I was trying to describe - and failing - is where the mask contains the values which will be represented along the axis of the histogram, and the totals are a sum of values/vectors in the source image per each value in the mask. In that respect, it’s far more like the idea using warp.

Edit: as I say, this is easily done with math parser, for example eval[mask] "I[#-1,i]+=I#0". I had imagined a native command to be potentially much faster, but it turns out “only” 4 times faster. This type of gain probably doesn’t excite you enough to do it :slight_smile:

1 Like

What I understood yesterday was actually you’d like to add a possible argument to command histogram that tells the list of values that should be counted (and only these values).
That’s what I’ve been thinking about all night :slight_smile:

This actually changes the algorithm complexity a lot, as for each image pixel, you have first to determine if its value must be counted or not (this being at least in O(log(N)) complexity, where N is the number of prescribed values, if those are initially sorted).

But if we want to write a function that is generic enough for this task, it becomes quite painful because:

  • Managing float-values: when your image is float-valued, you wouldn’t want to count the exact occurence of a single value, but rather the occurence of a value in a specified (possibly small) range.
    For that, you need to provide a set of ranges as an argument to the function (rather than a set of values). This makes the algorithm even more complex, because then you have to check for each pixel value if there is a range that contains it.
  • And possibly there are several user-defined ranges that could contain it (ranges may overlap). You may want to restrict the function to work with non-overlapping ranges, but in that case, you have to check first that the specified ranges does not indeed overlap.

So, my impressions on this is that :

  • Writing a generic function for that task would represent quite a lot of work (and when adding a new native command, you want it to be generic-enough).
  • If you have a specialized use of this function, then you could probably write it in a “simplified” way (non-generic) that may have a better algorithm complexity (e.g. testing integer values rather than float-valued ranges).
  • The use cases of such a function seems very specific, so it doesn’t necessarily seem worth the effort to make it a native command.
  • And if it’s “only” x4 times slower in your case, It doesn’t indeed look too bad :slight_smile:

Tell me if you agree with this reasoning :slight_smile:

That’s quite an interesting idea too, not one I’d thought about! Indeed, when you try to search for values within a distance it gets a lot harder. Totally agree on not doing custom work, it seems silly for the amount of gain - I forgot the golden rule of testing assumed bottlenecks before optimising!

Also, not sure if that can help, but do you know histogram_nd ?


    Compute the 1D,2D or 3D histogram of selected multi-channels images (having 1,2 or 3 channels).
    If value range is set, the histogram is estimated only for pixels in the specified
    value range.

    Default values: 'value0=0%' and 'value1=100%'.

      [#1] image.jpg channels 0,1 +histogram_nd 256

Yes I discovered that one earlier when looking for ideas. The other option I thought about was using 3D pointcloud, but last time I checked it’s about the same performance as the math parser - I might try it for fun though.

  • 2023/11/10: Release of version 3.3.2.
1 Like

I’m considering making a command for solving non-negative least squares - is there something already available?

I don’t think so, your contribution is welcome! :beers:

1 Like

Is there a fast way to compute a matrix C = A'B (A transposed mmul B) without explicitly doing the transpose?