TMSB Tutorial 4C: Andrea G. Blum Colour Combination XML File

article by Ben Lincoln

This example is a good example of how a seemingly-simple functional description can be interpreted in numerous different ways. It is based on a request by Andrea G. Blum to provide a way for TMSB to generate (automatically) a false colour compositing method she used ("Purple-Orange-Blue/Green"):

[ Note: Paraphrased slightly. ]

I multiply (128, 0, 255) over the photo for the purple UV layer, (255, 128, 0) for the IR orange, and (0, 255, 128) for the VIS green-with-half-blue colour with no name, then diff the stack.

[ Note: "green-with-half-blue colour with no name" is a reference to a discussion we had in which I mistakenly assumed she was using cyan, which is not the case. ]

Andrea was unavailable to elaborate on this description at the time, so I started to think of all the implementations of this description. Handling the infrared and ultraviolet images is easy (although, to be completely accurate, there are a number of alternate options for those too), but I thought of five different ways of handling the human-visible image before converting it to bluish-green (the diagram shows six, but I left out the median method in the actual test configuration). In addition, I eventually came up with five methods of handling the difference operation (one of them uses sum instead of difference, so feel free to leave that one out).

Permutations Of This Model
 Visible-Light Combination Methods
 Difference Operation Permutations

The various permutations of the two major stages of this compositing method that came to mind.

Example Images
 Conventional R-G-B
 Conventional G-B-UVA [3C]
 Conventional NIR-G-B [3C]
 Andrea's method, using the maximum of the human-visible-light channels [3C]
 Andrea's method, without combining the human-visible-light channels [3C]

A few variations of this technique.

Date Shot: 2011-04-02
Camera Body: Nikon D70 (Modified)
Lens: Nikon EL-Nikkor 80mm f/5.6 on a Nikon PB-6 bellows
Filters: Standard Set
Date Processed: 2011-04-23
Version: 1.0

Example Images 2
 Big Bend
 Flowers

A few additional examples of this technique applied to a flower photo and a landscape shot.

Date Shot: 2010-07-07 (Big Bend), 2010-10-16 (Flowers)
Camera Body: Nikon D70 (Modified)
Lens: Nikkor-O 35mm f/2 (Big Bend)(?), Micro-Nikkor 105mm f/4 (Flowers)
Filters: Standard Set
Date Processed: 2011-05-01
Version: 1.0

This gives between 16 and 30 possible variations, all of which produce visibly different results.

These instructions assume that the reader has obtained basic familiarity with editing TMSB XML files by following the instructions in the first tutorial (TMSB Tutorial 4A: Basic XML File Customization). Following the other preceeding tutorials first is also a good idea.

Like all of the tutorial configuration files, complete (and tested) versions of the results below are included in the Tutorial subdirectory of TMSB_Config wherever you unpacked the software to (TMSB version 1.2 or later). These can be used to refer to if you run into trouble, or you can just copy them into your TMSB_Config directory if you would rather just use them instead of know how to create custom configurations.

This tutorial will cover the processing approach that turned out to be match Andrea's technique, which is the "absolute difference" method. For purposes of simplicity and brevity, it will also only cover two of the options for handling the human-visible component: leaving the three channels unchanged, and using the maximum value of the three channels. The prebuilt configuration file included in the Tutorial subdirectory of TMSB_Config has all of the variations.

Getting Started

Unlike the previous tutorials, in this one the entire configuration will be created from scratch, but we'll be reusing the <Metadata> block, so it's easier to start by copying an existing file.

