G'MIC exercises

In code shown above, G’MIC caps the diameter (D) of the Gaussian filter. IM can cap the radius (R) (EDIT: I mean R in parentheses, not registered trademark. I hate computers that think they are smarter than me.), where D = 2*R+1.

The following is Windows BAT syntax, but copy-paste removes the new lines, so you’ll have to imagine them.

First, with G’MIC:

%GMIC% 11,11,1,1 gaussian 2,2 normalize_sum print

[gmic]-0./ Start G'MIC interpreter. [gmic]-0./ Input black image at position 0 (1 image 11x11x1x1). [gmic]-1./ Draw centered gaussian on image [0] with standard deviations (2,2) an d angle 0 deg. [gmic]-1./ Normalize image [0] with a unitary sum. [gmic]-1./ Print image [0] = '[unnamed]'. [0] = '[unnamed]': size = (11,11,1,1) [484 b of floats]. data = (7.76554e-005,0.000239195,0.0005738,0.001072,0.00155975,0.00176743,0.00155975,0.001072,0.0005738,0.000239195,7.76554e-005;0.000239195,(...),0.000239195;7.76554e-005,0.000239195,0.0005738,0.001072,0.00155975,0.00176743,0.00155975,0.001072,0.0005738,0.000239195,7.76554e-005). min = 7.76554e-005, max = 0.0402265, mean = 0.00826446, std = 0.0100279, coords_min = (0,0,0,0), coords_max = (5,5,0,0). [gmic]-1./ End G'MIC interpreter.

Now, with IM:

%IM%convert ^ xc: ^ -define showkernel=1 ^ -morphology Convolve:0 Gaussian:5x2 ^ null:

Kernel "Gaussian" of size 11x11+5+5 with values from 0 to 0.0402265 Forming a output range from 0 to 1 (Normalized) 0: 7.76554e-005 0.000239195 0.0005738 0.001072 0.00155975 0.00176743 0.0015597 5 0.001072 0.0005738 0.000239195 7.76554e-005 1: 0.000239195 0.000736774 0.00176743 0.00330199 0.00480437 0.00544406 0.00480437 0.00330199 0.00176743 0.000736774 0.000239195 2: 0.0005738 0.00176743 0.00423984 0.00792106 0.0115251 0.0130596 0.0115251 0.00792106 0.00423984 0.00176743 0.0005738 3: 0.001072 0.00330199 0.00792106 0.0147985 0.0215317 0.0243986 0.0215317 0.0147985 0.00792106 0.00330199 0.001072 4: 0.00155975 0.00480437 0.0115251 0.0215317 0.0313284 0.0354997 0.0313284 0.0215317 0.0115251 0.00480437 0.00155975 5: 0.00176743 0.00544406 0.0130596 0.0243986 0.0354997 0.0402265 0.0354997 0.0243986 0.0130596 0.00544406 0.00176743 6: 0.00155975 0.00480437 0.0115251 0.0215317 0.0313284 0.0354997 0.0313284 0.0215317 0.0115251 0.00480437 0.00155975 7: 0.001072 0.00330199 0.00792106 0.0147985 0.0215317 0.0243986 0.0215317 0.0147985 0.00792106 0.00330199 0.001072 8: 0.0005738 0.00176743 0.00423984 0.00792106 0.0115251 0.0130596 0.0115251 0.00792106 0.00423984 0.00176743 0.0005738 9: 0.000239195 0.000736774 0.00176743 0.00330199 0.00480437 0.00544406 0.00480437 0.00330199 0.00176743 0.000736774 0.000239195 10: 7.76554e-005 0.000239195 0.0005738 0.001072 0.00155975 0.00176743 0.00155975 0.001072 0.0005738 0.000239195 7.76554e-005

Compare the values from G’MIC and IM: they are the same (phew!).

By asking for a radius of zero, IM will automatically calculate the minimum radius that doesn’t lose precision:

%IM%convert ^ xc: ^ -define showkernel=1 ^ -morphology Convolve:0 Gaussian:0x2 ^ null: 2>&1 | findstr Kernel

Kernel "Gaussian" of size 15x15+7+7 with values from 0 to 0.0398008

So, if we use 15,15,1,1 in GMIC, we will get the same values as IM’s “Gaussian:0x2” or “Gaussian:7x2”. I won’t bore you with it, but I have checked, and they are the same.

I don’t know if G’MIC can automatically calculate the radius. But we can make the kernel over-large and then “autocrop” (EDIT: which is like IM’s “-trim”):

%GMIC% 20,20,1,1 gaussian 2,2 normalize_sum autocrop print

2 Likes

