Writing Your Own Simple Image Processing Filter

Prepared by Garrett Potts

ImageLinks, Inc

We will take you through the steps to writing your first filter and adding it to the factory so it can be saved and loaded through the factory interface. We will show you both 1 ) through the shared library plugin support and 2) through manual editing of the internal OSSIM factories. We will start with a simple filter that takes all bands and performs a weighted average on them and outputs a single band. Our filter should work with any data type such as uchar, sint16, uint16, float(and normalized float), double (and normalized doubles). For this filter we have two ways to do this: 1) normalize the input data, do the weighted average on the normalized data, and unnormalize back to its original type and make sure all values keep to within the min max values, or 2) use a template method to operate within native scalar types. If we choose option 1 we will need to allocate 2 buffers, one for output and one for normalization, but if we choose option 2 we will only have a single tile buffered. For this filter we chose option 2. If you want to see examples of option 1 for normalizing the input just look at src/ossim_core/imaging/ossimScalarRemapper The min max for weighted average should not occure if all weights sum to 1. We will gurantee that all weights sum to 1. For complete code see src/examples/tutorial/ossimBandAverageFilter.h(.cc) and src/examples/tutorial/band_average.cc for example use of the filter.

1. Choosing a base class for our filter

   Since this is a single input in filter we will derive from ossimImageSourceFilter since it already implements the basic setting up the input connection and copying the pointer to an internal pointer call theInputConnection. It will also pass most of the requests to the input. Based on the description of the filter we will need to override the following: 1) getTile method for getting the data being filtered, 2) load and save state methods for being able to load and save the state of our new object, 3) get number of output bands method since we are going to always output a single band output, 4) general access methods for our internal attributes, and 5) getMinPixelValue, getMaxPixelValue and getNullPixelValue We will use a vector of doubles for the weights of each band. It will be up to us to make sure this array is of the correct size (i.e. Size is equal to the number of input bands). We will use two ossimImageData objects where one is for the outputtile which we will cal theTile and one is the normalized buffer which we will call theNormBufferTile.

2. getTile method

   This will be the main filtering algorithm. We must perform several checks before we actually execute the filter: 1) We need to see if there is an input to grab data from, 2) we need to see if our filter is actually enabled or not, 3) we need to see if any needed buffer data has been allocated, and 4) finally we need to set the output data rectangle. Please see source for complete implementation

3. Load and Save State Methods

   These methods are very important to allow your filter to be constructed from a keywordlist ( please see kwl.cc for sample usage of the keywordlist). For a reminder, a keywordlist is no more than unique name value pairs that identify all attributes within the system and your filter is just one of many attributes that might exist in any of the ossim applications. We will store the weights used in the weighted average into a string list of weights. Please see the filter source for detailed implementation.

4. getNumberOfOutputBands method

   Since our filter can be enabled and disabled this should return 1 if our filter is enabled. If our filter is not enabled we will need to return theInputConnection's getNumberOfOutputBands (Please see the filter source for detailed implementation).

5. getMinPixelValue, getMaxPixelValue, and getNullPixelValue

   These are important since we are taking multiple bands of data and collapsing it to a single band. Since each band can have a differnet min and max null pix of the first band. Really the NULL pixel value should be the same for al and null we need to keep it consistent. Our min output should be the min of all bands and the max should be the max of all bands and we will use the l bands.

6. Adding to the factory by Editing the Factory Manually

   Since this is a filter we will add it to the src/ossim_core/imaging/factory/ossimImageSourceFactory.cc file. Add your filter class name in the getTypeNameList and then add your filter to the createObject method. Note, the getTypeNameList uses the RTTI class name of the object. If you look at the bottom of the ossimBandAverageFilter.h file you will see TYPE_DATA and this declares the RTTI support for your class. If you look close to the top of ossimBandAverageFilter.cc file you will see RTTI_DEF1 that defines the RTTI support for your class where the 1 is the number of classes you are deriving from (please see code for implementation). The RTTI is very important since I use it to help uniquely id your new class since no 2 classes can have the same name in ossim. Once this is complete you now can compile OSSIM with the new filter and then access it through the factory.

7. Adding to the Factory through shared library

   You also have the option of placing your filter into a shared library and using the OSSIM plugin bridge to get access to code that instantiates you filter. It is important to note that this has only been tested under Linux using .so interface. I still need to test this in a .dll file found under windows and .dylib found under macs. The plugin interface is demonstrated in the src/examples/tutorial/ossimSharedBandAverageFilter.h(.cc) file. The shared support code for OSSIM bridge is located at the bottom of the .cc file. It is fully documented to specify what each line is doing. Use the shared_band_average application found in the same directory to demonstrate the loading of the shared library. OSSIM has a concept of a preference file and the current preferences and documentation can be found in the file ossim/etc/templates/ossim_preferences_template. For you convenience I have copied a preference file to the tutorial directory and only have the single plugin file. You wil have to change the path to match your location. The preference file found in the template directory shows you how to setup OSSIM to recognize the template file. Within the template is an explanation on how to add your plugin to be loaded by any OSSIM app that calls the ossimInit initialize code. Once this is done and if it is done correctly you should be able to run the application. To test the plugin to see if it is actually visible through the factory just run: shared_band_average -P<full path and filename of preference> . If it was done correctly then you should see it print out that it was able to construct ossimSharedBandAverageFilter else it will say unable to create it. Try running the application without specifying the preference file. You should see that it was unable to create the object of that type.