mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
aperturePhotometer.hpp
Go to the documentation of this file.
1 /** \file aperturePhotometer.hpp
2  * \brief Class for conducting aperture photometry on an image.
3  * \ingroup image_processing_files
4  * \author Jared R. Males (jaredmales@gmail.com)
5  *
6  */
7 
8 //***********************************************************************//
9 // Copyright 2018-2022 Jared R. Males (jaredmales@gmail.com)
10 //
11 // This file is part of mxlib.
12 //
13 // mxlib is free software: you can redistribute it and/or modify
14 // it under the terms of the GNU General Public License as published by
15 // the Free Software Foundation, either version 3 of the License, or
16 // (at your option) any later version.
17 //
18 // mxlib is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 // GNU General Public License for more details.
22 //
23 // You should have received a copy of the GNU General Public License
24 // along with mxlib. If not, see <http://www.gnu.org/licenses/>.
25 //***********************************************************************//
26 
27 #ifndef improc_aperturePhotometer_hpp
28 #define improc_aperturePhotometer_hpp
29 
30 #include <map>
31 #include <mx/improc/eigenImage.hpp>
32 #include <mx/improc/imageMasks.hpp>
33 
34 
35 namespace mx
36 {
37 namespace improc
38 {
39 
40 /// Class for performing aperture photometry on images.
41 /** Designed to very efficiently calculate the cumulative flux as a function of radius,
42  * with minimal cost for performing the measurement on multiple images.
43  *
44  * This initial version assumes the source is at 0.5*(rows-1) and 0.5*(cols-1).
45  *
46  * First call resize with the desired size. This organizes the radius vector and
47  * the index image which maps pixels to position in the radius vector.
48  *
49  * Then call cumPhot with the image, which will sum the flux contained within each radius.
50  *
51  * \ingroup improc
52  *
53  * \tparam realT the real floating point type of the data
54  */
55 template<typename realT>
57 {
58 
59 protected:
60 
61  int m_sizeX {0}; ///< The size of the image in X (rows).
62  int m_sizeY {0}; ///< The size of the image in Y (columns).
63 
64  realT m_xcen {0}; ///< The x coordinate of the center of the image. Radii are caculated relative to this point. Default is 0.5*(sizeX-1).
65  realT m_ycen {0}; ///< The y coordinate of the center of the image. Radii are caculated relative to this point. Default is 0.5*(sizeY-1).
66 
67  std::vector<realT> m_radius; ///< Holds the ordered unique radii of the pixels in the image.
68 
69  eigenImage<size_t> m_indexIm; ///< Maps a pixel in the image to the position in the radius vector.
70 
71  bool m_useNanMask {false};
72 
73  eigenImage<realT> * m_nanMask {nullptr};
74 
75  realT m_bgMin;
76  realT m_bgMax;
77 
78  std::vector<realT> m_bgx;
79  std::vector<realT> m_bgy;
80 
81 public:
82 
83  ///Resize the photometer, recalculating the radius vector and index image.
84  /** If size and center are unchanged, nothing is done.
85  *
86  * \note Source must be at geometric center of image.
87  *
88  * \returns 0 on success
89  * \returns -1 on error
90  */
91  int resize( int sizeX, ///< [in] The new size in rows
92  int sizeY, ///< [in] The new size in columns
93  realT xcen, ///< The x coordinate of the center of the image. Radii are caculated relative to this point. Default is 0.5*(sizeX-1).
94  realT ycen ///< The y coordinate of the center of the image. Radii are caculated relative to this point. Default is 0.5*(sizeY-1).
95  );
96 
97  ///Resize the photometer for a centered image, recalculating the radius vector and index image.
98  /** If size and center are unchanged, nothing is done.
99  *
100  * This version uses the geometric center of the image.
101  *
102  * \overload
103  *
104  * \returns 0 on success
105  * \returns -1 on error
106  */
107  int resize( int sizeX, ///< [in] The new size in rows
108  int sizeY ///< [in] The new size in columns
109  );
110 
111  /// Get the cumulative photometry of an image as a function of radius.
112  /**
113  *
114  * \returns 0 on success
115  * \returns -1 on error
116  */
117  int cumPhot( std::vector<realT> & cumPhot, ///< [out] the cumulative photometry at each point in the radius vector. Resized.
118  eigenImage<realT> & im, ///< [in] the image on which to perform the calculation
119  realT maxr = 0 ///< [in] [optional] the maximum radius to which to calculate. If <= 0 then max possible is used.
120  );
121 
122  /// Get the cumulative photometry of an image as a function of radius.
123  /**
124  * \overload
125  *
126  * \returns 0 on success
127  * \returns -1 on error
128  */
129  int cumPhot( std::vector<realT> & cumPhot, ///< [out] the cumulative photometry at each point in the radius vector. Resized.
130  std::vector<realT> & deltaPhot, ///< [out] [optional] the photometry at each point in the radius vector, not-cumulative. Resized.
131  eigenImage<realT> & im, ///< [in] the image on which to perform the calculation
132  realT maxr = 0 ///< [in] [optional] the maximum radius to which to calculate. If <= 0 then max possible is used.
133  );
134 
135 protected:
136 
137  /// Get the cumulative photometry of an image as a function of radius.
138  /** This is called by the public cumPhot functions.
139  *
140  *
141  * \returns 0 on success
142  * \returns -1 on error
143  */
144  int cumPhotWork( std::vector<realT> & cumPhot, ///< [out] the cumulative photometry at each point in the radius vector. Resized.
145  std::vector<realT> * deltaPhot, ///< [out] if not `nullptr`, this vector is filled with the sum at each radius.
146  eigenImage<realT> & im, ///< [in] the image on which to perform the calculation
147  realT maxr = 0 ///< [in] [optional] the maximum radius to which to calculate. If <= 0 then max possible is used.
148  );
149 
150 public:
151 
152  ///Get the radius value at an index of the vector.
153  realT radius( size_t i /**< [in] the index of the radius vector */ )
154  {
155  return m_radius[i];
156  }
157 
158  void bgMin( realT bgm )
159  {
160  m_bgMin = bgm;
161  }
162 
163  void bgMax( realT bgx )
164  {
165  m_bgMax = bgx;
166  }
167 
168  void bg( realT bgm, realT bgx )
169  {
170  m_bgMin = bgm;
171  m_bgMax = bgx;
172  }
173 
174 };
175 
176 template<typename realT>
178  int sizeY,
179  realT xcen,
180  realT ycen
181  )
182 {
183  //Don't bother if we don't have to.
184  if( sizeX == m_sizeX && sizeY == m_sizeY && xcen == m_xcen && ycen == m_ycen) return 0;
185 
186 
187  m_sizeX = sizeX;
188  m_sizeY = sizeY;
189  m_xcen = xcen;
190  m_ycen = ycen;
191 
192  m_indexIm.resize(m_sizeX, m_sizeY);
193 
194  //Get radius of each pixel up front, since we need it twice.
195  eigenImage<realT> radIm;
196  radIm.resize(m_sizeX, m_sizeY);
197  radiusImage( radIm, m_xcen, m_ycen ); //mx function to fill in the radius array
198 
199  std::map<realT, size_t> unrads; // Map of unique radii to their indices in the radius vector.
200 
201  //First populate the map
202  for(int i=0;i<radIm.cols();++i)
203  {
204  for(int j=0;j<radIm.rows();++j)
205  {
206  //unrads[radIm(j,i)] = 0;
207  unrads.insert(std::pair<realT, size_t>( radIm(j,i), 0));
208  }
209  }
210 
211  //Now fill in the radius vector, and set map values to the indices
212  m_radius.resize(unrads.size());
213  typename std::map<realT, size_t>::iterator it;
214  int n = 0;
215  for(it = unrads.begin(); it!=unrads.end(); ++it)
216  {
217  m_radius[n] = it->first;
218  it->second = n;
219  ++n;
220  }
221  //Finally, fill in the index image with index of the radius vector for that pixel.
222  for(int i=0;i<radIm.cols();++i)
223  {
224  for(int j=0;j<radIm.rows();++j)
225  {
226  it = unrads.find(radIm(j,i));
227  m_indexIm(j,i) = it->second;
228  }
229  }
230 
231  if(m_bgMax > m_bgMin && m_bgMin > 0)
232  {
233  m_bgx.clear();
234  m_bgy.clear();
235 
236  for(int cc=0; cc<radIm.cols(); ++cc)
237  {
238  for(int rr=0; rr< radIm.rows(); ++rr)
239  {
240  if(radIm(rr,cc) >= m_bgMin && radIm(rr,cc) <= m_bgMax)
241  {
242  m_bgx.push_back(rr);
243  m_bgy.push_back(cc);
244  }
245  }
246  }
247  }
248 
249  return 0;
250 }
251 
252 template<typename realT>
254  int sizeY
255  )
256 {
257  realT xcen = 0.5*(1.0*sizeX - 1.0);
258  realT ycen = 0.5*(1.0*sizeY - 1.0);
259 
260  return resize(sizeX, sizeY, xcen, ycen);
261 
262 }
263 
264 template<typename realT>
265 int aperturePhotometer<realT>::cumPhot( std::vector<realT> & cumPhot,
266  eigenImage<realT> & im,
267  realT maxr
268  )
269 {
270  return cumPhotWork(cumPhot, nullptr, im, maxr);
271 }
272 
273 template<typename realT>
274 int aperturePhotometer<realT>::cumPhot( std::vector<realT> & cumPhot,
275  std::vector<realT> & deltaPhot,
276  eigenImage<realT> & im,
277  realT maxr
278  )
279 {
280  return cumPhotWork(cumPhot, &deltaPhot, im, maxr);
281 }
282 
283 template<typename realT>
284 int aperturePhotometer<realT>::cumPhotWork( std::vector<realT> & cumPhot,
285  std::vector<realT> * deltaPhot,
286  eigenImage<realT> & im,
287  realT maxr
288  )
289 {
290  realT xcen = 0.5*(m_indexIm.rows()-1);
291  realT ycen = 0.5*(m_indexIm.cols()-1);
292 
293  if(maxr <= 0) maxr = m_radius.back();
294 
295  cumPhot.resize(m_radius.size(),0);
296 
297  //Make sure we stay in bounds
298  int x0 = xcen-maxr;
299  if(x0 < 0) x0 = 0;
300  int x1 = xcen + maxr;
301  if(x1 > m_indexIm.rows()-1) x1 = m_indexIm.rows()-1;
302 
303  int y0 = ycen-maxr;
304  if(y0 < 0) y0 = 0;
305  int y1 = ycen + maxr;
306  if(y1 > m_indexIm.cols()-1) y1 = m_indexIm.rows()-1;
307 
308  realT bg = 0;
309  //If using background annulus, first calc background;
310  if(m_bgx.size() > 0)
311  {
312  std::vector<realT> bgann(m_bgx.size());
313  for(size_t n=0; n < m_bgx.size(); ++n)
314  {
315  bgann[n] = im(m_bgx[n], m_bgy[n]);
316  }
317 
318  bg = math::vectorMedian(bgann);
319  std::cerr << "background: " << bg << "\n";
320 
321  }
322 
323  //First get sum at each unique radius
324  //Note: switched order of cols/rows indices for speeed
325  if(maxr == m_radius.back())
326  {
327  for(int i= y0; i<= y1; ++i)
328  {
329  for(int j=x0; j<=x1; ++j)
330  {
331  cumPhot[ m_indexIm(j,i) ] += im(j,i) - bg;
332  }
333  }
334  }
335  else
336  {
337  for(int i= y0; i<= y1; ++i)
338  {
339  for(int j=x0; j<=x1; ++j)
340  {
341  if(m_radius[m_indexIm(j,i)] <= maxr) cumPhot[ m_indexIm(j,i) ] += im(j,i);
342  }
343  }
344  }
345 
346  //If deltaPhot is desired, output it here.
347  if(deltaPhot != nullptr)
348  {
349  deltaPhot->assign(cumPhot.begin(), cumPhot.end());
350  }
351 
352  //Now perform cumulative sum
353  for(int i=1; i<cumPhot.size(); ++i)
354  {
355  cumPhot[i] += cumPhot[i-1];
356  }
357 
358  return 0;
359 }
360 
361 }//namespace improc
362 }//namespace mx
363 
364 #endif //improc_aperturePhotometer_hpp
Class for performing aperture photometry on images.
eigenImage< size_t > m_indexIm
Maps a pixel in the image to the position in the radius vector.
realT radius(size_t i)
Get the radius value at an index of the vector.
int resize(int sizeX, int sizeY, realT xcen, realT ycen)
Resize the photometer, recalculating the radius vector and index image.
int cumPhot(std::vector< realT > &cumPhot, eigenImage< realT > &im, realT maxr=0)
Get the cumulative photometry of an image as a function of radius.
std::vector< realT > m_radius
Holds the ordered unique radii of the pixels in the image.
realT m_ycen
The y coordinate of the center of the image. Radii are caculated relative to this point....
int cumPhotWork(std::vector< realT > &cumPhot, std::vector< realT > *deltaPhot, eigenImage< realT > &im, realT maxr=0)
Get the cumulative photometry of an image as a function of radius.
int m_sizeY
The size of the image in Y (columns).
int m_sizeX
The size of the image in X (rows).
realT m_xcen
The x coordinate of the center of the image. Radii are caculated relative to this point....
Eigen::Array< scalarT, -1, -1 > eigenImage
Definition of the eigenImage type, which is an alias for Eigen::Array.
Definition: eigenImage.hpp:44
void radiusImage(eigenT &m, typename eigenT::Scalar xc, typename eigenT::Scalar yc, typename eigenT::Scalar scale=1)
Fills in the cells of an Eigen 2D Array with their radius from the center.
Definition: imageMasks.hpp:49
vectorT::value_type vectorMedian(const vectorT &vec, vectorT *work=0)
Calculate median of a vector, leaving the vector unaltered.
The mxlib c++ namespace.
Definition: mxError.hpp:107