# G'MIC exercises

(G'MIC staff) #22

@afre : To me the correct terminology for kernels is something like:

• Kernels defined on finite domain :
• `size` : Size of the kernel, for instance `size=7` means a `7x7` kernel.
• `radius` : Radius of the kernel, which means an equivalent `size = 2 * radius + 1`. You can’t have even-sized kernel when specifying a radius.
• Kernel defined on infinite domain (usually gaussian) :
• `std_deviation` : standard deviation (sigma) used in the gaussian function. Almost 100% of the significant values of the gaussian function are located in range `|x|<3.5 * radius` (see https://en.wikipedia.org/wiki/68–95–99.7_rule), so you can get an idea of what the equivalent `radius` could be, if the kernel had a finite domain.

It may happen that this terminology is not the one used in some commands (I’ve not checked all of them ), but this is probably how it should be done.

Well, yes, as the number of shortcut is quite limited, we can always construct this list manually

``````  +3d (+): Shortcut for command 'add3d'
/3d (+): Shortcut for command 'div3d'
*3d (+): Shortcut for command 'mul3d'
-3d (+): Shortcut for command 'sub3d'
ac : Shortcut for command 'apply_channels'
apc : Shortcut for command 'apply_parallel_channels'
apo : Shortcut for command 'apply_parallel_overlap'
ap : Shortcut for command 'apply_parallel'
a (+): Shortcut for command 'append'
b (+): Shortcut for command 'blur'
c3d : Shortcut for command 'center3d'
col3d (+): Shortcut for command 'color3d'
c (+): Shortcut for command 'cut'
d0 : Shortcut for command 'display0'
d3d (+): Shortcut for command 'display3d'
da : Shortcut for command 'display_array'
db3d (+): Shortcut for command 'double3d'
dfft : Shortcut for command 'display_fft'
dg : Shortcut for command 'display_graph'
dh : Shortcut for command 'display_histogram'
dp0 : Shortcut for command 'display_parallel0'
dp : Shortcut for command 'display_parallel'
dq : Shortcut for command 'display_quiver'
drgba : Shortcut for command 'display_rgba'
d (+): Shortcut for command 'display'
dt : Shortcut for command 'display_tensors'
dw : Shortcut for command 'display_warp'
endl (+): Shortcut for command 'endlocal'
e (+): Shortcut for command 'echo'
f3d (+): Shortcut for command 'focale3d'
fc : Shortcut for command 'fill_color'
fi (+): Shortcut for command 'endif'
frame : Shortcut for command 'frame_xy'
f (+): Shortcut for command 'fill'
g (+): Shortcut for command 'gradient'
h : Shortcut for command 'help'
ig : Shortcut for command 'input_glob'
ir : Shortcut for command 'inrange'
i (+): Shortcut for command 'input'
j3d (+): Shortcut for command 'object3d'
j (+): Shortcut for command 'image'
k (+): Shortcut for command 'keep'
l3d (+): Shortcut for command 'light3d'
l (+): Shortcut for command 'local'
m3d (+): Shortcut for command 'mode3d'
md3d (+): Shortcut for command 'moded3d'
m (+): Shortcut for command 'command'
m/ (+): Shortcut for command 'mdiv'
m* (+): Shortcut for command 'mmul'
mv (+): Shortcut for command 'move'
n3d : Shortcut for command 'normalize3d'
nm (+): Shortcut for command 'name'
n (+): Shortcut for command 'normalize'
o3d (+): Shortcut for command 'opacity3d'
on : Shortcut for command 'outputn'
op : Shortcut for command 'outputp'
o (+): Shortcut for command 'output'
ow : Shortcut for command 'outputw'
ox : Shortcut for command 'outputx'
p3d (+): Shortcut for command 'primitives3d'
p (+): Shortcut for command 'print'
q (+): Shortcut for command 'quit'
r2dx : Shortcut for command 'resize2dx'
r2dy : Shortcut for command 'resize2dy'
r3d (+): Shortcut for command 'rotate3d'
r3dx : Shortcut for command 'resize3dx'
r3dy : Shortcut for command 'resize3dy'
r3dz : Shortcut for command 'resize3dz'
rm (+): Shortcut for command 'remove'
rr2d : Shortcut for command 'resize_ratio2d'
r (+): Shortcut for command 'resize'
rv3d (+): Shortcut for command 'reverse3d'
rv (+): Shortcut for command 'reverse'
s3d (+): Shortcut for command 'split3d'
+ (+): Shortcut for command 'add'
& (+): Shortcut for command 'and'
<< (+): Shortcut for command 'bsl'
>> (+): Shortcut for command 'bsr'
/ (+): Shortcut for command 'div'
== (+): Shortcut for command 'eq'
>= (+): Shortcut for command 'ge'
> (+): Shortcut for command 'gt'
<= (+): Shortcut for command 'le'
< (+): Shortcut for command 'lt'
% (+): Shortcut for command 'mod'
* (+): Shortcut for command 'mul'
!= (+): Shortcut for command 'neq'
| (+): Shortcut for command 'or'
^ (+): Shortcut for command 'pow'
= (+): Shortcut for command 'set'
- (+): Shortcut for command 'sub'
sh (+): Shortcut for command 'shared'
sl3d (+): Shortcut for command 'specl3d'
sp : Shortcut for command 'sample'
ss3d (+): Shortcut for command 'specs3d'
s (+): Shortcut for command 'split'
t3d (+): Shortcut for command 'texturize3d'
to : Shortcut for command 'text_outline'
t (+): Shortcut for command 'text'
up : Shortcut for command 'update'
u (+): Shortcut for command 'status'
v (+): Shortcut for command 'verbose'
w (+): Shortcut for command 'window'
x (+): Shortcut for command 'exec'
y (+): Shortcut for command 'unroll'
z (+): Shortcut for command 'crop'
``````

(Alan Gibson) #23

That’s very helpful, thanks. Can I ask that you make the list a part of your standard documentation? Perhaps as a file that you maintain, so other folk can download as and when needed?

(G'MIC staff) #24

It’s already a part of the official doc : http://gmic.eu/reference.shtml#subsection22

(Alan Gibson) #25

That’s great, thanks.

#26

Thanks for connecting the dots. Typo?

``|x|<3.5 * radius``
If we are talking about percentages, would `radius = 3.5 * max_dimension * std_deviation (expressed in %) / 100`?

(G'MIC staff) #27

Yes, `|x| < 3.5*std_dev`.

#28

Yes to this statement as well?

New question.

``````gmic sp tiger,dog,wall echo_test

# tiger
# dog
# wall

echo_test:
echo_stdout "\n"
repeat \$! local[\$>]
echo_stdout ""{b}""
endl done quit
``````

What if I wanted to do this without `local`? Something like `b#\$>` doesn’t work. I am asking because I cannot use `local` in some cases; e.g., when iterating over pixels like for MSE but I still want to echo the input names with the respective MSE values.

(G'MIC staff) #29
``````echo_stdout {\$>,b}
``````

More generally, `{ind,feature}` works for all kind of image features.

#30

That’s right, I flipped the items by mistake to `{feature,ind}`!

What is the simplest way to store values and strings into a vector? Two ways demonstrated by @garagecoder post #9 and @David_Tschumperle post #12 of the other thread seem over complicated (or I am just not used to doing it that way). Here is an example. Goal: make each line a vector element in `s` and echo the fifth element of `s` somewhere down the pipeline.

``````This
is
the
number
0
okay?
``````

(G'MIC staff) #31

For that, I usually use numbered variables as `\$lineN` (where `N` is an integer) to simulate an array of variables. It’s quite easy to manage. For instance, the following code read each non-empty line of a text file:

``````read_lines:
verbose -
input raw:"\$1",uchar   # Get ascii values of the file as a new image of data in [0,255].
split -,{'\n'}  # Decompose as lines (and discard '\n').
repeat \$! line\$>={\$>,t} done # Assign line content to numbered variables
remove
verbose +
echo[] "Fifth non-empty line : "\$line4
echo[] "First 5 non-empty-lines :"
repeat 5 echo[] "    ["{1+\$>}"] = "\${line\$>} done
``````

Then, using it like this : `\$ gmic read_lines README` gives:

``````\$ gmic read_lines README
[gmic]-0./ Start G'MIC interpreter.
Fifth non-empty line :                       | |  __  |_| |   / | | || |
First 5 non-empty-lines :
[1] = --------------------------------------------------------------------------------
[2] = --------------------------------------------------------------------------------
[3] =                         _____   _   __  __ _____ _____
[4] =                        / ____| | | |  /  |_   _/ ____|
[5] =                       | |  __  |_| |   / | | || |
[gmic]-0./ End G'MIC interpreter.
``````

#32

Thanks: `read_lines` explains a lot. The part that I was missing was `split -,{'\n'}`. I don’t quite know when to use `echo[]` and `echo_stdout` though. Besides error versus standard output, `echo[]` appears to require less quoting `"`, so maybe I will stick with that one. I guess my choice would affect the logs…? I also discovered the `string` command, so I could do

``````echo_test:
string "hello world"
split -,{'\ '}
repeat \$! word\$>={\$>,t} done
echo[] ""
echo[] \$word1
echo[] ""
q

# world
``````

Next question. I have been playing around with `norm`s and deciding what I could use them for. I wanted to try calculating the Frobenius norm but I don’t know a simple way to add all the elements of a matrix. `norm` is `sqr compose_channels + sqrt`; I guess that is supposed to be done before `compose_channels +`… Wait, are we already calculating the f-norm since an image is already a matrix?

#33

I’m not sure how you define this for multi channel images because it’s equivalent to euclidean norm of an m x n matrix treated as a vector (i.e. output is a scalar). In other words sum the squares of the elements then take the square root of that. For single channel image it would just be:

``sqr echo {sqrt(is)}  # output to console``

#34

Yes, that occurred to me after writing the post . I think `norm` takes the L2-norm of every `I` vector.

by @afre, using Inkscape

If that is true, then a matrix would be a line of pixels… I think a more useful application might be to move a f-norm window over an image for each channel but I don’t know how to do that yet . Sure enough, Google Scholar does yield papers where people use norms as a filter.

Speaking of image filtering, one exercise would be to write a command that passes an arbitrary kernel (given by user) through an image like the Convolution matrix filter in GIMP, but it might not be able to do a f-norm, because I don’t know what the matrix is…?

#35

Yes, it’s per pixel vector norm

One way is with a convolution kernel:

``````sp dog
sqr
(1)  # a single pixel image with value 1
resize. 5,5
convolve.. .  # convolve input by kernel
rm.
sqrt
``````

For larger kernels you could do that with the boxfilter command (approximate but fast), there’s also the option of using the math parser. It’s very easy to specify a kernel by image values (here I use the backslash to escape newline for clarity):

``````(0,1,0;\
1,1,1;\
0,1,0)``````

#37

I need some ideas to get started with finding edges. There are so many commands that I don’t know where to start. So far, I have only made threshold images based on Boolean expressions. Not necessarily but something like this would be nice:

Source: Images borrowed from this paper.

What I have so far. Not great but a start .

``````edge_test0:
l50_ 1  # L* channel from L*a*b* D50
laplacian - {im}
fill i<ia+sqrt(iv)&&i>ia-sqrt(iv)
negate 1
``````

#38

Edge detection is a large subject in itself, but the one I usually end up using is gradient_norm. Combined with an exponent or a threshold (of which there are many, perhaps give ‘otsu’ a try) it’s quite hard to beat in general situations, for such a simple operation.

#39

Used `gradient_norm` before and wanted to try `laplacian`. `Otsu` is cleaner overall but may ignore weaker edges. Turns out it is still the right one to use:

#40

Speaking of convolution, I came across Sharpening Images with Edge Detection in the Imagemagick docs. I am having trouble understanding and reproducing the first command.

``````convert face.png -define convolve:scale='100,100%' \
-morphology Convolve 'Log:0x2' face_sharpen.png
``````

Hint: jump here for details on `-define` and here for `-morphology`. Actually, `0x2` might have to do with `-gaussian-blur`. I am not quite sure; I haven’t used IM in a while. (@snibgo, maybe you could help me with the explanation.)

This is what I have but it doesn’t match.

``````convolve_test0:
(-1,-1,-1;\
-1,+8,-1;\
-1,-1,-1)
/. 8
(0,0,0;\
0,1,0;\
0,0,0)
+[-2,-1]
b {2/3.5},1,1
convolve.. .
rm.
``````

#41

Hmm those docs have some suspect descriptions of so-called ‘LoG’. I assume the -define part is setting parameters for the convolution (I never use imagemagick). The idea of that kernel is to save doing two separate steps (blur then laplacian) by using laplacian of a gaussian as the kernel:

``````gmic image.png blur 2 laplacian
``````

becomes:

``````gmic 11,11,1,1 gaussian 2,2 laplacian image.png convolve. ..
``````

however for gmic I doubt this saves any time due to the fast blur command.

Edit: oops was in a hurry there, it should really be normalised and I guess you want to actually sharpen! In which case it’s:

``````gmic 11,11,1,1 gaussian 2,2 normalize_sum laplacian image.png +convolve. .. rm... +
``````

I suppose some memory can be saved by adding 1 to the kernel centre instead of copy and add…

``gmic 11,11,1,1 gaussian 2,2 normalize_sum laplacian +f 0 =. 1,50%,50% + sp dog convolve. ..``

#42

The trouble that I am having and your examples seem to do as well is that we end up with a softer image. At least they appear to have less of a punch.

`sp tiger`

`'Log:0x2'`

`'Log:0x.5'`

PS
I also came across fun effects.

And wrote a filter that highlights or darkens edges.