Logo Search packages:      
Sourcecode: passage version File versions  Download package

Image.h

/*
 * Modification History
 *
 * 2000-December-21           Jason Rohrer
 * Created. 
 *
 * 2001-January-6       Jason Rohrer
 * Fixed a bug in filter( ChannelFilter * ).
 * Set mSelection to NULL by default.
 *
 * 2001-January-10            Jason Rohrer
 * Made class serializable. 
 *
 * 2001-January-15            Jason Rohrer
 * Made copy() not-virtual, so it can be overridden by subclasses 
 * while allowing pointer type to determine which function 
 * implementation is invoked. 
 *
 * 2001-January-31            Jason Rohrer
 * Fixed a bug in copy().
 *
 * 2001-February-3            Jason Rohrer
 * Updated serialization code to use new interfaces. 
 *
 * 2001-February-4            Jason Rohrer
 * Rewrote the serialization code to send the image across as a byte
 * array with one byte per channel.  This will reduce the transfer size by
 * a factor of 8.  Keeping images in double format is convennient for image
 * creation, but the added quality never affects the end user anyway, so
 * there's no point in sending the extra data to a stream.
 * Removed an unused array allocation.
 *
 * 2005-February-21           Jason Rohrer
 * Made destructor virtual to avoid compiler warnings.
 *
 * 2006-August-25       Jason Rohrer
 * Made zero init of pixels optional (for speed).
 */
 
 
#ifndef IMAGE_INCLUDED
#define IMAGE_INCLUDED

#include <stdio.h> 
#include <string.h>
 
#include "ChannelFilter.h"

#include "minorGems/io/Serializable.h"
 
/**
 * A multi-channel, double-valued image.
 *
 * Is Serializable.  Note that a serialized image doesn't have a selection.
 *
 * @author Jason Rohrer 
 */
00058 class Image : public Serializable { 
      
      public:
            
            /**
             * Constructs an image.
             *
             * @param inWidth width of image in pixels.
             * @param inHeight height of image in pixels.
             * @param inNumChannels number of channels in image.
         * @param inStartPixelsAtZero true to initialize all pixels
         *   to zero, or false to leave default memory values (garbage)
         *   in place (pixels must be initialized by caller in this case).
         *   Defaults to true.
             */
            Image( int inWidth, int inHeight, int inNumChannels,
               char inStartPixelsAtZero = true );
            
            
            virtual ~Image();
            
            
            // gets the dimensions of this image.
            virtual long getWidth();
            virtual long getHeight();
            virtual long getNumChannels();
            
            /**
             * Gets the values of a particular channel.
             *
             * Values are not copied.
             *
             * @param inChannel the channel to get.
             * 
             * @return the values of the specified channel in row-major order.
             */
            virtual double *getChannel( int inChannel );
             
            
            /**
             * Selects a region of the image.  Default is a clear selection,
             * which means all regions of image are affected by an applied
             * filter.
             *
             * @param inSelection the image to use as the selection mask.
             *   Values of 0 indicate pixels that are not selection, and 1
             *   indicate pixels that are selected, with selection amount
             *   varying linearly between 0 and 1.
             *   If inSelection is a single channel, then that channel is 
             *   used as a selection mask for all channels in this image.
             *   If inSelection contains the same number of channels as this 
             *   image, then the corresponding channels of inSelection are
             *   are used to mask each channel of this image.
             *   If inSelection contains a number of channels different
             *   from the number in this image, the first channel of inSelection
             *   is used to mask each channel in this image.
             *
             * Note that inSelection is not copied or destroyed by this class.
             * Thus, modifying inSelection after calling setSelection will
             * modify the selection in this image.
             */
            virtual void setSelection( Image *inSelection );
            
            
            
            /**
             * Gets the selection for this image.
             *
             * @return the selection for this image.  Returns NULL
             *   if there is no selection.  Must not be destroyed
             *   by caller before calling clearSelection.
             */
            virtual Image *getSelection();
            
            
            
            /**
             * Clears the selection.  Effectively selects the entire image.
             */
            virtual void clearSelection();
            
            
            /**
             * Applies a filter to the selected region of 
             * a specified channel of this image.
             *
             * @param inFilter the filter to apply.
             * @param inChannel the channel to filter.
             */
            virtual void filter( ChannelFilter *inFilter, int inChannel );
            
             
            /**
             * Applies a filter to the selected region of 
             * all channels of this image.
             *
             * @param inFilter the filter to apply.
             */
            virtual void filter( ChannelFilter *inFilter );
            
            
            /**
             * Copies the selected region of this image.  Not virtual,
             * so can be overridden by subclasses while allowing pointer
             * type to determine which function implementation is invoked.
             *
             * @return a new image with the same number of channels
             *   as this image, each containing the selected region
             *   from each corresponding channel of this image.  Unselected
             *   regions are set to black.  Returned image has no selection.
             */
            Image *copy();
            
            
            /**
             * Pastes the selected region from another image into
             * the selected region of this image.
             *
             * @param inImage the image to paste.  Let c be the number
             *   of channels in this image, and cp be the number
             *   of channels in the image being pasted.
             *   If c<cp, then only the first c channels of inImage
             *   are pasted.  If c>cp, then only the first cp channels
             *   of this image are pasted into.
             */
            virtual void paste( Image *inImage );
            
            
            /**
             * Copies the data from the selected region of a channel.
             *
             * @param inChannel the channel to copy.
             *
             * @return a copy of the channel data.  Must be destroyed
             *   by the caller.
             */
            virtual double *copyChannel( int inChannel );
            
            
            
            /**
             * Pastes channel data into the selected region of a specified channel.
             *
             * @param inChannelData an array containing the channel 
             *   data to be pasted.  Must be destroyed by caller.
             * @param inChannel the channel to paste into.
             */
            virtual void pasteChannel( double *inChannelData, int inChannel );
            
      
            /**
             * Gets the mask for a specified channel.
             *
             * @param inChannel the channel to get a mask for.
             *
             * @return the mask data for the specified channel.
             *   If selection has the same number of channels as this image
             *   then a different mask is returned for each channel.  Otherwise,
             *   the first channel from the selection is returned as the
             *   mask for every channel.  Returns NULL if there is no selection.
             */
            virtual double *getChannelSelection( int inChannel );
            
            
            // implement the Serializable interface
            virtual int serialize( OutputStream *inOutputStream );
            virtual int deserialize( InputStream *inInputStream );
      
      protected:
            long mWide, mHigh, mNumPixels, mNumChannels;
            
            double **mChannels;
            
            // NULL if nothing selected.
            Image *mSelection;
            
            
            
            
            
            /**
             * Pastes masked channel data into the selected region of a 
             * specified channel.
             *
             * @param inChannelData an array containing the channel 
             *   data to be pasted.  Must be destroyed by caller.
             * @param inMask the selection mask to use for passed-in channel.
             *   Set to NULL for no mask.
             * @param inChannel the channel to paste into.
             */
            virtual void pasteChannel( double *inChannelData, double *inMask,
                  int inChannel );
            
      };