1. In the TMSB GUI, switch to the Processing Configuration tab.
2. Make sure something is selected in the drop-down menu (it doesn't matter what), then click the Export XML button.
3. In the File name field, enter Process-Custom-AGB.xml, then click Save.
4. Launch your text editor and open the file you just saved.
1. In the <Name> section, change the text to read Custom: Andrea G. Blum Purple/Orange/Bluish-Green.
2. In the <Description> section, change the text to something you find appropriately descriptive.
3. If you like, enter the date/time, in XML format in the <Created> and/or <LastModified> sections.
6. Delete everything between the <ProcessingConfig> and </ProcessingConfig> tags, but leave those two tags themselves in place.
7. Copy the following XML code, and paste it in-between those two tags:

<StatisticalGreyscaleCubes>

</StatisticalGreyscaleCubes>

<CustomGreyscaleChannels>

</CustomGreyscaleChannels>

<CombinedBandChannels>

</CombinedBandChannels>

<CalculatedChannelSets>

</CalculatedChannelSets>

<CustomThreeChannelImages>

</CustomThreeChannelImages>

<DCSVariations>

</DCSVariations>

<TintMapping>

</TintMapping>

<GenerateStatisticalChannels>

false

</GenerateStatisticalChannels>

<GenerateCalculatedChannels>

false

</GenerateCalculatedChannels>

<GenerateCustomChannels>

false

</GenerateCustomChannels>

<GenerateTintedImages>

false

</GenerateTintedImages>

false

<GenerateThreeChannelImages>

false

</GenerateThreeChannelImages>

<GenerateStandardThreeChannelImages>

false

</GenerateStandardThreeChannelImages>

<GenerateCustomThreeChannelImages>

false

</GenerateCustomThreeChannelImages>

<GenerateCalculatedThreeChannelImages>

false

</GenerateCalculatedThreeChannelImages>

<GenerateLumaColourImages>

false

</GenerateLumaColourImages>

<GenerateDCSImages>

false

</GenerateDCSImages>

<GenerateStatisticalImageThreeChannelPermutations>

false

</GenerateStatisticalImageThreeChannelPermutations>

<GenerateStatisticalImageThreeChannelPermutationsUnrestricted>

false

</GenerateStatisticalImageThreeChannelPermutationsUnrestricted>

<GenerateLumaColourVariationsFromIndividualBands>

false

</GenerateLumaColourVariationsFromIndividualBands>

<GenerateLumaColourVariationsFromCombinedChannels>

false

</GenerateLumaColourVariationsFromCombinedChannels>

<GenerateLumaColourVariationsFromStatisticalChannels>

false

</GenerateLumaColourVariationsFromStatisticalChannels>

<GenerateLumaColourVariationsFromThreeChannelImages>

false

</GenerateLumaColourVariationsFromThreeChannelImages>

<GenerateLumaColourVariationsFromDCSImages>

false

</GenerateLumaColourVariationsFromDCSImages>

<GenerateDCSImagesFromIndividualChannels>

false

</GenerateDCSImagesFromIndividualChannels>

<GenerateDCSImagesFromCombinedChannels>

false

</GenerateDCSImagesFromCombinedChannels>

<GenerateDCSImagesFromCustomThreeChannelImages>

false

</GenerateDCSImagesFromCustomThreeChannelImages>

<GenerateDCSEnhancedContrast>

false

</GenerateDCSEnhancedContrast>

8. In the XML block you just pasted in, change the values for the following from false to true:
1. <GenerateCustomChannels> - this option controls whether or not any custom greyscale channels defined in the configuration will be generated, and this tutorial will make use of quite a few of those.
2. <GenerateThreeChannelImages> - this option controls whether or not any three-channel false colour images (images in which three greyscale channels are mapped to red, green, and blue) will be generated.
3. <GenerateCustomThreeChannelImages> - this option controls whether or not custom-defined (as opposed to permutation-based) three-channel false colour images will be generated. This configuration will be making use of those as well.
9. Scroll back up to the <CustomGreyscaleChannels> tag. This block is where most of the content will be defined, as this configuration is built up from several layers of discrete greyscale images.
10. In-between the <CustomGreyscaleChannels> and </CustomGreyscaleChannels> tags, paste in the following XML code, which defines a greyscale image consisting of the maximum value of any of the bands categorized as "human-visible" in whichever input configuration is being used:

<CustomGreyscaleChannel>

<ChannelName>

Visible_(Max)

</ChannelName>

<Type>

BandCategory

</Type>

<CategoryName>

HumanVisible

</CategoryName>

<BandCombineMethod>

Max

</BandCombineMethod>

<UseAsLuminanceChannel>

false

</UseAsLuminanceChannel>

<UseAsThreeChannelChannel>

false

</UseAsThreeChannelChannel>

<OutputTransformation>

Normalize: Standard

</OutputTransformation>

</CustomGreyscaleChannel>

11. Paste in the following XML code after the block you just pasted in (but before the </CustomGreyscaleChannels> tag). This set of three custom greyscale images are the red, green, and blue channels of the purple ultraviolet image (which is one of the intermediate steps in creating the final composite). Unlike the block in the previous step, these channels use custom script code, which is passed straight through to the DaVinci script processor, with the exception of special values (the ones contained in percent signs, like %SpecialBand:UltravioletA%).

For the moderately-advanced user, note that instead of the 8-bit multipliers (255 and 128) from Andrea's original description, the values 1.0 and 0.5 are used here instead. This is because TMSB handles per-pixel levels as floating-point numbers between 0.0 and 1.0 (inclusive) instead of 8-bit integers between 0 and 255.

<CustomGreyscaleChannel>

<ChannelName>

Custom-AGB_UV_Purple-Red

</ChannelName>

<Type>

CustomScriptCode

</Type>

<CustomScriptCode>

= (%SpecialBand:UltravioletA% * 0.5)

</CustomScriptCode>

<UseAsLuminanceChannel>

false

</UseAsLuminanceChannel>

<UseAsThreeChannelChannel>

false

</UseAsThreeChannelChannel>

</CustomGreyscaleChannel>

<CustomGreyscaleChannel>

<ChannelName>

Custom-AGB_UV_Purple-Green

</ChannelName>

<Type>

CustomScriptCode

</Type>

<CustomScriptCode>

= (%SpecialBand:UltravioletA% * 0.0)

</CustomScriptCode>

<UseAsLuminanceChannel>

false

</UseAsLuminanceChannel>

<UseAsThreeChannelChannel>

false

</UseAsThreeChannelChannel>

</CustomGreyscaleChannel>

<CustomGreyscaleChannel>

<ChannelName>

Custom-AGB_UV_Purple-Blue

</ChannelName>

<Type>

CustomScriptCode

</Type>

<CustomScriptCode>

= (%SpecialBand:UltravioletA% * 1.0)

</CustomScriptCode>

<UseAsLuminanceChannel>

false

</UseAsLuminanceChannel>

<UseAsThreeChannelChannel>

false

</UseAsThreeChannelChannel>

</CustomGreyscaleChannel>

12. Paste in the following XML code after the block you just pasted in (but before the </CustomGreyscaleChannels> tag). This set of three custom greyscale images are the red, green, and blue channels of the orange infrared image.

For the advanced user who wants to create their own custom script code, note that the multipliers are placed after the object that represents an image (for example, %SpecialBand:NearInfraredNonSpecific% * 0.5). The DaVinci script processor does not treat this type of operation the same way as reversing the positions of the two values being multiplied, unless the two objects represent objects of the same dimensions. In this case, %SpecialBand:NearInfraredNonSpecific% represents a two-dimensional array of arbitrary size (because it is a greyscale image), whereas 0.5 represents a 1-dimensional array containing a single value.

In this specific case, the operation %SpecialBand:NearInfraredNonSpecific% * 0.5 in DaVinci will result in a two-dimensional array containing the values from the original image, but with each one multiplied by 0.5. On the other hand, 0.5 * %SpecialBand:NearInfraredNonSpecific% will result in a one-dimensional array containing 0.5 times one particular value out of the many values from the original image, which is not at all what you want. This is true for all mathematical operations in DaVinci, not just multiplication.

<CustomGreyscaleChannel>

<ChannelName>

Custom-AGB_IR_Orange-Red

</ChannelName>

<Type>

CustomScriptCode

</Type>

<CustomScriptCode>

= (%SpecialBand:NearInfraredNonSpecific% * 1.0)

</CustomScriptCode>

<UseAsLuminanceChannel>

false

</UseAsLuminanceChannel>

<UseAsThreeChannelChannel>

false

</UseAsThreeChannelChannel>

</CustomGreyscaleChannel>

<CustomGreyscaleChannel>

<ChannelName>

Custom-AGB_IR_Orange-Green

</ChannelName>

<Type>

CustomScriptCode

</Type>

<CustomScriptCode>

= (%SpecialBand:NearInfraredNonSpecific% * 0.5)

</CustomScriptCode>

<UseAsLuminanceChannel>

false

</UseAsLuminanceChannel>

<UseAsThreeChannelChannel>

false

</UseAsThreeChannelChannel>

</CustomGreyscaleChannel>

<CustomGreyscaleChannel>

<ChannelName>

Custom-AGB_IR_Orange-Blue

</ChannelName>

<Type>

CustomScriptCode

</Type>

<CustomScriptCode>

= (%SpecialBand:NearInfraredNonSpecific% * 0.0)

</CustomScriptCode>

<UseAsLuminanceChannel>

false

</UseAsLuminanceChannel>

<UseAsThreeChannelChannel>

false

</UseAsThreeChannelChannel>

</CustomGreyscaleChannel>

13. The next block you paste in will contain six greyscale channels instead of three. This is because it defines the red, green, and blue channels for two different variations of the "bluish-green" image - one in which the red, green, and blue channels of the original human-visible image are used directly, and one in which the greyscale maximum image defined earlier is used instead.

Moderately-advanced readers may be wondering at this time why this configuration bothers to perform a multiplication by 1.0, since the result will be the same as the input. Could, for example, = (%SpecialBand:NearInfraredNonSpecific% * 1.0) not be simplified to = %SpecialBand:NearInfraredNonSpecific%, and save a fraction of a second in terms of processing time? The answer is "yes", but I wrote this configuration to easily allow the user to use custom coefficients instead of 0.0, 0.5, and 1.0, and having * 1.0 as a placeholder makes that easier.

Along those same lines, an operation in which the entire image is multiplied by zero seems to be something of a waste of time and disk space. I did this for similar reasons: it's easier to see where to replace coefficients if there's * 0.0 as a placeholder than if the custom three-channel images (which we haven't even defined yet) refer to a single "all black" image. It's also much more straightforward to make a new image of the same dimensions as an existing image in DaVinci by this method than by using clone().

<CustomGreyscaleChannel>

<ChannelName>

Custom-AGB_VIS_BluishGreen_NoBandCombination-Red

</ChannelName>

<Type>

CustomScriptCode

</Type>

<CustomScriptCode>

= (%SpecialBand:Red% * 0.0)

</CustomScriptCode>

<UseAsLuminanceChannel>

false

</UseAsLuminanceChannel>

<UseAsThreeChannelChannel>

false

</UseAsThreeChannelChannel>

</CustomGreyscaleChannel>

<CustomGreyscaleChannel>

<ChannelName>

Custom-AGB_VIS_BluishGreen_NoBandCombination-Green

</ChannelName>

<Type>

CustomScriptCode

</Type>

<CustomScriptCode>

= (%SpecialBand:Green% * 1.0)

</CustomScriptCode>

<UseAsLuminanceChannel>

false

</UseAsLuminanceChannel>

<UseAsThreeChannelChannel>

false

</UseAsThreeChannelChannel>

</CustomGreyscaleChannel>

<CustomGreyscaleChannel>

<ChannelName>

Custom-AGB_VIS_BluishGreen_NoBandCombination-Blue

</ChannelName>

<Type>

CustomScriptCode

</Type>

<CustomScriptCode>

= (%SpecialBand:Blue% * 0.5)

</CustomScriptCode>

<UseAsLuminanceChannel>

false

</UseAsLuminanceChannel>

<UseAsThreeChannelChannel>

false

</UseAsThreeChannelChannel>

</CustomGreyscaleChannel>

<CustomGreyscaleChannel>

<ChannelName>

Custom-AGB_VIS_BluishGreen_VisMax-Red

</ChannelName>

<Type>

CustomScriptCode

</Type>

<CustomScriptCode>

= (%ChannelByName:Visible_(Max)% * 0.0)

</CustomScriptCode>

<UseAsLuminanceChannel>

false

</UseAsLuminanceChannel>

<UseAsThreeChannelChannel>

false

</UseAsThreeChannelChannel>

</CustomGreyscaleChannel>

<CustomGreyscaleChannel>

<ChannelName>

Custom-AGB_VIS_BluishGreen_VisMax-Green

</ChannelName>

<Type>

CustomScriptCode

</Type>

<CustomScriptCode>

= (%ChannelByName:Visible_(Max)% * 1.0)

</CustomScriptCode>

<UseAsLuminanceChannel>

false

</UseAsLuminanceChannel>

<UseAsThreeChannelChannel>

false

</UseAsThreeChannelChannel>

</CustomGreyscaleChannel>

<CustomGreyscaleChannel>

<ChannelName>

Custom-AGB_VIS_BluishGreen_VisMax-Blue

</ChannelName>

<Type>

CustomScriptCode

</Type>

<CustomScriptCode>

= (%ChannelByName:Visible_(Max)% * 0.5)

</CustomScriptCode>

<UseAsLuminanceChannel>

false

</UseAsLuminanceChannel>

<UseAsThreeChannelChannel>

false

</UseAsThreeChannelChannel>

</CustomGreyscaleChannel>

14. At this point, the greyscale images that represent the intermediate (purple, orange, and bluish-green) images are defined, but the ones which represent the difference operation have not. Paste in the following block of XML code, which takes care of that.

For the moderately-advanced user, notice that in this next layer of channels, instead of refering to spectral bands directly (using e.g. %SpecialBand:Red%), the custom script code here makes reference to the custom channels defined in the previous block (%ChannelByName:Custom-AGB_VIS_BluishGreen_NoBandCombination-Red%, et cetera). For more detail on this topic, see TMSB XML Schema Part 4: Processing Configuration.

For the advanced user, notice that the custom script code here is making use of the abs() function in DaVinci to return the absolute value. Because the custom script code is passed through to DaVinci, you can use nearly any of the many built-in DaVinci functions in custom script code, as well as many of the new functions defined in the dshadow.dvrc file included with DaVinci's Shadow.

<CustomGreyscaleChannel>

<ChannelName>

Custom-AGB_VisNBC_DiffVariation4-Red

</ChannelName>

<Type>

CustomScriptCode

</Type>

<CustomScriptCode>

= abs(%ChannelByName:Custom-AGB_VIS_BluishGreen_NoBandCombination-Red% - abs(%ChannelByName:Custom-AGB_IR_Orange-Red% - %ChannelByName:Custom-AGB_UV_Purple-Red%))

</CustomScriptCode>

<UseAsLuminanceChannel>

false

</UseAsLuminanceChannel>

<UseAsThreeChannelChannel>

false

</UseAsThreeChannelChannel>

</CustomGreyscaleChannel>

<CustomGreyscaleChannel>

<ChannelName>

Custom-AGB_VisNBC_DiffVariation4-Green

</ChannelName>

<Type>

CustomScriptCode

</Type>

<CustomScriptCode>

= abs(%ChannelByName:Custom-AGB_VIS_BluishGreen_NoBandCombination-Green% - abs(%ChannelByName:Custom-AGB_IR_Orange-Green% - %ChannelByName:Custom-AGB_UV_Purple-Green%))

</CustomScriptCode>

<UseAsLuminanceChannel>

false

</UseAsLuminanceChannel>

<UseAsThreeChannelChannel>

false

</UseAsThreeChannelChannel>

</CustomGreyscaleChannel>

<CustomGreyscaleChannel>

<ChannelName>

Custom-AGB_VisNBC_DiffVariation4-Blue

</ChannelName>

<Type>

CustomScriptCode

</Type>

<CustomScriptCode>

= abs(%ChannelByName:Custom-AGB_VIS_BluishGreen_NoBandCombination-Blue% - abs(%ChannelByName:Custom-AGB_IR_Orange-Blue% - %ChannelByName:Custom-AGB_UV_Purple-Blue%))

</CustomScriptCode>

<UseAsLuminanceChannel>

false

</UseAsLuminanceChannel>

<UseAsThreeChannelChannel>

false

</UseAsThreeChannelChannel>

</CustomGreyscaleChannel>

<CustomGreyscaleChannel>

<ChannelName>

Custom-AGB_VisMax_DiffVariation4-Red

</ChannelName>

<Type>

CustomScriptCode

</Type>

<CustomScriptCode>

= abs(%ChannelByName:Custom-AGB_VIS_BluishGreen_VisMax-Red% - abs(%ChannelByName:Custom-AGB_IR_Orange-Red% - %ChannelByName:Custom-AGB_UV_Purple-Red%))

</CustomScriptCode>

<UseAsLuminanceChannel>

false

</UseAsLuminanceChannel>

<UseAsThreeChannelChannel>

false

</UseAsThreeChannelChannel>

</CustomGreyscaleChannel>

<CustomGreyscaleChannel>

<ChannelName>

Custom-AGB_VisMax_DiffVariation4-Green

</ChannelName>

<Type>

CustomScriptCode

</Type>

<CustomScriptCode>

= abs(%ChannelByName:Custom-AGB_VIS_BluishGreen_VisMax-Green% - abs(%ChannelByName:Custom-AGB_IR_Orange-Green% - %ChannelByName:Custom-AGB_UV_Purple-Green%))

</CustomScriptCode>

<UseAsLuminanceChannel>

false

</UseAsLuminanceChannel>

<UseAsThreeChannelChannel>

false

</UseAsThreeChannelChannel>

</CustomGreyscaleChannel>

<CustomGreyscaleChannel>

<ChannelName>

Custom-AGB_VisMax_DiffVariation4-Blue

</ChannelName>

<Type>

CustomScriptCode

</Type>

<CustomScriptCode>

= abs(%ChannelByName:Custom-AGB_VIS_BluishGreen_VisMax-Blue% - abs(%ChannelByName:Custom-AGB_IR_Orange-Blue% - %ChannelByName:Custom-AGB_UV_Purple-Blue%))

</CustomScriptCode>

<UseAsLuminanceChannel>

false

</UseAsLuminanceChannel>

<UseAsThreeChannelChannel>

false

</UseAsThreeChannelChannel>

</CustomGreyscaleChannel>

15. Now that all of the greyscale channels are in place, you can proceed to define the two colour images which make use of them. In the configuration file, locate the <CustomThreeChannelImages> and </CustomThreeChannelImages> tags, which should have nothing between them at this time.
16. In-between those two tags, paste in the following content, which defines the two custom colour images based on the custom greyscale channels. These are just references (by name) to each of the appropriate greyscale images.

<CustomThreeChannelImage>

<UserDefinedName>

FC-3C-Custom-AGB_VisNBC_DiffVariation4

</UserDefinedName>

<RedChannelName>

Custom-AGB_VisNBC_DiffVariation4-Red

</RedChannelName>

<GreenChannelName>

Custom-AGB_VisNBC_DiffVariation4-Green

</GreenChannelName>

<BlueChannelName>

Custom-AGB_VisNBC_DiffVariation4-Blue

</BlueChannelName>

<IncludeInSecondOrderImages>

true

</IncludeInSecondOrderImages>

<OutputTransformation>

Normalize: Standard

</OutputTransformation>

</CustomThreeChannelImage>

<CustomThreeChannelImage>

<UserDefinedName>

FC-3C-Custom-AGB_VisMax_DiffVariation4

</UserDefinedName>

<RedChannelName>

Custom-AGB_VisMax_DiffVariation4-Red

</RedChannelName>

<GreenChannelName>

Custom-AGB_VisMax_DiffVariation4-Green

</GreenChannelName>

<BlueChannelName>

Custom-AGB_VisMax_DiffVariation4-Blue

</BlueChannelName>

<IncludeInSecondOrderImages>

true

</IncludeInSecondOrderImages>

<OutputTransformation>

Normalize: Standard

</OutputTransformation>

</CustomThreeChannelImage>

17. Save the file and exit.
18. If you closed out of TMSB previously, launch the GUI again. Otherwise, from the Tools menu, select Reload Configuration Files. In the Processing Configuration tab, the drop-down should now contain a new entry (named Custom: Andrea G. Blum Purple/Orange/Bluish-Green, if you followed all of the instructions correctly).
19. If you like, give the new configuration a try, any of the sample image sets here that contain at least NIR.TIF, RGB.TIF, and UVA.TIF.