G'MIC exercises


(Alan Gibson) #272

Here’s another way of thinking about the situation. For simplicity, I’ll assume only one dimension.

Suppose we have a curve y=f(x). We don’t know what the curve is, we know only that for two values x0 and x1, the y values are y0 and y1. For a resampling (enlargement or reduction, or some other process) we need to guess the values of y for some other values of x.

Well, if we know only two points, we might guess the function is linear. That guess is as good as any other. But if we know four points, we might guess the function is piecewise linear between each pair, but a better guess would be a curve that passes through the known points but doesn’t suddenly change direction at any point. A spline curve would qualify, and is probably more accurate than a piecewise linear function.

However, sadly, we don’t really know the y-values at exact values of x because each camera sensor element capturea light over an area, not a point. So we really know the average value of y summed over a certain range of x-values. We don’t know that the curve passes through any particular points, only that the curve has a certain average at various ranges of x. And the task is to find the average of the curve at certain other (smaller) ranges.

This opens more possibilities. A wide range of curves can be considered. Which we choose depends on many factors. For example, a Nikon D800 has an anti-aliasing filter, which creates a blur. So the ranges of x-values overlap. We know the average values of y at various overlapping ranges of x. And I suppose that “average” is bell-shaped, so light hitting the centre of the sensor pixel has a greater weight than light hitting near the edge. An accurate resampling method (eg to simulate a photo taken with a camera that had greater resolution) should take these factors into account.

The result is that the curve for a resampled image might have characteristics including:

  • sharpness vs blurry (steep vs shallow curve)
  • aliasing (“jaggies”, “staircase”; over-sharp)
  • halos (“overshoot”, increases perceived sharpness; may be useful or obtrusive)

These characteristics are trade-offs.

How do we choose? In my work, I choose visually.


Take the following sample image.

gmic sp tiger > 240

1. Which are the largest or smallest i and I patches?
2. Is there a way to mask them based on their size? E.g.,
   < 10 pixels in area?
   < 3 pixels in width (for elongated or ring shapes)?

(dumb) #274

To complement the CubeHelix filter I’ve been using satellite image enhancement colour schemes; they’re useful for bringing out contrast in images. I found a load of text files from with some which the NOAA use and I’ve used an online awk clone to sort out all the prepare the data for fill.

Filter, table for the last scheme that I’m including and sample image:

I’ll be adding more soon before I make a PR on GH. Should I have used map instead? Also, yes, I know that this’ll be used for fakery but genuine products always come from the respective websites. Also it’s really easy to tell that this is fake because I’ve never seen any cloud tops that get yellow colours before when using this scheme.


I tend to learn about my images using statistics. It would be beneficial if I could acquire the stats of a region that isn’t a rectangle; say that I have a binary or grey scale mask.

(Karsten R) #276

Say you have image and mask (0/1):

gmic image mask +extract_region[0] [1],0,1 e {stats()}

will print out a list of image features for the region defined by mask pixels of “1”!

from help file:
. 'stats(_#ind) returns the statistics vector of the running image ‘[ind]’, i.e the vector
[ im,iM,ia,iv,xm,ym,zm,cm,xM,yM,zM,cM,is,ip ] (14 values).


That would only work for specific labels. Is a grey scale selection possible?

I am aware of stats() but don’t know, or remember, how to use it; e.g.,

  • How does _#ind work again?
  • Could I choose which statistic(s) to include in the vector, or does it always output 14 values to be retrieved from the vector afterward?

(Karsten R) #278

… of course, you have to prepare the mask image for selection accordingly or you have a binary mask with many different regions, label it and select the wished label number. E.g.