Thanks @garagecoder and @snibgo for your insights. I think I figured it out. Merging both worlds can be confusing for all of us but I learned a lot :smile:.

PS @snibgo Unfortunately, null: doesn’t output anything for me. I am currently using ImageMagick 7.0.7-21 Q16 x64 2018-01-06. I tried txt:

convert xc: -define showkernel=1 -morphology Convolve:0 Gaussian:0x2 txt:

and that output

# ImageMagick pixel enumeration: 1,1,65535,srgb
0,0: (65535,65535,65535)  #FFFFFFFFFFFF  white

Also, autocrop doesn’t crop to 15,15,1,1. Without parameters, I believe it discards 0s; therefore, it crops to 56,56,1,1. I guess I could mathematically determine the value. Or someone better at math could tell me how :wink:.

I’m not sure what you mean. “null:” is part of the command that starts with “%IM%convert”. Forget the IM part. Each ^ shows where I had a line-break, but those get stripped out by some software. I’ll try again:

convert xc: -define morphology:showkernel=1 ^
  -morphology Convolve:0 Gaussian:0x2 null: 2>&1 | findstr Kernel

That’s a single command line.

“findstr” is a Windows command, like grep on unix. We don’t care about the image, just the text output from “showkernel”.

I misread the G’MIC output: the command with autocrop I showed doesn’t crop at all. If I start with 300x300 pixels, it crops to 56x56, and most of the values are very small (less than 1e-16). Oops, sorry.

To use autocrop, you could first adjust so values that are near zero become exactly zero. I don’t know the best way to do this in G’MIC. But one method that seems to work is:

%GMIC% 300,300,1,1 gaussian 2,2 normalize_sum ^
  +select_color 1e-8,0 oneminus. mul autocrop 0 print output x.tiff

Explanation: make a 300x300 image, gaussian with SD=2, normalized. Make a copy that has values near zero to white, and make the others black. Flip black and white. Multiply this by the gaussian image, so now we have a gaussian that has all values near zero, actually zero. Autocrop to trim off columns and rows with just zeros. Print info, and save to x.tiff.

I think that’s what it does, but I’m probably wrong. Adjust the limit (1e-8) to whatever you want.

EDIT: IM v7 needs “-define morphology:showkernel=1”, with that “morphology:” prefix. V6 doesn’t need that prefix, and works fine with or without it.

What I meant was that the command up to null: doesn’t output anything so there is nothing to redirect. Must be something wrong with my IM version or setup…

PS I just posted about this in the IM forums under Bugs: http://www.imagemagick.org/discourse-server/viewtopic.php?f=3&t=33645.

PPS They got back to me. It isn’t a bug but a change in syntax. In IM7, we prefix showkernel with morphology:.  convert xc: -define morphology:showkernel=1 -morphology Convolve:0 Gaussian:0x2 null: 2>&1 | findstr Kernel

I have 2 problems that I am trying to figure out.

A. Dilate and erode aren’t very smooth. We end up with distinct shapes (square being the default).


If is better if I do a partial open



B. Related to #1 is that I would like to blur inward and outward.

My attempts here aren’t great. When inward, some outward pixels appear to have been affected and vice versa. Also the differences between the edges and the first blur values are too large to be natural. Maybe combine blurring with morphology?

This problem might be similar to the one that raw processors address where highlight and detail reconstruction are concerned.

Default morphological operations dilate and erode are indeed working in binary mode (Dilation (morphology) - Wikipedia), this is the most usual way dilation/erosion with a structuring element are defined.
But there exists also a real mode which makes them work with float-valued kernels (Dilation (morphology) - Wikipedia). This mode can be activated by setting the argument is_real to 1 when calling those operators.
E.g.:

gmic sp tiger 32,32 gaussian. 20% n. 100,255 dilate.. .,1,1

Same for erode:

About blurring a mask inward/outward, one suggestion:

It’s not really a blur, but using the distance function is great to get shaded mask around the contours:

$ gmic sp tiger norm ge 30% distance. 0 c 0,10 n 0,1

That’s a linear decay, but you can still make it more gaussian if needed afterwards.

1 Like

Nice example for functional morphology.
Still I would recommend odd kernel sizes to avoid shifts!

@samj’s thread Place some points on outlines with G'MIC got me thinking about making a starry sky out of an image. Here is what I have come up with so far:

I am naive about what stars are supposed to look like because I haven’t really examined a night sky. In my mind, stars should be round points of various sizes, colors and intensities, with a small Gaussian blur and perhaps a twinkle caused by our atmosphere and other forms of scattering (e.g., as a result of the camera hardware). Right now the image has lines, though I have finely chopped them up.