00255 inline Image::Image( int inWidth, int inHeight, int inNumChannels,
                     char inStartPixelsAtZero ) 
      : mWide( inWidth ), mHigh( inHeight ), mNumPixels( inWidth * inHeight ),
      mNumChannels( inNumChannels ), mChannels( new double*[inNumChannels] ),
      mSelection( NULL ) {
      
      // initialize all channels
      for( int i=0; i<mNumChannels; i++ ) {
            mChannels[i] = new double[ mNumPixels ];
        if( inStartPixelsAtZero ) {
            for( int j=0; j<mNumPixels; j++ ) {
                mChannels[i][j] = 0.0;
                }
            }
            }
      }
            
            
            
inline Image::~Image() {
      for( int i=0; i<mNumChannels; i++ ) {
            delete [] mChannels[i];
            }
      delete [] mChannels;    
      }
            


inline long Image::getWidth() {
      return mWide;
      }
      
      
      
inline long Image::getHeight() {
      return mHigh;
      }



inline long Image::getNumChannels() {
      return mNumChannels;
      }
      
      
            
00301 inline double *Image::getChannel( int inChannel ) {
      return mChannels[ inChannel ];
      }
      
             
            
00307 inline void Image::setSelection( Image *inSelection ) {
      mSelection = inSelection;
      }



00313 inline Image *Image::getSelection() {
      return mSelection;
      }
            
            
            
00319 inline void Image::clearSelection() {
      mSelection = NULL;
      }
      
      
            
00325 inline void Image::filter( ChannelFilter *inFilter, int inChannel ) {

      if( mSelection == NULL ) {
            inFilter->apply( mChannels[ inChannel ], mWide, mHigh );
            }
      else { // part of image selected
            // turn selection off and filter channel entirely
            Image *tempSelection = mSelection;
            mSelection = NULL;
            // filter a copy of the channel
            double *filteredChannel = copyChannel( inChannel );
            inFilter->apply( filteredChannel, mWide, mHigh );
            
            // now paste filtered channel back into selected region
            mSelection = tempSelection;
            pasteChannel( filteredChannel, inChannel );
            }
      }
            
      
            
00346 inline void Image::filter( ChannelFilter *inFilter ) {
      for( int i=0; i<mNumChannels; i++ ) {
            filter( inFilter, i );
            }     
      }



00354 inline Image *Image::copy() {
      Image *copiedImage = new Image( mWide, mHigh, mNumChannels );
      copiedImage->paste( this );
      
      return copiedImage;
      }
            
            
            
00363 inline void Image::paste( Image *inImage ) {
      // copy paste in the min number of channels only
      int numChannelsToPaste = mNumChannels;
      if( numChannelsToPaste > inImage->getNumChannels() ) {
            numChannelsToPaste = inImage->getNumChannels();
            }
      
      for( int i=0; i<numChannelsToPaste; i++ ) {
            pasteChannel( inImage->getChannel(i), 
                  inImage->getChannelSelection(i), i );
            }
      }



