[ Beneath the Waves ]

TMSB Tutorial 4F: Yellow Filter Processing

article by Ben Lincoln

 

This tutorial describes a second customization suggested by Steve Smeed - the ability to recover near infrared, red, and green images from a single shot takes with a multispectrally-converted camera using a yellow filter in front of the lens.

As discussed in False Colour From Filters (and Simulated Filters), this is a technique developed by other photographers for mimicking Kodak's old EIR false-colour film, which mapped near infrared to red, red to green, and green to blue. It's simple, conceptually: a yellow filter blocks blue light, but allows near infrared through. As a result, the red channel is a mix of red and near infrared light, the green channel is a mix of green and near infrared light, and the blue channel is exclusively near infrared. So if one were to subtract the infrared value from the red channel and the green channel, they should end up with images that represent just red and just green, respectively.

This is a little harder to pull off in reality, because the exact mix of spectral bands will vary with lighting conditions, the camera's sensitivity to the various parts of the spectrum, and so on. But it is certainly possible to obtain very usable images, and the actual photos can be shot handheld, which I've found incredibly useful for doing "scouting" of areas to see if they are interesting enough in terms of infrared to do a full tripod-based shoot.

An enormous advantage to this technique is that autofocus and an optical viewfinder can both be used.

There are also a couple of disadvantages, assuming the shooter is using a conventional lens that doesn't focus near infrared to the same plane as human-visible light, and is using a conventional camera with a Bayer filter (IE not a camera with a Foveon sensor). The reasons for this are discussed further in the Cameras and Lenses articles.

In any case, as noted above, I definitely think this is worth doing. If nothing else, being able to shoot multispectral imagery handheld is a nice break from 15-minutes-per-shot tripod-based photography, and it allows scenes to be captured that are impractical or impossible with multiple exposures (e.g. non-posed photos of people, living animals, falling water, flames, clouds on a windy day).

The method used in this tutorial requires that the source images be accurately white-balanced using a grey card which is grey into the near infrared part of the spectrum (such as the WhiBal card). When this is done, the images will have a very distinctive look: most plants will be purple or blue, most skies will be green, and so on:

White-Balanced Example Images
[ Plant stalk closeup ]
Plant stalk closeup
[ Flowers ]
Flowers
[ Houses on top of Queen Anne ]
Houses on top of Queen Anne
[ A butterfly ]
A butterfly
[ A second butterfly ]
A second butterfly
[ A third butterfly ]
A third butterfly
[ A larger flower ]
A larger flower
[ Baby plant leaves ]
Baby plant leaves
[ Lake Union, Gasworks Park, and Fremont ]
Lake Union, Gasworks Park, and Fremont
[ Downtown Seattle ]
Downtown Seattle

The "distinctive look" mentioned above. I think (but am not sure) that the "plant stalk" is a baby bamboo tree.

Date Shot: 2011-01-22 (Downtown Seattle), 2011-04-12 (Lake Union), 2011-04-25 (butterflies and some of the plants), 2011-04-28 (everything else)
Camera Body: Nikon D70 (Modified)
Lens: Nikon AFS-DX Zoom-Nikkor 18-55mm f/3.5-5.6 EDII, Nikkor-Q 200mm f/4 (Lake Union), Nikkor-O 35mm f/2 (Downtown Seattle)
Filters: Tiffen Yellow 12
Date Processed: 2011-04-30
Version: 1.0

 

This "look" is partly due to the white-balance actually over-correcting the blue channel. Because the red and green channels both consist of infrared plus another band, the blue channel is "brought up to their level", more or less doubling its brightness relative to the other two. However, having this fixed relationship between the channels is what makes the math easy enough to get right most of the time. Trying to create a formula that will work with arbitrary white-balance settings would be a significant effort.

These images can then be processed using a couple of variations (described below), and once the red and green images have been isolated, processing that requires them (such as the emulated "Classic R72" filter, or NDVI) can also be generated:

