G'MIC Tutorial Fragments

I agree.

1 Like

@David_Tschumperle OK I see that the gmic.eu 's .gmd files are located here.
What is the command to see an offline preview of any .gmd file as html?
Found gmd2html
Would the calling method be gmd2html myfile.gmd. The reference page does not mention a .gmd file, and I have not found an example command usage yet.
@grosgood I guess you know how it works as well

1 Like

(just to make a general gmic.eu gmic-py-related help page to point towards the gmic-py readthedocs website)

Everything is explained here: G'MIC - GREYC's Magic for Image Computing: A Full-Featured Open-Source Framework for Image Processing - G'MIC Markdown
(see last section to convert .gmd to .html).

1 Like

OK thank you!

gmic it input.gmd gmd2html ot output.html

1 Like

Necessary Topic: Indexing - Using a math expression pixel iterator to drive changes to other (arbitrary) images. Works even when an image is being newly created, as in ...x,y,z,c,<fill math expression> where <fill math expression> references other images on the list via #<index> notation. However, as @Reptorian observes in looking for a gmic python scripter to help me out here, the image-in-the-process-of-being-created is not indexed yet, so relative indexing from the end of the list is still with respect to the last, fully extant, image on the list.

Tutorial material on the math expression parser is still very scant and I don’t think the topic of indexing other images in math expressions has been dealt with outside Mathematical Expressions. See Specific functions, in particular i(), j() i[], j[] I[], J[] and the next-to-the-last paragraph in the -fill tutorial, where the notation is covered, but not the delicate question of what peg does relative indexing count from when the math expression is operating on an image in the process of being created.

Shouldn’t also leave out the technique which prompted this entry: newly creating an image just for the purpose of being an “iteration controller” in math expressions primarily designed to alter other images on the list. See rep_pfrac in include/reptorian.gmic around line 922.

Addendum -fill & -input: The tutorial doesn’t cover an aspect of -store and the math expression function store() which can stuff selected images into a command line variable, removing the selected images from the image list. That command line variable can be a pixel source for -fill and -input.

In light of that, a tutorial on -store and the math expression function store() are in order sooner rather than later, because the two variants, in conjunction with -fill and -input can set up the passing of wholesale data quantities between the two environments. Tutorials are still written along the line that the two environments are rather closed-off, in the matter of data sharing. That limitation no longer is true.

OK… details!
Note that in gmic-py, G’MIC image list objects (ie. list()) are emptied then refilled on each Python run, but the list reference stays the same.

1 Like

Haven’t forgotten you! cloned your repository locally and am sitting on the cookbook → origin/cookbook branch, with about 2.1K words in cookbook.rst. If I push my commits to origin/cookbook, I won’t trigger any publish event will I?

1 Like

Super good news!!! Thanks Garry!!
I think I have omitted a few commands in my Github issue explanations on local building. Nonetheless, “lazy is clever” and pushing just to the origin branch will really trigger a publish but in the documentation website’s ‘cookbook’-branch version, which is a proper sandboxing place for now. So here: https://gmic-py.readthedocs.io/en/cookbook/cookbook.html (you can change the branch by clicking some popping-up list at the bottom left on v:cookbook).

@grosgood: What do you think of bringing up morphological math evaluator coding? Kinda hard to explain, but it is a technique where one inserts a string into variable, and then when one use it in a math evaluator code, the math evaluator reads the string as a code and then run it. When a variable don’t exist, it is just empty. So, in other words, gmic can run dynamic codes. I think this is what set the scripting language apart from most other, the huge flexibility in dynamic coding.

‘rep_tfrac’ has a basic form of this. ‘rep_pfrac’ as well. Chirikov-Taylor filter of mine utilize a bit more convolutated form of this. I’m working on a new strange attractor filter that makes heavy use of morphological math evaluator coding.

1 Like

You’re probably familiar with L-Systems from Aristid Lindenmayer, part of that whole visual cloud centering on The Algorithmic Beauty of Plants that was such a Siggraph darling ages ago (1990 or so). The fun idea behind all that is a coded string that is both morphed by a process, (stage n) and then goes on to drive the next generation of that process (n+1), which further morphs the coded string, and so on, maybe forever. Somewhere in the loop is a “camera” that snaps a picture of the stage; all of the snapshots become an animation.

