Use G'MIC to combine separate R,G,B images to create RGB image

By the time you guys are done with me I expect that I’ll be much better at G’MIC.

Running the following command:
gmic Ferniegair-GE3D-RGB.tif / 257 rgb2lab lab2rgb mul 257 output Ferniegair-GE3D-RGBxv2.tif

does give me a perfect looking image in Irfanvew but causes RawTherapee to go belly up and opens as an all white image in GIMP and Photoshop.

Ditto for the following command:
gmic Ferniegair-GE3D-RGB.tif / 257 rgb2lab lab2rgb output Ferniegair-GE3D-RGBxv3.tif

Here is my proposal:

$ gmic Ferniegair-GE3D-RGB.tif Ferniegair-GE3D-B8.tif div 257 srgb2lab8.. j.. . rm. lab82srgb mul 257 round o output16.tiff

Several things to note here :

  • I use commands srgb2lab8 and lab82srgb rather than srgb2lab and lab2srgb. This is basically the same Lab colorspace, but renormalized so that each L,a,b channel has a [0,255] range.
  • I use round before saving. This ensures you get only integer values in your image (here in range [0,65535]), so the output .tif file is saved as 16bits-integers, and not 32bits float-valued (some viewers do not read float-valued tiff).
  • Otherwise, it uses the same technique I’ve shown before: the command j (aka image) is used to draw the scalar image of the lightness directly in the first channel of the Lab image.
    Be sure your lightness image is always a single channel one, otherwise you’ll need to use channel 0 or something similar to constrain it having a single channel.

Because the usual Lab colorspace has a range for the lightness which is [0,100] instead.

Hi David,
Thanks to your invaluable help I am able to replace a part of my workflow for which I formerly relied on Photoshop. Following is my minor mod to your command along with my commentary as to my understanding what each component is doing.

gmic Ferniegair-GE3D-RGB.tif Ferniegair-GE3D-B8.tif div 257 rgb2lab8[0] j[0] [1] rm[1] lab82srgb mul 257 round o output16d.tiff

Ferniegair-GE3D-RGB.tif # read in 1st image (color)
Ferniegair-GE3D-B8.tif  # read in 2nd image (gray for L channel)
div 257                 # divide all pixel values in both images by 257 to remap from range 0-65535 to range 0.0 - 255.0
rgb2lab8[0]             # convert the 1st image from RGB to LAB8 mode 
j[0] [1]                # Image command (not certain of) to draw the 2nd image onto the 1st image
rm[1]                   # remove the 2nd image from the list 
lab82srgb               # convert the remaining image from LAB8 to SRGB 
mul 257                 # multiply each pixel value by 257 to get back to the 0-65535 value range 
round                   # Assuming that round insures all values in the 0-65535 range are integer values 
o output16rgbl.tiff     # output final image

What I don’t understand is the image command (j) as I am unclear what it means to draw the b/w image onto the rgb image. Someone used to working with layers would conclude
that the result would be a b/w image. I am assuming that G’MIC sees the b/w image as having only one channel and simple “draws” that on top of the 1st channel of the LAB image, thus replacing that image’s L channel only since that is the 1st channel. I infer this to mean that if the second image had 3 channels, then drawing it onto the 1st image would have resulted in the 1st image becoming just a copy of the 2nd image.

Once again, thank you.

2 Likes

The image command replaces part of the original image with the image given as an argument. Since the image given as an argument has only a single channel, the part replaced in the original image is only replaced on one channel as well (in this case the luminance channel).
Here, you copy a smaller image into a larger image. But the smaller dimension is not in width or height (which are identical), but in number of channels. But the idea is the same: you copy a table of values into a larger table of values.

The call to j[0] [1] is actually equivalent to j[0] [1],0,0,0,0 (as the default values for the other arguments are 0). If you want to copy your single-channel image in the a channel for instance, rather than on the L channel, then you would have to write j[0] [1],0,0,0,1.

2 Likes

What is _max_opacity_mask?

That’s the value defined in [sprite_mask] for which the opacity of the drawing will be 100%. Usually, its value is chosen to be 1 (default) or 255 (when dealing with alpha channels from RGBA images for instance).

