Homepage Demos Overview Downloads Tutorials Reference
Credits

FilterBankGenerator.h

Go to the documentation of this file.
00001 //-*-c++-*-
00002 #ifndef INCLUDED_FilterBankGenerator_h_
00003 #define INCLUDED_FilterBankGenerator_h_
00004 
00005 #include "Events/EventGeneratorBase.h"
00006 #include "Shared/LoadSave.h"
00007 
00008 //! Abstract base class for generators of FilterBankEvent's
00009 /*! This is needed to provide an interface for the FilterBankEvent to
00010  *  call back when the actual image data is requested from it.  This
00011  *  facilitates lazy calculation of image data...  no sense in
00012  *  processing layers or channels which aren't actually going to be
00013  *  used...
00014  *
00015  *  Also this way we save on allocating/deallocating large memory
00016  *  blocks on each event... the buffers allocated here can be reused
00017  *  frame to frame.
00018  *
00019  *  Larger layer indicies generally indicate higher resolution images
00020  *  in a scaling pyramid, but you are free to store your own data
00021  *  however you wish.
00022  *
00023  *  <h3>Serialization Format</h3>
00024  *
00025  *  First, be sure to get a good overview of the LoadSave style.  Most
00026  *  serialization is handled using this interface.
00027  *
00028  *  When, for instance, RawCameraGenerator::SaveBuffer() is called, it
00029  *  first calls it's super class, FilterBankGenerator::SaveBuffer(),
00030  *  which will write out the general image information, common to all
00031  *  subclasses of FilterBankGenerator. (i'll cover the specifics in a
00032  *  second) Once that's done, the RawCameraGenerator adds it's own bit
00033  *  of header and then saves the image data itself.
00034  *
00035  *  Note that only a single channel is being saved at this point.  So
00036  *  for instance, all the Y information.  No interleaving is going
00037  *  on. (unless you're saving from InterleavedYUVGenerator of course,
00038  *  which treats the 3 interleaved channels as a single image)
00039  *  Otherwise,only one image (selected with selectSaveImage()) of the
00040  *  bank will loaded or saved at a time.
00041  *  
00042  *  So, anyway.  The first header will be the same for all
00043  *  FilterBankGenerator subclasses.  In the specification below, I'm
00044  *  going to use one field per line (the new lines are not literal,
00045  *  it's a binary stream).  Each field is of the form '<@c type:name>
00046  *  <i>(notes)</i>'
00047  *  
00048  *  FilterBankGenerator Header: (from FilterBankGenerator::SaveBuffer())
00049  *  - <@c string: "FbkImage">  <i>(remember a 'string' is len+str+0; so this is the literal "\010\0\0\0FbkImage\0"; also remember "\010" is octal for 8)</i>
00050  *  - <@c unsigned @c int: width> 
00051  *  - <@c unsigned @c int: height> 
00052  *  - <@c unsigned @c int: image layer> 
00053  *  - <@c unsigned @c int: image channel> <i>(so notice you can tell which channel it is after it's been saved)</i>
00054  * 
00055  *  Generator Specific Header (selected examples follow, or similarly, any of the other generators)
00056  *  
00057  *  - RawCameraGenerator: (from RawCameraGenerator::SaveBuffer())
00058  *    - <@c string: "RawImage">
00059  *    - <<tt>char[</tt>width<tt>*</tt>height<tt>]</tt>: image data> <i>(note, just once channel being stored)</i>
00060  *  - InterleavedYUVGenerator: (from InterleavedYUVGenerator::SaveBuffer())
00061  *    - <@c string: "InterleavedYUVImage">
00062  *    - <<tt>char[</tt>width<tt>*</tt>height<tt>*3]</tt>: image data> <i>(in YVU order, technically YCbCr)</i>
00063  *  - SegmentedColorGenerator: (from SegmentedColorGenerator::SaveBuffer())
00064  *    - <@c string: "SegColorImage">
00065  *    - <<tt>char[</tt>width<tt>*</tt>height<tt>]</tt>: image data> <i>(one byte per sample)</i>
00066  *    - <@c unsigned @c int: num_cols> <i>(number of different colors available)</i>
00067  *    - for each of num_col:
00068  *      - <@c char: red> <i>red color to use for display of this index</i>
00069  *      - <@c char: green> <i>green color to use for display of this index</i>
00070  *      - <@c char: blue> <i>blue color to use for display of this index</i>
00071  *  - RLEGenerator: (from RLEGenerator::SaveBuffer())
00072  *    - <@c string: "RLEImage">  <i>(remember a 'string' is len+str+0; so this is the literal "\010\0\0\0RLEImage\0"; also remember "\010" is octal for 8)</i>
00073  *    - <@c unsigned @c int: num_runs> <i>(how many runs will follow)</i>
00074  *    - for each of num_runs:
00075  *      - <@c char: color> <i>(index value of color of run)</i>
00076  *      - <@c short: x> <i>(x position of start of run ("unknown" runs are skipped - assume index 0 for pixels which are jumped))</i>
00077  *      - <@c short: width> <i>(length of run, will not exceed remaining width of image)</i>
00078  *    - <i>notice there's no color information from RLE - it's not (shouldn't be) assuming anything about the data being compressed)</i>
00079  *
00080  *  However, while we're on the topic, I'll mention that although this
00081  *  is the same image format used for streaming to VisionGUI, there's
00082  *  a few more fields added by RawCamBehavior or SegCamBehavior at the
00083  *  beginning of each packet.  See those classes for more information
00084  *  on the wireless protocol. That should tell you everything you need
00085  *  to know to interpret the vision stream as well.
00086  *
00087  *  <h3>Adding New FilterBankGenerator Subclasses</h3>
00088  *
00089  *  If you're doing fancy memory stuff, you probably want to override
00090  *  the freeCaches() and destruct() functions so that the default
00091  *  implementation won't try to free something it shouldn't.  Don't
00092  *  forget to call them from your own destructor though, otherwise
00093  *  your versions won't get called before the default implementation's
00094  *  does.
00095  *
00096  *  If you want to be able to transmit or save your images, you will
00097  *  need to override the LoadSave functions (listed below) to provide
00098  *  your own code for interpreting the image data itself, and then
00099  *  create or modify a behavior to open a socket and transmit the
00100  *  information.  (you could do that from within the generator itself
00101  *  if you like)
00102  *
00103  *  You will probably also want to add a few extra functions to allow
00104  *  users to set compression/data format parameters.
00105  *
00106  *  @see RawCameraGenerator, SegmentedColorGenerator for the basic
00107  *  image access
00108  * 
00109  *  @see RLEGenerator, RegionGenerator for some relatively simple
00110  *  examples of vision stages if you want to make some of your own.
00111  */
00112 class FilterBankGenerator : public EventGeneratorBase, public LoadSave {
00113 public:
00114   //! constructor, calls setNumImages(1,1)
00115   FilterBankGenerator()
00116     : EventGeneratorBase(), numLayers(0), numChannels(0), widths(NULL), heights(NULL), skips(NULL), strides(NULL), increments(NULL), images(NULL), imageValids(NULL), selectedSaveLayer(0), selectedSaveChannel(0), frameNumber(0), framesProcessed(0)
00117   {
00118     setNumImages(1,1);
00119   }
00120 
00121   //! constructor
00122   FilterBankGenerator(unsigned int layers, unsigned int channels)
00123     : EventGeneratorBase(), numLayers(0), numChannels(0), widths(NULL), heights(NULL), skips(NULL), strides(NULL), increments(NULL), images(NULL), imageValids(NULL), selectedSaveLayer(0), selectedSaveChannel(0), frameNumber(0), framesProcessed(0)
00124   {
00125     setNumImages(layers,channels);
00126   }
00127 
00128   //! constructor
00129   FilterBankGenerator(const std::string& name,unsigned int layers, unsigned int channels, EventBase::EventGeneratorID_t srcgid, unsigned int srcsid, EventBase::EventGeneratorID_t mgid, unsigned int msid)
00130     : EventGeneratorBase(name,mgid,msid,srcgid,srcsid), numLayers(0), numChannels(0), widths(NULL), heights(NULL), skips(NULL), strides(NULL), increments(NULL), images(NULL), imageValids(NULL), selectedSaveLayer(0), selectedSaveChannel(0), frameNumber(0), framesProcessed(0)
00131   {
00132     setNumImages(layers,channels);
00133   }
00134 
00135   //! destructor
00136   ~FilterBankGenerator() {
00137     freeCaches();
00138     destruct();
00139   }
00140 
00141   //! returns the number of image layers (e.g. different resolutions available)
00142   virtual unsigned int getNumLayers() const { return numLayers; }
00143 
00144   //! returns the number of channels per image (e.g. Y, U, or V components)
00145   virtual unsigned int getNumChannels() const { return numChannels; }
00146   
00147   //! returns pointer to the beginning of the image data for the specified layer and channel
00148   /*! this will cause the data to be calculated and cached if it's not already available */
00149   virtual unsigned char * getImage(unsigned int layer, unsigned int channel) const;
00150 
00151   //! returns width (in samples) of the image in a given layer
00152   unsigned int getWidth(unsigned int layer) const { return widths[layer]; }
00153 
00154   //! returns height (in samples) of the image in a given layer
00155   unsigned int getHeight(unsigned int layer) const { return heights[layer]; }
00156   
00157   //! returns the bytes to skip from the one-past-end of a row to get the beginning of the next
00158   unsigned int getSkip(unsigned int layer) const { return skips[layer]; }
00159   
00160   //! returns the bytes to skip from the beginning of one row to get the beginning of the next
00161   /*! This is just for convenience; the stride is just the skip plus the width, but it's precomputed for you for speed and clarity */
00162   unsigned int getStride(unsigned int layer) const { return strides[layer]; }
00163 
00164   //! returns the increment (in bytes) to use to go from one sample to the next
00165   unsigned int getIncrement(unsigned int layer) const { return increments[layer]; }
00166   
00167   //! returns the frame number of the current frame, see #frameNumber
00168   unsigned int getFrameNumber() const { return frameNumber; }
00169   
00170   //! returns the number of frames processed, see #framesProcessed
00171   unsigned int getFramesProcessed() const { return framesProcessed; }
00172   
00173   //! deletes storage of cached images and marks it invalid
00174   /*! you should override this if the images cache pointer isn't actually an array of bytes... 
00175    *  Don't forget to call it in your subclass's destructor or your version won't get called... */
00176   virtual void freeCaches();
00177 
00178   //! marks all of the cached images as invalid (but doesn't free their memory)
00179   /*! You probably want to call this right before you send the FilterBankEvent */
00180   virtual void invalidateCaches();
00181 
00182   //! default implementation ignore events, just so you don't have to define it if you don't receive events
00183   virtual void processEvent(const EventBase & /*event*/) {}
00184   
00185   //!@name LoadSave interface
00186 
00187   virtual unsigned int getBinSize() const;
00188 
00189   virtual unsigned int LoadBuffer(const char buf[], unsigned int len);
00190 
00191   virtual unsigned int SaveBuffer(char buf[], unsigned int len) const;
00192 
00193   //! not actually part of the LoadSave interface, but allows you to select which image of the bank will be saved
00194   /*! when loading, the saved image's layer and channel will reset this */
00195   virtual void selectSaveImage(unsigned int layer, unsigned int channel) { selectedSaveLayer=layer; selectedSaveChannel=channel; }
00196 
00197   virtual unsigned int getSelectedSaveLayer() const { return selectedSaveLayer; } //!< returns layer to be saved, or layer of last image loaded
00198   virtual unsigned int getSelectedSaveChannel() const { return selectedSaveChannel; } //!< returns channel to be saved, or channel of last image loaded
00199 
00200   //@}
00201 
00202 
00203 protected:
00204   //! resizes the filter bank information storage area, you should override this to do your setup and call it from your constructor
00205   /*! In general, it isn't expected that FilterBankGenerator's should
00206    *  necessarily be dynamically resizeable (although it would be
00207    *  nice), which is why this isn't public.  If yours is, just add
00208    *  some pubic accessor functions which call this.  In general, the
00209    *  included subclasses should be able to handle being resized, but
00210    *  there's no reason to do so since the system won't be changing
00211    *  its available resolutions at run time. */
00212   virtual void setNumImages(unsigned int nLayers, unsigned int nChannels);
00213 
00214   //! create new image data storage area for the cache - this called by getImage() only when the corresponding entry in images is NULL
00215   /*! You should return the pointer you want stored in images to be
00216    *  returned by any calls to getFirstRow.  Interpretation of the
00217    *  data it points to is dependant on the the generator which
00218    *  creates it */
00219   virtual unsigned char * createImageCache(unsigned int layer, unsigned int channel) const=0;
00220 
00221   //! should calculate new image data, called by getImage() only when #imageValids indicates the image being requested is dirty (and only after getImage() has already called createImageCache())
00222   /*! This is where you'll want to put your user-specific code for calculating the image data */
00223   virtual void calcImage(unsigned int layer, unsigned int channel) const=0;
00224 
00225   //! deletes the arrays
00226   virtual void destruct();
00227 
00228   unsigned int numLayers;   //!< current number of layers available
00229   unsigned int numChannels; //!< current number of channels available
00230 
00231   unsigned int * widths;    //!< an array of size numLayers, width (in samples) in pixels of each layer
00232   unsigned int * heights;   //!< an array of size numLayers, height (in samples) in pixels of each layer
00233   unsigned int * skips;     //!< an array of size numLayers, skip (in bytes) from row end to next row begin
00234   unsigned int * strides;   //!< an array of size numLayers, stride (in bytes) from a given column in one row to the same column in the next row
00235   unsigned int * increments;//!< an array of size numLayers, increment (in bytes) to use to get from one sample to the next
00236   
00237   mutable unsigned char *** images; //!< an array [numLayers][numChannels], stores pointer to cached image data
00238   mutable bool ** imageValids;      //!< an array [numLayers][numChannels], entry is true if cached data is still valid
00239 
00240   unsigned int selectedSaveLayer;   //!< layer to be manipulated with the LoadSave functions
00241   unsigned int selectedSaveChannel; //!< channel to be manipulated with the LoadSave functions
00242 
00243   //! the current frame number - subclasses will need to set to the source's frameNumber when they receive a new frame (probably from processEvent()) 
00244   /*! The idea is to use this as a unique serial number for each
00245    *  frame.  That way you can know if the current image in different
00246    *  generators is actually the same camera image before you try to
00247    *  compare or combine them.
00248    *
00249    *  You could also figure out the number of dropped frames by
00250    *  subtracting framesProcessed from this value.  Give some leeway
00251    *  however, because it takes the first 40-70 frames just to boot
00252    *  up, so there's no way they can be processed.
00253    */
00254   unsigned int frameNumber; 
00255   unsigned int framesProcessed; //!< subclasses should increment this any time they make a new filter bank available (probably by throwing an event)
00256 
00257 private:
00258   FilterBankGenerator(const FilterBankGenerator& fbk); //!< don't call
00259   const FilterBankGenerator& operator=(const FilterBankGenerator& fbk); //!< don't call
00260 };
00261 
00262 /*! @file
00263  * @brief Describes abstract base class for generators of FilterBankEvent's
00264  * @author ejt (Creator)
00265  *
00266  * $Author: ejt $
00267  * $Name: tekkotsu-2_0_1+Doc $
00268  * $Revision: 1.12 $
00269  * $State: Exp $
00270  * $Date: 2004/02/05 23:33:48 $
00271  */
00272 
00273 #endif

Tekkotsu v2.0.1+Doc
Generated Mon Feb 9 22:16:49 2004 by Doxygen 1.3.5