# G'MIC exercises

Learning how to write commands isn’t easy. I think I need to do some exercises. This thread will be a collection of them.

Minimum noise B&W conversion
(http://www.guillermoluijk.com/elmomentodecisivo/bwalgorithm.R)

http://www.elmomentodecisivo.com/2017/04/combinacion-optima-de-senales-para_9.html

I am not getting it right; I probably read the code wrong. This is what I have, ending up with more noise rather than less!

``````gmic s.tif n 0,255 to_gray
``````
``````dcraw -v -r 1 1 1 1 -o 0 -4 -T -O s.tif SnowOnSpiderWeb.cr2
dcraw -v -w -o 2 -4 -T -O p.tif SnowOnSpiderWeb.cr2

gmic s.tif p.tif bw_test
``````
``````bw_test:
l[1]
b 3,1,1 s c nm R,G,B +/[G] [R] +/[B] [R] k[-2,-1]
+f. 1/(1+i#0^2+i#1^2) +f. i#3*i#0^2 +f. i#3*i#1^2 rm[0,1] a c
endl
* s c + apply_gamma 2.2
``````
3 Likes

Looks interesting, I’ll comment properly later when time is less short! For now a small suggestion for all us G’MIC posters; I often forget about the long form of the commands and how difficult the shorthand is to read (and probably quite offputting to newcomers). Where possible shall we attempt to make it as readable as we can by using long form and expanded formatting?

A while ago I did speak about auto code expansion/formatting for G’MIC but it’s a distant dream for now…

As someone who isn’t a programmer, engineer or scientist, abbreviation is not the problem. I can look it up anytime using `help` in command line or CTRL+F on the reference page. In fact, shorthand makes the code look cleaner and more comfortable to read. E.g., G’MIC stdlib is much more comfortable to read than C++, which I don’t think I can ever learn .

Rather, the difficult part is figuring out the syntax and what everything does in layman’s terms: commands, what they do, their parameters, what their parameters mean (conceptually and value-wise), what sort of input they would expect and what sort of output they would give. The reference page, stdlib file and tutorials don’t help because they deal with the how but not so much on the what and why.

The most helpful thing that people have done for me recently is explain the darn code or command underneath the code example! Then the light bulbs turn on!

Good timing
I prefer abbreviation too, I’m thinking of our poor visitors! Perhaps potential users aren’t the kind who care about that anyway so who knows… as an experiment I’ll try it here anyway:

``````bw_test : skip \${1=10}
to_rgb    # ensure 3 channels
+blur \$1%    # blur this as a new image
split[1] c    # split blur channels to separate images: R, G, B
name[-3,-2,-1] R,G,B    # rename the images
div[G] [R]
div[B] [R]
remove[R] name[G,B] k,kp
sqr[k,kp]
move[mapR] 1
mul[k] [mapR]
mul[kp] [mapR]
append[mapR,k,kp] c    # combine channels into one image
mul compose_channels +    # multiply original * map then = R+G+B
``````

The author doesn’t appear to state the blur radius. I’m not familiar with ‘R’ so not certain if some parts are matrix operations rather than vectors. I’m unable to make much sense of the math scribbles either I’m afraid!
Edit: you’ll notice I skip anything regarding input from dcraw or linear gamma conversion - I leave that to the user

1 Like

I modified my filter slightly to match yours

``````bw_testv2:
+l
b 10% s c nm R,G,B +/[G] [R] +/[B] [R] k[-2,-1]
+f. 1/(1+i#0^2+i#1^2) +f. i#32*i#0^2 +f. i#32*i#1^2 rm[0,1] a c
endl
* s c +
``````

but the result didn’t match, until I discovered that I was using the wrong index value. I wonder why `i#3` doesn’t produce an error and is equal to `i#0`.

Image indices in math parser are indeed cyclic, so you’ll never get an error with out-of-bounds indices.
Two reasons for that:

• Using negative indices is often convenient : `i(#-1,x,y)`.
• As the indice can be a variable, e.g. `i(#ind,x,y)`, we don’t want to check if `ind` is out-of-bounds because it would be slower than applying a simple modulo. And as the math parser code is often run on millions of pixels, these extra tests could make a difference on the execution time.

I wonder if the entire command you wrote could not be more easily written using only the math parser.
I’ll give a try maybe today.

Something like this maybe could do the job :

``````foo2 : skip \${1=10}
repeat \$! l[\$>]
to_rgb +b \$1%
100%,100%,1,1,"k2 = (G#1/R#1)^2;  kp2 = (B#1/R#1)^2;
(R#0 + k2*G#0 + kp2*B#0)/(1 + k2 + kp2)"
k.
endl done
``````

I’ve not checked the correctness of the calculations though, so maybe I’m wrong.

• Minimize the number of image buffers allocated for the calculations.
• Do the calculations using `double` instead of `float`.
• Parallelized computation.
• Shorter code

Does this look OK ?

1 Like

My ‘dcraw’ does not have an -O option to specify the output file name.
Does your version have it or is this a typo?
I am on linux Debian Sid up-to-date.

Looks okay. I will check later. I was following Guillermo’s code but this is what I would have worked toward .

Too intentional for a typo, don’t you think? Regular `dcraw` doesn’t have this switch.

Speaking of radius, is there a difference between std_variation[]_ and _radius[]? Is one statistical and the other spatial? Is there a way to determine an optimal value when dealing with noise? I have tried a few things in the past but none of it is based on anything concrete. Excuse my ignorance . Thoughts?

Yes you’re right, once again I’m loose with terms
It is indeed a statistical scale parameter rather than a radius. As for optimal values and noise, even basic probability theory is outside my knowledge I’m afraid (it’s on my todo list… ). Radius is for me just a convenient way to think about it, like a spatially weighted average.

@David_Tschumperle Could you explain where `std_variation[%]` comes from? E.g., if I use %, what is it a percentage of? Standard deviation?

Yes, basically a `radius` or `size` argument in a command means you have some fixed size used to do something in that command (e.g. blur with `boxfilter`).
When you have a `std_deviation` it means the kernel used has virtually an infinite support but has values decreasing following a gaussian distribution of given `std_deviation`. Usually, you can consider that the equivalent `radius` would be something like `radius = 3.5 x std_deviation`.
Now, if you add a `%` to the argument, this means it is computed from the image `width` and `height` (and `depth` if any), often using something as `new_std = max(width,height,depth)*std_%/100`
(this may depends on what the command does of course, sometimes `depth` won’t be considered for instance, if the command is intended to work separately on 2d slices).

1 Like

“-O” isn’t an option in dcraw as distributed by Dave Coffin. It is in distributions that come with ImageMagick, and is used to set the name of the output file. It is a useful addition, so you might also find it in other patched versions (such as my own).

My ignorance of Spanish prevents me from understanding the “El momento decisivo” article, and my ignorance of G’MIC prevents me from understanding the shorthand codes. Sure, I can look then up, but it’s like attempting to translate Spanish by looking up every word in a dictionary.

@garagecoder’s version is more understandable, for me.

G’MIC shorthand is like any jargon: useful for people who know it, and a barrier for others.

As I don’t understand the topic, I hesitate to answer.

As others say, a radius implies a binary choice: pixels within the radius are fully changed, and those outside aren’t changed at all. We often prefer a fading effect, and a Gaussian (or “bell curve”) fade is often used. For that, the usual measure is standard deviation (aka “stddev” or “SD”). See Standard deviation - Wikipedia

Noise in digital photos usually affects individual pixels, so I expect filter radii would be around 1 to 2 pixels, or SD around 0.3 to 0.6.

EDIT: I should add: I’ve never heard of a “standard variation”. I don’t know what that is. Perhaps a typo for “standard deviation”, or for “variance”.

2 Likes

I wasn’t very helpful with my answer to @xaos52. If he is still following, it is possible to name the output without the `-O` option. I would use

``````-c        Write image data to standard output
``````

and then redirect it to a file.

@snibgo Thanks for your thoughts. I liked the way you included a diff file for your custom dcraw so that we know what you changed. Also, I think 0.01% is a good clipping level, but as you mentioned, considering the other channels would be a good idea. Personally, I prefer unbounded output.

I was like that when trying to learn a second language . What I meant was that, in my perspective, the long form is only slightly less cryptic than the shorthand; I have to look up the commands anyway. However, in your case, it is harder to skim and provide feedback . I liked the way @garagecoder added comments next to the code. I will try to do that next time.

Good: that is how I have been approaching the problem, although I am still unsure how SD works. E.g., where does 0.3-0.6 come from? Is this related to the 68–95–99.7 rule?

@David_Tschumperle Looks like you have changed `std_variation` to `std_deviation`. It makes sense now. Would it also be appropriate to make this adjustment in the stdlib? One followup question is where does `radius = 3.5 x std_deviation` come from? Is `3.5` a constant or a variable? Also, does `new_std = max(width,height,depth)*std_%/100` mean “percentage of max dimension multiplied by standard deviation”?

One related question to everyone is what is the definition of radii wrt to the filter kernel? E.g., what is the width of the actual window when radius=2?

This is good to know about. I know you have less time these days, but is there possibility to generate a simple delimited list of all built-in commands with the shorthand equivalent? Example:

``````div,/
mul,*
blur,b
``````

If this is available there’s a greater chance somebody can make simple code formatting tools (or the reverse; compression/obfuscation!).

@garagecoder G’MIC already compresses the stdlib. Maybe you could rig that part of the code to switch between long form and shorthand… Perhaps even beautify the code along the way .

Yes, indeed, that is a typo I’ve made multiple times.

For gaussian functions, it is often assumed that when `|x|>3.5*std_deviation`, then the function value is close enough to zero.

No, it means : `max dimension * std_deviation (expressed in %) / 100`.

Hmm maybe I’m wrong but I think at various points it’s either whitespace removal or a usual data compression algorithm, rather than translation to/from short forms.
@David_Tschumperle is my earlier proposition possible somehow?

Would it produce a 5x5 window? Or something else?

Most commands I think now use interpolated input, with type sometimes specified as a parameter. Not sure of the type used for this (maybe just linear?), but even convolution commands such as ‘convolve’ will be exactly centred and use interpolated input. In older versions this was not the case.