So, I’m thinking, as an Example for a -store tutorial, a morphing string that gets tossed back and forth between the command line and math evaluator environments, with state residing both in the coded string and the images, and state is conveyed back and forth through variables, their contents exchanged between the two environments via -store and store() So - yes - I think in this regard we’re both noodling along in similar directions. The coded string is dynamically composed. It both drives - and is re-coded by - the process.

I’m not married to L-systems specifically; that’s just where the germ of the idea came from. Mainly, I want to illustrate (1) exchanging state between math evaluator and command line environment, and (2) do more G’MIC animations, a step beyond Caudron, which I think is of interest to people who want to animate textures for Blender models, a la Daniel Bystedt.

Big chunks of Real Life work to do, though. However, looks like some G’MIC time will open up for this weekend. Maybe we can play a bit in this area.

1 Like

Speaking of which… Just a big “Thanks!” to @grosgood for the latest tutorial updates. It looks great and I know that represents a lot of work, that should not keep hidden :slight_smile:

1 Like

New and renewed in tutorials, from when @afre poked a stick in my cave and bought me out of hibernation (15-August-2017 - 06-March-2021). He should count the number of arms that he has; I might have bitten one off:

  1. -store New, 19-April-2021
  2. -name Refurbished, 18-April-2021. Didn’t include ghost cat as an example, but continued my obsession with the Goudy 1911 ampersand instead.
  3. -mix_rgb Refurbished 16-April-2021
  4. Beginner’s Cookbook Refurbished Cookbook, in collaboration with @David_Tschumperle; 1.6x anachronisms. 06-April-2021
  5. Cauldron Refurbished Cookbook, in collaboration with @David_Tschumperle; finished the example 04-April-2021
  6. -luminance Refurbished 04-April-2021 Now featuring overly loud people!
  7. Tutorial Directory New 02-April-2021
  8. Command Decorations Refurbished Basics, in collaboration with @David_Tschumperle; 01-April-2021. Aligned with 2.9x notation. Finally. Maybe.
  9. Basics Refurbished Basics, in collaboration with @David_Tschumperle; Removed some 1.6x anachronisms. 01-April-2021.
  10. -compose_channels Refurbished 23-March-2021
  11. -eigen2tensor Refurbished 23-March-2021
  12. Fingerpainting Upgraded to 2.9x notation 21-March-2021
  13. -roundify New, 18-March-2021
  14. -norm Refurbished 17-March-2021
  15. -orientation Refurbished 17-March-2021
  16. -fill Refurbished 14-March-2021
  17. -map Refurbished 14-March-2021
  18. -threshold Refurbished 13-March-2021
  19. Contribute New 12-March-2021 Just contribute, darn it.

Credit where credit is due. @David_Tschumperle was also scurrying around during this time bringing other tutorial pages into line. Do Your Own Diffusion Tensor Fields was dusted off almost entirely by him, and he conjured 3D Bouncing Balls from whole cloth. Probably most significant, however, was grounding the entire tutorial writing enterprise on G’MIC Markdown and housing content in the gmic-community GitHub repository. The previous approach was considerably more haphazard…

On tap: My side of the collaboration with @Reptorian on Quantum Wells has the makings of a Cookbook; more notes on that to go to that thread. Busy week just past, and a busy weekend, but maybe some G’MIC time is in store. Have fun…

4 Likes

Math Expression Parser Department: const foo=3;, constant scalar and the relationship of these constant positive integer variable data types to ‘Just In Time’ compilation need elucidation, particularly for pythonistas. For example, this will not obtain a dynamically sized vector in the Math Expression Parser environment:

$ gmic -input '(0,1024)' -store. 'param' -eval "ref(get('param',2),myp);ref(resize([0],myp[1]),dynamicallysized)"
[gmic]-0./ Start G'MIC interpreter.
[gmic]-0./ Input image at position 0, with values (0,1024) (1 image 2x1x1x1).
[gmic]-1./ Store image [0] as  variable 'param'
[gmic]-0./ Evaluate expression 'ref(get('param',2),myp);ref(resize([0],myp[1]),dynamicallysized)' and assign it to status.
[gmic]-0./ *** Error *** Command 'eval': Function 'resize()': Second argument (of type 'scalar') is not a strictly positive integer constant, in expression '...ref(resize([0],myp[1]),dynamicallysized)...'.

The contents of vector myp, cannot be constant, as, in general, the Math Expression Parser has no hint as to the content of storage variables like param ( See tutorial -store ) at the moment that a JIT compiler digests the math expression. Consequently the the notion of a dynamically sized zero vector, dynamicallysized, based upon circumstances-of-the-moment such as the contents of myp[1], is not well supported. A constant scalar or a strictly positive constant integer is a type to which a JIT-compiler can assign a specific numeric value at the point of compilation. In particular, striving for some dynamically sized vector based upon a quantity not knowable until the expression runs is a bit wistful. Some math parser functions are not alarmed by dynamically set values at runtime, ( rot(u,v,w,angle) ) but those involving run-time sizing seem generally adverse to parameters other than constant scalar.

1 Like

The solution for stimulating dynamic vector size is to do it outside of eval, fill, input block, and then assign it within the eval, fill, input block. Another solution is to use dar_insert(). I think I remember having to do that, but don’t remember which script I had to do that for. Possibly a test.

1 Like

Thank you for pointing such out. This:

G’MIC math evaluator now deals with vectors (and matrices, and custom functions!)

With a specific mention in Post 20.

Goes the route of ‘image-assisted’ dynamic storage, no? That’s the alternative for the poor moth fluttering toward the shining light of “dynamically sized, determined at run-time” storage, allocated and released wholly in the MEP.

So. tutorial: Runtime allocated and free-ed storage. That doesn’t happen entirely in the context of MEP. Instead, steal an image for something like dynamic storage. dar_***() and heap_***(), which reference (pre-existing) images for backing store. There are also crop(...) and copy(...) for image ↔MEP data exchange. But one also needs to be mindful that this “dynamic space” is coming from fixed, pre-existing images and be mindful of overrunning (per dar_insert() macro advisory):

# Inserts new element 'elt' into dynamic array #ind, at index [pos] ('pos' must be in [0,dar_size(#ind)]).
  dar_insert(ind,elt,pos) = (...)

So. Also. tutorial: eval ${-math_lib} notation which pulls these dar_*** macros in.

And. tutorial: const declarations (which doesn’t automagically convert run time numbers into compile time integers) constant scalar and the MEP functions which require those kind of parameters.

More than enough fragments to roll up into tutorials some day…

Thanks for pointing that out.

Tee, hee. Except I can overrun. :astonished:
memstuff.gmic:

foo:
   1
   -name. onegraypixel
   -print.
   -eval ${-math_lib}" for(j=0,j<10,++j,dar_insert(#0,10*j););for(k=0,k<dar_size(#0),++k,print(I[#0,k]););"
   -display.

From shell:

gosgood@bertha ~ $ gmic -command memstuff.gmic -foo
[gmic]-0./ Start G'MIC interpreter.
[gmic]-0./ Import commands from file 'memstuff.gmic' (1 new, total: 4352).
[gmic]-1./foo/ Print image [0] = 'onegraypixel'.
[0] = 'onegraypixel':
  size = (1,1,1,1) [4 b of floats].
  data = (0).
  min = 0, max = 0, mean = 0, std = 0, coords_min = (0,0,0,0), coords_max = (0,0,0,0).