00378 inline double *Image::copyChannel( int inChannel ) {
      
      // first, copy the channel
      double *copiedChannel = new double[mNumPixels];
      memcpy( copiedChannel, 
            mChannels[inChannel], sizeof( double ) * mNumPixels );
      
      
      if( mSelection != NULL ) {
            // apply selection to copied channel
            double *selection = getChannelSelection( inChannel ); 
            
            // scale copied channel with selection
            for( int i=0; i<mNumPixels; i++ ) {
                  copiedChannel[i] = copiedChannel[i] * selection[i];
                  }
            }
      
      return copiedChannel;   
      }



00401 inline double *Image::getChannelSelection( int inChannel ) {
      if( mSelection == NULL ) {
            return NULL;
            }
      else {
            if( mSelection->getNumChannels() == mNumChannels ) {
                  // use separate selection for each channel
                  return mSelection->getChannel( inChannel );
                  }
            else {
                  // use first channel of selection for all channels
                  return mSelection->getChannel( 0 );
                  }
            }
      }


            
00419 inline void Image::pasteChannel( double *inChannelData, int inChannel ) {
      pasteChannel( inChannelData, NULL, inChannel );
      }



// We've abstracted away the complexity in the other fuctions,
// but it all seemed to filter down into this function, which
// is very messy.
00428 inline void Image::pasteChannel( double *inChannelData, double *inMask,
      int inChannel ) {
      
      double *thisChannel = mChannels[inChannel];
      if( mSelection != NULL ) {
            // scale incoming data with this selection
            double *selection = getChannelSelection(inChannel);
            
            if( inMask != NULL ) {
                  // scale incoming data with both masks
                  for( int i=0; i<mNumPixels; i++ ) {
                        thisChannel[i] = ( thisChannel[i] * (1-selection[i])
                              + 
                              ( thisChannel[i] * (1-inMask[i]) 
                                    + inChannelData[i] * inMask[i] ) * selection[i] );
                        }
                  }
            else {      
                  // scale incomming data with this selecition only
                  for( int i=0; i<mNumPixels; i++ ) {
                        thisChannel[i] = ( thisChannel[i] * (1-selection[i])
                              + inChannelData[i] * selection[i] );
                        }
                  }
            }
      else {      // no selection in this image
            if( inMask != NULL ) {
                  // scale incoming data with its masks
                  for( int i=0; i<mNumPixels; i++ ) {
                        thisChannel[i] = thisChannel[i] * (1-inMask[i]) 
                              + inChannelData[i] * inMask[i];
                        }
                  }
            else {
                  // copy channel directly, with no mask
                  memcpy( thisChannel, inChannelData, sizeof(double) * mNumPixels );
                  }
            }     
      }



00470 inline int Image::serialize( OutputStream *inOutputStream ) {
      // first output width and height
      
      int numBytes = 0;
      
      numBytes += inOutputStream->writeLong( mWide );
      numBytes += inOutputStream->writeLong( mHigh );
      
      // then output number of channels
      numBytes += inOutputStream->writeLong( mNumChannels );
      
      // now output each channel
      for( int i=0; i<mNumChannels; i++ ) {
            unsigned char *byteArray = new unsigned char[mNumPixels];
            
            // convert each 8-bit double pixel to one byte
            for( int p=0; p<mNumPixels; p++ ) {
                  //numBytes += inOutputStream->writeDouble( mChannels[i][p] );
                  byteArray[p] = (unsigned char)( mChannels[i][p] * 255 );
                  }
            
            numBytes += inOutputStream->write( byteArray, mNumPixels );
                  
            delete [] byteArray;    
            }
      
      return numBytes;
      }
      
      
      
00501 inline int Image::deserialize( InputStream *inInputStream ) {
      int i;
      // first delete old image channels
      for( i=0; i<mNumChannels; i++ ) {
            delete [] mChannels[i];
            }
      delete [] mChannels;
      
      
      // input width and height
      
      int numBytes = 0;
      
      numBytes += inInputStream->readLong( &mWide );
      numBytes += inInputStream->readLong( &mHigh );
      
      mNumPixels = mWide * mHigh;
      
      // then input number of channels
      numBytes += inInputStream->readLong( &mNumChannels );
      
      mChannels = new double*[mNumChannels];
      
      // now input each channel
      for( i=0; i<mNumChannels; i++ ) {
            mChannels[i] = new double[mNumPixels];
            
            unsigned char *byteArray = new unsigned char[mNumPixels];
            numBytes += inInputStream->read( byteArray, mNumPixels );
            
            // convert each byte to an 8-bit double pixel
            for( int p=0; p<mNumPixels; p++ ) {
                  //numBytes += inInputStream->readDouble( &( mChannels[i][p] ) );
                  mChannels[i][p] = (double)( byteArray[p] ) / 255.0;
                  }
            
            delete [] byteArray;    
            }
      
      return numBytes;
      }


      
#endif

Generated by  Doxygen 1.6.0   Back to index