G'MIC - GREYC's Magic for Image Computing: A Full-Featured Open-Source Framework for Image Processing
GREYC CNRS ENSICAEN UNICAEN

A Full-Featured Open-Source Framework for Image Processing



Latest stable version: 3.4.3        Current pre-release: 3.5.0 (2024/12/20)

Tutorial

local(l) … done


localartThe -local <local scope> -done commands form syntactical units that defines local scopes. These local scopes provide convenient cloistered environments for extended operations on image list subsets. Commands bracketed by -local … -done pairs constitute local pipelines; the images selected by the -local command's decorator constitute local image lists. Frequently, such local scopes constitute <repeating blocks> for -repeat-done pairs, forming image list iterators.

Without selection decorators, -local commands encompass entire image lists. With empty selection decorators, -local commands form empty local image lists. Local pipelines can add images to these. Consider the effects of images created in local scopes on global re-indexing. See Rules Preserving Locally Created Ajacencies and Image Creation and List Iteration.

-local[>$] … -done pairs may nest to an arbitrary depth and -local … -done pairings must balance. It is good practice to indent like -local … -done pairs the same amount, indenting one step more the commands they bracket, making visually clear what commands form the inner pipeline for a given -local … -done pair.

By adroit use of the selection decorator, one may pull together disjoint images into contiguous local image lists, reducing or eliminating the need to account for stride. Through -local[0--1:4] … -done, for example, one may pull every fourth image from an outer image list onto an inner list, where they form a contiguous sequence, and then operate on them without having to account for an "every fourth image" stride. The -local command also insulates images of the outer list from local pipeline operations, so whatever is done to every fourth image is done only to those images.

Example


gtov
A gradient from blue to gold
gtovbroken
Every 7th pixel color-rotated 163.625°; every 5th color-rotated -147.25°; every 3rd color-rotated 44.71325°, with sequence reversed.
-input (32,224^100,218^234,38)Two differently colored pixels — a two-step gradient. See -input Prescribed Values
-resize. 256,1,1,3,5
-expand_y. 32
Expand into a 256 step gradient
-split. xSplit pixels along the x axis into separate, one pixel wide images
-local[0--1:7]Select every seventh image for inclusion into a local list. See Command Decorations.
   -fill ">
         wv=vector3(1/sqrt(3));
         rot(wv,163.625°)*I"
Locally apply first color space rotation
-doneFinished with local list
-local[0--1:5]Select every fifth image for inclusion into a local list
   -fill ">
         wv=vector3(1/sqrt(3));
         rot(wv,-147.25°)*I"
Locally apply second color space rotation
-doneFinished with local list
-local[0--1:3]Select every third image for inclusion into a local list
   -fill ">
         wv=vector3(1/sqrt(3));
         rot(wv,44.71325°)*I"
   -reverse
Locally apply third color space rotation, then reverse items locally.
-doneFinished with local list
-append xMerge images back into one gradient image

The -local command, through its decorator, selects a set of images — the local image list — for extended operations, these taken from commands bracketed by the -local … -done pair and constituting a local pipeline. Only the commands constituting the local pipeline operate on items on the local image list, leaving undisturbed images outside this local scope. Insofar as the local pipeline goes, these "exterior" images effectively disappear.

When first constituted, the images on the local list are ordered relatively the same way as their placement on the global list, but numeric indices necessarily change; now being indexed with respect to the local list. Outer list indexing is put to one side. Command selection decorators on local pipelines necessarily are with respect to local indexing; an inadvertent confusion with global indexing is a common source of surprise.

Images in the local list may be altered, reordered and removed. New images can appear. While the command processor operates over the local pipeline, it reindexes images as necessary. When the command processor encounters -done, the local pipeline has completed its operations and the "masked" images from the global list reappear, undisturbed by any local pipeline operation. Necessarily, -done triggers re-indexing of the merged image list.

Rules Preserving Locally Created Ajacencies

