Cheat #6: Substitutions
Fetchpels | Substitution — aliasing condensed expressions to stand in for longer constructs — is indispensible to G'MIC pipeline processing.
TL;DR:
G'MIC's pipeline interpreter commonly employs two kinds of substitutions:
1. Pipeline variables: assignments of values to keys, key=value; downstream, a dereference operator $ retrieves the value when applied to the key.
2. Substituting Expressions: bracketed with curly braces, {}, G'MIC executes the sub expression and replaces it with the outcome. |
Example: You want to define a value in one place and use it in many places, easing updates should the value change. For that, create a
pipeline variable.
namethings:
morethanthree=3.71234176
-echo "More than three: "$morethanthree
$ gmic namethings.gmic -namethings
[gmic]-0./ Start G'MIC interpreter.
[gmic]-0./ Input custom command file 'namethings.gmic' (1 new, total: 4552).
More than three: 3.71234176
[gmic]-0./ End G'MIC interpreter.
1. | Write a key (morethanthree); assign a value (3.71234176). This defines a pipeline variable, or variable for short. |
2. | Elsewhere in the same scope (see Scope), a $ dereference operator followed by a key induces its substitution by the value. $morethanthree ⇒ 3.71234176 |
3. | A value has never been assigned to a key? Dereferencing produces an empty string. |
4. | Keys beginning with single or double underscores: _visibleeverywhere=3 may be referenced in all scopes. Single underscores means that visibility does not extend beyond the current thread of execution. Double underscore keys are visible in all scopes and across all threads of execution. |
5. | G'MIC's pipeline interpreter hosts a number of predefined local and global pipeline variables. See Substitution Rules. |
6. | Custom-defined commands also introduce predefine $-expressions pipeline variables for retrieving arguments given to the custom commands. |
Example: You want to fetch or derive values from image properties or environmental features. For that, use a
Substitution Expression.
mkramp:
steps={expr('x/15',16)}
-echo "Ramp: "$steps
$ gmic mkramp.gmic -mkramp
[gmic]-0./ Start G'MIC interpreter.
[gmic]-0./ Input custom command file 'mkramp.gmic' (1 new, total: 4552).
Ramp: 0,0.066666670143604279,0.13333334028720856,0.20000000298023224,0.26666668057441711,0.3333333432674408,0.40000000596046448,0.46666666865348816,0.53333336114883423,0.60000002384185791,0.66666668653488159,0.73333334922790527,0.80000001192092896,0.86666667461395264,0.93333333730697632,1
[gmic]-0./ End G'MIC interpreter.
1. | Define a key, steps, with the outcome of a substitution expression. G'MIC defines a number of sub expressions, each written as strings within curly braces:{ <string> }; the pipeline interpreter examines the contents between the curly braces, determines its type, evaluates the sub expression and replaces it with the outcome. |
2. | A Mathematical Expression is probably the most frequently occuring sub expression type; see mkramp. A mathematical expression computes a list of values for $steps. It is one of a number of image feature sub expressions. Others provide string conversions, access to image properties or fetch properties about the environment. |
Example: You want to dump image data into a variable.
fetchpels:
-input 8,8,1,3,u(255)
pixels={0,^}
-echo "Image pixels: "$pixels
$ gmic fetchpels.gmic -fetchpels
[gmic]-0./ Start G'MIC interpreter.
[gmic]-0./ Input custom command file 'fetchpels.gmic' (1 new, total: 4552).
Image pixels: 65.3987808,184.827057,180.305084,22.791893,193.793228,249.993576,…,64.4772949,208.904846,122.990273
[gmic]-1./ Display image [0] = '[u(255)]'.
[0] = '[u(255)]':
size = (8,8,1,3) [768 b of float32].
data = (65.3988,184.827,180.305,22.7919,193.793,249.994,186.936,111.367;195.481,68.0421,168.053,34.2839,(...),16.8831,176.693,47.1033,100.211;154.623,106.028,234.712,96.7332,226.984,64.4773,208.905,122.99).
min = 7.90898, max = 253.586, mean = 133.529, std = 69.8871, coords_min = (0,4,0,0), coords_max = (6,5,0,2).
[gmic]-1./ End G'MIC interpreter.
1. | {0,^} is one of G'MIC's image feature sub expressions; these take two arguments. The first, numeric, selects an image by its list index; it is optional and when absent defaults to the last image on the list: ([-1]). Image feature sub expressions almost always associate with some image unless the image list is empty. The second, a single character, requests a specific image feature. Here ^ solicits the contents of the selected image. See Substitution Rules for others. G'MIC replaces {0,^} with a vector of pels in row major order, first by x, then by y, then by channels c, and finally by image slices or frames, z. This organization follows from that of G'MIC Images. |
2. | The single character second argument may also be omitted. When absent, the image sub expression defaults to a mathematical expression. |
3. | Mathematical expressions may appear in habitats other than image feature sub expressions. They may appear outside of curly braces {} in: |
a. | pixel or pel processors. These iterate over images ( pixel ) or image planes ( pel ) to programmatically define image content; they are given as arguments to fill, input or eval and operate on every pixel or pel composing an image. In fetchpels, the mathematical expression u(255) appears as an argument to the input command and is a pel processor. For every pel, the u() function returns a random integer in the range 0 – 255, which sets the value of the current pel. See the fill command tutorial. |
b. | logic expressions. Mathematical expressions may assess image properties or elements of the processing environment and evaluate to True or False. Such expressions are given to many of the flow control commands to direct script logic. |
Example: What does the green channel look like when resized by cubic interpolation?
vrange:
-input (255,0,0^0,255,0^0,0,255)
-permute cyzx
-resize 16,1,1,3,5
startgreen={w}
endgreen={2*w-1}
grnch={0,@$startgreen-$endgreen}
-echo "Green Channel: "$grnch
$ gmic vrange.gmic -verbose + -vrange -verbose -
[gmic]-0./ Start G'MIC interpreter.
[gmic]-0./ Input custom command file 'vrange.gmic' (1 new, total: 4552).
[gmic]-0./ Increment verbosity level (set to 2).
[gmic]-0./vrange/ Input image at position 0, with values (255,0,0^0,255,0^0,0,255) (1 image 3x1x1x3).
[gmic]-1./vrange/ Permute axes of image [0], with permutation 'cyzx'.
[gmic]-1./vrange/ Resize image [0] to 16x1x1x3, with cubic interpolation, dirichlet boundary conditions and alignment (0,0,0,0).
[gmic]-1./vrange/ Set local variable 'startgreen=16'.
[gmic]-1./vrange/ Set local variable 'endgreen=31'.
[gmic]-1./vrange/ Set local variable 'grnch=0,25.159999847412109,63.013332366943359,108.12000274658203,155.03999(...).
Green Channel: 0,25.159999847412109,63.013332366943359,108.12000274658203,155.03999328613281,198.33332824707031,232.55999755859375,252.27999877929688,252.27999877929688,232.55999755859375,198.33332824707031,155.03999328613281,108.12000274658203,63.013332366943359,25.159999847412109,0
[gmic]-1./ Decrement verbosity level (set to 1).
[gmic]-1./ Display image [0] = '(255,0,0^0,255,0^0,0,255)'.
[0] = '(255,0,0^0,255,0^0,0,255)':
size = (16,1,1,3) [192 b of float32].
data = (255,231.804,198.636,159.12,116.884,75.5556,38.76,10.1244,-7.40444,-16.32,-18.8889,-16.9244,(...),-16.9244,-18.8889,-16.32,-7.40444,10.1244,38.76,75.5556,116.884,159.12,198.636,231.804,255).
min = -18.8889, max = 255, mean = 85, std = 98.859, coords_min = (10,0,0,0), coords_max = (0,0,0,0).
1. | {0,@$startgreen-$endgreen} is another image feature sub expression: it selectively extracts a subset of the image pel vector; see previous example. Extract a single pel with one number following @, the pel's index counting from zero. Use a hyphen, as in the example, to extract a contiguous closed-set range of pels. Use a comma-separated list of pel indices to extract an arbitrary set of pels. |
2. | This example uses a range of substitution technique: keys representing the start and end of the range are set with sub expressions, these mathematical expressions; the subset image feature sub expression sets a third pipeline variable with green channel pels. Observe that de-referencing operators are at work "inside" the sub expression. The pipeline interpreter performs $ dereferencing early on, then it expands sub expressions. It is common to place pipeline variables with dereference operators inside mathematical expressions. The pipeline interpreter performs all $ dereferencing first before invoking the mathematical expression parser. The mathematical expression parser does not see the dereference operators, just the results of their operation: numerical constants. |
Scope
At any instant, the
current scope of the
G'MIC pipeline interpreter is the sequence of commands, arguments and other items undergoing processing. Unless defined with leading underscores, key-value pairs defined in other scopes are invisible to the interpreter the current scope. Keys beginning with single underscores are visible in all scopes in the current thread of execution. Keys beginning with double underscores are visible in all scopes
and in all threads of execution. When the
G'MIC pipeline interpeter encounters a
custom command, one defined by a
G'MIC pipeline, it enters a new scope and variables lacking global visibility disappear; they reappear when the interpreter completes the pipeline embodied in the custom command, returning to the so-called
parent scope. See
Debug Cheats for further remarks on scope.
Example: You want a pipeline variable to be visible in every scope.
globalvisibility:
_onehalfe={exp(1)/2}
-newscope
newscope:
-echo "One half of e is: "$_onehalfe
$ gmic globalvisibility.gmic -verbose + -globalvisibility
[gmic]-0./ Start G'MIC interpreter.
[gmic]-0./ Input custom command file 'globalvisibility.gmic' (2 new, total: 5204).
[gmic]-0./ Increment verbosity level (set to 2).
[gmic]-0./globalvisibility/ Set global variable '_onehalfe=1.3591409142295225'.
[gmic]-0./globalvisibility/newscope/ One half of e is: 1.3591409142295225
[gmic]-0./ End G'MIC interpreter.
Locally scoped variables are the safest and least problematic kind in that they disappear when they fall out of scope. Locally scoped variables, usually few in number, serve the script-writer's immediate and transitory needs. One need not focus on anything else. On leaving a scope,
G'MIC deletes the locals, a kind of garbage collection. Globally scoped variables may seem better — one is relieved of visibility concerns — but globally visible variables place on the script-writer the burden of orderly initialization. This may not be an onerous burden in small scripts but an orderly initialization of everywhere-visible (and accessible) variables are prone to error in more labyrinthine scripts.
March 12 2023 10:35 UTC commit 985154b82a55acf98f042ca485cb5af902e73b7f