Processed Example Images
[ NIR-R-G (normalized) ]
NIR-R-G (normalized)
[ NIR-R-G (enhanced red/green separation, normalized) ]
NIR-R-G (enhanced red/green separation, normalized)
[ NIR-R-G (normalized) ]
NIR-R-G (normalized)
[ NIR-R-G (enhanced red/green separation, normalized) ]
NIR-R-G (enhanced red/green separation, normalized)
[
"Classic R72" emulation
[ Normalized Difference Vegetation Index [Greyscale] ]
Normalized Difference Vegetation Index [Greyscale]
[ NDVI [Gradient] ]
NDVI [Gradient]
[ NIR-R-G (normalized) ]
NIR-R-G (normalized)
[ NIR-R-G (normalized) ]
NIR-R-G (normalized)
[
"Classic R72" emulation
[ NIR-R-G (normalized) ]
NIR-R-G (normalized)
[ NIR-R-G (normalized) ]
NIR-R-G (normalized)
[ NIR-R-G (enhanced red/green separation, custom gamma) ]
NIR-R-G (enhanced red/green separation, custom gamma)
[ NIR-R-G (enhanced red/green separation, normalized) ]
NIR-R-G (enhanced red/green separation, normalized)
[ NDVI [Gradient] ]
NDVI [Gradient]
[ NIR-R-G (enhanced red/green separation, normalized) ]
NIR-R-G (enhanced red/green separation, normalized)
[ NIR-R-G (custom gamma) ]
NIR-R-G (custom gamma)
[
"Classic R72" emulation
[ NDVI [Gradient] ]
NDVI [Gradient]
[ NIR-R-G (normalized) ]
NIR-R-G (normalized)
[
"Classic R72" emulation
       

A few of the results of processible the white-balanced example images, above.

Date Shot: 2011-01-22 (Downtown Seattle), 2011-04-12 (Lake Union), 2011-04-25 (butterflies and some of the plants), 2011-04-28 (everything else)
Camera Body: Nikon D70 (Modified)
Lens: Nikon AFS-DX Zoom-Nikkor 18-55mm f/3.5-5.6 EDII, Nikkor-Q 200mm f/4 (Lake Union), Nikkor-O 35mm f/2 (Downtown Seattle)
Filters: Tiffen Yellow 12
Date Processed: 2011-04-30
Version: 1.0

 

To mimic the look of actual EIR film photos even further, one or more of these variations can be processed in your favourite image editor to increase the saturation, alter the contrast, and so forth. Steve suggested (based on one of my sample images), using a Selective Colour operation with the Colours set to Cyans, the Cyan level set to -25%, and the Magenta level set to +100%.

Steve also sent me a fairly dramatic Photoshop® action made by H.H. Pictures which performs the following operations after generating the initial NIR-R-G image (which it does using a slightly different technique):

  1. Auto Levels
  2. Applies a Contrast of 74, with the Use Legacy option disabled.
  3. Vibrance of 50, Saturation of 10.
  4. Colour Balance with the following settings:
    1. Shadow Levels: -21, -14, 14.
    2. Midtone Levels: 0, -3, 15.
    3. Highlight Levels: 18, 11, 32.
    4. Preserve Luminosity: enabled
  5. Hue/Saturation with the following settings:
    1. Range: Blues
    2. Lightness: -46.
  6. Hue/Saturation with the following settings:
    1. Range: Magentas
    2. Hue: 18.
    3. Saturation: 51.
    4. Lightness: -44.

The result is a little too intense for me in most cases, but it does look quite similar to actual EIR photos.

This tutorial makes use of a feature introduced in version 1.2 of The Mirror's Surface Breaks (custom script variables), so you will need that version or later. You will be creating at least two, and optionally four configuration files. A few sample source images are available at the bottom of the page to test with.

These instructions assume that the reader has gone through all of the previous tutorials in this section, except for TMSB Tutorial 4D: Klaus D. Schmitt Custom Colour-Processing Matrix, which is intended for advanced users only.

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.

Yellow 12 Input Configuration

The first file to be created is the input configuration for the (white-balanced) original images. This is a generic input configuration that can be reused without modification for variations of this technique that use magenta or cyan filters to capture NIR-R-B and NIR-G-B (respectively) images in a single shot.

  1. In the TMSB GUI, switch to the Input 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 Input-Full_Spectrum_Filtered-TIFF-1F.xml, then click Save.
  4. Launch your text editor and open the file you just saved.
  5. In the <Metadata> section:
    1. In the <Name> section, change the text to read Full-Spectrum Filtered (TIFF - 1 File).
    2. In the <Description> section, change the text to This input configuration assumes a single colour image shot on a full-spectrum-converted camera, using e.g. a cyan, magenta, or yellow filter. Intended for use with processing configurations such as "Specialized: Convert Yellow 12 Filter Images".
    3. If you like, enter the date/time, in XML format in the <Created> and/or <LastModified> sections.
  6. Delete everything between the <InputConfig> and </InputConfig> tags, but leave those two tags themselves in place.
  7. Copy the following XML code (which defines the three input channels), and paste it in-between those two tags.

     

    <SpectralBands>

    <SpectralBand>

    <BandName>

    FSF-Red_Channel

    </BandName>

    <DataSources>

    <DataSource>

    <FileName>

    In-FSF.TIF

    </FileName>

    <Plane>

    1

    </Plane>

    </DataSource>

    </DataSources>

    <UseAsLuminanceChannel>

    false

    </UseAsLuminanceChannel>

    <UseAsThreeChannelChannel>

    false

    </UseAsThreeChannelChannel>

    </SpectralBand>

    <SpectralBand>

    <BandName>

    FSF-Green_Channel

    </BandName>

    <DataSources>

    <DataSource>

    <FileName>

    In-FSF.TIF

    </FileName>

    <Plane>

    2

    </Plane>

    </DataSource>

    </DataSources>

    <UseAsLuminanceChannel>

    false

    </UseAsLuminanceChannel>

    <UseAsThreeChannelChannel>

    false

    </UseAsThreeChannelChannel>

    </SpectralBand>

    <SpectralBand>

    <BandName>

    FSF-Blue_Channel

    </BandName>

    <DataSources>

    <DataSource>

    <FileName>

    In-FSF.TIF

    </FileName>

    <Plane>

    3

    </Plane>

    </DataSource>

    </DataSources>

    <UseAsLuminanceChannel>

    false

    </UseAsLuminanceChannel>

    <UseAsThreeChannelChannel>

    false

    </UseAsThreeChannelChannel>

    </SpectralBand>

    </SpectralBands>

  8. Save the file and exit.

Yellow 12 Processing Configuration

Next, it's necessary to create the processing configuration that recovers red and green images and generates initial false-colour results.

  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-Specialized-Yellow_12_Filter.xml, then click Save.
  4. Launch your text editor and open the file you just saved.
  5. In the <Metadata> section:
    1. In the <Name> section, change the text to read Specialized: Convert Yellow 12 Filter Images.
    2. In the <Description> section, change the text to For use with the "Full-Spectrum Filtered" input configuration - recovers near infrared, red, and green imagery from photos shot with a yellow #12 filter on a full-spectrum-converted digital camera..
    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:

     

    <ScriptVariables>

    </ScriptVariables>

    <StatisticalGreyscaleCubes>

    </StatisticalGreyscaleCubes>

    <CustomGreyscaleChannels>

    </CustomGreyscaleChannels>

    <CombinedBandChannels>

    </CombinedBandChannels>

    <CalculatedChannelSets>

    </CalculatedChannelSets>

    <CustomThreeChannelImages>

    </CustomThreeChannelImages>

    <DCSVariations>

    </DCSVariations>

    <TintMapping>

    </TintMapping>

    <GradientMapping>

    </GradientMapping>

    <GenerateStatisticalChannels>

    false

    </GenerateStatisticalChannels>

    <GenerateCalculatedChannels>

    false

    </GenerateCalculatedChannels>

    <GenerateCustomChannels>

    false

    </GenerateCustomChannels>

    <GenerateTintedImages>

    false

    </GenerateTintedImages>

    <GenerateGradientImages>

    false

    </GenerateGradientImages>

    <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>
    2. <GenerateThreeChannelImages>
    3. <GenerateCustomThreeChannelImages>
  9. Scroll back up to the <ScriptVariables> tag.
  10. In-between the <ScriptVariables> and </ScriptVariables> tags, paste in the following XML code, which defines the five variables used later on in the configuration: the relative percentages of infrared versus red and green in their respective channels, custom gamma values for the recovered red and green images, and the amount to "separate" the red and green channels by (this is discussed later).

     

    <ScriptVariables>

    <ScriptVariable>

    <Name>

    RedChannelIRLevel

    </Name>

    <Value>

    0.5

    </Value>

    </ScriptVariable>

    <ScriptVariable>

    <Name>

    GreenChannelIRLevel

    </Name>

    <Value>

    0.5

    </Value>

    </ScriptVariable>

    <ScriptVariable>

    <Name>

    RedCustomGamma

    </Name>

    <Value>

    0.6

    </Value>

    </ScriptVariable>

    <ScriptVariable>

    <Name>

    GreenCustomGamma

    </Name>

    <Value>

    1.29

    </Value>

    </ScriptVariable>

    <ScriptVariable>

    <Name>

    RedGreenSeparation

    </Name>

    <Value>

    0.2

    </Value>

    </ScriptVariable>

    </ScriptVariables>

  11. Scroll down to the <CustomGreyscaleChannels> tag.
  12. In-between the <CustomGreyscaleChannels> and </CustomGreyscaleChannels> tags, paste in the following XML code, which defines the method for recovering the spectral bands of interest, as well as several variations (normalized, custom gamma levels, enhanced separation between red and green, and so on). Note that this code makes use custom script variables, since if someone is interested in tweaking around the percentage of e.g. red versus infrared in the red channel, it's much easier to have that value isolated than to have to remember which number it is in the custom equation.

     

    <CustomGreyscaleChannel>

    <ChannelName>

    NIR

    </ChannelName>

    <Type>

    CustomScriptCode

    </Type>

    <CustomScriptCode>

    = %ChannelByName:FSF-Blue_Channel%

    </CustomScriptCode>

    <UseAsLuminanceChannel>

    false

    </UseAsLuminanceChannel>

    <UseAsThreeChannelChannel>

    false

    </UseAsThreeChannelChannel>

    </CustomGreyscaleChannel>

    <CustomGreyscaleChannel>

    <ChannelName>

    Red

    </ChannelName>

    <Type>

    CustomScriptCode

    </Type>

    <CustomScriptCode>

    = (%ChannelByName:FSF-Red_Channel% - (%ChannelByName:NIR% * %Var:RedChannelIRLevel%)) / (1.0 - %Var:RedChannelIRLevel%)

    </CustomScriptCode>

    <UseAsLuminanceChannel>

    false

    </UseAsLuminanceChannel>

    <UseAsThreeChannelChannel>

    false

    </UseAsThreeChannelChannel>

    <OutputTransformation>

    Clip: 0.0 - 1.0

    </OutputTransformation>

    </CustomGreyscaleChannel>

    <CustomGreyscaleChannel>

    <ChannelName>

    Green

    </ChannelName>

    <Type>

    CustomScriptCode

    </Type>

    <CustomScriptCode>

    = (%ChannelByName:FSF-Green_Channel% - (%ChannelByName:NIR% * %Var:GreenChannelIRLevel%)) / (1.0 - %Var:RedChannelIRLevel%)

    </CustomScriptCode>

    <UseAsLuminanceChannel>

    false

    </UseAsLuminanceChannel>

    <UseAsThreeChannelChannel>

    false

    </UseAsThreeChannelChannel>

    <OutputTransformation>

    Clip: 0.0 - 1.0

    </OutputTransformation>

    </CustomGreyscaleChannel>

    <CustomGreyscaleChannel>

    <ChannelName>

    NIR-Normalized

    </ChannelName>

    <Type>

    CustomScriptCode

    </Type>

    <CustomScriptCode>

    = %ChannelByName:FSF-Blue_Channel%

    </CustomScriptCode>

    <UseAsLuminanceChannel>

    false

    </UseAsLuminanceChannel>

    <UseAsThreeChannelChannel>

    false

    </UseAsThreeChannelChannel>

    <OutputTransformation>

    Normalize: Militant

    </OutputTransformation>

    </CustomGreyscaleChannel>

    <CustomGreyscaleChannel>

    <ChannelName>

    Red-Normalized

    </ChannelName>

    <Type>

    CustomScriptCode

    </Type>

    <CustomScriptCode>

    = (%ChannelByName:FSF-Red_Channel% - (%ChannelByName:NIR% * %Var:RedChannelIRLevel%)) / (1.0 - %Var:RedChannelIRLevel%)

    </CustomScriptCode>

    <UseAsLuminanceChannel>

    false

    </UseAsLuminanceChannel>

    <UseAsThreeChannelChannel>

    false

    </UseAsThreeChannelChannel>

    <OutputTransformation>

    Normalize: Militant

    </OutputTransformation>

    </CustomGreyscaleChannel>

    <CustomGreyscaleChannel>

    <ChannelName>

    Green-Normalized

    </ChannelName>

    <Type>

    CustomScriptCode

    </Type>

    <CustomScriptCode>

    = (%ChannelByName:FSF-Green_Channel% - (%ChannelByName:NIR% * %Var:GreenChannelIRLevel%)) / (1.0 - %Var:RedChannelIRLevel%)

    </CustomScriptCode>

    <UseAsLuminanceChannel>

    false

    </UseAsLuminanceChannel>

    <UseAsThreeChannelChannel>

    false

    </UseAsThreeChannelChannel>

    <OutputTransformation>

    Normalize: Militant

    </OutputTransformation>

    </CustomGreyscaleChannel>

    <CustomGreyscaleChannel>

    <ChannelName>

    Red-Custom_Gamma

    </ChannelName>

    <Type>

    CustomScriptCode

    </Type>

    <CustomScriptCode>

    = pow(%ChannelByName:Red%, (1.0 / %Var:RedCustomGamma%))

    </CustomScriptCode>

    <UseAsLuminanceChannel>

    false

    </UseAsLuminanceChannel>

    <UseAsThreeChannelChannel>

    false

    </UseAsThreeChannelChannel>

    <OutputTransformation>

    Clip: 0.0 - 1.0

    </OutputTransformation>

    </CustomGreyscaleChannel>

    <CustomGreyscaleChannel>

    <ChannelName>

    Green-Custom_Gamma

    </ChannelName>

    <Type>

    CustomScriptCode

    </Type>

    <CustomScriptCode>

    = pow(%ChannelByName:Green%, (1.0 / %Var:GreenCustomGamma%))

    </CustomScriptCode>

    <UseAsLuminanceChannel>

    false

    </UseAsLuminanceChannel>

    <UseAsThreeChannelChannel>

    false

    </UseAsThreeChannelChannel>

    <OutputTransformation>

    Clip: 0.0 - 1.0

    </OutputTransformation>

    </CustomGreyscaleChannel>

    <CustomGreyscaleChannel>

    <ChannelName>

    Red-Separated

    </ChannelName>

    <Type>

    CustomScriptCode

    </Type>

    <CustomScriptCode>

    = (%ChannelByName:Red% - (%ChannelByName:Green% * %Var:RedGreenSeparation%) + (%ChannelByName:Red% * %Var:RedGreenSeparation%))

    </CustomScriptCode>

    <UseAsLuminanceChannel>

    false

    </UseAsLuminanceChannel>

    <UseAsThreeChannelChannel>

    false

    </UseAsThreeChannelChannel>

    <OutputTransformation>

    Clip: 0.0 - 1.0

    </OutputTransformation>

    </CustomGreyscaleChannel>

    <CustomGreyscaleChannel>

    <ChannelName>

    Green-Separated

    </ChannelName>

    <Type>

    CustomScriptCode

    </Type>

    <CustomScriptCode>

    = (%ChannelByName:Green% - (%ChannelByName:Red% * %Var:RedGreenSeparation%) + (%ChannelByName:Green% * %Var:RedGreenSeparation%))

    </CustomScriptCode>

    <UseAsLuminanceChannel>

    false

    </UseAsLuminanceChannel>

    <UseAsThreeChannelChannel>

    false

    </UseAsThreeChannelChannel>

    <OutputTransformation>

    Clip: 0.0 - 1.0

    </OutputTransformation>

    </CustomGreyscaleChannel>

    <CustomGreyscaleChannel>

    <ChannelName>

    Red-Separated-Normalized

    </ChannelName>

    <Type>

    CustomScriptCode

    </Type>

    <CustomScriptCode>

    = (%ChannelByName:Red% - (%ChannelByName:Green% * %Var:RedGreenSeparation%) + (%ChannelByName:Red% * %Var:RedGreenSeparation%))

    </CustomScriptCode>

    <UseAsLuminanceChannel>

    false

    </UseAsLuminanceChannel>

    <UseAsThreeChannelChannel>

    false

    </UseAsThreeChannelChannel>

    <OutputTransformation>

    Normalize: Militant

    </OutputTransformation>

    </CustomGreyscaleChannel>

    <CustomGreyscaleChannel>

    <ChannelName>

    Green-Separated-Normalized

    </ChannelName>

    <Type>

    CustomScriptCode

    </Type>

    <CustomScriptCode>

    = (%ChannelByName:Green% - (%ChannelByName:Red% * %Var:RedGreenSeparation%) + (%ChannelByName:Green% * %Var:RedGreenSeparation%))

    </CustomScriptCode>

    <UseAsLuminanceChannel>

    false

    </UseAsLuminanceChannel>

    <UseAsThreeChannelChannel>

    false

    </UseAsThreeChannelChannel>

    <OutputTransformation>

    Normalize: Militant

    </OutputTransformation>

    </CustomGreyscaleChannel>

    <CustomGreyscaleChannel>

    <ChannelName>

    Red-Separated-Custom_Gamma

    </ChannelName>

    <Type>

    CustomScriptCode

    </Type>

    <CustomScriptCode>

    = pow(%ChannelByName:Red-Separated%, (1.0 / %Var:RedCustomGamma%))

    </CustomScriptCode>

    <UseAsLuminanceChannel>

    false

    </UseAsLuminanceChannel>

    <UseAsThreeChannelChannel>

    false

    </UseAsThreeChannelChannel>

    <OutputTransformation>

    Clip: 0.0 - 1.0

    </OutputTransformation>

    </CustomGreyscaleChannel>

    <CustomGreyscaleChannel>

    <ChannelName>

    Green-Separated-Custom_Gamma

    </ChannelName>

    <Type>

    CustomScriptCode

    </Type>

    <CustomScriptCode>

    = pow(%ChannelByName:Green-Separated%, (1.0 / %Var:GreenCustomGamma%))

    </CustomScriptCode>

    <UseAsLuminanceChannel>

    false

    </UseAsLuminanceChannel>

    <UseAsThreeChannelChannel>

    false

    </UseAsThreeChannelChannel>

    <OutputTransformation>

    Clip: 0.0 - 1.0

    </OutputTransformation>

    </CustomGreyscaleChannel>

     

    To break down the basic equation:

    [Red] = (%ChannelByName:FSF-Red_Channel% - (%ChannelByName:NIR% * %Var:RedChannelIRLevel%)) / (1.0 - %Var:RedChannelIRLevel%)

     
    What is going on here is a three-step operation. First, the known near infrared values (%ChannelByName:NIR%) are being scaled by the relative percentage of near infrared to red in the red channel (%Var:RedChannelIRLevel%). Second, that set of scaled values is subtracted from the raw red channel (%ChannelByName:FSF-Red_Channel%) to obtain the approximate "real" red image. However, this image needs to have its brightness scaled back to take up the full dynamic range available, which is performed by the division operation (the third, and final step). Because the equation makes use of the custom script variables, it's easy (or at least easier) to experiment with different values for the relative percentage.
     
    Those of you who have worked with more complicated processing tools like J.W. "Infrachrome" Wong's method may be surprised at the simplicity of this equation. I actually experimented with something closer to that method, but I found that the results were not significantly better to the point of outweighing the complexity. In addition, specific implementations (like the PixelBender plugins) seem to depend on truly wacky ways that PixelBender handles situations like raising a negative number to an exponent[2].
     
    The "enhanced red/green separation" variation is a technique I've been experimenting with after realizing that the idea of subtracting one channel from another could help achieve more "pure" colours for human-visible spectral bands as well - sort of a virtual didymium filter[3].
  13. Scroll down to the <CustomThreeChannelImages> tag.
  14. In-between the <CustomThreeChannelImages> and </CustomThreeChannelImages> tags, paste in the following XML code, which defines the custom colour images created out of the greyscale channels defined earlier.

     

    <CustomThreeChannelImage>

    <UserDefinedName>

    FC-3C-NIR-R-G

    </UserDefinedName>

    <RedChannelName>

    NIR

    </RedChannelName>

    <GreenChannelName>

    Red

    </GreenChannelName>

    <BlueChannelName>

    Green

    </BlueChannelName>

    <IncludeInSecondOrderImages>

    true

    </IncludeInSecondOrderImages>

    <OutputTransformation>

    Normalize: Standard

    </OutputTransformation>

    </CustomThreeChannelImage>

    <CustomThreeChannelImage>

    <UserDefinedName>

    FC-3C-NIR-R-G_(Custom_Gamma)

    </UserDefinedName>

    <RedChannelName>

    NIR

    </RedChannelName>

    <GreenChannelName>

    Red-Custom_Gamma

    </GreenChannelName>

    <BlueChannelName>

    Green-Custom_Gamma

    </BlueChannelName>

    <IncludeInSecondOrderImages>

    true

    </IncludeInSecondOrderImages>

    <OutputTransformation>

    Normalize: Standard

    </OutputTransformation>

    </CustomThreeChannelImage>

    <CustomThreeChannelImage>

    <UserDefinedName>

    FC-3C-NIR-R-G_(Normalized)

    </UserDefinedName>

    <RedChannelName>

    NIR-Normalized

    </RedChannelName>

    <GreenChannelName>

    Red-Normalized

    </GreenChannelName>

    <BlueChannelName>

    Green-Normalized

    </BlueChannelName>

    <IncludeInSecondOrderImages>

    true

    </IncludeInSecondOrderImages>

    <OutputTransformation>

    Normalize: Standard

    </OutputTransformation>

    </CustomThreeChannelImage>

    <CustomThreeChannelImage>

    <UserDefinedName>

    FC-3C-NIR-R-G_(RG_Separated)

    </UserDefinedName>

    <RedChannelName>

    NIR

    </RedChannelName>

    <GreenChannelName>

    Red-Separated

    </GreenChannelName>

    <BlueChannelName>

    Green-Separated

    </BlueChannelName>

    <IncludeInSecondOrderImages>

    true

    </IncludeInSecondOrderImages>

    <OutputTransformation>

    Normalize: Standard

    </OutputTransformation>

    </CustomThreeChannelImage>

    <CustomThreeChannelImage>

    <UserDefinedName>

    FC-3C-NIR-R-G_(RG_Separated-Normalized)

    </UserDefinedName>

    <RedChannelName>

    NIR-Normalized

    </RedChannelName>

    <GreenChannelName>

    Red-Separated-Normalized

    </GreenChannelName>

    <BlueChannelName>

    Green-Separated-Normalized

    </BlueChannelName>

    <IncludeInSecondOrderImages>

    true

    </IncludeInSecondOrderImages>

    <OutputTransformation>

    Normalize: Standard

    </OutputTransformation>

    </CustomThreeChannelImage>

    <CustomThreeChannelImage>

    <UserDefinedName>

    FC-3C-NIR-R-G_(RG_Separated-Custom_Gamma)

    </UserDefinedName>

    <RedChannelName>

    NIR

    </RedChannelName>

    <GreenChannelName>

    Red-Separated-Custom_Gamma

    </GreenChannelName>

    <BlueChannelName>

    Green-Separated-Custom_Gamma

    </BlueChannelName>

    <IncludeInSecondOrderImages>

    true

    </IncludeInSecondOrderImages>

    <OutputTransformation>

    Normalize: Standard

    </OutputTransformation>

    </CustomThreeChannelImage>

  15. Save the file and exit.
  16. If you closed out of TMSB previously, launch the GUI again. Otherwise, from the Tools menu, select Reload Configuration Files. In the Input Configuration tab, the drop-down should now contain a new entry (named Full-Spectrum Filtered (TIFF - 1 File), if you followed all of the instructions correctly), and in the Processing Configuration tab, the drop-down should now contain a new entry (named Specialized: Convert Yellow 12 Filter Images, if you followed all of the instructions correctly).
  17. If you like, give the new configurations a try, using the example input image set available at the bottom of this page.

Extra Credit Part 1: NIR-R-G Input Configuration

To create further output variations, we'll build a file that re-reads the NIR-R-G false colour image output by the first set as a new input file, and maps it to the special band names NearInfraredNonspecific, Red, and Green, for use with existing processing configurations.

  1. In the TMSB GUI, switch to the Input 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 Input-NIR_R_G-TIFF-1F.xml, then click Save.
  4. Launch your text editor and open the file you just saved.
  5. In the <Metadata> section:
    1. In the <Name> section, change the text to read NIR-R-G (TIFF - 1 File).
    2. In the <Description> section, change the text to This input configuration uses up to three spectral bands (near infrared, red, and green) in TIFF format. The bands should be contained in a single three-channel file ("FC-3C-NIR-R-G.TIF"), in which the red channel contains the near infrared image, the green channel contains the red image, and the blue channel contains the green image.
    3. If you like, enter the date/time, in XML format in the <Created> and/or <LastModified> sections.
  6. Delete everything between the <InputConfig> and </InputConfig> tags, but leave those two tags themselves in place.
  7. Copy the following XML code (which defines the three input channels), and paste it in-between those two tags.

     

    <SpectralBands>

    <SpectralBand>

    <BandName>

    NIR

    </BandName>

    <DataSources>

    <DataSource>

    <FileName>

    FC-3C-NIR-R-G.TIF

    </FileName>

    <Plane>

    1

    </Plane>

    </DataSource>

    </DataSources>

    <BandCategory>

    NearInfrared

    </BandCategory>

    <SpecialBandName>

    NearInfraredNonspecific

    </SpecialBandName>

    <UseAsLuminanceChannel>

    true

    </UseAsLuminanceChannel>

    <UseAsThreeChannelChannel>

    true

    </UseAsThreeChannelChannel>

    </SpectralBand>

    <SpectralBand>

    <BandName>

    R

    </BandName>

    <DataSources>

    <DataSource>

    <FileName>

    FC-3C-NIR-R-G.TIF

    </FileName>

    <Plane>

    2

    </Plane>

    </DataSource>

    </DataSources>

    <BandCategory>

    HumanVisible

    </BandCategory>

    <SpecialBandName>

    Red

    </SpecialBandName>

    <UseAsLuminanceChannel>

    false

    </UseAsLuminanceChannel>

    <UseAsThreeChannelChannel>

    true

    </UseAsThreeChannelChannel>

    </SpectralBand>

    <SpectralBand>

    <BandName>

    G

    </BandName>

    <DataSources>

    <DataSource>

    <FileName>

    FC-3C-NIR-R-G.TIF

    </FileName>

    <Plane>

    3

    </Plane>

    </DataSource>

    </DataSources>

    <BandCategory>

    HumanVisible

    </BandCategory>

    <SpecialBandName>

    Green

    </SpecialBandName>

    <UseAsLuminanceChannel>

    false

    </UseAsLuminanceChannel>

    <UseAsThreeChannelChannel>

    true

    </UseAsThreeChannelChannel>

    </SpectralBand>

    </SpectralBands>

  8. Save the file and exit.
  9. If you like, you can now use this input configuration to re-process any directory processed by the two previously-defined configurations in this tutorial, using any standard processing configuration. For example, Focused: Calculated Images, Focused: Filter Emulation, or Focused: Vegetation Indices - Standard. You won't get any new output by using a processing configuration like No Funny Business, because with only three bands to work with, the one colour image that configuration would generate has already been created.

Extra Credit Part 2: Example Processing Configuration

Optionally, create a custom processing file to generate your favourite variations that require near infrared and red source imagery. This section assumes that "your favourite variations" are the "Classic R72" filter emulation and the NDVI variation which uses the most conservative (colour-wise) gradient.

  1. In the TMSB GUI, switch to the Processing Configuration tab.
  2. In the drop-down menu, select Focused: Vegetation Indices - Standard, then click the Export XML button.
  3. In the File name field, enter Process-Custom-R72_And_NDVI.xml, then click Save.
  4. Launch your text editor and open the file you just saved.
  5. In the <Metadata> section:
    1. In the <Name> section, change the text to read Custom: Classic R72 and NDVI.
    2. In the <Description> section, change the text to Creates "Classic R72" emulated filter and gradient-mapped Normalized Difference Vegetation Index images (requires near infrared and red special bands).
    3. If you like, enter the date/time, in XML format in the <Created> and/or <LastModified> sections.
  6. In the <CustomGreyscaleChannels> section, delete everything except the first <CustomGreyscaleChannel> block (the one that defines the Calculated-NDVI_(Full_Range) image). That is, only the following should be left in this section:

     

    <CustomGreyscaleChannel>

    <ChannelName>

    Calculated-NDVI_(Full_Range)

    </ChannelName>

    <Type>

    CustomScriptCode

    </Type>

    <CustomScriptCode>

    = ndi(%SpecialBand:NearInfraredNonspecific%, %SpecialBand:Red%)

    </CustomScriptCode>

    <UseAsLuminanceChannel>

    false

    </UseAsLuminanceChannel>

    <UseAsThreeChannelChannel>

    false

    </UseAsThreeChannelChannel>

    <OutputTransformation>

    Specialized: Vegetation Index Biased Normalization

    </OutputTransformation>

    </CustomGreyscaleChannel>

  7. Delete everything in-between the <CustomThreeChannelImages> and </CustomThreeChannelImages> tags, but leave those two tags themselves in place.
  8. In the <GradientMapping> section, delete everything except the first <GradientMappedChannel> block (the one that references the Calculated-NDVI_(Full_Range) image). That is, only the following should be left in this section:

     

    <GradientMappedChannel>

    <ReferenceType>

    ChannelByName

    </ReferenceType>

    <ChannelReference>

    Calculated-NDVI_(Full_Range)

    </ChannelReference>

    <GradientName>

    Vegetation_Index_Single_Scale

    </GradientName>

    <IncludeInSecondOrderImages>

    true

    </IncludeInSecondOrderImages>

    </GradientMappedChannel>

  9. Save the file, but leave it open, because we're not done yet.
  10. In the TMSB GUI, switch to the Processing Configuration tab.
  11. In the drop-down menu, select Focused: Filter Emulation, then click the Export XML button.
  12. In the File name field, enter Process-Focused-Filter_Emulation-Temp.xml, then click Save.
  13. Launch your text editor and open the file you just saved.
  14. In the <CustomGreyscaleChannels> section, locate the three blocks which define the "Custom-R72" channels. Select all three of these blocks, copy them to the clipboard, and then paste them into the <CustomGreyscaleChannels> section of the other file that you still have open (Process-Custom-R72_And_NDVI.xml).
     
    That is, you want to copy this content from the Process-Focused-Filter_Emulation-Temp.xml file into the <CustomGreyscaleChannels> section of Process-Custom-R72_And_NDVI.xml:

     

    <CustomGreyscaleChannel>

    <ChannelName>

    Custom-R72_Classic-Red

    </ChannelName>

    <Type>

    CustomScriptCode

    </Type>

    <CustomScriptCode>

    = (pow((((%SpecialBand:NearInfraredNonspecific% * 0.8) + (%SpecialBand:Red% * 0.2))), 0.65) - 0.10) * 1.30

    </CustomScriptCode>

    <UseAsLuminanceChannel>

    false

    </UseAsLuminanceChannel>

    <UseAsThreeChannelChannel>

    false

    </UseAsThreeChannelChannel>

    <OutputTransformation>

    Clip: 0.0 - 1.0

    </OutputTransformation>

    </CustomGreyscaleChannel>

    <CustomGreyscaleChannel>

    <ChannelName>

    Custom-R72_Classic-Green

    </ChannelName>

    <Type>

    CustomScriptCode

    </Type>

    <CustomScriptCode>

    = pow(((%SpecialBand:NearInfraredNonspecific% - 0.06) / 1.02), 0.97)

    </CustomScriptCode>

    <UseAsLuminanceChannel>

    false

    </UseAsLuminanceChannel>

    <UseAsThreeChannelChannel>

    false

    </UseAsThreeChannelChannel>

    <OutputTransformation>

    Clip: 0.0 - 1.0

    </OutputTransformation>

    </CustomGreyscaleChannel>

    <CustomGreyscaleChannel>

    <ChannelName>

    Custom-R72_Classic-Blue

    </ChannelName>

    <Type>

    CustomScriptCode

    </Type>

    <CustomScriptCode>

    = pow(((%SpecialBand:NearInfraredNonspecific% - 0.01) / 0.91), 0.87) - 0.04

    </CustomScriptCode>

    <UseAsLuminanceChannel>

    false

    </UseAsLuminanceChannel>

    <UseAsThreeChannelChannel>

    false

    </UseAsThreeChannelChannel>

    <OutputTransformation>

    Clip: 0.0 - 1.0

    </OutputTransformation>

    </CustomGreyscaleChannel>

  15. In Process-Focused-Filter_Emulation-Temp.xml, scroll down to the <CustomThreeChannelImages> section. Locate the <CustomThreeChannelImage> block which defines the FC-3C-Custom-R72_Classic image (it should be the first one). Copy and paste that one block into the <CustomThreeChannelImages> section of the Process-Custom-R72_And_NDVI.xml file. That is, you should end up with a block of code that looks more or less like this in that section of Process-Custom-R72_And_NDVI.xml:

     

    <CustomThreeChannelImage>

    <UserDefinedName>

    FC-3C-Custom-R72_Classic

    </UserDefinedName>

    <RedChannelName>

    Custom-R72_Classic-Red

    </RedChannelName>

    <GreenChannelName>

    Custom-R72_Classic-Green

    </GreenChannelName>

    <BlueChannelName>

    Custom-R72_Classic-Blue

    </BlueChannelName>

    <IncludeInSecondOrderImages>

    true

    </IncludeInSecondOrderImages>

    <OutputTransformation>

    Normalize: Standard

    </OutputTransformation>

    </CustomThreeChannelImage>

  16. Save the file and exit.
  17. Delete the Process-Focused-Filter_Emulation-Temp.xml file. This is important - if you don't, you'll see duplicate entries for this configuration in TMSB. Now that you've copied what you needed out of this temporary file, you don't need it anymore.
  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 Full-Spectrum Filtered (TIFF - 1 File), if you followed all of the instructions correctly), and in the Processing Configuration tab, the drop-down should now contain a new entry (named Custom: Classic R72 and NDVI, if you followed all of the instructions correctly).
     
    Reminder: you cannot use this processing configuration with the Full-Spectrum Filtered (TIFF - 1 File) input configuration directly. You must have used that input configuration combined with the Specialized: Convert Yellow 12 Filter Images processing configuration to recover the near infrared, red, and green images before switching to the NIR-R-G (TIFF - 1 File) input configuration and the Custom: Classic R72 and NDVI processing configuration.
     
    However, this new processing configuration will work just fine with existing input configurations that define the NearInfraredNonspecific, Red, and Green special band names, like the NIR-R-G-B-UVA (TIFF - 3 Files), NIR-R-G-B-UVA (PNG - 3 Files), and OnEarth Greyscale Layer Data (TIFF - 10 Files) input configurations incuded with TMSB.
  19. If you like, give the new configurations a try, using NIR-R-G images generated from the input image set available at the bottom of this page.
 
Download
File Size Version Release Date Author
Yellow 12 Filter Example Images 7 MiB 1.0 2011-05-01 Ben Lincoln
A set of three sample images for use with the TMSB tutorial "Yellow Filter Processing". Each source image will generate output images that occupy about 2.5 MiB on disk for each variation in the selected processing configuration.
 
Footnotes
1. If someone wanted to put the time into developing this method, they could probably take it one step further: after recovering the red and green images, subtract those from the original red and green channels to obtain the near infrared data from those, and then take the median, maximum, or average to get a higher-resolution version of the image.
2. My working assumption is currently that PixelBender does something like reposition values so that none of them are negative. IE a simple example would be that if it is guaranteed that no input values are less than -1.0, then add 1.0 to everything before applying exponential functions, and subtract 1.0 afterward. Because it doesn't seem to be just applying regular math, I didn't feel like spending more time trying to reverse-engineer its bizarre behaviour.
3. Basically, the idea (in a standard red/green/blue image) is to subtract some percentage of the red channel from the green channel, that same percentage of the green channel from the red channel, some percentage of the blue channel from the green channel, that same percentage of the green channel from the blue channel, and then boost the levels of all three channels back up to compensate. I'll be posting a full description of this soon (assuming it's not already a commonly-known technique), but ran out of time while working on this update.
 
[ Page Icon ]