Care has to be taken with selection decorators to accommodate changes in stride. See Image Creation and List Iteration. In merging local and global lists, G'MIC preserves locally created adjacencies, keeping relative ordering when merging local and global image lists. The rule pertains to images created on local image lists and are to be indexed for the first time globally.

In the following, n represents non-negative positions of images first selected by -local's decorator, with offsets from merges already applied. k represents the smallest index referenced in -local's decorator and is undefined if that decorator is empty.
1.  The new image has a predecessor; its global image list index is n. The new image assumes an index of n + 1 on the global list, preserving its local list adjacency.
2.  The new image has no predecessor; it is the first image on the local list.
    a. k is defined. The new image takes k as its global list index.
    b. k is undefined (local's decorator is empty). The new image's global index is the length of the global list plus 1. That is, the new image goes to the end of the global image list.
3.  The new image has a predecessor; it is also a new image. Step forward to that predecessor and reapply rules until either 1. or 2. obtains and which provide for an index. Assign it, then step back, incrementing and assigning this index to successors until the block is indexed. That is, adjacency within new image blocks is preserved.

List Iteration

The pattern:
…  -repeat $!
     -local[$>]
     …
     -done
  -done…
constructs a forward image list iterator, while writing -local[$<] constructs a reverse image list iterator. In both constructs, the innermost -local[>$] … -done pair applies the commands comprising the <local scope> to the current item of the iteration.

1.  The command line interpreter replaces instances of the substitution sequence $! with the number of images on the list, setting up the iterator to cycle as many times as there are images on the list.
2.  In kind, the interpreter replaces instances of index variables, $> for forward iteration, $< for reverse, with the current loop count (forward), or the number of images on the list less the current loop count (reverse).
3.  Consequently, on each loop, -local[$>], or -local[$<], the local image list consists of just one image — the one whose global index matches the index variable.
4.  The bulk of the implementation can then be designed to operate on just that one item; this design need not accommodate the existence of the outer list. The commands comprising that implementation constitute the local pipeline, created by the bracketing -local[>$] … -done pair.

Image list iterators are probably the most common pattern using the -local command. Many standard library commands employ this pattern. A designer can work out the details of acting upon just one image. Then, the corresponding multiple-image implementation follows directly by placing the single item implementation within the -local[>$] … -done pair of an image iterator.


Image Creation and List Iteration

G'MIC supports image creation within -local … -done environments. However, when a -local … -done scope is also the <repeat block> in a -repeat … -done pair, then accounting for stride changes is important.

Consider this -makeyellowmasks custom command:
# Make one mask for each selected image, which picks this yellow: [250,200,100]
makeyellowmasks :
   -repeat $!
      -local[$>]
         +select_color[-1] 20%,250,200,100
      -done
   -done
The aim of -makeyellowmasks is to compute, via select_color, one yellow-selective mask for each image on the list, preserving the original and placing the mask after it. Following the command, the user expects one mask for each original image to follow the original on the image list. Thus the pipeline:

 $ gmic                                  \
   -command makeyellowmasks.gmic         \
   -sample parrots,pencils,peppers,0,200 \
   -makeyellowmasks

is expected to complete and leave six images on the lists (0 — 5), the originals even-numbered (0,2,4) and the masks odd-numbered (1,3,5).

As written, -makeyellowmasks produces this image list:
 baditer
 Beware undiagnosed re-indexing
Three masks for parrot follow that image and no masks were computed for pencils and peppers. How is this so?

First pass through the loop exhibits expected behavior. -repeat is set to iterate three times with loop counts 0, 1, and 2. On the first iteration, -loop's selector decoration contains [0]. That selects the parrot image as the sole item on the local image list. -select_color duplicates (+) and computes the mask for that image, which becomes the second item on the local list ([1]). -done prompts the merging of image lists.

That is where actualities depart expectations. On the second pass through the loop, -local's selector decoration contains [1], the second value that index variable $> generates. Once upon a time, that index did select pencils, but since the completion of the first iteration and its concomitant release of <local scope>, the mask for parrots now occupies the second slot in the image list — [1], displacing pencils to the third ([2]). Thus, on the second pass, the newly-created mask for parrots enters into the local scope, not pencils as intended. The same maladay happens on the third and final loop.

There are two corrective approaches:
1.   Iterate forward, accounting for the doubled stride: -local[{2*$>}]
2.   Iterate backward, -local[$<]

In the latter approach, list items are first selected, duplicated and the mask is made. They aren't displaced until their lower-numbered predecessors become selected. But by then processing is done on the successor and its displacement in the global list doesn't matter. The latter approach is the preferred style when local pipelines multiplex local lists, as there is less concern in accommodating changes to stride.

 gooditer
 Iterate backwards with -local[$<] or double your stride with -local[{2*$>}]

Using the -onfail command

Inserting -onfail within the block formed by -local … -done pair creates an exception handler. The -onfail command splits the local block into normal and exception processing blocks.

Exception processing has these features:

1.   Commands between -local and -onfail always execute and constitute the normal processing block.
2.   Failures occuring in the normal processing block are caught by the -onfail command.
      a.The exception block, consisting of the commands between -onfail and -done, executes.
      b.G'MIC prints an error message, but does not exit. Instead, it resumes with commands following -done.
3.   The status substitution sequence, ${}, resolves to the error message that G'MIC prints to the error stream.

One is not obligated to write commands for the exception handler. -onfail itself catches the exception, and if the exception processing block is empty, G'MIC continues processing after the -local … -done block.

-onfail Example

-local[]
    -input nosuchimage.png
    -echo[] "Have 'No Such Image'."
    -onfail
       -echo[] ${}
-done
-echo[] "The script is executing here!"
If there is no such image as nosuchimage.png, the G'MIC interpreter throws an exception, which, in the absence of a -onfail command, terminates the script. In this example, -onfail catches the the exception. Observe that when the exception is thrown, the first -echo command, and any commands following, will not execute. For all practical purposes, the exception causes the interpreter to skip ahead to the first command following -onfail, here the second -echo command, which executes. This second -echo command illustrates a simple, but redundant, use of the status substitution sequence, which the interpreter replaces with the error message associated with the exception. It's illustrative, but redundant, as the G'MIC interpreter echoes the error message in any case. We trust the reader can conceive of more interesting behavior.

When exception processing is complete, the G'MIC interpreter exits the local scope and executes the third -echo command. This -echo command executes almost in any case, unless a second, uncaught, exception occurs in the exception processor itself.

Though it is probably clear to the reader, it is worth noting that a second exception occuring in the exception processor will not be caught unless the programmer writes another -local … -onfail … -done block, nested within the exception processor itself. Such an elaboration is permissible, and, in principle, there no limits to how elaborate an exception processor may be. Practice, custom and programmer sanity usually dictate simple exception processors, however, the kind including no commands whatsoever being quite common.

It is also probably clear to the reader that the scope of a particular exception processor is limited to the immediate enclosing -local … -onfail … -done block. Errors in an enclosing block are uncaught unless the enclosing block itself is a -local … -onfail … -done block.

Command Reference

$ gmic -h local

local (+):

Start a 'local...[onfail]...done' block, with selected images.
(equivalent to shortcut command 'l').

Example:
[#1] image.jpg local[] 300,300,1,3 rand[0] 0,255 blur 4 sharpen 1000 done
[#2] image.jpg +local repeat 3 { deform 20 } done

Tutorial: https://gmic.eu/oldtutorial/_local
Updated: 06-March-2022 13:21 UTC Commit: af5405e3a2cb
G'MIC - GREYC's Magic for Image Computing: A Full-Featured Open-Source Framework for Image Processing

G'MIC is an open-source software distributed under the CeCILL free software licenses (LGPL-like and/or
GPL-compatible). Copyrights (C) Since July 2008, David Tschumperlé - GREYC UMR CNRS 6072, Image Team.