00001 00002 //# ImageFit1D.h: Class to fit profiles to vectors from images 00003 //# Copyright (C) 2004 00004 //# Associated Universities, Inc. Washington DC, USA. 00005 //# 00006 //# This library is free software; you can redistribute it and/or modify it 00007 //# under the terms of the GNU Library General Public License as published by 00008 //# the Free Software Foundation; either version 2 of the License, or (at your 00009 //# option) any later version. 00010 //# 00011 //# This library is distributed in the hope that it will be useful, but WITHOUT 00012 //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00013 //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 00014 //# License for more details. 00015 //# 00016 //# You should have received a copy of the GNU Library General Public License 00017 //# along with this library; if not, write to the Free Software Foundation, 00018 //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA. 00019 //# 00020 //# Correspondence concerning AIPS++ should be addressed as follows: 00021 //# Internet email: aips2-request@nrao.edu. 00022 //# Postal address: AIPS++ Project Office 00023 //# National Radio Astronomy Observatory 00024 //# 520 Edgemont Road 00025 //# Charlottesville, VA 22903-2475 USA 00026 //# 00027 //# $Id: ImageFit1D.h 20229 2008-01-29 15:19:06Z gervandiepen $ 00028 00029 #ifndef IMAGES_IMAGEFIT1D_H 00030 #define IMAGES_IMAGEFIT1D_H 00031 00032 //# Includes 00033 #include <casa/aips.h> 00034 #include <casa/Arrays/Vector.h> 00035 #include <scimath/Mathematics/NumericTraits.h> 00036 #include <measures/Measures/MDirection.h> 00037 #include <measures/Measures/MFrequency.h> 00038 #include <measures/Measures/MDoppler.h> 00039 #include <coordinates/Coordinates/CoordinateSystem.h> 00040 #include <components/SpectralComponents/ProfileFit1D.h> 00041 00042 #include <memory> 00043 00044 namespace casa { 00045 00046 class SpectralElement; 00047 class SpectralList; 00048 class ImageRegion; 00049 template<class T> class ImageInterface; 00050 00051 00052 // <summary> 00053 // Fit spectral components to a Vector of data from an image 00054 // </summary> 00055 00056 // <use visibility=export> 00057 00058 // <reviewed reviewer="" date="" tests="tImageFit1D.cc"> 00059 // </reviewed> 00060 00061 // <prerequisite> 00062 // <li> <linkto class="SpectralElement">SpectralElement</linkto> 00063 // <li> <linkto class="SpectralList">SpectralList</linkto> 00064 // <li> <linkto class="SpectralFit">SpectralFit</linkto> 00065 // <li> <linkto class="ProfileFit1D">ProfileFit1D</linkto> 00066 // </prerequisite> 00067 00068 // <synopsis> 00069 // Fit lists (held in class SpectralList) of SpectralElements to a Vector of data 00070 // from the image. Each SpectralElement can be one from a variety of types. 00071 // The values of the parameters for each SpectralElement provide the initial 00072 // starting guesses for the fitting process. 00073 // 00074 // You specify the domain in which the fit is to be done via the 00075 // enum AbcissaType. The CoordinateSystem in the image is used 00076 // to convert the pixel coordinates to the desired abcissa. 00077 // You can change the units of the CoordinateSystem if you want 00078 // to fit in different units. If you set an estimate yourself 00079 // (function setElements or addElement) it is the callers responsibility 00080 // that the elements are in the correct abcissa domain. Function 00081 // setGaussianElements will automatically make an estimate in the 00082 // correct domain. 00083 // 00084 // Also, a SpectralElement object holds a mask indicating whether 00085 // a parameter should be held fixed or solved for. After the 00086 // fitting is done, a new SpectralList holding SpectralElements with 00087 // the fitted parameters is created. 00088 // 00089 // For all the functions that return a status Bool, True is good. If 00090 // False is returned, an error message can be recovered with function 00091 // <src>errorMessage</src>, You should not proceed if False is returned. 00092 // 00093 // Exceptions will be thrown if you do not set the Image and axis 00094 // via the constructor or <src>setImage</src> function. 00095 // </synopsis> 00096 00097 // <example> 00098 // <srcblock> 00099 // PagedImage<Float> im("myimage"); 00100 // Int axis = 2; 00101 // ImageFit1D<Float> fitter(image, axis); 00102 // IPosition pos(in.ndim(),0); 00103 // fitter.setData(pos, ImageFit1D<Float>::IM_NATIVE); // Fit in native coordinate space 00104 // fitter.setGaussianElements(3); // FIt 3 Gaussians 00105 // if (fitter.fit()) { 00106 // cerr << fitter.getList() << endl; // Print result 00107 // } 00108 // 00109 // </srcblock> 00110 // </example> 00111 00112 // <todo asof="2004/07/10"> 00113 // <li> Add constraints 00114 // </todo> 00115 00116 00117 template <class T> class ImageFit1D { 00118 public: 00119 00120 using FitterType = typename NumericTraits<T>::PrecisionType; 00121 00122 enum AbcissaType { 00123 PIXEL = 0, 00124 IM_NATIVE = 1, 00125 VELOCITY = 2, 00126 N_TYPES}; 00127 00128 00129 // Constructor. Fitting weights are assumed all unity. 00130 ImageFit1D(SHARED_PTR<const ImageInterface<T> > image, uInt axis=0); 00131 00132 // Constructor with fitting weights image. The data and weights images must 00133 // be the same shape. 00134 ImageFit1D( 00135 SHARED_PTR<const ImageInterface<T> > image, 00136 SHARED_PTR<const ImageInterface<T> > weights, uInt axis=0 00137 ); 00138 00139 // Destructor 00140 ~ImageFit1D(); 00141 00142 // Copy constructor. Uses reference semantics. 00143 ImageFit1D(const ImageFit1D& other); 00144 00145 // Assignment operator. Uses reference semantics. 00146 ImageFit1D& operator=(const ImageFit1D& other); 00147 00148 00149 // Set the data to be fit. All non-profile axes data are averaged. 00150 // For the profile axis, the full spectrum is taken. The abscissa 00151 // world values are computed when you call these functions unless they 00152 // have been set previously by a call to setAbscissa() in which case 00153 // the values that were passed to that method are used. Use the first 00154 // form of setData() in this case. The domain of the 00155 // abscissa values is controlled by <src>AbcissaType</src> and 00156 // <src>doAbs</src> (absolute coordinates). The CoordinateSystem in 00157 // the image is used to convert from pixels to world values. 00158 // If <src>type</src>=IN_NATIVE and <src>abscissaDivisor</src> is not null, 00159 // the world abscissa values will be divided by the value pointed to by 00160 // <src>abscissaDivisor</src>. This mitigates having very large or very small 00161 // abscissa values when fitting. If xfunc and/or yfunc is not NULL, the x and/or 00162 // y values are fed to the specified function and the resultant values are what 00163 // are used for the x and/or y values in the fit. If xfunc is not NULL and 00164 // setAbscissa values has been called prior, no abscissa value transformation occurs. 00165 // Thus if you want to apply a function to the abscissa values, the caller should 00166 // pass the result of that function into setAbscissaValues. 00167 // <group> 00168 void setData ( 00169 const IPosition& pos, /*const ImageFit1D<T>::AbcissaType type, 00170 const Bool doAbs=True, const Double* const &abscissaDivisor=0, 00171 Array<Double> (*xfunc)(const Array<Double>&)=0, */ 00172 Array<FitterType> (*yfunc)(const Array<FitterType>&)=0 00173 ); 00174 00175 void setData ( 00176 const IPosition& pos, const ImageFit1D<T>::AbcissaType type, 00177 const Bool doAbs=True, const Double* const &abscissaDivisor=0, 00178 Array<Double> (*xfunc)(const Array<Double>&)=0, 00179 Array<FitterType> (*yfunc)(const Array<FitterType>&)=0 00180 ); 00181 00182 /* 00183 Bool setData ( 00184 const ImageRegion& region, const ImageFit1D<T>::AbcissaType type, 00185 Bool doAbs=True 00186 ); 00187 */ 00188 // </group> 00189 00190 // Set a SpectralList of SpectralElements to fit for. These elements 00191 // must be in the correct abcissa domain set in function <src>setData</src>. 00192 // You must have already called <src>setData</src> to call this function. 00193 // The SpectralElements in the list hold the 00194 // initial estimates. They also contain the information about whether 00195 // specific parameters are to be held fixed or allowed to vary in 00196 // the fitting process. 00197 // You can recover the list of elements with function getList. 00198 void setElements (const SpectralList& list) {_fitter.setElements(list);}; 00199 00200 // Add new SpectralElement(s) to the SpectralList (can be empty) 00201 // of SpectralElements to be fit for. 00202 // You must have already called <src>setData</src> to call this function. 00203 //<group> 00204 void addElement (const SpectralElement& el) {_fitter.addElement(el);}; 00205 void addElements (const SpectralList& list) {_fitter.addElements(list);}; 00206 // </group> 00207 00208 // Set a SpectralList of Gaussian SpectralElements to fit for. 00209 // The initial estimates for the Gaussians will be automatically determined 00210 // in the correct abcissa domain. 00211 // All of the parameters created by this function will be solved for 00212 // by default. You can recover the list of elements with function getList. 00213 // Status is returned, if False, error message can be recovered with <src>errorMessage</src> 00214 void setGaussianElements (uInt nGauss); 00215 00216 // Clear the SpectralList of elements to be fit for 00217 void clearList () {_fitter.clearList();}; 00218 00219 // Do the fit and return convergence status. Errors in the fitting 00220 // process will generate an AipsError exception and you should catch 00221 // these yourself. 00222 Bool fit (); 00223 00224 // Get Chi Squared of fit 00225 Double getChiSquared () const {return _fitter.getChiSquared();} 00226 00227 // Get number of iterations for last fit 00228 Double getNumberIterations () const {return _fitter.getNumberIterations();} 00229 00230 // Recover the list of elements. You can get the elements 00231 // as initially estimated (fit=False), or after fitting 00232 // (fit=True). In the latter case, the SpectralElements 00233 // hold the parameters and errors of the fit. 00234 const SpectralList& getList (Bool fit=True) const {return _fitter.getList(fit);}; 00235 00236 // Recover vectors for the estimate, fit and residual. 00237 // If you don't specify which element, all elements are included 00238 // If the Vectors are returned with zero length, it means an error 00239 // condition exists (e.g. asking for fit before you do one). In this 00240 // case an error message can be recovered with function <src>errorMessage</src>. 00241 //<group> 00242 Vector<T> getEstimate (Int which=-1) const; 00243 Vector<T> getFit (Int which=-1) const; 00244 Vector<T> getResidual (Int which=-1, Bool fit=True) const; 00245 //</group> 00246 00247 Bool setXMask(const std::set<uInt>& indices, Bool specifiedPixelsAreGood) { 00248 return _fitter.setXMask(indices, specifiedPixelsAreGood); 00249 } 00250 00251 // get data mask 00252 Vector<Bool> getDataMask () const {return _fitter.getDataMask();}; 00253 00254 // Get Total Mask (data and range mask) 00255 Vector<Bool> getTotalMask () const {return _fitter.getTotalMask();}; 00256 00257 // did the fit succeed? should only be called after fit(). 00258 Bool succeeded() const; 00259 00260 // did the fit converge? should only be called after fit(). 00261 Bool converged() const; 00262 00263 // Helper function. Sets up the CoordinateSystem to reflect the choice of 00264 // abcissa unit and the doppler (if the axis is spectral). 00265 static Bool setAbcissaState (String& errMsg, ImageFit1D<T>::AbcissaType& type, 00266 CoordinateSystem& cSys, const String& xUnit, 00267 const String& doppler, uInt pixelAxis); 00268 00269 00270 // flag the solution as invalid based on external criteria. 00271 void invalidate(); 00272 00273 // is the solution valid? If False, some external logic has 00274 // called invalidate() 00275 Bool isValid() const; 00276 00277 // Set the abscissa values prior to running setData. If this is done, then 00278 // the abscissa values will not be recomputed when setData is called. 00279 // This can imporove performance if, for example, you are looping over several fitters for 00280 // which you know the abscissa values do not change. 00281 void setAbscissa(const Vector<Double>& x) { _x.assign(x); } 00282 00283 // make the abscissa values, <src>x</src>. If <src>type</src>=IN_NATIVE 00284 // and <src>abscissaDivisor is not null, then divide the native values 00285 // by the value pointed to by <src>abscissaDivisor</src> in making the abscissa 00286 // values. 00287 Vector<Double> makeAbscissa ( 00288 ImageFit1D<T>::AbcissaType type, 00289 Bool doAbs, const Double* const &abscissaDivisor 00290 ); 00291 private: 00292 SHARED_PTR<const ImageInterface<T> > _image, _weights; 00293 uInt _axis; 00294 00295 // In the future I will be able to template the fitter on T. For now 00296 // it must be Double. 00297 00298 ProfileFit1D<FitterType> _fitter; 00299 Bool _converged, _success, _isValid; 00300 Vector<Double> _x, _unityWeights, _weightSlice; 00301 IPosition _sliceShape; 00302 00303 // Disallow default constructor 00304 ImageFit1D() {} 00305 00306 void check() const; 00307 void checkType() const; 00308 void _construct(); 00309 void copy (const ImageFit1D<T>& other); 00310 00311 //void setWeightsImage (const ImageInterface<T>& im); 00312 00313 // reset the fitter, for example if we've done a fit and want to move 00314 // to the next position in the image 00315 void _resetFitter(); 00316 00317 00318 // Set Image(s) and axis 00319 // <group> 00320 // void setImage (const ImageInterface<T>& im, const ImageInterface<T>& weights, uInt pixelAxis); 00321 // void setImage (const ImageInterface<T>& im, uInt pixelAxis); 00322 // </group> 00323 00324 }; 00325 00326 } //#End casa namespace 00327 00328 #ifndef CASACORE_NO_AUTO_TEMPLATES 00329 #include <imageanalysis/ImageAnalysis/ImageFit1D.tcc> 00330 #endif //# CASACORE_NO_AUTO_TEMPLATES 00331 #endif