Core Optical, Inc.
SubBandProcessor ClassIndustrial Strength, Scientific Grade
The root abstract class for all sub-band processing objects.
Inheritance Hierarchy

OnlineSystem Object
  PrecisionImage.WaveletProcessing SubBandProcessor
    PrecisionImage.WaveletProcessing BAYESShrinkOperator
    PrecisionImage.WaveletProcessing SUREShrinkOperator

Namespace: PrecisionImage.WaveletProcessing
Assembly: PrecisionImage (in PrecisionImage.dll) Version: 2.0.0.0 (2.0.0.0)
Syntax

public abstract class SubBandProcessor
Remarks

The SubBandProcessor class is an abstract type that enables custom adaptive processing of wavelet coefficient sub-bands. By inheriting the SubBandProcessor class and overriding the ProcessSubBand(Int32, Int32, Int32, Int32, Int32,  Single ) method, consuming code can adaptively process the wavelet coefficient sub-bands efficiently and in parallel.

Objects inherting the SubBandProcessor type are passed into the ProcessSubBands(SourceData, Int32, SourceData, Int32, Int32, Int32, Int32, SubBandProcessor) method. Internally, the DiscreteWaveletTransform and/or DiscreteWaveletPacketTransform objects pass the wavelet coefficients from each sub-band into the ProcessSubBand(Int32, Int32, Int32, Int32, Int32,  Single ) method along with the decomposition level the coefficients originate from, the dimensions of the sub-band (width and height), the array containing the coefficient values, and the sub-band row and column. Each sub-band is assigned a thread so the bands are processed in parallel. This means, of course, that the order in which the sub-bands are processed is non-deterministic.

The row/column values refer to the sub-band row and column within a given decomposition level. For data that has undergone a forward discrete wavelet transformation, only the final decomposition level contains both row and column of zero i.e coordinate (0,0). The (row,column) layout is illustrated in the following image for data decomposed via DWT to 3 decomposition levels and DWPT to 2 decomposition levels. "L1/2/3" refers to the decomposition level, and "(0,1)" refers to the (row,column) coordinates within the level. For example, the diagonal fluctuation coefficients for the 2nd decomposition level in the DWT data is denoted as "L2 (1,1)".

During runtime processing, when the ProcessSubBand(Int32, Int32, Int32, Int32, Int32,  Single ) method is invoked for this particular sub-band (level 2, diagonal), the "decompositionLevel" input argument will have the value 2, "subBandRow" and "subBandColumn" will both have the value 1, "subBandWidth" and "subbandHeight" will contain the data columns and rows of the sub-band, and "coefficientValue" will contain the actual coefficient data from the sub-band.

Examples

The first example uses one of the built-in sub-band processor objects (BAYESShrinkOperator) to perform band-adaptive thresholding of an x-ray corrupted with gaussian noise. A forward 3-level DWT is performed on the x-ray and the noise is estimated using Donoho's robust median estimator (the noise standard deviation can be estimated by dividing the median absolute value of the level-1 diagonal fluctuation coefficients by 0.6745). A BAYESShrinkOperator sub-band processor is instantiated using this estimated noise level and passed into ProcessSubBands(SourceData, Int32, SourceData, Int32, Int32, Int32, Int32, SubBandProcessor). An inverse DWT is then performed on the thresholded data to retrieve the denoised image.
using PrecisionImage;
using PrecisionImage.WaveletProcessing;
using PrecisionImage.WaveletProcessing.Wavelets;

// Load the image into a SourceData object: 
Uri imageUri              = new Uri("NoisyXray.tif", UriKind.Relative);
TiffBitmapDecoder decoder = new TiffBitmapDecoder(imageUri, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
BitmapSource sourceImage  = decoder.Frames[0];
SourceData dataSource     = new SourceData(sourceImage, GammaEncoding.None);

// Instantiate a DWT object and the Cohen-Daubechies-Feauveau 9/7 wavelet object to use with it; 
DiscreteWaveletTransform transform = new DiscreteWaveletTransform();
CDF97 wavelet = new CDF97();

// Set the decomposition levels as well as the processing start and stop levels: 
Int32 decompLevels         = 3;
Int32 processingStartLevel = 1;
Int32 processingStopLevel  = decompLevels;

// Perform a forward DWT in-place to 3 levels of decomposition:
transform.ComputeForwardDWT(dataSource, 0, dataSource, 0, wavelet, decompLevels);

// Instantiate a Utility object and get the median absolute value of the level-1 diagonal sub-band:
Utilitites utilities            = new Utilities();
Int32Rect diagonalSubBandCoords = transform.GetSubBandCoordinates(dataSource, 1, DWTSubBand.DiagonalFluctuation);
Single AbsMedianValue           = utilities.GetMedianAbsoluteValue(dataSource, 0, diagonalSubBandCoords);

// Instantiate a BAYESShrink object initialized with the noise estimate: 
BAYESShrinkOperator processor = new BAYESShrinkOperator(AbsMedianValue / 0.6745f);

// Process sub-band levels 1-3 in-place using the BAYESShrink adaptive threshold operator:
transform.ProcessSubBands(dataSource, 0, dataSource, 0, decompLevels, processingStartLevel, processingStopLevel, processor);

// Retrieve the de-noised image by in-place inverse DWT:
transform.ComputeInverseDWT(dataSource, 0, dataSource, 0, wavelet, decompLevels);

// Display the denoised x-ray in an Image control:
image.Source = datasource.GetChannelImage(GrayBitDepth.EightBit, 0, GammaEncoding.None);

The following image shows the original noisy x-ray before and after BayesShrink adaptive thresholding:

The prevous example used the BAYESShrinkOperator to apply the Bayes wavelet-shrinking operation with a noise level estimated using the diagonal fluctuation coefficients in the level-1 sub-band. This second example shows how to implement custom logic when processing the coefficient sub-bands. In this example, a noise estimation is generated for each sub-band and used to apply a band-specific soft threshold operation.

using PrecisionImage;
using PrecisionImage.WaveletProcessing;


// Declare a new class (somewhere in your project) that inherits the SubBandProcessor type and override the ProcessSubBand method to  
// implement the band-specific logic: 

public class BandLocalSoftThreshold : SubBandProcessor
{

    // A property for passing state information to the object at runtime: 
    public Int32 Dimension { get; set; }

    public override void ProcessSubBand(int decompositionLevel, int subBandRow, int subBandColumn, int subBandWidth, int subBandHeight, float[] coefficientValues)
    {

        // Make sure the current sub-band isn't the average sub-band (average sub-band has (row,column) coordinates (0,0)) 
        // and that there are at least 4 coefficients: 
        if((subBandRow != 0 || subBandColumn != 0) && coefficientValues.Length >= 4)
        {    
            // Estimate the band-local noise from the sub-band coefficients using Donoho's  
            // estimator (the median of the absolute values divided by 0.6745). 

            Single[] absCoefficients = new Single[coefficientValues.Length]; 

            // Compute absolute values of the coefficients: 
            for(Int32 x = 0; x < coefficientValues.Length; x++){ absCoefficients[x] = Math.Abs(coefficientValues[x]); } 

            // Sort the absolute values in ascending order: 
            Array.Sort(absCoefficients);

            // Get the median value by computing the average of the two central coefficients in the array: 
            Int32 Index      = absCoefficients.Length / 2;
            Single AbsMedian = (absCoefficients[Index] + absCoefficients[Index - 1]) * 0.5f;

            // Estimate the noise: 
            Single NoiseStdDev = AbsMedian / 0.6745f;

            // Compute the threshold using the a modified base threshold approach of Donoho et al: 
            Single BandThreshold = 0.125f * NoiseStdDev * (Single)Math.Sqrt(2 * Math.Log(Dimension));

            // Apply a soft threshold using the noise value: 
            for(Int32 x = 0; x < coefficientValues.Length; x++)
            {
                if(coefficientValues[x] >= BandThreshold)
                {
                    coefficientValues[x] = coefficientValues[x] - NoiseStdDev;
                }
                else if(coefficientValues[x] <= -BandThreshold)
                {
                    coefficientValues[x] = coefficientValues[x] + NoiseStdDev;
                }
                else
                {
                    coefficientValues[x] = 0.0f;
                }
            }
        }
    }
}

Now use the above class to process the coefficient sub-bands:

using PrecisionImage;
using PrecisionImage.WaveletProcessing;
using PrecisionImage.WaveletProcessing.Wavelets;


// Load the image into a SourceData object: 
Uri imageUri              = new Uri("NoisyXray.tif", UriKind.Relative);
TiffBitmapDecoder decoder = new TiffBitmapDecoder(imageUri, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
BitmapSource sourceImage  = decoder.Frames[0];
SourceData dataSource     = new SourceData(sourceImage, GammaEncoding.None);

// Instantiate a DWT object and the Cohen-Daubechies-Feauveau 9/7 wavelet object to use with it; 
DiscreteWaveletTransform transform = new DiscreteWaveletTransform();
CDF97 wavelet = new CDF97();

// Set the decomposition levels as well as the processing start and stop levels: 
Int32 decompLevels         = 3;
Int32 processingStartLevel = 1;
Int32 processingStopLevel  = decompLevels;

// Perform a forward DWT in-place to 3 levels of decomposition:
transform.ComputeForwardDWT(dataSource, 0, dataSource, 0, wavelet, decompLevels);

// Process the forward transformed data in-place with the custom sub-band processor class defined above:
transform.ProcessSubBands(dataSource, 0, dataSource, 0, decomplevels, processingStartLevel, processingStopLevel, new BandLocalSoftThreshold());

// Retrieve the result via in-palce inverse DWT:
transform.ComputeInverseDWT(dataSource, 0, dataSource, 0, decompLevels, wavelet);

// Display the processed x-ray in an Image control:
image.Source = datasource.GetChannelImage(GrayBitDepth.EightBit, 0, GammaEncoding.None);

The following image shows the original x-ray before and after custom sub-band processing:

See Also