I will address color first. I would have to know how to color each line-object with a random but plausible color. I blotted out the greens and purples to the rainbow_lut but don’t know how to remove the black bars. I would also have to randomize the intensities within a reasonable range.

star_lut

Bonjour,

@afre

-to_rgba[-1]
-replace_color[-1] 100%,0,0,0,0,255,255,255,255,255

:o)

@samj The intent is to generate a rainbow clut without greens and purples. A lazy way is to use the rainbow_lut and remove the offending I elements. I don’t know how to do that. ATM I can only make them black. Then the plan is to apply this to the white specks of the tiger.

@afre

Can you illustrate your request because the French translation is not understandable.

:o)

This would be the French. Google Translate was helpful but I had to revise it.

Je voudrais représenter les couleurs de l’arc-en-ciel sans les verts et les pourpres dans un clut. Une manière paresseuse est d’utiliser rainbow_lut et d’enlever les couleurs que je ne veux pas. Au lieu de remplacer la couleur avec du blanc ou du noir, je voudrais enlever l’élément RGB (I) de clut lui-même.

@samj, sometimes DeepL:

gives more understandable translations: ???

L’intention est de générer un clut arc-en-ciel sans greens et violets. Une façon paresseuse est d’utiliser le rainbow_lut et d’enlever les éléments I offensants. Je ne sais pas comment faire ça. ATM Je ne peux que les rendre noirs. Ensuite, il est prévu de l’appliquer aux taches blanches du tigre.

@afre, to remove a particular vector value in an image:

foo :
  # Generate rainow lut with random holes (filled with -1).
  rainbow_lut f ">set()=(f=x+u(w/10);d=u(w/20));init(set());x<f?I:x<f+d?vector3(-1):(set();I)"

  # Discard colors having values -1.
  +discard. -1 r. {h/3},1,1,3,-1

discard: couldn’t remember what it was called! What does “-1=none (memory content)” mean? How does it differ from “0=none”?

For command resize, argument interpolation means:

  • 0 (none) : does not interpolate the pixel data, just enlarge or cut image dimensions, but keep the meaning of the axes.
  • -1 (none, memory content) : does not interpolate the pixel data and does not keep the meaning of the axes. Just consider the pixel data as a linear buffer and resize it.
    Typical example:
$ gmic sp lena,512 +r[0] 256,256,1,3,0 +r[0] 256,256,1,3,-1

gives:

In the first case (interpolation=0), the image is just cut to half-size, in the second case (interpolation=-1), that’s the image buffer which is cut at the end.

There are two subjects that I have been blindly exploring.
1 Dealing with chromatic aberration.
2 How to make a filter more noise and / or edge-aware.

1 What I have been doing so far is finding the highlights and then greying the edges. It is such a crude method because (a) the fringing can have inconsistent thicknesses, and (b) there a loss in colour data and no colour recovery. I just realized that stdlib already has the fx_chromatic_aberrations filter, though I don’t understand it completely.

2 I don’t quite understand how the weights are generated in fx_equalize_local_histograms. It is likely to do with it being abstracted by math expressions. Something to do with the standard deviation and how pixels differ from adjacent and global values.

I found a paper with a nice figure on various conditions a filter might want to consider.
image

PS I wouldn’t mind if devs of other apps chime in (e.g., @agriggio who likes to make experimental modules in RT and @snibgo who likes to explore different topics with IM).

dcraw corrects for chromatic aberration, with its “-C” option, by moving the values of two channels towards or away from the centre. Effectively, the image is split by channel into three images (ImageMagick “-separate”), then two are resized, and they are then merged ("-combine").

In experiments with Nikon 20mm and 15mm lenses, I concluded this simple scheme is helpful, but may not be enough. I suspect (but haven’t verified) that a better correction needs barrel/pincushion distortion. But I didn’t finish the experiments, and haven’t written them up.

On noise – well, I like it. Call me weird. It’s the digital version of grain. I detest the modern fashion for smoothing skin so it looks like sprayed plastic. Instagram has a lot to answer for.

But we can do smooth, if we want. For example by separating an image into cartoon and texture, manipulating in various ways, and re-combining.

hi @afre, interesting that you mentioned me and ‘eqalise local histograms’ in the same message: I’ve just recently started to take a look at the “local histogram equalisation” in gmic, because I like its results. unfortunately, the gmic language is very hard to read for me (I blame myself as I didn’t properly RTFM :slight_smile: so my progress is slow. I plan to read some more about the underlying algorithm, but I wouldn’t mind some tips from the knowledgeable people…