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

Tekkotsu v2.2.1
Generated Tue Nov 23 16:36:38 2004 by Doxygen 1.3.9.1