##############################################################################
# Spectral Python (SPy) package change log
##############################################################################

2013-01-05	tboggs <tboggs@users.sourceforge.net>

    Allow modifying `ImageView` classes even when the `classes` arg was not
    provided.

    * graphics/spypylab.py:
      (ImageViewKeyboardHandler.handle_event): Check ImageView.classes instead
        of ImageView.class_axes.
      (ImageView.init_callbacks): Make class update callback handle `classes`
        being None.
      (ImageView.set_display_mode): Call .show_classes if classes are set but
        .class_axes is not (i.e., if classes were set since last update).

    Added Modified SAM (code contributed by Christian Mielke).

    * algorithms/algorithms.py:
      (spectral_angles): Compute angles in 64 bits. Clip dot products to
      prevent bad values in arccos due to roundoff.
      (msam): New function.

    Removed deprecated functions:

    * algorithms/algorithms.py: Removed principalComponents,
      linearDiscriminant, reduceEigenvectors, logDeterminant, ,
      createTrainingClasses, bhattacharyyaDistance, bDistanceTerms,
      transformImage, spectralAngles.

2013-12-27	tboggs <tboggs@users.sourceforge.net>

    Avoid a bug in `wx.NewId` that can cause exceptions when right-clicking in
    an ND window.

    * graphics/ndwindow.py (MouseMenu.__init__): Cache menu item ID's instead of
     regenerating them every time the menu is opened. This avoids an exception
     that intermittantly occurs in wx.

    * graphics/spypylab.py:
      (ImageViewMouseHandler.handle_event): Force redraw of spectrum plots.

    Fixed bug that caused an exception when a SpyFile object is used in an
    ImageView.

    * graphics/spypylab.py (ImageView.set_data): Use `shape` member instead of
      `ndim`.

2013-12-23	tboggs <tboggs@users.sourceforge.net>

    Make selection rectangle disappear when canceling selection and stay when
    selection is complete.

    * graphics/spypylab:
      (ImageViewKeyboardHandler.on_key_release): Suppress cancellation message
       if mouse was never clicked. Hide rectangle if SHIFT is released while
       selecting.
      (ImageViewKeyboardHandler.handle_event): Make selection rectangle
       disappear after pixels are assigned to a class.
      (ImageView._select_rectangle): Make selection rectangle continue to be
       displayed until the next GUI event (the default mpl behavior is for it
       to disappear).

2013-12-11	tboggs <tboggs@users.sourceforge.net>

    Completed initial implementation of pixel class labeling.

    * graphics/spypylab.py:
      (MplCallbacks.show_events): New boolean class attribute that indicates
       whether matplotlib events should be printed to the console.
      (ImageViewKeyboardHandler.on_key_release): Check whether selector exists.
      (ImageViewKeyboardHandler.handle_event):
       - Check whether selector exists.
       - Call self.view.label_region.
      (ImageView.init_callbacks): Only create selector if settings say so.
      (ImageView.label_region): New method to reassign image pixel class IDs.
    * spectral.py (SpySettings): Added imshow_enable_rectangle_selector.
      
2013-12-10	tboggs <tboggs@users.sourceforge.net>

    Partial implementation of pixel class labeling.

    * graphics/spypylab.py:
      (MplCallback.children): New member list for child callbacks.
      (ImageViewKeyboardHandler.__init__): Add child key release handler.
      (ImageViewKeyboardHandler.on_key_release): New method.
      (ImageViewKeyboardHandler.handle_event): Handling for pixel labeling.
      (ImageView.selection): New member for rectangular region selections.
      (ImageView.init_callbacks): Attach RectanglSelector.
      (ImageView._select_rectangle): Handles creation of `selection` from
       RectangleSelector callback.

    Made ImageView mouse handler an external callback object.

    * spectral/graphics/spypylab.py:
      (ImageViewMouseHandler): New class
      (ImageView.init_callbacks): Use ImageViewMouseHandler.
      (ImageView.on_click): Replaced by ImageViewMouseHandler

    Fixed a bug in linear_discriminant (not dividing num num classes). Also,
    make cov_w an unbiased estimator.

    * algorithms/algorithms.py (linear_discriminant):
      - Divide cov_b by (K - 1) - bug fix.
      - Divide cov_b by (N - 1) instead if N to make unbiased estimator.

    Added `cov_avg` to compute class averaged covariance
    
    * algorithms/algorithms.py (cov_avg): New function.

    Fixed saving/loading training class data. Saving training data is now done
    using `TrainingClassSet.save`. Loading can be done with either
    `TrainingClassSet.load` or `load_training_sets`.

    * algorithms/algorithms.py:
      (linear_discriminant):
      - Call classes.calc_stats
      - Get nbands from training data.
      (TrainingClass.__init__): Don't assume `image` is not None.
      (TrainingClass._size): Removed member.
      (TrainingClass.stats_valid): If called with no arg, return current value.
      (TrainingClass.dump): Removed method.
      (TrainingClass.load): Removed method.
      (TrainingClassSet.calc_stats): New method. Only calcs stats if needed.
      (TrainingClassSet.save): New method.
      (TrainingClassSet.load): New method.
      (create_training_classes): Changed `calc_stats` arg to bool.
    * algorithms/classifiers.py:
      (Classifier.classify): New method. Calls classify_spectrum or
      classify_image, as appropriate.
      (GaussianClassifier.classify_spectrum): Simplified logic.
      (GaussianClassifier.classify_image): Catch potential exception in np.dot
      when array is not contiguous.
      (MahalanobisDistanceClassifier.classify_spectrum): Simplified logic.
      (create_training_classes): Simplified code.
    * spectral.py (load_training_sets): Use TrainingClassSet.load.
    * tests/__init__.py: Include classifiers tests.
    * tests/classifiers.py: New file.
    * tests/spytest.py (SpyTest.run): Supress sys.stdout while running tests.
    * tests/test_template.txt: Reflect recent changes to SpyTest.


2013-12-05	tboggs <tboggs@users.sourceforge.net>

    Performance improvements for kmeans, GaussianClassifier, and
    MahalanobisDistanceClassifier.

    * algorithms/classifiers.py:
      (Classifier): Converted to new-style class (derived from `object`).
      (GaussianClassifier.classify_image): Override classify_image using
      cached class scores to provide 14x speedup on test image.
      (Classifier.cache_class_scores): Class attribute that indicates whether
      to compute classifier scores for each class for the entire image and
      cache the result prior to selecting the best match. This can yield big
      speed improvements but could cause problems on systems with lower RAM.
      (MahalanobisDistanceClassifier.classify_image): Overloading base class
      method to use `RX` class to compute result. Over 7x speedup.
    * algorithms/clustering.py (kmeans_ndarray): Up to 3x speedup using einsum.

    Added `figsize` argument to imshow.

    * graphics/spypylab (imshow): Accept figsize arg.

    Fixed error when bands not specified in `imshow` and incorrect handling of
    `stretch_all` keyword to get_rgb).

    * graphics/__init__.py: Import ImageView from spypylab
    * graphics/graphics.py(get_rgb): Corrected handling of `stretch_all`
      kwarg (was stretching when strech_all was provided but False (or 0)).
    * graphics/spypylab:
      (ImageView.set_data):
      - Separate get_rgb and mpl.imshow keywords.
      - Avoid exception when bands not specified.
      (ImageView.set_classes): Filter get_rgb keywords.
      (imshow):
      - Make `colors` a positional argument.
      - Simplified setup of ImageView object.

2013-12-05	tboggs <tboggs@users.sourceforge.net>

    Provide settings for spectral.imshow windows.

    * spectral.py (SpySettings):
      - Converted attributes to class attributes
      - Added imshow settings

    Disable matplotlib key event handlers that conflict with SPy handlers.
    Use common interpolation for data and class layers.

    * graphics/spypylab.py:
      (check_disable_mpl_callbacks): New function.
      (ImageViewKeyboardHandler.handle_event): "i" toggles pixel interpolation.
      (ImageView.interpolation): New property method.
      (ImageView.__init__): disable mpl callbacks. Use common interpolation.
      (ImageView.set_data): Use common interpolation
      (ImageView.set_classes): ditto
      (ImageView.refresh): ditto
      (ImageView.open_zoom): ditto

2013-12-03	tboggs <tboggs@users.sourceforge.net>

    Simplified unit test interface.

    * tests/spytest.py:
      (SpyTest.run): New method that elimiates need for `run` method or
      `test_method` decorators in subclasses.
    * tests/detectors.py: Remove `test_method` decorators and `run` methods.
    * tests/envi.py: ditto
    * tests/memmap.py: ditto
    * tests/spyfile.py: ditto
    * tests/spymath.py: ditto
    * tests/transforms.py: ditto

    Allow matched_filter to be called without specifying background stats.

    * algorithms/detectors.py(matched_filter): Handle missing background stats
      (compute from data).
    * tests/detectors.py(MatchedFilterTest.test_mf_target_no_bg_eq_one): New
      test.

2013-11-30	tboggs <tboggs@users.sourceforge.net>

    Added a common callback event registry in the ImageView class to enable a
    group of windows to respond to a common event (e.g., class labels modified).

    * graphics/ndwindow.py:
      (NDWindow.view_class_image): Share callback registry with class view.
    * graphics/spypylab.py:
      (ImageView.__init__): Initialize `callbacks` and `callbacks_common`.
      (ImageView.show): Call init_callbacks.
      (ImageView.init_callbacks): Initialize callback registry and default
      callbacks.
      (ImageView.open_zoom): Share callbacks_common with zoom window.

    Use "nearest" pixel interpolation by default instead of "none" since some
    backends don't support the latter.

    * graphics/spypylab.py:
      (ImageView.open_zoom): Use "nearest" interpolation, by default.
      (imshow): Use "nearest" interpolation, by default.


2013-11-24	tboggs <tboggs@users.sourceforge.net>

    Created a WindowedGaussianBackgroundMapper class, which applies algorithms
    to an image, updating the background statistics for each image pixel,
    using an inner/outer window. The RXW class was eliminated but the same
    calculations are performed by passing an RX object to a
    WindowedGaussianBackgroundMapper object. This new class can also be used
    with a wrapped MatchedFilter object.

    Use `np.einsum` in RX for faster calculation.

    * algorithms/detectors.py:
      (MatchedFilter): Use property methods of the GaussianStats class.
      (MatchedFilterWrapper): A wrapper class to make a MatchedFilter object
      compatible with a WindowedGaussianBackgroundMapper.
      (matched_filter): New function to execute a matched filter (with or
      without a windowed background).
      (RX): Use property methods of the GaussianStats class.
      (RX.__call__): Use einsum or faster computation.
      (RXW): Class eliminated (`rx` can now use an RX object with a
      WindowedGaussianBackgroundMapper object.
      (WindowedGaussianBackgroundMapper): New class
      (window_mask_creator): Returned function now returns both inner and
      outer window limits and, optionally, the window mask.

2013-11-20	tboggs <tboggs@users.sourceforge.net>

    Added detector unit tests.

    * tests/__init__.py: Include detector tests.
    * tests/detectors.py: New file for detector tests.
    * test_template.txt: Template file for creating new tests.

    Store PCA/LDA eigenvectors in columns, consistent with numpy. Ensure that
    eigen{values,vectors} are in descending order.

    * algorithms/__init__.py: Import * from detectors (__all__ is defined
      locally in the file).
    * algorithms/algorithms.py:
      (PrincipalComponents): Eigenvectors are now stored in columns.
      (principal_components): Make sure eigen{values,vectors} are sorted.
      (FisherLinearDiscriminant): Store eigenvectors in columns
      (linear_discriminant):
      - Store eigenvectors in columns
      - Make whitening optional
      (GaussianStats): Store eigenvectors in columns
      (GaussianStats.log_det_cov): New property method
      (TrainingClass):
      - Don't explicitly compute derived stats.
      - Don't save/load derived stats
    * test/detectors.py: Update tests for detector changes above.

    Added new tests for PCA and LDA.

    * tests/spymath.py:
      (PCATest): New test for PCA
      (LDATest): New tests for linear discriminant

2013-11-17	tboggs <tboggs@users.sourceforge.net>

    Add property methods to Gaussian stats to compute (and cache) derived
    statistics on-demand.

    * algorithms/algorithms.py:
      (GaussianStats): Added several property methods for derived stats.
      (GaussianStats.__init__): Converted keyword args to positional.

    Added optional `eigs` argument to matrix_sqrt to speed up computation.

    * algorithms/spymath.py (matrix_sqrt): Accept optional `eigs` keyword.

    The ND window created by `view_nd` can now open a dynamic raster image of
    class values that is updated whenever classes are modified in the ND view.

    * graphics/spypylab:
      (MplCallback.connect): Connect self instead of the callback function.
      (MplCallback.__call__): When an exception is encountered, disconnect
      regardless of whether or not the exception is rethrown.
      (SpyMplEvent): New SPy event base class.
    * graphics/ndwindow.py:
      (NDWindowProxy.view_class_image): New method.
      (NDWindow.__init__):
      - Remove duplicative setting of self.classes.
      - Create new self.classes array as np.int (not np.uint).
      - Set callback registry member for class raster view window.
      (NDWindow.reassign_selection): Create callback event in registry.
      (NDWindow.view_class_image): New method.
      
2013-11-15	tboggs <tboggs@users.sourceforge.net>

    Added class attribute to MplCallback for debugging exceptions and created
    a KeyParser class for safer parsing of matplotlib event key values.

    * graphics/spypylab.py:
      (MplCallback.raise_event_exceptions): New class attribute.
      (MplCallback.__call__): Raise exceptions, when appropriate.
      (ImageViewCallback): Use KeyParser class.
      (KeyParser): New class to parse matplotlib event key strings.
      (ImageView.on_click): Use KeyParser class.

2013-11-15	tboggs <tboggs@users.sourceforge.net>

    Huge improvment in speed for windowed RX when covariance is specified.

    * algorithms/detectors.py
      (RXW.__init__): Compute inverse covariance
      (RXW.__call__): Use cached covariance

    Fixed a bug causing an exception in windowed RX for non-square images.

    * algorithms/detectors.py (RXW.__call__): Swap C/R iteration variables.

2013-11-13	tboggs <tboggs@users.sourceforge.net>

    Major change to `imshow` and `ImageView` to support additional display
    modes and interactivity (e.g. zoom windows, adjustable class alpha
    transparency).

    * graphics/spypylab.py:
      (MplCallback): New base class for callback classes.
      (ImageViewCallback): New base class for ImageView callbacks.
      (ParentViewPanCallback): New class to pan an image, based on click
      events in another image window.
      (ImageView): Support showing data, classes, or data with overlayed
      classes. Supports mouse and keyboard event handlers.
      (imshow): Supports updated ImageView class.

2013-11-05	tboggs <tboggs@users.sourceforge.net>

    Minor improvement to matrix_sqrt and added associated unit tests.

    * algorithms/spymath.py (matrix_sqrt): added optional `inverse` arg.
    * tests/__init__.py: Include spymath testing module
    * tests/spymath.py: New file.

2013-11-02	tboggs <tboggs@users.sourceforge.net>

    Added `cov` keyword to `rx` function.

    * algorithms/detectors.py:
      (RXW.__init__): Accept `cov` keyword
      (RXW.__call__): Use optional covariance.
      (rx): Accept `cov` keyword.

    Added ImageView class for imshow wrapper.

    * graphics/__init__.py: Import imshow from spypylab.
    * graphics/spypylab.py:
      (ImageView): New class
      (imshow): Moved from graphics.py. Added `parent` keyword for
        implementing zoom windows.

2013-09-06	tboggs <tboggs@users.sourceforge.net>

    Updated version to 0.12

2013-09-06	tboggs <tboggs@users.sourceforge.net>

    Allow calling `envi.create_image` with keyword args instead of a metadata
    dict using ENVI-specific parameter names.

    * io/envi.py:
      (gen_params): Cast data type to str.
      (create_image): Make `metadata` arg optional and accept keywords.
    * tests/__init__.py: Added ENVI tests
    * tests/envi.py: New file

2013-09-02	tboggs <tboggs@users.sourceforge.net>

    Default WX_GL_DEPTH_SIZE to 24 bits.

    * spectra.py (SpySettings): Changed WX_GL_DEPTH_SIZE to 24.

    Added `show_progress` to settings object.

    * spectral.spectral.SpySettings:
      (show_progress): New member
    * utilities/status:
      (__init__): Remove self.silent and use settings.show_progress instead.
      (display_percentage): ditto
      (update_percentage): ditto
      (end_percentage): ditto

    Encapsulate Status members.

    * utilities/status.py:
      - pre-Text -> _pretext
      - percentage -> _percentage
      - overwriteLine -> _overwrite
      - percentFormat -> _percent_fmt
      - textLength -> _text_len
      (update_percentage): member name changes
      (end_percentage): ditto
      (write): ditto

    
    Encapsulate status object:

    * algorithms/algorithms.py:
      (mean_cov): Use spectral._status
      (PrincipalComponents): ditto
    * algorithms/classifiers:
      (Classifier): ditto
    * algorithms/clustering:
      (kmeans): ditto
      (kmeans_ndarray): ditto
    * algorithms/detectors.py: (RXW): ditto
    * algorithms/perceptron.py (Perceptron): ditto


    Fixed cube texture edge display issue

    * graphics.hypercube.py:
      (HypercubeWindow.load_textures): Set texture wrap parameter to GL_CLAMP.
      
2013-08-13	tboggs <tboggs@users.sourceforge.net>

    Added `imshow` wrapper around matplotlib's imshow.

    * graphics/__init__.py: Import `imshow`.
    * graphics/graphics.py(imshow): New function.

    Automatically determine image format in `save_rgb`.

    * graphics/graphics(save_rgb): Let PIL determine image format.

    Add image band info to saved file. Corrected band_quantity member name.

    * io/envi.py:
      (open): BandInfo member changed from "bandQuantity" to "band_quantity".
      (SpectralLibrary.__init__): Ditto
      (save_image): Include band info from image being saved, unless metadata
      arg already contains the values.
      (add_band_info_to_metadata): New function.

2013-08-12	tboggs <tboggs@users.sourceforge.net>

    Added windowed mode to the RX anomaly detector.

    * algorithms/__init__.py: Import `MatchedFilter` and `rx`.
    * algorithms/detectors.py:
      (RXW): New class for windowed RX algorithm.
      (rx): New function for implementing RX, creating an `RX` or `RXW`
      object, as needed.
      (window_mask_creator): New function for creating image window masks.
      (rx_numpy_masked_arrays): A new file, promptly deleted, which used
      numpy.ma for masked arrays but was ~8x slower than just extracting
      pixels from the window.
      (window_mask_creator_numpy_masked_arrays): Mask creator for the
      `rx_numpy_masked_arrays` function.

2013-08-10	tboggs <tboggs@users.sourceforge.net>

    Accept ndarray as `top` keyword in view_cube.

    * graphics/graphics.py:
      (view_cube): Update doc string.
      (get_rgb): Handle case where an ImageArray may have len(shape) < 3.
      This can happen with the result of calling __getitem__ on an ImageArray.
    * graphics/hypercube.py (HypercubeWindow.load_textures): Check if `top`
      keyword is an ndarray.

    Cast ImageArray method results to non-ImageArray types. This prevents
    misinterpretation by other functions regarding the content of these data
    items

    * spectral/spectral.py:
      (ImageArray.read_band): Cast result to ndarray.
      (ImageArray.read_bands): Cast result to ndarray.
      (ImageArray.read_pixel): Cast result to ndarray.
      (ImageArray.read_datum): Cast result to scalar.
    
2013-08-09	tboggs <tboggs@users.sourceforge.net>

    Added new memmap interface for SpyFile objects.

    * io/spyfile.py: (MemmapFile): New class for memmap interface.
    * io/bilfile.py:
      (BilFile): Class now also derived from MemmapFile.
      (BilFile.memmap): Renamed to BilFile._memmap.
      (BilFile._open_memmap): New method for creating new memmaps.
    * io/bipfile.py:
      (BipFile): Class now also derived from MemmapFile.
      (BipFile.memmap): Renamed to BipFile._memmap.
      (BipFile._open_memmap): New method for creating new memmaps.
    * io/bsqfile.py:
      (BsqFile): Class now also derived from MemmapFile.
      (BsqFile.memmap): Renamed to BsqFile._memmap.
      (BsqFile._open_memmap): New method for creating new memmaps.
    * io/envi.py:
      (save_image): Use new memmap interface.
      (create_image): Use new memmap interface.
    * tests/__init__.py: Include memmap unit tests.
    * tests/memmap.py: New file.
    * tests/run.py: Include memmap unit tests.

    Print summary stats for unit test results.

    * tests/__init__.py:
      (_num_tests_run, _num_tests_failed): New members for summary stats.
      (testdir): Name of directory to create for unit test files.
    * tests/run.py:
      (parse_args, reset_stats, print_summary): Common functions for test
      modules.
    * tests/spytest.py (test_method): Track success/failure of tests.
    * tests/memmap.py: Handle command-line args and track stats.
    * tests/spyfile.py: Ditto
    * tests/transforms.py: Ditto

    Removed ImageArray.__getitem__. This method was uneccessary and turned
    scalar values into ndarray objects, which caused various problems.

    * spectral.py (ImageArray.__getitem__): Removed method.

2013-08-06	tboggs <tboggs@users.sourceforge.net>

    Turned `Image` into new-style class.

    * spectral.py:
      (Image): Now derived from object.
      (ImageArray.__new__): Fixed to work as new-style class.
      (ImageArray.__init__): New method.

    Renamed `get_image_display_data` to `get_rgb` and avoid exception due
    to missing attributes in ImageArray objects.

    * graphics/__init__.py: import get_rgb
    * graphics/graphics.py:
      (view): get_image_display_data renamed get_rgb.
      (make_pil_image): Ditto.
      (get_image_display_data):
      - Renamed get_rgb.
      - Handle ImageArray object with missing attributes.
      - Deprecate colorScale and autoScale kwargs.
    * graphics/spywxpython.py (view):
      - get_image_display_data renamed get_rgb.
      - Replace oldnumeric imports.

2013-08-04	tboggs <tboggs@users.sourceforge.net>

    Enable setting custom background color in hypercube window.

    * graphics/graphics.py (view_cube): Include `background` in doc string.
    * graphics/hypercube.py (HypercubeWindow.__init__): Set self.clear_color
      based on keyword arg, if provided.

    * spectral/spectral.py (help): Removed legacy help function.

2013-07-24	tboggs <tboggs@users.sourceforge.net>

    * algorithms/detectors.py (RX.__init__): Initialize background.

2013-04-14	tboggs <tboggs@users.sourceforge.net>

    * io/envi.py (create_image): Applied Ferdinand Deger's bug fix patch.

2013-03-30	tboggs <tboggs@users.sourceforge.net>

    * __init__.py: Updated SPy version to 0.11

2013-03-20	tboggs <tboggs@users.sourceforge.net>

    Added unit-testing sub-package.

    * tests/__init__.py: New file.
    * tests/run.py: New file to execute all standard unit tests.
    * tests/spyfile.py: New file for testing SpyFile I/O.
    * tests/spytest.py: New file with base class for unit tests.
    * tests/transforms.py: New file for testing LinearTransform objects.

    Changed envi.save option from `byteswap` to `byteorder`.

    * io/envi.py (save_image): Switched to `byteorder` keyword.

2013-03-19	tboggs <tboggs@users.sourceforge.net>

    * io/spyfile.py:
      (FileNotFoundError): New class
      (find_file_path): raise FileNotFoundError.

2013-03-18	tboggs <tboggs@users.sourceforge.net>

    Replaced `image` and `save_image` with `open_image` and
    `save_rgb`, respectively.

    * __init__.py: Import open_image.
    * spectral.py:
      - Renamed `image` to `open_image`.
      - Provide deprecation warning for `image`.
    * graphics/__init__.py: Import `save_rgb`.
    * graphics/graphics.py:  Rename `save_image` to `save_rgb` and
        provide deprecation warning for `save_image`.

2013-03-09	tboggs <tboggs@users.sourceforge.net>

    Applied autopep8 to all files.

    Switched to using byte order in image dtypes (rather than swapping bytes
    after reading data) for performance and simplification.

    * io/aviris.py (open): Set byte order in dtype.
    * io/bilfile.py (BilFile.read_*): Set byte order in dtype.
    * io/bipfile.py (BilFile.read_*): Set byte order in dtype.
    * io/bsqfile.py (BilFile.read_*): Set byte order in dtype.
    * io/envi.py (open, gen_params, save_image, create_image): Set byte
      order in dtype.
    * io/erdas.py (open): Set byte order in dtype.
    * io/spyfile.py (load): Set byte order in dtype.

2013-03-07	tboggs <tboggs@users.sourceforge.net>

    Fixed setting `status` object in top-level package and allow
    envi.save_image to handle TransformedImage objects.

    * io/envi.py:
      (envi_to_dtype): Make dict creation compatible with python version < 2.7.
      (save_image): Handle TransformedImage objects.
    * io/spyfile/py
      (SpyFile.transform): New method.
      (TransformedImage.__str__): New method.
    * spectral.py (_init): Fixed setting `status` member in top-level package.
    
2013-03-06	tboggs <tboggs@users.sourceforge.net>

    Fixed writing of description parameter for ENVI file and possible incorrect
    transpose in envi.save.
    
    io/envi.py:
      (save_image): Handle correct transpose and byte-swapping of image data
        when using memmaps.
      (_write_header_param): Perform special handling of description parameter.

    Made speed improvement to envi.save_image.
    
    * io/envi.py (save_image): Write directly to file instead of using
      numpy's `tofile` function.

    Move clutter out of top-level namespace.
    
    * __init__.py: Move initialization code into _init() in spectral.py
    * graphics/spypylab.py (plot): Move spectral.xyplot to spectral._xyplot.
    * io/spyfile.py: Remove unecessary warning imports.
    * spectral.py (_init): New function for package initialization.

    Added RX anomaly detector. Now importing `detectors` submodule into
    top-level namespace.

    * __init__.py: import algorithms.detectors into top-level namespace.
    * algorithms/__init__.py: Do not import MatchedFilter.
    * algorithms/detectors.py: Applied autopep8
      (RX): New class.
    
2013-03-05	tboggs <tboggs@users.sourceforge.net>

    Ran autopep8 on envi.py and fixed two incorrect exception statements.
    
    * io/envi.py: Fixed whitespace and code formatting via autopep8
      (check_new_filename): Add missing arguments to exception statements.

    Added a new function `calc_stats` that returns a `GaussianStats` object.
    Modified principal components, linear transforms, and matched filter to
    use the stats object instead of passing separate means & covariances.

    * algorithms/__init__.py: Import calc_stats.
    * algorithms/algorithms:
      (PrincipalComponents.__init__): Accept a `GaussianStats` object insted
        of separate mean & covariance.
      (PrincipalComponents.reduce): Use stats object.
      (principal_components): Use stats object.
      (GaussianStats.__init__): Accept parameters.
      (GaussianStats.transform): New method.
      (GaussianStats.get_whitening_transform): New method
      (calc_stats): New function.
      (TrainingClass.__init__): Use stats object.
    * algorithms/detectors.py:
      (MatchedFilter.__init__): Use stats object.
    * algorithms/transforms.py:
      (LinearTransform.__call__): Apply to any object with a `transform`
        method.

    Fixed several bugs introduced when migrating to numpy dtypes that caused
    improper file read operations only when memmap is not used.
    
    * io/bilfile.py (read_datum): Fixed file read bug.
    * io/bipfile.py:
      (read_bands): Fixed file read bug.
      (read_pixel): Fixed file read bug.
      (read_subimage): Fixed file read bug.
      (read_datum): Fixed file read bug.
    * io/bsqfile.py:
      (read_bands): Fixed file read bug.
      (read_subregion): Fixed file read bug.
      (read_datum): Fixed file read bug.

2013-03-03	tboggs <tboggs@users.sourceforge.net>

    Added ability to create new, writable image files.  Thanks to Ferdinand
    Deger for contributing code for this.
    
    * io/envi.py:
      (gen_params): New function to create a `Params` object from ENVI header
        metadata.
      (open):
        - Use `gen_params` instead of building object directly.
	- Added "hyspex" to list of recognized image file extensions.
      (save_image): If image being saved is SpyFile object, do not coerce its
        data type or apply scaling factor when loading the data.  Set the
	"reflectance scale factor" in the header file instead.
      (create_image): New function to create a new image file with memmap
        access.
      (write_envi_header): Fixed bug from previous commit that prevents
        "non-standard" parameters from being written. Added
	"reflectance scale factor" to the list of standard parameters.
    * io/spyfile.py (SpyFile.load): Now accepts optional keywords:
      `dtype` - Specifies explicit dtype for loaded image data.
      `scale` - When set to False, prevents data from being scaled when loaded
        if the SpyFile has a non-unity `scale_factor` value.

2013-03-02	tboggs <tboggs@users.sourceforge.net>

    Added ability to save images in ENVI format.
    
    * io/envi.py:
      (open): Do not set "header file" in metadata dict to avoild polluting
        ENVI header file parameters.
      (check_new_file_name): New function.
      (save_image): New function.
      (write_envi_header): Write correct "file type" parameter and write the
        standard parameters at the top of the file.
    * io/spyfile.py
      (SpyFile.load): Accept optional dtype parameter.
      (interleave_transpose): New function

2013-03-02	tboggs <tboggs@users.sourceforge.net>

    Removed `typecode` and `format` variables throughout the code, switching
    instead to using numpy.dtype for representing data types.  In file read
    operations, the array module now always uses a byte ('b') data type and
    numpy is used to convert to the desired image data type.  This enables
    support for additional data types that aren't supported by array (e.g.,
    64-bit unsigned integers and complex data types).
    
    A bug was also fixed that prevented 32-bit integer data types from being
    read properly.
    
    No longer removing newline characters from ENVI header `description`
    parameter.
    
    * algorithms/algorithms.py (ImageMaskIterator.__iter__): Use dtype instead
      of typecode.
    * algorithms/clustering.py (OnePassClusterer.classify_image): Use dtype
      instead of typecode.
    * io/aviris.py (open): Use dtype instead of typecode.
    * io/bilfile.py (BilFile.{__init__,read_band,read_bands,read_pixel,
      read_subregion,read_subimage,read_datum}): Use dtype instead of typecode.
    * io/bipfile.py (BilFile.{__init__,read_band,read_bands,read_pixel,
      read_subregion,read_subimage,read_datum}): Use dtype instead of typecode.
    * io/bsqfile.py (BilFile.{__init__,read_band,read_bands,read_pixel,
      read_subregion,read_subimage,read_datum}): Use dtype instead of typecode.
    * io/envi.py: Created mapping between ENVI data types and dtype chars.
      (read_envi_header): Do not remove newlines from `description` parameter.
      (open): Use dtype mapping insted of old format/typecode.  Fixed a bug
        causing incorrect import of 32-bit integer data type.
    * io/erdas.py:
      (open): Use dtype instead of typecode/format.
      (read_erdas_lan_header): Do not set typecode or raise exception
        (duplicates code in `open`).
    * io/spyfile.py
      (SpyFile.set_params): No longer using typecode/format.
      (SpyFile.__str__): Get data type from dtype.
      (SpyFile.typecode): Removed method.
      (SpyFile.load): Use array module to read byte data type and use numpy
        to convert to appropriate numeric type.
      (TransformedImage): Set class-level `dtype` instead of `_typecode`.
      (TransformedImage.__init__): Removed unecessary code.
      (TransformedImage.typecode): Removed method.
      (typecode): Removed function.
      (transformImage): Removed deprecated function.
    * spectral.py:
      (Image.set_params): Set dtype instead of _typecode.
      (Image.params): Set dtype instead of _typecode.
      (ImageArray.__new__): Set dtype to data type (not source image dtype).
      (ImageArray.typecode): Removed method.
      (ImageArray.info): Use dtype instead of typecode.

2013-02-22	tboggs <tboggs@users.sourceforge.net>

    Updated SPy version to 0.10.1.

    Fixed bug introduced by SPy 0.10 that caused incorrect spectrum to be
    displayed when double-clicking a raster image.
    
    * __init__.py: Updated version to 0.10.1
    * graphics/rasterwindow.py (RasterWindow.left_double_click): Incorrectly
      had GetX() and GetY() reversed for double-click handler.

2013-02-17	tboggs <tboggs@users.sourceforge.net>

    Updated SPy version to 0.10
    
    * __init__.py: Updated version to 0.10.
    * HISTORY.txt: Added version 0.10 info.

2013-02-14	tboggs <tboggs@users.sourceforge.net>

    Handle multiple wx versions in view_cube and return a proxy for all
    GUI functions.
    
    * graphics/graphics.py:
      (SpyWindow): New class - Base class for all GUI windows.
      (view): Return a window proxy object.
      (view_cube): Return a window proxy object.
    * graphics/hypercube.py:
      (HypercubeWindow): Now also derived from SpyWindow (inherits get_proxy).
      (HypercubeWindow.__init__): Explicitly call wx.Frame.__int__.
      (HypercubeWindow.on_resize): Handle wx 2.8.x and 2.9.x.
    * graphics/rasterwindow.py (RasterWindow): Now also derived from SpyWindow
      (inherits get_proxy).     
      
2013-02-14	tboggs <tboggs@users.sourceforge.net>

    Update default orientation of hypercube display.
    
    * graphics.hypercube.py:
      (HypercubeWindow.load_textures): Create textures so they display
        correctly when drawn on cube faces from lower left CCW to upper left
	vertices when viewed from outside the cube.
      (HypercubeWindow.draw_cube): Ditto.  Also draw bottom of cube.
    * io/aviris.py (load): Fixed help message for reading spectral bands.

2013-02-14	tboggs <tboggs@users.sourceforge.net>

    Handle possible missing GLUT module and handle multiple wx series (2.8/2.9).
    
    * graphics/graphics.py (WindowProxy): New class.
    * graphics/ndwindow.py:
      (NDWindowProxy): Class now derived from WindowProxy.
      (NDWindow.__init__): Added new member _have_glut.
      (NDWindow.create_axes_list): Check if GLUT is present before making calls.
      (NDWindow.initgl): Handle missing GLUT.
      (NDWindow.on_resize): Use different GLContext conditions for wx 2.8/2.9.
    
2013-02-12	tboggs <tboggs@users.sourceforge.net>

    Enabled setting NDWindow features from command line.  Simplified window
    proxy interface, and fixed ND and hypercube window resizing.
    
    * graphics/graphics.py:
      (_next_window_data_proxy_id): Removed module variable.
      (_window_data_proxies): Removed module variable.
      (view_nd): Use `NDWindowProxy` object.
      (WindowData): Removed class.
      (WindowDataProxy): Removed class.
      (create_window_data_proxy_id): Removed function.
    * graphics/hypercube.py:
      (HypercubeWindow.on_resize): Remove GetContext check.
      (HypercubeWindow.resize): Added needed OpenGL.GLU import
    * graphics/ndwindow:
      (NDWindowProxy): New class to give user access to class labels and to set
        display features in an open NDWindow.
      (NDWindow.__init__): Remove obsolete proxy_id arg. Send EVT_SIZE to the
        frame instead of the GLCanvas.
      (NDWindow.on_event_close): Remove old proxy cleanup code.
      (NDWindow.set_data):  Remove old proxy cleanup code.
      (NDWindow.set_features): New method for user to set features from CLI.
      (NDWindow.on_resize): Remove GetContext check.
      (NDWindow.get_proxy): New method.
      (NDWindowData): Removed class.
      (NDWindowDataProxy): Removed class.
      
2013-02-11	tboggs <tboggs@users.sourceforge.net>

    Moved START_WX_APP into settings object and make configurable
    WX_GL_DEPTH_SIZE.
    
    * __init__.py: Moved START_WX_APP to settings object.
    * algorithms/__init__.py: Import LinearTransform.
    * graphics/graphics.py:
      (check_wx_app): Moved START_WX_APP to settings object.
    * graphics/hypercube.py:
      (HypercubeWindow.__init__): Use WX_GL_DEPTH_SIZE value from settings.
    * graphics/ndwindow.py:
      (NDWindow.__init__): Use WX_GL_DEPTH_SIZE value from settings.
      (NDWindow.reassign_selection): Print dots for each pass instead of number
        of reassigned pixels.
      (NDWindow.create_axes_list): Put try block around GLUT calls.
      (NDWindow.initgl): Call glutInit()
    * spectral.py (SpySettings.__init__): Add START_WX_APP and WX_GL_DEPTH_SIZE.
    
2013-02-10	tboggs <tboggs@users.sourceforge.net>

    Improved performance of class covariance calculation for in-memory images
    and fixed a bug introduced by 0.9 when computing covariance for SpyFile
    objects.
    
    * algorithms/algorithms.py (mean_cov): Always use numpy.cov when computing
      covariance for in-memory images (even when class mask is present). Fixed
      a bug due to Int16 comptations that cause incorrect covariance calculation
      for SpyFile objects (introduced by SPy 0.9).

    Warn users if they try to call a GUI function outside of ipython and start
    a wx.App if there is not one already
    
    * __init__.py: Added parameter `START_WX_APP`.
    * graphics/__init__.py: Removed unecessary imports.
    * graphics/graphics.py:
      (view): Check if running ipython and if wx.App exists.
      (view_cube): ditto
      (view_nd): ditto
      (view_indexed): ditto
      (running_ipython): New function
      (warn_no_ipython): New function
      (check_wx_app): New function

    Set raster plotting module on initialization
    
    * __init__.py: Set raster plotter.

    Handle scalar valued transforms (e.g., scaling spectral data by a constant).
    
    * algorithms/transforms.py:
      (LinearTransform.__init__): Handle scalar transforms.
      (LinearTransform.__call__): Handle scalar transforms.
    * io/spyfile.py:
      (TransformedImage.__init__): Handle scalar valued transforms.

    Fixed error when double-clicking on transformed image raster view.
    
    * graphics/spypylab (plot): Check for presence of `bands` member of data.
    * io/spyfile.py:
      - Changed doc string for ipython.
      (TransformedImage.bands): New property method.

    Search spectral data directories for files opened not via `spectral.image`.
    
    * io/envi.py (open): Search data directories for optional `image` arg.
    * io/erdas.py (open): Search data directories for file arg.

    * io/aviris.py (open): Remove deprecated call to `readAvirisBands`.

    * graphics/graphics.py (view_indexed): Remove deprecated call to
      `init_graphics`.
    
2013-02-03	tboggs <tboggs@users.sourceforge.net>

    This is the first commit for SPy migration to using ipython for running
    GUI windows in a separate thread.  As of this commit, interactive use of
    SPy requires ipython (likely started with "ipython --pylab" and setting
    the appropriate matplotlib backend).
    
    * __init__.py:
      * Incremented __version__ to '0.9+'
      * Set up pylab for creating spectral plots.
    * graphics/__init__.py: Updated imports to relfect new view functions.
    * graphics/graphics.py:
      (init_graphics): Deleted function (no longer required).
      (view): Create display window directly (not via separate thread).
      (init_wxpython): Deleted function (no longer required).
      (initNumTut): Deleted function (deprecated long ago).
      (view_cube): New function that replaces `hypercube`. Creates display
        window directly (not via separate thread).
      (view_nd): New function that replaced `ndwindow`. Creates display
        window directly (not via separate thread).
    * graphics/hypercube.py:
      (WxHypercubeFrame): Class renamed `HypercubeWindow`.  Several changes to
        accomodate wx 2.9, including explicitly setting GLContext.
      (HypercubeFunctor): Class removed - no longer necessary since integrating
        with ipython.
      (hypercube): Function replace by `view_cube` and modified for integration
        with ipython.  New function is in graphics.py.
    * graphics/ndwindow:
      (MouseHandler.left_down): Expicitly set GLContext manager for wx 2.9
      (MouseHandler.left_up): Expicitly set GLContext manager for wx 2.9
      (WxNDWindowFrame): Class renamed `NDWindow`.
      (NDWindow.__init__): Handle case when `classes` kwarg is not given.
      (NDWindow.right_click): Expicitly set GLContext manager for wx 2.9
      (NDWindow.create_axes_list): Do not display axes labels if
        glutBitmapCharacter is not available.
      (NDWindowFunctor): Class removed - no longer necessary since integrating
        with ipython.
      (ndwindow): Function renamed `view_nd` and moved to graphics.py.
    * graphics/rasterwindow.py: New file that holds RasterWindow class.
    * graphics/spywxpythonthread:
      (WxImageServer.OnInit): Remove deprecated call `wx.InitAllImageHandlers`.
      

2013-01-22	tboggs <tboggs@users.sourceforge.net>

    * __init__.py: Incremented __version__ to '0.9'

2013-01-22	tboggs <tboggs@users.sourceforge.net>

    * algorithms/algorithms.py
      (TrainingClass.transform): Remove superfluous `if` block from previous
        commit.
    * algorithms/transforms.py: doc string changes
    * algorithms/__init__.py: import MatchedFilter from detectors module.

2013-01-21	tboggs <tboggs@users.sourceforge.net>

    LinearTransform objects can now be chained together and can be passed a
    specific dtype for output.  They also have dim_in and dim_out members.
    `transform_image` optionally accepts LinearTransform arg instead of an
    ndarray.

    * io/spyfile.py
      (transform_image): Alternately accept a LinearTransform as arg.
      (TransformedImage.__init__): Alternately acccept a LinearTransform as arg.
        Store the transform as a LinearTransform object.
      (TransformedImage.__getitem__): Use the `transform` member.
      (TransformedImage.read_pixel): Use the `transform` member.
      (TransformedImage.load): Use the `transform` member.
      (TransformedImage.read_subregion): Use the `transform` member.
      (TransformedImage.read_subimage): Use the `transform` member.
      (TransformedImage.read_datum): Use the `transform` member.
      (TransformedImage.read_bands): Use the `transform` member.
    * algorithms/transforms.py
      (LinearTransform.__init__): Added dim_in, dim_out, and dtype members.
      (LinearTransform.__call__): Cast transformed data to appropriate type.
      (LinearTransform.chain): New method to chain two transforms together.
    * algorithms/algorithms.py
      (TrainingClass.transform): Explicitly use LinearTransform.

2013-01-19	tboggs <tboggs@users.sourceforge.net>

    Added a FisherLinearDiscriminant class, fixed doc strings, and handle
    LinearTransformation objects in TrainingClass.transform.

    * algorithsm/algorithms.py
      (FisherLinearDiscriminant): New class.
      (linear_discriminant): Returns a FisherLinearDiscriminant object instead
        of a tuple.
      (reduce_eigenvectors): Function removed (replaced by method in
        PrincipleComponents class).
      (TrainingClass.transform): Also accept a LinearTransform as arg.
      (TrainingClassSet.transform): Get nbands from one of the classes.
    * algorithms/detectors.py (MatchedFilter): Fixed latex markup in doc string.
    * algorithms/transforms.py (LinearTransform): Fixed doc string.
    * algorithms/__init__.py: Removed reduce_eigenvectors from imports
    
2013-01-17	tboggs <tboggs@users.sourceforge.net>

    Added a matched filter function and created a PrincipalComponents object.
    
    * graphics/ndwindow.py
      (WxNDWindowFrame.create_axes_list): Call glutInit to prevent error if
        `ndwindow` is called without class labels.
    * algorithms/algorithms.py
      (mean_cov): Use 64-bit floats for covariance calculation.
      (PrincipalComponents): New class.
      (principal_components): Function now returns a PrincipalComponents object
        instead of a tuple.
    * algorithms/detectors.py: New file. Contains MatchedFilter class.
    * algorithms/transforms.py: New file. Contains LinearTransform class.
    * algorithms/spymath.py: New file.  Contains matrix_sqrt function.

2012-07-08	tboggs <tboggs@users.sourceforge.net>

    Added a right-click meny to the `WxNDWindowFrame` for pixel class
    reassignment.  `ndwindow` now returns a proxy object by which client code
    can access the current value of the `classes` array associated with the
    displayed data.

    * graphics/graphics.py
      (_next_window_data_proxy_id): Module-level counter for data proxy IDs.
      (_window_data_proxies): Module-level dict of window data objects.
      (WindowData): New base class for window data objects.
      (WindowDataProxy): New proxy base class for accessing WindowData objects.
      (create_window_data_proxy_id): Returns a new WindowDataProxy ID and
        adds an associated entry in _window_data_proxies.
    * graphics/ndwindow.py:
      (MouseMenu): New class for implementing a right-click menu.
      (WxNDWindowFrame.__init__): Take proxy ID as an argument.
      (WxNDWindowFrame.on_event_close): New method for updating proxy data prior
        to closing the window.
      (WxNDWindowFrame.right_click): New method to pop up the right-click menu.
      (WxNDWindowFrame.on_char):
      * Call `on_event_close` when closing the window.
      * Only allow single-octant mode if fewer than six features are available.
      (WxNDWindowFrame.reassign_selection): If pixels were reassigned to the max
        class, increment the max class so a new empty class will be available
	next time the mouse menu is opened.
      (WxNDWindowFrame.set_data): Only allow single-octant mode if fewer than
        six features are available.
      (NDWindowData): New class for holding returnable client data.
      (NDWindowDataProxy): New data proxy used by client (calling) code.
      (NDWindowFunctor.__init__): Take proxy ID argument.
      (NDWindowFunctor.__call__): Pass proxy ID to window constructor.
      (validate_args): New function to validate args passed to `ndwindow`.
      (ndwindow): Return a proxy object to allow client code to access updated
        values of `classes` array. Call `validate_args`. Added doc string.
    * graphics/hypercube.py: Code cleanup.
      
2012-06-20	tboggs <tboggs@users.sourceforge.net>

    Initial ND window capability.  Automatically initialize display thread when
    `hypercube` is called, if needed.  Removed global import of OpenGL namespace
    from hypercube.py.
    
    * graphics/__init__.py: Import `hypercube` and `ndwindow` functions.
    * graphics/hypercube.py: Eliminated global import of OpenGL namespace.
      (hypercube): Automatically call `init_graphics`, if needed.
    * graphics/ndwindow.py: New file for ND window display.
    * graphics/spywxpython.py: Init module-level `viewer` to None.
    
2012-06-17	tboggs <tboggs@users.sourceforge.net>

    Fixed broken deprecation warnings that cause infinite recursion
    
    * spectral.py: Fixed deprection warnings for `tileImage`,
      `saveTrainingSets`, and `loadTrainingSets`.

2012-06-17	tboggs <tboggs@users.sourceforge.net>

    * graphics/hypercube.py: Added mouse control for hypercube display.

2012-06-14	tboggs <tboggs@users.sourceforge.net>

    Fixed mismatch in parameter names in kmeans_ndarray.
    
    * spectral/algorithms/clustering.py(kmeans_ndarray): Changed `startClusters`
      to `start_clusters`.


2012-05-30	tboggs <tboggs@users.sourceforge.net>

    Fixed bad search/replace that caused infinite recursion in some read funcs.
    
    * spectral.py(ImageArray):
      (read_band): Mislabled readBand warning caused infinite recursion.
      (read_bands): Mislabled readBands warning caused infinite recursion.
      (read_pixel): Mislabled readPixel warning caused infinite recursion.
      (read_datum): Mislabled readDatum warning caused infinite recursion.
    * io/spyfile.py: Fixed doc string
    
2012-02-23	tboggs <tboggs@users.sourceforge.net>

    Added numpy.memmap objects to SpyFile instances.  This improves read speed
    by about a factor of 10 (although algorithms are still about 10 times faster
    when using in-memory arrays).
    
    * io/bilfile.py:
      (BilFile.__init__): Set memmmap member for buffered input.
      (BilFile.read_band, read_bands, read_pixel, read_subregion, read_subimage,
       read_datum): Use memmap for reading file, if available.
    * io/bipfile.py:
      (BipFile.__init__): Set memmmap member for buffered input.
      (BipFile.read_band, read_bands, read_pixel, read_subregion, read_subimage,
       read_datum): Use memmap for reading file, if available.
    * io/bsqfile.py:
      (BsqFile.__init__): Set memmmap member for buffered input.
      (BsqFile.read_band, read_bands, read_pixel, read_subregion, read_subimage,
       read_datum): Use memmap for reading file, if available.

2012-02-19	tboggs <tboggs@users.sourceforge.net>

    Updated version number to '0.7' in __init__.py

2012-02-19	tboggs <tboggs@users.sourceforge.net>

    Changed many method and function names to be consitent with external
    modules (this affects almost every file so I won't list them here). Fixed
    several bugs affecting file reading for several formats.
    
    * io/bipfile.py (BipFile.read_bands): convert tuple to list to prevent
      an exception.
    * io/bsqfile:
      (BsqFile.read_subregion):  Fixed a bug that caused reading wrong section
      of data when lower row limit is non-zero.
      (BsqFile.read_subimage):  Fixed a bug that caused reading wrong data
      values when lower row limit is non-zero.

2011-01-28	tboggs <tboggs@users.sourceforge.net>

    Updated ERDAS/LAN file interface to handle either endian, regardless of host
    byte order.  The handler previously assumed little endian header parameters
    and big endian image data because the sample image previously used was a
    mixed endian file.  The handler will no longer work as expected with that
    image (`92AV3C`) because it is considered a badly formatted file.  To use
    that file, open it as normal, then toggle the value of ``img.swap`` (change
    from 0 to 1 or 1 to 0).

    * io/erdas.py:
      (open): Read header as little endian.  If that fails, try big endian.
      (readErdasLanHeader): Accept parameter specifying byte order of file.
      Assume header and image data have same byte order.
    
    A specialized version of the kmeans function was created for numpy ndarrays
    (kmeans_ndarray).  For in-memory images, this function is about 10 times
    faster than the original function (about 100 times faster than using SpyFile
    objects). The specialized version of the function is automatically called by
    kmeans if the image argument is an instance of a numpy.ndarray. Several
    positional arguments of kmeans are now keyword arguments and the default
    distance measure is L2 (Euclidean) distance.  If initial cluster centers are
    not passed as a keyword argument, they will be initialized evenly along the
    diagonal of the image data bounding box.
    
    * algorithms/clustering.py:
      (L2): Don't force type of difference operator.
      (kmeans): Several arguments changed to keywords.  Default distance is L2.
      Default for initial cluster centers is along diagonal of image data
      bounding box.  If image argument is an ndarray, call kmeans_ndarray.
      (kmeans_ndarray): New function - a version of kmeans specialized for
    
    Improved status display output.
    
    * utilities/status.py (StatusDisplay): Call sys.stdout.flush() after
      printing status output.
      

2011-01-17	tboggs <tboggs@users.sourceforge.net>

    * __init__.py: Import names from database submodule.
    * graphics/__init__.py: import ColorScale from colorscale.py
    
    * io/spyfile.py (findFilePath): SPECTRAL_DATA directory changed to ":".

    * Changed doc strings to sphinx format:
	* graphics/graphics.py
	* graphics/colorscale.py
	* graphics/hypercube.py
	* database/aster.py
	* spectral.py
	* io/bipfile.py
	* io/spyfile.py
	* io/aviris.py
	* io/erdas.py
	* io/envi.py
	* io/bsqfile.py
	* io/bilfile.py
	* algorithms/algorithms.py
	* algorithms/clustering.py
	* algorithms/perceptron.py
	* algorithms/resampling.py
	* algorithms/classifiers.py

2011-01-11	tboggs <tboggs@users.sourceforge.net>

    * io/bilfile.py (BilFile.readDatum): Add missing byte swap (if needed)
    * io/bipfile.py (BipFile.readDatum): Add missing byte swap (if needed)

2011-01-10	tboggs <tboggs@users.sourceforge.net>

    * algorithms/algorithms.py (unmix, spectralAngles): Fixed import statements.

2011-01-09	tboggs <tboggs@users.sourceforge.net>

    * __init__.py: import AsterDatabase into main module namespace.
    * database/aster.py
      (AsterDatabase.query): Now returns result set instead of string
      (AsterDatabase.printQuery): New method that prints results of a query
       (what query used to do).

2011-01-05	tboggs <tboggs@users.sourceforge.net>

    * algorithms/__init__.py: import BandResampler.
    * algorithms/resampling.py (BandResampler.__init__): Allow BandInfo objects
      to be passed as arguments

2011-01-02	tboggs <tboggs@users.sourceforge.net>

    * algorithms/clustering.py (kmeans): Allow keyboard interrupt (CTRL-c) to
      terminate k-means algorithm.

2010-12-13	tboggs <tboggs@users.sourceforge.net>

    * algorithms/algorithms.py (mean_cov): Use 64 bit float for covariance.
    * algorithms/perceptron(PerceptronClassifier.train): Raise Exception, not
      string.

2010-12-09	tboggs <tboggs@users.sourceforge.net>

    * io/spyfile.py:
      (transformImage): New function to apply a linear transform to either as
        numpy.ndarray, ImageArray, or SpyFile object.
      (TransformedImage.__init__): raise Exception objects instead of strings.
    * algorithms/algorithms.py (TrainingClass.transform): Catch all exceptions
      when calculating log of determinant of covariance.  Call transformImage
      instead of creating a TransformedImage object.

2010-12-05	tboggs <tboggs@users.sourceforge.net>

    * spectral.py: Changed default colors in spyColors.
    * io/envi.py (open): Fixed bug causing open to miss images with no extension.
    * io/aviris.py (readAvirisBands) Use findFilePath to locate cal files.

2010-11-28	tboggs <tboggs@users.sourceforge.net>

    * algorithms/algorithms.py (logDeterminant): Don't sum negative values.

2010-11-14	tboggs <tboggs@users.sourceforge.net>

    cluster algorithm modified to handle cases with only 2 clusters.  Fixed
    reported number of reassigned pixels in kmeans.

    * algorithms/clustering.py:
      (kmeans)
      - Use "cluster" function to initialize clusters if none supplied in args.
      - Corrected calculation of number of reassigned pixels (note: the error
        reported incorrect value to stdout but didn't affect stopping criteria).
      - Fixed default param value in doc string.
      (OnePassClusterer.calcDistances): Force distance matrix to be float type.
      (OnePassClusterer.findNextToGo): Now handles cases with only 2 clusters.
      
    * graphics/graphics.py (getImageDisplayData): Raise Exception object instead
      of string.

2010-11-09	tboggs <tboggs@users.sourceforge.net>

    Fixed several bugs revealed when producing ENVI spectral libraries from
    the Aster database.

    * algorithms/resampling.py (BandResampler.__init__): Compare args to None
      to avoid errors with numpy arrays in logical expressions.
    * io/envi.py
      (SpectralLibrary.save): Fixed call to writeEnviHdr.
      (_writeHeaderParam): Replace commas in parameter values with dashes to
        prevent read errors.
      (writeEnviHdr): Fixed call to _writeHeaderParam.
    * io/spyfile.py (findFilePath): Add missing param to exception string.

2010-10-26	tboggs <tboggs@users.sourceforge.net>

    * algorithms/clustering.py (OnePassClusterer.classifyImage): Fixed typo
      in module import statement

2010-10-18	tboggs <tboggs@users.sourceforge.net>

    Fixed typo in ENVI import and color scale bug.
    
    * graphics/colorscale.py (__init__): Fixed bug when color scale contains
      negative values.
    * io/envi.py (open): Fixed typo when importing bilfile modules.

2010-09-17	tboggs <tboggs@users.sourceforge.net>

    Improved support for ENVI header parameters.  Added search for image file
    names with interleave as extension (e.g., ".bsq").
    
    * io/envi.py
      (readEnviHdr): Modified parsing code to handle text parameters with "=" in
      the parameter value.  Thanks to Robin Wilson for a patch.
      (open): Search for image files with interleave as extension (.bsq, .bil,
      or .bip).
      
    Automatically recognize host byet order.

    * __init__.py: Determine host byte order and set in SPy package.
    
    
2010-09-09	tboggs <tboggs@users.sourceforge.net>

    Added creation of ENVI spectral libraries from the ASTER database and the
    ability to save ENVI spectral libraries to files.
    
    * database/aster.py (AsterDatabase.create) New method to create an ENVI
      spectral library from a list of ASTER spectrum IDs.
    * io/aviris.py (readAvirisBands): Set band unit to "nm".
    * io/envi.py
      (SpectralLibrary.__init__): Import header vals and set ignored value to "NaN".
      (SpectralLibrary.save): New method to save the library to a file.
      (writeEnviHdr): New method to write an ENVI header file.
      (_writeHeaderParam): New method to write an ENVI header file parameter.
      
2010-08-21	tboggs <tboggs@users.sourceforge.net>

    * graphics/hypercube.py (WxHypercubeFrame.LoadTextures): Made name change
      overlooked during package/module name migration.

2010-08-19	tboggs <tboggs@users.sourceforge.net>

    Added a sub-package for ASTER spectral library support. This enables parsing
    ASTER data files & metadata and putting the data into an sqlite database.
    
    * database: New sub-package.
    * database/__init__: New file.
    * database/aster.py: New file for importing & managing ASTER data
    
    * __init__.py: Import BandInfo into top-level spectral namespace.
    
2010-08-17	tboggs <tboggs@users.sourceforge.net>

    * Changed package/module names.  Top-level package is now "spectral" instead
      of "Spectral" (note capitalization).  Sub-packages/modules have also been
      changed but that should be transparent to most users.  Almost all files
      are affected.

2010-07-10	tboggs <tboggs@users.sourceforge.net>

    * Spectral.py (ImageArray.__getitem__): Added method to ensure that data
      extracted is returned as numpy array and not another ImageArray object.

    * __init__.py: Import spyColors from Spectral.py (accidentally removed with
      previous commit).
    
    * Algorithms/Cluster.py (kmeans): Fixed typo in status message.

2010-07-10	tboggs <tboggs@users.sourceforge.net>

    Move GUI-related functions into the Graphics sub-package.  Also, no longer
    attempt to initialize NumTut for image display if wx fails since NumTut no
    longer exists.
    
      * __init__.py: Import GUI functions from Graphics instead of Spectral
      * Spectral.py (initGraphics, initWxPython, initWxPython, initNumTut, view,
        viewIndexed, makePilImage, saveImage): Moved functions from Spectral.py to Graphics.py
      * Graphics/__init__.py: Explicitly import names from the Graphics module.
      * Graphics/Graphics.py(initGraphics, initWxPython, initWxPython, initNumTut,
        view, viewIndexed, makePilImage, saveImage): Moved functions from
	Spectral.py to Graphics.py
      * Graphics/SpyGnuplot.py (plot): Take "source" keyword as argument (although
        it is unused because Gnuplot module is deprecated.)
      * Graphics/Hypercube.py: Import GUI functions from Graphics insted of Spectral.
      
2010-07-10	tboggs <tboggs@users.sourceforge.net>

    * Io/Envi.py (SpectralLibrary): New class for handling spectra read from
      spectral library files in ENVI .hdr./sli format.
      
    * Spectral.py:
      (view, viewIndexed): If GUI thread hasn't been initialized yet,
      try to initialize it.
      (makePilImage): Changed how getImageDisplayData is imported from Graphics.
    
    * Algorithms/Resampling.py: New file for spectral band resampling functions.  

    * Graphics/Graphics.py (getImageDisplayData): Fix data types that were missed
      when removing old Numeric module references.
      
    * Io/SpyFile.py (load): read static member of ImageArray class to decide which
      numeric type to use for loaded data arrays.
      
    * Algorithms/Clustering (kmeans, KmeansClusterer): Changed default number of
      clusters to 10 (to be consistent with the cluster function).

    Create common interface for opening files from different Io modules.
    
      * Spectral.py (image) Use "open" function in I/O modules.
      * Io/__init__.py: Import Aviris, Erdas, and Envi sub-packages.
      * Io/Avris.py (open): New name for the openAviris function.
        (readAvirisBands): Explicitly use __builtin__.open for opening file.
      * Io/Erdas.py (open): New name for the ErdasLan function.
        (readErdasLanHeader): Changed name from ReadErdasLanHeader. Also, explicitly
	use __builtin__.open for opening file.
      * Io/Envi.py (readEnviHdr): Name changed from ReadEnviHdr.
        (open): New name for EnviHdr function.   Now also handles opening spectral
	libraries in ENVI .hdr/.sli format.
	
    Explicityly import names from sub-packages/modules to avoid polluting the
    top-level namespace.
    
      * __init__.py: Explicitly import sub-package/module names.
      * Algorithms/__init__.py: Explicitly import sub-package/module names.
      
2010-07-08	tboggs <tboggs@users.sourceforge.net>

    * Io/Envi.py (EnviHdr): Added support for additional image data types.

2010-07-05	tboggs <tboggs@users.sourceforge.net>

    Updated TransformedImage class to support being initialized from an
    ImageArray object.
    
	* Spectral.py (Image.params): New method.  Some of the content of
	  SpyFile.params has been moved here.
	  (ImageArray.format): New static variable specifying the numpy array type.
	* Io/SpyFile.py:
	  (SpyFile.load): Use ImageArray.format to define array type.
	  (SpyFile.params): Call Image.params and only add parameters not set there.
	  (TransformedImage): Class now derived from Image instead of SpyFile.
	  Added _typecode class varialble to specify type of returned numpy arrays.
	  (TransformedImage.__getitem__): __getitem__, readSubImage, and readSubRegion
	  now handle case when TransformedImage is defined relative to an ImageArray object.
	  (TransformedImage.typecode): New method.

2010-07-03	tboggs <tboggs@users.sourceforge.net>

    The isoCluster function has been re-named k-means, which is a more accurate
    description of the algorithm.
    
	* Algorithms/__init__.py: Explicitly import functions from Clustering
	* Algorithms/Cluster.py:
	  (IsoClusterer): Class renamed KmeansClusterer
	  (isoCluster): Function renamed kmeans. The isoCluster function is now
	  a pass-through to the kmeans function and issues a deprecation warning.

2010-07-02	tboggs <tboggs@users.sourceforge.net>

    Added an Image base class from which SpyFile and the new ImageArray class are
    derived.  ImageArray is also derived from numpy.ndarray - It is used when
    loading an entire image and can be treated like a numpy array but also has
    much of the additional info that was contained in the SpyFile class.
    
    SpyFile objects now have a scaleFactor member which represents a multiplier
    for data in HSI files.  When data are read from a file, they are divided by
    scale factor to return the actual reflectance (or other quantity).
    
	* Spectral/Spectral.py:
	  (BandInfo): New class to characterize spectral bands for an image.
	  (Image): A base class for hyperspectral image classes. Some of the
	  image metadata formerly contained in the SpyFile class (now derived
	  from Image) has been moved here.
	  (ImageArray): A new class derived from Spectral.Image and Spectral.SpyFile.
	  It contains data loaded from a file refered-to by a SpyFile object.
	  (image): Aviris function was renamed to openAviris.
	* __init__.py: import openAviris function.
	* Io/BilFile.py (readBand, readBands, readPixel, readSubRegion, readSubImage, readDatum):
	  Divide data by scaleFactor before returning.
	* Io/BipFile.py: Ditto
	* Io/BsqFile.py: Ditto
	* Io/SpyFile: (__init__): initialize scaleFactor member
	  (load): divide data by scaleFactor before returning.
	* Io/Aviris.py (Aviris): Function renamed to openAviris.  Read band info if
	  spectral calibration file is specified.
	  (readAvirisBands): New function to read AVIRIS spectral calibration file.
	* Io/Envi.py (EnviHdr): Set scale factor and add spectral band info if present.
    
    Updated graphics code to plot spectra for double-clicks on generic Image
    objects and plot spectral bands along with data for pixel spectrum plots.

	* Graphics/Graphics.py:
	  (getImageDisplayData): Removed references to oldnumeric data types.
	  Support generic Spectral.Image objects (not just SpyFile objects).
	  (doubleClick): Unused method removed.
	* Graphics/SpyPylab.py (plot): If available, plot data against spectral
	  bands associated with the band and display band unit in x-label.
	* Graphics/SpyWxPythonThread.py (WxImageFrame.leftDoubleClick): Support
	  generic Spectral.Image objects (not just SpyFile objects).

2010-06-28	tboggs <tboggs@users.sourceforge.net>

    Added ImageArray class to handle data loaded from SpyFile objects.

	* Spectral.py (Image, ImageArray): New classes.
	* Io/SpyFile.py (SpyFile): Now derived from Spectral.Image class.
	  (__init__): Call base class setParams before SpyFile.setParams.
	  (setParams): Only initialize params not handled by base class.
	  (load): New method to read all data into a Spectral.ImageArray object.
	  Graphics/SpyWxPython.py (view): Associate data source when requesting
	  spectrum plot for an ImageArray object.
	
    * Io/Envi.py(ReadEnviHdr): Don't skip first parameter in file.
    
    * Io/BilFile.py(readBand, readBands, readSubRegion, readSubImage): Removed
      unecessary code for Numeric compatibility.

2010-06-21	tboggs <tboggs@users.sourceforge.net>

    Migrating from Gnuplot to Pylab (Matplotlib)

	* Spectral.py (viewIndexed): Updated for new viewer interface introduced
	  with previous commit.

2010-06-03	tboggs <tboggs@users.sourceforge.net>

    Migrating from Gnuplot to Pylab (Matplotlib)

	* Spectral.py (initWxPython, initNumTut, initGraphics, view, viewIndexed):
	  Use package-level settings object to specify viewer and plotter.
	* Graphics/Hypercube.py (WxHypercubeFrame.__init__): Handle case when
	  window name is not passed as kwarg.
	* Graphics/SpyGnuplot.py (plot) Updated line style for new Gnuplot syntax.
	* Graphics/SpyPylab.py: New file for Pylab interface.
	* Graphics/SpyWxPythonThread.py:
	  (WxImageFrame.leftDoubleClick): Import generic plotter
	* __init__.py: Do not set "qp" or "plot" variable.  Instead, use "settings"
	  object that is imported from Spectral.py.
	  
    Removing CVSROOT directory since we are now using Subversion
        * CVSROOT/*: Deleted

2010-05-21	tboggs <tboggs@users.sourceforge.net>

    Changes to handle migration of Set to built-in type and Numeric-NumPy changes.

	* Spectral.py (initGraphics): prevent multiple initializations of graphics handlers
	* Io/SpyFile (typecode): Return appropriate typecode for NumPy arrays.
	* Algorithms/Algorithms.py:
	  Set correct numpy array typecodes
	  (createTrainingClasses): Handle migration of Set to built-in type.
	* Algorithms/Classifiers (MahalanobisDistanceClassifier.train):
	  numpy.Float changed to numpy.float

	* Algorithms/Perceptron.py: Major rewrite to fix bug in perceptron bias
	   and to support arbitrary number of hidden layers.

2009-12-12	tboggs <tboggs@users.sourceforge.net>

    Changed SpyGnuplot.py for python 2.6 compatibility.

	* Graphics/SpyGnuplot.py: Removed "with" parameter from function calls.

2008-02-28	tboggs <tboggs@users.sourceforge.net>

    Massive updates to upgrade SPy to Python 2.5, NumPy, and wxPython 2.8.

	* __init__.py: Changed import from Numeric to numpy
	* Spectral.py: Updated copyright.  Converted to numpy import.
	  (makePilImage): Converted to numpy.
	  (tileImage): Converted to numpy.
	* Algorithms/Algorithms.py: Updated copyright. Converted to numpy import.
	  (ImageIterator.__iter__): Removed unecessary typecode variable.
	  (ImageMaskIterator): Converted to numpy.
	  (iterator): Converted to numpy.
	  (mean_cov): Converted to numpy.
	  (principalComponents): Converted to numpy.  Note that eigenvectors
	    returned by numpy are in columns (not rows like Numeric).
	  (linearDiscriminant): Converted to numpy.  Note that eigenvectors
	    returned by numpy are in columns (not rows like Numeric).
	  (reduceEigenvectors): Converted to numpy.
	  (logDeterminant): Converted to numpy.
	  (TrainingClass.size): Converted to numpy.
	  (TrainingClass.calcStatistics): Converted to numpy. Calculate
	    invCov and logDetCov.
	  (TrainingClass.transform): Converted to numpy.
	  (TrainingClassSet.__item__): Renamed method __getitem__.
	  (createTrainingClasses): Converted to numpy.
	  (ndvi): Converted to numpy.
	  (bDistanceTerms): Corrected to use values in stats objects of
	    training class objects.
	  (transformImage): Converted to numpy.
	  (orthogonalize): Converted to numpy.
	  (unmix): Converted to numpy.
	  (spectralAngles): Converted to numpy.
	* Algorithms/Classifiers.py: Updated copyright.
	  (Classifier.classifyImage): Converted to numpy.
	  (GaussianClassifier.train): Converted to numpy.
	  (GaussianClassifier.classifySpectrum): Converted to numpy.
	  (MahalanobisDistanceClassifier.train): Converted to numpy.
	  (MahalanobisDistanceClassifier.classifySpectrum): Converted to numpy.
	* Algorithms/Cluster.py: Updated copyright.
	  (L1): Converted to numpy.
	  (L2): Converted to numpy. Return distance instead of distance^2.
	  (isoCluster): Converted to numpy.
	  (clusterOnePass): Converted to numpy.
	  (OnePassClusterer): Converted to numpy.
	* Algorithms/Perceptron.py: Updated copyright.
	  (Perceptron.__init__): Converted to numpy.
	  (Perceptron.input): Converted to numpy.
	  (Perceptron.train): Converted to numpy.
	  (MultiLayerPerceptron.input): Converted to numpy.
	  (MultiLayerPerceptron.train): Converted to numpy.
	  (MultiLayerPerceptron.resetCorrections): Converted to numpy.
	  (PerceptronClassifier.classifySpectrum): Converted to numpy.
	  (PerceptronClassifier.initializeWeights): Converted to numpy.
	* Graphics/ColorScale.py: Updated copyright.
	  (ColorScale.__init__): Converted to numpy.
	  (ColorScale.createDefaultColorScale): Converted to numpy.
	* Graphics/Graphics.py: Updated copyright.
	  (getImageDisplayData): Converted to numpy.
	* Graphics/Hypercube.py: Massive rewrite to accomdate changes in wx and switch
	  to numpy.  Updated copyright.
	* SpyGnuplot.py: Updated copyright.
	  (plot): Converted to numpy.
	* Graphics/SpyNumTut.py: Updated copyright.
	  (view): Converted to numpy.
	* Graphics/SpyWxPython.py: Updated copyright.
	  (SpyWxPythonThreadStarter.view): wx 2.8 syntax change. Converted to numpy.
	* Graphics/SpyWxPythonThread.py: Updated copyright. Handle numpy and wx changes.
	  (ViewImageRequest.__init__): wx 2.8 syntax change.
	  (HiddenCatcher): wx 2.8 syntax change.
	  (HiddenCatcher.__init__): wx 2.8 syntax change.
	  (HiddenCatcher.viewImage): wx 2.8 syntax change.
	  (WxImageFrame): wx 2.8 syntax change.
	  (WxImageFrame.__init__): wx 2.8 syntax change.
	  (WxImageFrame.viewImage): wx 2.8 syntax change.
	  (WxImageFrame.OnPaint): wx 2.8 syntax change.
	  (WxImageServer): wx 2.8 syntax change.
	  (WxImageServer.OnInit): wx 2.8 syntax change.
	* Io/Aviris.py: Updated copyright.
	  (Aviris): Changed typecode for numpy.
	* Io/BilFile.py: Updated copyright.
	  (BilFile.readBand): Converted to numpy.
	  (BilFile.readBands): Converted to numpy - Using dtype instead of typecode.
	  (BilFile.readPixel): Converted to numpy.
	  (BilFile.readSubRegion): Converted to numpy - Using dtype instead of typecode.
	  (BilFile.readSubImage): Converted to numpy - Using dtype instead of typecode.
	* Io/BipFile.py: Updated copyright.
	  (BipFile.readBand): Converted to numpy.
	  (BipFile.readBands): Converted to numpy - Using dtype instead of typecode.
	  (BipFile.readPixel): Converted to numpy.
	  (BipFile.readSubRegion): Converted to numpy - Using dtype instead of typecode.
	  (BipFile.readSubImage): Converted to numpy - Using dtype instead of typecode.
	* Io/BdsqFile.py: Updated copyright.
	  (BsqFile.readBand): Converted to numpy.
	  (BsqFile.readBands): Converted to numpy - Using dtype instead of typecode.
	  (BsqFile.readPixel): Converted to numpy.
	  (BsqFile.readSubRegion): Converted to numpy - Using dtype instead of typecode.
	  (BsqFile.readSubImage): Converted to numpy - Using dtype instead of typecode.
	* Io/Erdas.py: Updated copyright.
	  (ErdasLan): Converted to numpy - Using dtype instead of typecode.
	  (ReadErdasLanHeader): Converted to numpy - Using dtype instead of typecode.
	* Io/Envi.py: Updated copyright.
	  (EnviHdr): Converted to numpy - Using dtype instead of typecode.
	* Io/SpyFile.py: Updated copyright.
	  (SpyFile.__str__): Fixed bug incorrectly accessing typecode.
	  (TransformedImage.__init__): Converted to numpy.
	  (TransformedImage.__getitem__): Converted to numpy.
	  (TransformedImage.readPixel): Converted to numpy.
	  (TransformedImage.readSubRegion): Converted to numpy.
	  (TransformedImage.readSubImage): Converted to numpy.
	  (TransformedImage.readDatum): Converted to numpy.
	  (TransformedImage.readBands): New function.




2006-07-16	tboggs <tboggs@users.sourceforge.net>

    Documentation:

	* Algorithms/Classifiers.py: Added module-level doc string.
	* Algorithms/Cluster.py: Added module-level doc string.
	* Io/SpyFile.py:  Added module-level doc string.

	* Algorithms/Algorithms.py
	  (linearDiscriminant, bDistanceTerms, orthogonalize): Fixed doc string.


2006-07-14	tboggs <tboggs@users.sourceforge.net>

    Implemented formal TrainingClassSet class to hold training classes.

    Renamed canonicalAnalysis to proper linearDiscriminant.

    Added several sample iterator classes.

	* Algorithms/Algorithms.py
	  (ImageMaskIterator.__iter__): Handle case where shape of sample is
	    rank-3 instead of rank-1.
	  (canonicalAnalysis): Renamed to linearDiscriminant.
	  (TrainingClass): Added numBands member. Added sample iteration.
	    Renamed transformStatistics to simply transform.
	  (SampleIterator): New class.
	  (TrainingClassSet): New class.
	* Algorithms/Classifiers.py:
	  (GaussianClassifier.classifySpectrum): Handling TrainingClassSet
	    objects now instead of lists of TrainingClass objects.
	  MahalanobisDistanceClassifier.classifySpectrum): Ditto.

    Added Multi-Layer Perceptron neural network classifier.

	* Algorithms/__init__.py: Importing PerceptronClassifier.
	* Algorithms/Perceptron.py: New file containing multi-layer Perceptron
	  classifier.

    Fixed bug where glGenTextures was returning bad numbers under linux

	* Graphics/Hypercube.py(WxHypercubeWindow): Wait to load textures
          until after window is initialized.


2006-06-24	tboggs <tboggs@users.sourceforge.net>

    Added code for rendering interactive hypercubes.

	* Graphics/ColorScale.py: New file for creating color scales.
	* Graphics/Hypercube.py: New file for rendering hypercubes.
	* Graphics/SpyWxPython.py:
	  Updated copyright header.
	  (SpyWxPythonThreadStarter.view) - Converted kwargs to **kwargs.
	  (view) - Converted kwargs to **kwargs.
	* Graphics/SpyWxPythonThread.py:
	  Updated copyright header.
	  (ViewImageRequest.__init__): Converted kwargs from arg to **kwargs.
	  (HiddenCatcher.viewImage):  Now accepts an arbitrary functor (that
	    returns a wxFrame) to perform window construction and rendering.
	  (WxImageFrame.__init__): Converted kwargs from arg to **kwargs.
	  (WxImageServer.OnInit): Settting app reference in HiddenCatcher.

    Fixed bug in file exception handling code.

	* Io/SpyFile.py:
	  Updated copyright header.
	  (findFilePath): Fixed [ironic] error in exception handling code.

    Searching for additional ENVI file extensions.

	* Io/Envi.py (EnviHdr): Look for .dat and .DAT file extensions.

    Prevent import warnings.

	* Io/BipFile.py:
	  (BipFile.readSubRegion): Avoid method-level import *.
	  (BipFile.readSubImage): Avoid method-level import *.


2006-06-20	tboggs <tboggs@users.sourceforge.net>

    Functions that open data files now search for the files in directories
    specified in the SPECTRAL_DATA environment variable. SPECTRAL_DATA contains
    a semi-colon delimited list of directories.  cwd is always searched first.

	* Io/Erdas.py (ErdasLan): Modified to search SPECTRAL_DATA directories. 
	* Spectral.py (image): Ditto.
	* Io/Envi.py (EnviHdr): Ditto
	* Io/Aviris.py (Aviris): Ditto
	* Io/SpyFile.py (SpyFile.setParams): Ditto.
	*   (findFilePath): New function to determine data file path.

    * __init__.py : Updated __version__ to 0.3

2006-06-16	tboggs <tboggs@users.sourceforge.net>

    * Converted clustering functions into Classifier classes.
    * Added Mahalanobis Classifier.
    * Corrected several copyright headers.

	* Algorithms/__init__.py: Corrected copyright header.
	* Algorithms/Algorithms.py:
	  (mean_cov): Corrected doc string. Removed unused time import.
	* Algorithms/Classifiers.py: Added copyright header.
	  (Classifier.classifiyImage): Changed typecode of classification map.
	  (MahalanobisDistanceClassifier): New class
	* Algorithms/Cluster.py:
	  (cluster): Modified to use new OnePassClusterer class.
	  (IsoClusterer.): New class
	  (OnePassClusterer): New class replacing OnePassClusterEngine.
	* Io/BsqFile.py: Corrected copyright header.
	* Utilities/Status.py: Corrected copyright header.

2006-05-25	tboggs <tboggs@users.sourceforge.net>

    * Created new directories for Algorithms and Utilities.
    * Encapsulated classification algorithms into classes.
    * Added status display object for cleaner status output.

	* __init__.py:
	  Changed several imports due to package restructuring.
	  Setting package-level status member.
	  Incremented SPy version to 0.2
	* Spectral.py (tileImage): Now reads SubImages instead of SubRegions.
	* Algorithms/Algorithms.py : Moved file from Spectral/.
	  Added iterator classes and functions for generic iteration over image
	    pixels.
	  (mean_cov): Now additionally returns number of pixels used in
	    calculating the mean and std dev.
	  (TrainingSet) Several changes and is renamed TrainingClass.
	* Algorithms/__init__.py: New file.
	* Algorithms/Classifiers.py: New file.
	* Algorithms/Cluster.py: Moved from Spectral/.
	* Io/BilFile.py (readSubRegion): Upper bound is now exclusive to match
	  python slice syntax
	* Io/BipFile.py: ditto
	* Io/BsqFile.py: ditto
	* Io/SpyFile.py (TransformedImage): Fixed broken logic for reading
	  data from TransformedImage objects.
	* Utilities/__init__.py: New file.
	* Utilities/Status.py: New file containing StatusDisplay class that
	  provides pretty output for status messages.