gmic sincos , +gt 120 label. +eq. 1070 +extract_region[0] [1],0,1070 e {stats(#-1)}

stats() is a gathering, look into the mathematical processor part of the description, there are the names (or variables) which constitute the stats vector.

stats() looks for image -1, hence it is the same as stats(#-1).

(G'MIC staff) #279

For info, I’ve recoded command extract_region this morning, and it should be faster than the previous version. If you encounter any issues with this new version, please let me know !


I see several commands that have “command” as an argument. E.g.,


Been burnt out lately; staring at gmic_stdlib.gmic isn’t helping. :confused: Could someone show me how it works. Thanks!

(Karsten R) #282

There is an example in references page 441. command means gmic command script peace to be applied to the camera image (apply_camera).

gmic apply_camera “+mirror x +mirror y add div 4”

(G'MIC staff) #283

Well, yes, as @KaRo said, an argument "command" can be any G’MIC pipeline you want.
For instance command apply_channels is able to apply a G’MIC command to a particular color channel of the image (can be for any kind of color basis).
So, for instance,

$ gmic sample tiger +apply_channels \"blur 10 mirror x\",lab_ab

will apply the G’MIC pipeline blur 10 mirror x only on the chroma parts ab of the image decomposed in the Lab colorspace (assuming input image is sRGB ).
This results in :


Take e.g.,

gmic sample tiger blur 5 dilate 3 equalize print
gmic sample tiger equalize_after "blur 5 dilate 3"

How would I pass on “command” to equalize_after and make the two lines equivalent?

PS I have another syntactic question.

I typically use single line math expressions like

gmic 256,1,1,1,x + 10 n 0,1 f gauss(i-.5) n 0,1 plot

Notice how I normalized the values before and after the expression; I used 0,1 but it could be any range. If I incorporate the normalization into the expression, I guess it would be

gmic 256,1,1,1,x + 10 f a=(i-im)/(iM-im);b=gauss(a-.5);what_goes_here? plot

(G'MIC staff) #286

I’m not sure I understand, the command equalize_after doesn’t exist. Do you ask me I show you how to write it ?

(G'MIC staff) #287

You can’t do post-normalization in a math expression easily, as the normalization requires to knowledge of the minimal and maximal value of your image.
You basically have to wait the math parser to have computed all values before you can normalize.


Sorry for not being clear. This works for me.

However, for my sample command, I would need to double quote. Escaping doesn’t work. What is different?

quoted_arg_: skip ${1="equalize print"}

gmic sp tiger quoted_arg_ ,                      #all
gmic sp tiger quoted_arg_ ""equalize print""     #three
gmic run "sp tiger quoted_arg_ "equalize print"" #work


Back to curves. So far we have focused on 1-2 curves in the [0,1] range. What about 3 or more curves? How do we attach them using math or code to create an increasing curve? Independently, the curves I use work in the [0,1] range.

3-4 curves example; i.e., the s-curve could be 1 or 2 curves.


The above example could be looked at another way. It might be applying an s-curve on a range [a,b] other than [0,1].

PS Of course, keep your explanation or links as gentle as possible. I am not good or fast in math or programming. :blush:


I’d answer if I knew… there are various spline/interp type commands that I’ve never used myself. The x_spline command may give some hints, but perhaps not the simplest. Would be good to use what G’MIC already has, rather than building one up from the ground!

Edit: @afre this is possibly a good start:

gmic 256,1,1,1,x apply_curve 1,0,0,48,48,100,64,128,128,224,192,255,255 dg 400,400


I’m struggling with “string handling” again - it’s the one thing in G’MIC which makes me frown! Hard to predict when it’s partly macro based and not totally clear what’s under the hood. If there was a GUI parameter type that added an unaltered string directly as an image (with no weird string escaping issues) I’d be in heaven :slight_smile:

(G'MIC staff) #291

I’m a bit surprised, I find the management of strings quite convenient in G’MIC, so convenient that I even wrote a lot of different text files parsers and generators directly as G’MIC scripts (gallery, filter updating script, documentation generator and so on…).
What kind of issues do you have ?

The thing you have to keep in mind is that some characters have a different meaning when they are quoted or not (those characters are $, {, }, , and " ).
Technically speaking, they actually have different ascii values when they are encoded in a string !

Now, to pass from one representation to another is quite easy :

  • From unquoted characters to quoted characters : Use the substitution syntax {``string}.
foo :
#  0 text. $var,1%,1%,24,1,1  # -> Error, invalid arguments '1,2,3,1%,1%,24,1,1' for command 'text'
  0 text. {``$var},1%,1%,24,1,1 # OK !

  var="1,2,3"  # The comma has a different meaning here, as it is double-quoted!
  0 text. $var,1%,1%,24,1,1  # OK !
  • From quoted characters to unquoted characters : Use status command, i.e. u $string . Also depending on the context, the command may unquote its argument automatically (when it has only one arg, e.g. input).
  0 text. ${"u "$var}

What kind of things do you need to know otherwise ?


I guess it’s more the macro side of things. That it’s convenient/powerful if well understood I have no doubt :slight_smile:

I struggle when handling GUI inputs and outputs, for example to turn a parameter into an image in the stack: ({'"$1"'}). Then I find great difficulty trying to send that same input string back to the GUI parameter unaltered, if there are certain characters in the input (commas, backslash and so on). I’ll try to find more specific examples.

What I’d really like to understand is how a string is actually stored. For example if I assign mystring="$1", does the variable actually hold the quotes (which I wouldn’t expect)? Direct variable to variable assignments don’t seem to lose any backslashes, but in other cases they vanish.

Anyway, for now it’s a moan with no clear examples. I’m probably too used to other languages! I think what you wrote above will help anyway :slight_smile:

Edit: maybe I misunderstand completely - are they even “variables” at all, or just a macro definition?

Edit2: stranger the closer I look… if I compare a=1,2 to a="1,2" there’s no change to the normal output. But in debug mode, the assignment with quotes shows a=1\,2 whereas without shows a=1,2