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
00115   FilterBankGenerator()
00116     : EventGeneratorBase(), src(NULL), 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 
00119   //! constructor
00120   FilterBankGenerator(const std::string& name,EventBase::EventGeneratorID_t srcgid, unsigned int srcsid, EventBase::EventGeneratorID_t mgid, unsigned int msid)
00121     : EventGeneratorBase(name,mgid,msid,srcgid,srcsid), src(NULL), 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)
00122   { }
00123 
00124   //! destructor
00125   /*! Your own subclasses should also have destructors which call
00126    *  freeCaches() and destruct().  Otherwise, if you override these
00127    *  functions to delete any custom memory you allocate, those
00128    *  implementations won't be called by this destructor... a
00129    *  destructor ignores virtual functions, only calls at its own
00130    *  class level.\n
00131    *  So it really doesn't matter if you aren't allocating any extra
00132    *  memory other than what's in the image cache, but it's still good
00133    *  form just in case you add stuff later so you won't forget and
00134    *  leak memory everywhere */
00135   virtual ~FilterBankGenerator() {
00136     freeCaches();
00137     destruct();
00138   }
00139 
00140   //! returns the generator this is receiving its events from (or the last one anyway)
00141   virtual const FilterBankGenerator * getSourceGenerator() const { return src; }
00142 
00143   //! returns the number of image layers (e.g. different resolutions available)
00144   virtual unsigned int getNumLayers() const { return numLayers; }
00145 
00146   //! returns the number of channels per image (e.g. Y, U, or V components)
00147   virtual unsigned int getNumChannels() const { return numChannels; }
00148   
00149   //! returns pointer to the beginning of the image data for the specified layer and channel
00150   /*! this will cause the data to be calculated and cached if it's not already available */
00151   virtual unsigned char * getImage(unsigned int layer, unsigned int channel) const;
00152 
00153   //! returns width (in samples) of the image in a given layer
00154   unsigned int getWidth(unsigned int layer) const { return widths[layer]; }
00155 
00156   //! returns height (in samples) of the image in a given layer
00157   unsigned int getHeight(unsigned int layer) const { return heights[layer]; }
00158   
00159   //! returns the bytes to skip from the one-past-end of a row to get the beginning of the next
00160   unsigned int getSkip(unsigned int layer) const { return skips[layer]; }
00161   
00162   //! returns the bytes to skip from the beginning of one row to get the beginning of the next
00163   /*! This is just for convenience; the stride is just the skip plus the width, but it's precomputed for you for speed and clarity */
00164   unsigned int getStride(unsigned int layer) const { return strides[layer]; }
00165 
00166   //! returns the increment (in bytes) to use to go from one sample to the next
00167   unsigned int getIncrement(unsigned int layer) const { return increments[layer]; }
00168   
00169   //! returns the frame number of the current frame, see #frameNumber
00170   unsigned int getFrameNumber() const { return frameNumber; }
00171   
00172   //! returns the number of frames processed, see #framesProcessed
00173   unsigned int getFramesProcessed() const { return framesProcessed; }
00174   
00175   //! deletes storage of cached images and marks it invalid
00176   /*! you should override this if the images cache pointer isn't actually an array of bytes... 
00177    *  Don't forget to call it in your subclass's destructor or your version won't get called... */
00178   virtual void freeCaches();
00179 
00180   //! marks all of the cached images as invalid (but doesn't free their memory)
00181   /*! You probably want to call this right before you send the FilterBankEvent */
00182   virtual void invalidateCaches();
00183 
00184   //! default implementation does a few common housekeeping chores for you - probably should just take a look at its code
00185   /*! It doesn't throw any events for you - that's probably the main
00186    *  reason you'd still want to override it\n
00187    *  Also, if your class has a set number of layers or channels - for
00188    *  instance, always 1 channel like InterleavedYUVGenerator, you
00189    *  should override setNumImages() to enforce that constraint by
00190    *  throwing away the appropriate argument and passing the your own
00191    *  value to the superclass implementation.*/
00192   virtual void processEvent(const EventBase & event);
00193   
00194   //!@name LoadSave interface
00195 
00196   virtual unsigned int getBinSize() const;
00197 
00198   virtual unsigned int LoadBuffer(const char buf[], unsigned int len);
00199 
00200   virtual unsigned int SaveBuffer(char buf[], unsigned int len) const;
00201 
00202   //! not actually part of the LoadSave interface, but allows you to select which image of the bank will be saved
00203   /*! when loading, the saved image's layer and channel will reset this */
00204   virtual void selectSaveImage(unsigned int layer, unsigned int channel) { selectedSaveLayer=layer; selectedSaveChannel=channel; }
00205 
00206   virtual unsigned int getSelectedSaveLayer() const { return selectedSaveLayer; } //!< returns layer to be saved, or layer of last image loaded
00207   virtual unsigned int getSelectedSaveChannel() const { return selectedSaveChannel; } //!< returns channel to be saved, or channel of last image loaded
00208 
00209   //@}
00210 
00211 
00212 protected:
00213   //! resizes the filter bank information storage area, you should override this to do your setup and call it from your constructor
00214   /*! In general, it isn't expected that FilterBankGenerator's should
00215    *  necessarily be dynamically resizeable (although it would be
00216    *  nice), which is why this isn't public.  If yours is, just add
00217    *  some pubic accessor functions which call this.  In general, the
00218    *  included subclasses should be able to handle being resized, but
00219    *  there's no reason to do so since the system won't be changing
00220    *  its available resolutions at run time. 
00221    *
00222    *  The default implementation is a no-op if(numLayers==nLayers && numChannels==nChannels)
00223    */
00224   virtual void setNumImages(unsigned int nLayers, unsigned int nChannels);
00225 
00226   //! resets width and height parameters to that of the #src
00227   /*! You'll probably want to override this to also set #skip and #stride */
00228   virtual void setDimensions();
00229   
00230   //! create new image data storage area for the cache - this called by getImage() only when the corresponding entry in images is NULL
00231   /*! You should return the pointer you want stored in images to be
00232    *  returned by any calls to getFirstRow.  Interpretation of the
00233    *  data it points to is dependant on the the generator which
00234    *  creates it */
00235   virtual unsigned char * createImageCache(unsigned int layer, unsigned int channel) const=0;
00236 
00237   //! 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())
00238   /*! This is where you'll want to put your user-specific code for calculating the image data */
00239   virtual void calcImage(unsigned int layer, unsigned int channel) const=0;
00240 
00241   //! deletes the arrays
00242   virtual void destruct();
00243 
00244   const FilterBankGenerator * src; //!< the generator of the last FilterBankEvent received
00245 
00246   unsigned int numLayers;   //!< current number of layers available
00247   unsigned int numChannels; //!< current number of channels available
00248 
00249   unsigned int * widths;    //!< an array of size numLayers, width (in samples) in pixels of each layer
00250   unsigned int * heights;   //!< an array of size numLayers, height (in samples) in pixels of each layer
00251   unsigned int * skips;     //!< an array of size numLayers, skip (in bytes) from row end to next row begin
00252   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
00253   unsigned int * increments;//!< an array of size numLayers, increment (in bytes) to use to get from one sample to the next
00254   
00255   mutable unsigned char *** images; //!< an array [numLayers][numChannels], stores pointer to cached image data
00256   mutable bool ** imageValids;      //!< an array [numLayers][numChannels], entry is true if cached data is still valid
00257 
00258   unsigned int selectedSaveLayer;   //!< layer to be manipulated with the LoadSave functions
00259   unsigned int selectedSaveChannel; //!< channel to be manipulated with the LoadSave functions
00260 
00261   //! the current frame number - subclasses will need to set to the source's frameNumber when they receive a new frame (probably from processEvent()) 
00262   /*! The idea is to use this as a unique serial number for each
00263    *  frame.  That way you can know if the current image in different
00264    *  generators is actually the same camera image before you try to
00265    *  compare or combine them.
00266    *
00267    *  You could also figure out the number of dropped frames by
00268    *  subtracting framesProcessed from this value.  Give some leeway
00269    *  however, because it takes the first 40-70 frames just to boot
00270    *  up, so there's no way they can be processed.
00271    */
00272   unsigned int frameNumber; 
00273 
00274   //! subclasses should increment this any time they make a new filter bank available
00275   /*! this is automatically incremented if you use the FilterBankGenerator::processEvent() */
00276   unsigned int framesProcessed; 
00277 
00278 private:
00279   FilterBankGenerator(const FilterBankGenerator& fbk); //!< don't call
00280   const FilterBankGenerator& operator=(const FilterBankGenerator& fbk); //!< don't call
00281 };
00282 
00283 /*! @file
00284  * @brief Describes abstract base class for generators of FilterBankEvent's
00285  * @author ejt (Creator)
00286  *
00287  * $Author: ejt $
00288  * $Name: tekkotsu-2_2 $
00289  * $Revision: 1.13 $
00290  * $State: Exp $
00291  * $Date: 2004/02/18 21:13:32 $
00292  */
00293 
00294 #endif

Tekkotsu v2.2
Generated Tue Oct 19 14:19:14 2004 by Doxygen 1.3.9.1