[gmic_math_parser] I[#0,k] = [ 0 ] (size: 1)
[gmic_math_parser] I[#0,k] = [ 10 ] (size: 1)
[gmic_math_parser] I[#0,k] = [ 20 ] (size: 1)
[gmic_math_parser] I[#0,k] = [ 30 ] (size: 1)
[gmic_math_parser] I[#0,k] = [ 40 ] (size: 1)
[gmic_math_parser] I[#0,k] = [ 50 ] (size: 1)
[gmic_math_parser] I[#0,k] = [ 60 ] (size: 1)
[gmic_math_parser] I[#0,k] = [ 70 ] (size: 1)
[gmic_math_parser] I[#0,k] = [ 80 ] (size: 1)
[gmic_math_parser] I[#0,k] = [ 90 ] (size: 1)
[gmic]-1./foo/ Print image [0] = 'onegraypixel'.
[0] = 'onegraypixel':
  size = (1,16,1,1) [64 b of floats].
  data = (0;10;20;30;40;50;60;70;80;90;0;0;0;0;0;10).
  min = 0, max = 90, mean = 28.75, std = 32.0156, coords_min = (0,0,0,0), coords_max = (0,9,0,0).
[gmic]-1./foo/ Display image [0] = 'onegraypixel', from point (0,8,0).
[0] = 'onegraypixel':
  size = (1,16,1,1) [64 b of floats].
  data = (0;10;20;30;40;50;60;70;80;90;0;0;0;0;0;10).
  min = 0, max = 90, mean = 28.75, std = 32.0156, coords_min = (0,0,0,0), coords_max = (0,9,0,0).
[gmic]-1./ End G'MIC interpreter.

onegraypixel
So.
But one also needs to be mindful that this “dynamic space” is coming from fixed, pre-existing images and be mindful of overrunning
Tee. Hee.

Maybe some additional notes about static and dynamic vectors in the MEP :

  • Vector variables, just as scalar variables are indeed allocated during the compilation time, not during the evaluation time. This means that MEP variables always have a const size (equivalent to double array[N] in C, where N is a constant integer). Storing vector variables like this prevents the MEP to deal with memory allocation/deallocation during expression evaluation, which is often not desired (at least for efficiency reasons). Indeed, most of the time, math expressions won’t require the use of ‘dynamic’ vector objects.

  • But, when you really have to deal with a dynamic-size vector, you have two solutions :

    1. Allocate a ‘big’ vector (like vector65536()) and store its ‘real’ size in a variable, then manage its values and size. Valid only if you have a reasonable bound for the vector size.

    2. Or, use the dar_* functions from math_lib (dar means dynamic array). This is based on the storage of array values inside an image, whose size is dynamically expanded if needed (done with function resize()). The trick here is that the implementation of functions dar_*() use the functions h(#ind) which returns the current size of the image #ind (while the constant value h#ind returns the initial size of the image #ind when enterin the MEP).
      Most of the time, in a math expression, the height h(#ind) is indeed a value that stays constant, so it’s more efficient (and short) to use h#ind rather than h(#ind), but with dar_*() of course, it’s not always the case.

1 Like

Following -eval, I gather that onegraypixel's dynamic allocation growth is (at least) to the nearest even float32 increment, and that the 0x0a value at position 1,15 in the image list representation is a ‘behind-the-curtains’ marker that (on the MEP side) indicates a vector10[…]. I also just gathered that dar_insert(…) has two argument signatures: dar_insert(ind,elt,pos) and dar_insert(ind,elt) and I was using the latter in -foo ( gmic_stdlib.gmic ):

25730:   # Inserts new element 'elt' at the end of dynamic array #ind.
25731:  dar_insert(ind,elt) = (
25732:    _dar_siz = dar_size(#ind);
25733:    _dar_siz>=h(#ind) - 1?resize(#ind,1,_dar_siz*2 + 2,1,s(#ind),0);
25734:    unref(_dar_elt); _dar_elt = elt;
25735:    copy(i[#ind,_dar_siz],_dar_elt,max(1,size(_dar_elt)),h(#ind),1);
25736:    (dar_size(ind#)) = ++_dar_siz;
25737:  );

I gather that the resize(…) call on 25733: dictates the ‘grow-by-row’ character of the change in image size of onegraypixel.

It was with this other flavor of resize(A, size, _interpolation, _boundary_conditions) that I became aware that parameters like size must be, at compile time, traceable back to a constant positive integer, else the JIT compiler is left at sea, and that started my ruminations on this Tutorial fragment (Fragmentary? indeed it is. Gentle Reader: “Tutorial Fragments” are just that, posted here so that people like @Reptorian, @David_Tschumperle and others can drop thought bombs on them. And so that I can figure out, eventually, what it is I’m supposed to write. Don’t come here expecting coherency…)