Hi David,

Ah, so the ‘c’ in the ref doc stands for the channel to replace in the copy-to or target image.
So I can assume that the x,y,z,c parms all apply to the target image.

Therefore j[0] [1],100,150,0,0 means to copy from image ‘1’ to image ‘0’ but use as the upper left hand corner for image ‘0’ the x,y position 100,150. Is this a correct read on my part?

In this situation I understand the channel aspect: the source has only a single channel so will target a specific channel in the destination. From this I take it that the ‘c’ operation only works with a grayscale image as input, yes?

Thanks again.

1 Like

Makes sense. Is this parameter only available with image and not other blend commands?

AFAIK, only for image because that’s the only command which takes an opacity mask as an argument.

That is correct yes.

No, it works with any number of channels, just like for the other dimensions.
For instance, you can draw a 2-channels image into a 3-channels image :

gmic sp lena,tiger channels. 0,1 j.. .,0,0,0,1

I am actually referring to opacity in general as it is typically [0,1] in G’MIC lingo but [0,255] in GUI-oriented apps like GIMP and Krita, which causes some confusion. A max parameter might help (or make things even more confusing :sweat_smile:).

When the opacity argument is just a scalar, I think it’s better to have a fixed range for the opacity ([0,1] is good enough). In the case of an opacity mask, it would be not convenient nor efficient to be forced to renormalize it before being used, that’s why there is this extra argument for command image.

Hi David,

Can’t say that I’ve ever heard of a 2 channel image. But lets say I have a 3 channel image and I want to copy channel 3 from the source to channel 2 in the target. The image statement seems to lack the flexibility to do that since you only get to specify a single value for channel and that value is for the target channel - but there is no parm to specify the source image channel.

My guess is that I’d have to take the source, split the channels out and then do an individual image statement for each channel to be drawn.

Gray_Alpha is a example of a two channel image. RGB is 3 channel. RGBA is four channel.

The usage and applications of image aren’t obvious. I don’t use it myself because of that. Perhaps it needs a good old tutorial @grosgood, or at least, a few more examples @David_Tschumperle.

Examples but not necessarily the cases. G’MIC doesn’t care about what the channels are. Well, it depends on what the particular command wants…

Yes, that’s correct. Examples are what I intended to show. You could have 27 channels image in G’MIC though applications most likely aren’t going to understand that. 5 channels is treated as CMYKA, and 4 channels is treated as RGBA in general. 3 Channels is treated as RGB. When you go into 6 channels or more, there’s no interpretation in GIMP or Krita.

Well that’s one important point in G’MIC :slight_smile: , you are able to manage ‘images’ (aka multi-dimensional arrays of numbers) that have four dimensions : width, height, depth and number of channels (aka spectrum), with any possible values for each of these dimensions. You decide what meaning you give to each of these dimensions. And most of the commands are able to deal with these 4-dimensional arrays of numbers.

In that case, indeed, you need a pre-processing step that create the exact array of values you want to copy from the source to the target. This implies some kind of “crop”, and this can be achieved for instance with commands crop, or channels, or resize, or even shared which is adapted in the case you want to copy some channels of the source to the target.
Several solutions exist, just pick the easiest one :slight_smile:

Yes, that could be done like this too, using command split c :

$ gmic target_RGB.jpg source_RGB.jpg split. c j[0] [3],0,0,0,1 keep[0]

for instance will copy the Blue channel of the target into the Green channel of the source.
But this can be done also like this:

$ gmic target_RGB.jpg source_RGB.jpg +channels. 2 j[0] [-1],0,0,0,1 keep[0]

after that, it’s mostly about personal preferences :stuck_out_tongue:

Well all I can say is that this is wonderful. Using the command help I’ve received here I’ve been able to write a DOS BAT of G’MIC commands to fully process a single image set which is itself called by a Python script which will run the BAT once for each image set listed in an input file. This is so much more efficient than doing each manually in Photoshop.

Thank you for taking so much time to help a newbie like myself out on this.

2 Likes

I can see why you would use Python+CMD+G’MIC. It is likely more efficient for you to launch a G’MIC script from CMD that does everything. :wink: Someday. :stuck_out_tongue: