00001 //# ImageMoments.h: generate moments from images 00002 //# Copyright (C) 1996,1997,1998,1999,2000,2001,2002,2003 00003 //# Associated Universities, Inc. Washington DC, USA. 00004 //# 00005 //# This library is free software; you can redistribute it and/or modify it 00006 //# under the terms of the GNU Library General Public License as published by 00007 //# the Free Software Foundation; either version 2 of the License, or (at your 00008 //# option) any later version. 00009 //# 00010 //# This library is distributed in the hope that it will be useful, but WITHOUT 00011 //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00012 //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 00013 //# License for more details. 00014 //# 00015 //# You should have received a copy of the GNU Library General Public License 00016 //# along with this library; if not, write to the Free Software Foundation, 00017 //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA. 00018 //# 00019 //# Correspondence concerning AIPS++ should be addressed as follows: 00020 //# Internet email: aips2-request@nrao.edu. 00021 //# Postal address: AIPS++ Project Office 00022 //# National Radio Astronomy Observatory 00023 //# 520 Edgemont Road 00024 //# Charlottesville, VA 22903-2475 USA 00025 //# 00026 //# $Id: ImageMoments.h 20299 2008-04-03 05:56:44Z gervandiepen $ 00027 00028 #ifndef IMAGES_IMAGEMOMENTS_H 00029 #define IMAGES_IMAGEMOMENTS_H 00030 00031 #include <imageanalysis/ImageAnalysis/MomentsBase.h> 00032 00033 #include <imageanalysis/ImageTypedefs.h> 00034 00035 namespace casa { 00036 00037 class ImageMomentsProgressMonitor; 00038 template <class T> class MaskedLattice; 00039 00040 // <summary> 00041 // This class generates moments from an image. 00042 // </summary> 00043 00044 // <use visibility=export> 00045 00046 // <reviewed reviewer="" date="yyyy/mm/dd" tests="" demos=""> 00047 // </reviewed> 00048 00049 // <prerequisite> 00050 // <li> <linkto class="ImageInterface">ImageInterface</linkto> 00051 // <li> <linkto class="MomentsBase">MomentsBase</linkto> 00052 // <li> <linkto class="LatticeApply">LatticeApply</linkto> 00053 // <li> <linkto class="MomentCalcBase">MomentCalcBase</linkto> 00054 // </prerequisite> 00055 00056 // <etymology> 00057 // This class computes moments from images 00058 // </etymology> 00059 00060 // <synopsis> 00061 // The primary goal of this class is to help spectral-line astronomers analyze 00062 // their multi-dimensional images by generating moments of a specified axis. 00063 // The word "moment" is used loosely here. It refers to collapsing an axis 00064 // to one pixel and putting the value of that pixel (for all of the other 00065 // non-collapsed axes) to something computed from the data values along 00066 // the moment axis. For example, take an RA-DEC-Velocity cube, collapse 00067 // the velocity axis by computing the mean intensity at each RA-DEC 00068 // pixel. This class offers many different moments and a variety of 00069 // interactive and automatic ways to compute them. 00070 // 00071 // This class only accepts images of type <src>Float</src> and <src>Double</src>. 00072 // This restriction is because of the plotting capabilities which are a 00073 // bit awkward for other types. 00074 // 00075 // This class makes a distinction between a "moment" and a "method". This 00076 // boundary is a little blurred, but it claims to refer to the distinction 00077 // of what you are computing, as to how the pixels that were included in the 00078 // computation were selected. For example, a "moment" would be the average value 00079 // of some pixels. A method for selecting those pixels would be a simple range 00080 // specifying a range for which pixels should be included. 00081 // 00082 // The default state of this class is to do nothing. If you specify an image via 00083 // the <src>setImage</src> function then invoking the <src>createMoments</src> 00084 // function will cause it to compute the integrated itensity along the 00085 // spectral axis of the image (if it can find one). You can change the 00086 // computational state of the class from this basic form via the remaining 00087 // <src>set</src> functions. You can call any number of these functions to 00088 // suit your needs. 00089 // 00090 // Because there are a wide variety of methods available, if you specify an 00091 // invalid combination, a table showing the available methods is listed. It 00092 // is reproduced below for convenience. 00093 // 00094 // The basic method is to just compute moments directly from the pixel intensities. 00095 // This can be modified by applying pixel intensity inclusion or exclusion ranges. 00096 // You can then also smooth the image and compute a mask based on the inclusion or 00097 // exclusion ranges applied to the smoothed image. This mask is then applied to 00098 // the unsmoothed data for moment computation. 00099 // 00100 // The window method does no pixel intensity range selection. Instead a spectral 00101 // window is found (hopefully surrounding the spectral line feature) and only the 00102 // pixels in that window are used for computation. This window can be found from the 00103 // smoothed or unsmoothed data. The moments are always computed from the unsmoothed 00104 // data. For each spectrum, the window can be found interactively or automatically. 00105 // There are two interactive methods. Either you just mark the window with the 00106 // cursor, or you interactively fit a Gaussian to the profile and the +/- 3-sigma 00107 // window is returned. There are two automatic methods. Either Bosma's converging 00108 // mean algorithm is used, or an automatically fit Gaussian +/- 3-sigma window 00109 // is returned. 00110 // 00111 // The fitting method fits Gaussians to spectral features either automatically 00112 // or interactively. The moments are then computed from the Gaussian fits 00113 // (not the data themselves). 00114 // 00115 // When an output image is created, it will have N-1 axes, where the input image 00116 // has N axes. In the output image, the physical axis corresponding to the moment 00117 // axis will have been removed, but the coordinate information will be retained 00118 // for future coordinate transformations. For example, if you have a RA-DEC-VELOCITY 00119 // image and you collapsed axis 2 (the DEC axis) the output images would be 00120 // RA-VELOCITY with the coordinate information retained for the DEC axis so that 00121 // the coupled nature of RA/DEC coordinates is preserved. 00122 // 00123 // Output images are created with an all True (good) mask. If, for a given 00124 // pixel, the moment calculation fails, then the mask is set to F. 00125 // 00126 // When making plots, the order in which the spectra are displayed is determined 00127 // by the tiling sequence of the image (for optimum speed of access). 00128 // 00129 // 00130 // <srcblock> 00131 // Allowed Methods 00132 // --------------- 00133 // 00134 // Smooth Window Fit in/exclude Interactive 00135 // ----------------------------------------------------- 00136 // N N N N N 00137 // Y/N N N Y N 00138 // 00139 // Y/N Y N N Y 00140 // Y/N Y N N N 00141 // Y/N Y Y N Y/N 00142 // 00143 // N N Y N Y/N 00144 // ---------------------------------------------------- 00145 // </srcblock> 00146 // 00147 // <note role=caution> 00148 // Note that the <src>MEDIAN_COORDINATE</src> moment is not very robust. 00149 // It is very useful for generating quickly a velocity field in a way 00150 // that is not sensitive to noise. However, it will only give sensible 00151 // results under certain conditions. It treats the spectrum as a 00152 // probability distribution, generates the cumulative distribution for 00153 // the selected pixels (via an <src>include</src> or <src>exclude</src> 00154 // pixel range, and finds the (interpolated) coordinate coresponding to 00155 // the 50% value. The generation of the cumulative distribution and the 00156 // finding of the 50% level really only makes sense if the cumulative 00157 // distribution is monotonically increasing. This essentially means only 00158 // selecting pixels which are positive or negative. For this reason, this 00159 // moment type is *only* supported with the basic method (i.e. no smoothing, 00160 // no windowing, no fitting) with a pixel selection range that is either 00161 // all positive, or all negative. 00162 // </note> 00163 // 00164 // <note role=tip> 00165 // If you ignore return error statuses from the functions that set the 00166 // state of the class, the internal status of the class is set to bad. 00167 // This means it will just keep on returning error conditions until you 00168 // explicitly recover the situation. A message describing the last 00169 // error condition can be recovered with function errorMessage. 00170 // </note> 00171 // </synopsis> 00172 00173 // <example> 00174 // <srcBlock> 00176 // 00177 // Vector<Int> moments(2); 00178 // moments(0) = ImageMoments<Float>::AVERAGE; 00179 // moments(1) = ImageMoments<Float>::WEIGHTED_MEAN_COORDINATE; 00180 // Vector<int> methods(2); 00181 // methods(0) = ImageMoments<Float>::WINDOW; 00182 // methods(1) = ImageMoments<Float>::INTERACTIVE; 00183 // Vector<Int> nxy(2); 00184 // nxy(0) = 3; 00185 // nxy(1) = 3; 00186 // 00188 // 00189 // PagedImage<Float> inImage(inName); 00190 // 00192 // 00193 // LogOrigin or("myClass", "myFunction(...)", WHERE); 00194 // LogIO os(or); 00195 // ImageMoments<Float> moment(SubImage<Float>(inName), os); 00196 // 00198 // 00199 // if (!moment.setMoments(moments)) return 1; 00200 // if (!moment.setWinFitMethod(methods)) return 1; 00201 // if (!moment.setMomentAxis(3)) return 1; 00202 // if (!moment.setPlotting("/xs", nxy)) return 1; 00203 // 00205 // 00206 // if (!moment.createMoments()) return 1; 00207 // </srcBlock> 00208 // In this example, we generate two moments (average intensity and intensity 00209 // weighted mean coordinate -- usually the velocity field) of axis 3 by the 00210 // interactive window method. The interactive plotting is done on the 00211 // device called <src>/xs</src> (no longer supported). We put 9 subplots on each page. The output 00212 // file names are constructed by the class from the input file name plus some 00213 // internally generated suffixes. 00214 // </example> 00215 00216 // <motivation> 00217 // This is a fundamental and traditional piece of spectral-line image analysis. 00218 // </motivation> 00219 00220 // <todo asof="1996/11/26"> 00221 // <li> more control over histogram of image noise at start (pixel 00222 // range and number of bins) 00223 // <li> better algorithm for seeing if spectrum is pure noise 00224 // <li> Make this class extensible so users could add their own method. 00225 // </todo> 00226 00227 00228 template <class T> class ImageMoments : public MomentsBase<T> { 00229 public: 00230 00231 // Note that if I don't put MomentCalcBase as a forward declaration 00232 // and use instead "friend class MomentCalcBase<T>" The gnu compiler 00233 // fails with a typedef problem. But I can't solve it with say 00234 // <src>typedef MomentCalcBase<T> gpp_type;</src> because you can only do a 00235 // typedef with an actual type, not a <tt>T</tt> ! 00236 friend class MomentCalcBase<T>; 00237 00238 ImageMoments() = delete; 00239 00240 // Constructor takes an image and a <src>LogIO</src> object for logging purposes. 00241 // You specify whether output images are automatically overwritten if pre-existing, 00242 // or whether an intercative choice dialog widget appears (overWriteOutput=F) 00243 // You may also determine whether a progress meter is displayed or not. 00244 ImageMoments ( 00245 const ImageInterface<T>& image, 00246 LogIO &os, 00247 Bool overWriteOutput=False, 00248 Bool showProgress=True 00249 ); 00250 00251 ImageMoments(const ImageMoments<T> &other) = delete; 00252 00253 // Destructor 00254 ~ImageMoments(); 00255 00256 ImageMoments<T> &operator=(const ImageMoments<T> &other) = delete; 00257 00258 // Set the moment axis (0 relative). A return value of <src>False</src> 00259 // indicates that the axis was not contained in the image. If you don't 00260 // call this function, the default state of the class is to set the 00261 // moment axis to the spectral axis if it can find one. Otherwise 00262 // an error will result. 00263 Bool setMomentAxis (Int momentAxis); 00264 00265 // This function invokes smoothing of the input image. Give <src>Int</src> 00266 // arrays for the axes (0 relative) to be smoothed and the smoothing kernel 00267 // types (use the <src>enum KernelTypes</src>) for each axis. Give a 00268 // <src>Double</src> array for the widths (full width for BOXCAR and full 00269 // width at half maximum for GAUSSIAN) in pixels of the smoothing kernels for 00270 // each axis. For HANNING smoothing, you always get the quarter-half-quarter 00271 // kernel (no matter what you might ask for). A return value of <src>False</src> 00272 // indicates that you have given an inconsistent or invalid set of smoothing 00273 // parameters. If you don't call this function the default state of the 00274 // class is to do no smoothing. The kernel types are specified with 00275 // the VectorKernel::KernelTypes enum 00276 Bool setSmoothMethod( 00277 const Vector<Int>& smoothAxes, 00278 const Vector<Int>& kernelTypes, 00279 const Vector<Quantum<Double> >& kernelWidths 00280 ); 00281 00282 Bool setSmoothMethod( 00283 const Vector<Int>& smoothAxes, 00284 const Vector<Int>& kernelTypes, 00285 const Vector<Double>& kernelWidths 00286 ); 00287 00288 // This is the function that does all the computational work. It should be called 00289 // after the <src>set</src> functions. 00290 // If the axis being collapsed comes from a coordinate with one axis only, 00291 // the axis and its coordinate are physically removed from the output image. Otherwise, 00292 // if <src>removeAxes=True</src> then the output axis is logically removed from the 00293 // the output CoordinateSystem. If <src>removeAxes=False</src> then the axis 00294 // is retained with shape=1 and with its original coordinate information (which 00295 // is probably meaningless). 00296 // 00297 // The output vector will hold PagedImages or TempImages (doTemp=True). 00298 // If doTemp is True, the outFileName is not used. 00299 // 00300 // If you create PagedImages, outFileName is the root name for 00301 // the output files. Suffixes will be made up internally to append 00302 // to this root. If you only ask for one moment, 00303 // this will be the actual name of the output file. If you don't set this 00304 // variable, the default state of the class is to set the output name root to 00305 // the name of the input file. 00306 vector<SHARED_PTR<MaskedLattice<T> > > createMoments( 00307 Bool doTemp, const String& outFileName, 00308 Bool removeAxes=True 00309 ); 00310 00311 // Set a new image. A return value of <src>False</src> indicates the 00312 // image had an invalid type (this class only accepts Float or Double images). 00313 Bool setNewImage (const ImageInterface<T>& image); 00314 00315 // Get CoordinateSystem 00316 const CoordinateSystem& coordinates() {return _image->coordinates();}; 00317 00318 // Get shape 00319 IPosition getShape() const { return _image->shape(); } 00320 00321 //Set an ImageMomentsProgressMonitor interested in getting updates on the 00322 //progress of the collapse process. 00323 void setProgressMonitor(ImageMomentsProgressMonitor* progressMonitor); 00324 00325 private: 00326 00327 SPCIIT _image = SPCIIT(nullptr); 00328 ImageMomentsProgressMonitor* _progressMonitor = nullptr; 00329 00330 // Smooth an image 00331 SPIIT _smoothImage(); 00332 00333 // Determine the noise by fitting a Gaussian to a histogram 00334 // of the entire image above the 25% levels. If a plotting 00335 // device is set, the user can interact with this process. 00336 void _whatIsTheNoise (T& noise, const ImageInterface<T>& image); 00337 00338 protected: 00339 using MomentsBase<T>::os_p; 00340 using MomentsBase<T>::showProgress_p; 00341 using MomentsBase<T>::momentAxisDefault_p; 00342 using MomentsBase<T>::peakSNR_p; 00343 using MomentsBase<T>::stdDeviation_p; 00344 using MomentsBase<T>::yMin_p; 00345 using MomentsBase<T>::yMax_p; 00346 using MomentsBase<T>::out_p; 00347 using MomentsBase<T>::smoothOut_p; 00348 using MomentsBase<T>::goodParameterStatus_p; 00349 using MomentsBase<T>::doWindow_p; 00350 using MomentsBase<T>::doFit_p; 00351 using MomentsBase<T>::doSmooth_p; 00352 using MomentsBase<T>::noInclude_p; 00353 using MomentsBase<T>::noExclude_p; 00354 using MomentsBase<T>::fixedYLimits_p; 00355 using MomentsBase<T>::momentAxis_p; 00356 using MomentsBase<T>::worldMomentAxis_p; 00357 using MomentsBase<T>::kernelTypes_p; 00358 using MomentsBase<T>::kernelWidths_p; 00359 using MomentsBase<T>::moments_p; 00360 using MomentsBase<T>::selectRange_p; 00361 using MomentsBase<T>::smoothAxes_p; 00362 using MomentsBase<T>::overWriteOutput_p; 00363 using MomentsBase<T>::error_p; 00364 using MomentsBase<T>::convertToVelocity_p; 00365 using MomentsBase<T>::velocityType_p; 00366 using MomentsBase<T>::_checkMethod; 00367 }; 00368 00369 } 00370 00371 #ifndef CASACORE_NO_AUTO_TEMPLATES 00372 #include <imageanalysis/ImageAnalysis/ImageMoments.tcc> 00373 #endif 00374 #endif