mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
Loading...
Searching...
No Matches
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
32#include "eigenImage.hpp"
33#include "imageMasks.hpp"
34
35namespace mx
36{
37namespace 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 image_processing
52 *
53 * \tparam realT the real floating point type of the data
54 */
55template <typename realT>
57{
58
59 protected:
60 int m_sizeX{ 0 }; ///< The size of the image in X (rows).
61 int m_sizeY{ 0 }; ///< The size of the image in Y (columns).
62
63 realT m_xcen{ 0 }; ///< The x coordinate of the center of the image. Radii are caculated relative to this point.
64 ///< 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.
66 ///< Default is 0.5*(sizeY-1).
67
68 std::vector<realT> m_radius; ///< Holds the ordered unique radii of the pixels in the image.
69
70 eigenImage<size_t> m_indexIm; ///< Maps a pixel in the image to the position in the radius vector.
71
72 bool m_useNanMask{ false };
73
74 eigenImage<realT> *m_nanMask{ nullptr };
75
76 realT m_bgMin{ 0 };
77 realT m_bgMax{ 0 };
78
79 std::vector<realT> m_bgx;
80 std::vector<realT> m_bgy;
81
82 public:
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
94 ///< point. Default is 0.5*(sizeX-1).
95 realT ycen ///< The y coordinate of the center of the image. Radii are caculated relative to this
96 ///< point. Default is 0.5*(sizeY-1).
97 );
98
99 /// Resize the photometer for a centered image, recalculating the radius vector and index image.
100 /** If size and center are unchanged, nothing is done.
101 *
102 * This version uses the geometric center of the image.
103 *
104 * \overload
105 *
106 * \returns 0 on success
107 * \returns -1 on error f
108 */
109 int resize( int sizeX, ///< [in] The new size in rows
110 int sizeY ///< [in] The new size in columns
111 );
112
113 /// Get the cumulative photometry of an image as a function of radius.
114 /**
115 *
116 * \returns 0 on success
117 * \returns -1 on error
118 */
119 int cumPhot(
120 std::vector<realT> &cumPhot, ///< [out] the cumulative photometry at each point in the radius vector. Resized.
121 eigenImage<realT> &im, ///< [in] the image on which to perform the calculation
122 realT maxr =
123 0 ///< [in] [optional] the maximum radius to which to calculate. If <= 0 then max possible is used.
124 );
125
126 /// Get the cumulative photometry of an image as a function of radius.
127 /**
128 * \overload
129 *
130 * \returns 0 on success
131 * \returns -1 on error
132 */
133 int cumPhot(
134 std::vector<realT> &cumPhot, ///< [out] the cumulative photometry at each point in the radius vector. Resized.
135 std::vector<realT> &
136 deltaPhot, ///< [out] [optional] the photometry at each point in the radius vector, not-cumulative. Resized.
137 eigenImage<realT> &im, ///< [in] the image on which to perform the calculation
138 realT maxr =
139 0 ///< [in] [optional] the maximum radius to which to calculate. If <= 0 then max possible is used.
140 );
141
142 protected:
143 /// Get the cumulative photometry of an image as a function of radius.
144 /** This is called by the public cumPhot functions.
145 *
146 *
147 * \returns 0 on success
148 * \returns -1 on error
149 */
150 int cumPhotWork(
151 std::vector<realT> &cumPhot, ///< [out] the cumulative photometry at each point in the radius vector. Resized.
152 std::vector<realT> *deltaPhot, ///< [out] if not `nullptr`, this vector is filled with the sum at each radius.
153 eigenImage<realT> &im, ///< [in] the image on which to perform the calculation
154 realT maxr =
155 0 ///< [in] [optional] the maximum radius to which to calculate. If <= 0 then max possible is used.
156 );
157
158 public:
159 /// Get the radius value at an index of the vector.
160 realT radius( size_t i /**< [in] the index of the radius vector */ )
161 {
162 return m_radius[i];
163 }
164
165 void bgMin( realT bgm )
166 {
167 m_bgMin = bgm;
168 }
169
170 void bgMax( realT bgx )
171 {
172 m_bgMax = bgx;
173 }
174
175 void bg( realT bgm, realT bgx )
176 {
177 m_bgMin = bgm;
178 m_bgMax = bgx;
179 }
180};
181
182template <typename realT>
183int aperturePhotometer<realT>::resize( int sizeX, int sizeY, realT xcen, realT ycen )
184{
185 // Don't bother if we don't have to.
186 if( sizeX == m_sizeX && sizeY == m_sizeY && xcen == m_xcen && ycen == m_ycen )
187 return 0;
188
189 m_sizeX = sizeX;
190 m_sizeY = sizeY;
191 m_xcen = xcen;
192 m_ycen = ycen;
193
194 m_indexIm.resize( m_sizeX, m_sizeY );
195
196 // Get radius of each pixel up front, since we need it twice.
197 eigenImage<realT> radIm;
198 radIm.resize( m_sizeX, m_sizeY );
199 radiusImage( radIm, m_xcen, m_ycen ); // mx function to fill in the radius array
200
201 std::map<realT, size_t> unrads; // Map of unique radii to their indices in the radius vector.
202
203 // First populate the map
204 for( int i = 0; i < radIm.cols(); ++i )
205 {
206 for( int j = 0; j < radIm.rows(); ++j )
207 {
208 // unrads[radIm(j,i)] = 0;
209 unrads.insert( std::pair<realT, size_t>( radIm( j, i ), 0 ) );
210 }
211 }
212
213 // Now fill in the radius vector, and set map values to the indices
214 m_radius.resize( unrads.size() );
215 typename std::map<realT, size_t>::iterator it;
216 int n = 0;
217 for( it = unrads.begin(); it != unrads.end(); ++it )
218 {
219 m_radius[n] = it->first;
220 it->second = n;
221 ++n;
222 }
223 // Finally, fill in the index image with index of the radius vector for that pixel.
224 for( int i = 0; i < radIm.cols(); ++i )
225 {
226 for( int j = 0; j < radIm.rows(); ++j )
227 {
228 it = unrads.find( radIm( j, i ) );
229 m_indexIm( j, i ) = it->second;
230 }
231 }
232
233 if( m_bgMax > m_bgMin && m_bgMin > 0 )
234 {
235 m_bgx.clear();
236 m_bgy.clear();
237
238 for( int cc = 0; cc < radIm.cols(); ++cc )
239 {
240 for( int rr = 0; rr < radIm.rows(); ++rr )
241 {
242 if( radIm( rr, cc ) >= m_bgMin && radIm( rr, cc ) <= m_bgMax )
243 {
244 m_bgx.push_back( rr );
245 m_bgy.push_back( cc );
246 }
247 }
248 }
249 }
250
251 return 0;
252}
253
254template <typename realT>
255int aperturePhotometer<realT>::resize( int sizeX, int sizeY )
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
263template <typename realT>
264int aperturePhotometer<realT>::cumPhot( std::vector<realT> &cumPhot, eigenImage<realT> &im, realT maxr )
265{
266 return cumPhotWork( cumPhot, nullptr, im, maxr );
267}
268
269template <typename realT>
271 std::vector<realT> &deltaPhot,
273 realT maxr )
274{
275 return cumPhotWork( cumPhot, &deltaPhot, im, maxr );
276}
277
278template <typename realT>
280 std::vector<realT> *deltaPhot,
282 realT maxr )
283{
284 realT xcen = m_xcen; // 0.5*(m_indexIm.rows()-1);
285 realT ycen = m_ycen; // 0.5*(m_indexIm.cols()-1);
286
287 if( maxr <= 0 )
288 maxr = m_radius.back();
289
290 cumPhot.resize( m_radius.size(), 0 );
291
292 // Make sure we stay in bounds
293 int x0 = xcen - maxr;
294 if( x0 < 0 )
295 x0 = 0;
296 int x1 = xcen + maxr;
297 if( x1 > m_indexIm.rows() - 1 )
298 x1 = m_indexIm.rows() - 1;
299
300 int y0 = ycen - maxr;
301 if( y0 < 0 )
302 y0 = 0;
303 int y1 = ycen + maxr;
304 if( y1 > m_indexIm.cols() - 1 )
305 y1 = m_indexIm.rows() - 1;
306
307 realT bg = 0;
308 // If using background annulus, first calc background;
309 if( m_bgx.size() > 0 )
310 {
311 std::vector<realT> bgann( m_bgx.size() );
312 for( size_t n = 0; n < m_bgx.size(); ++n )
313 {
314 bgann[n] = im( (int)m_bgx[n], (int)m_bgy[n] );
315 }
316
317 bg = math::vectorMedian( bgann );
318 std::cerr << "background: " << bg << "\n";
319 }
320
321 // First get sum at each unique radius
322 // Note: switched order of cols/rows indices for speeed
323 if( maxr == m_radius.back() )
324 {
325 for( int i = y0; i <= y1; ++i )
326 {
327 for( int j = x0; j <= x1; ++j )
328 {
329 cumPhot[m_indexIm( j, i )] += im( j, i ) - bg;
330 }
331 }
332 }
333 else
334 {
335 for( int i = y0; i <= y1; ++i )
336 {
337 for( int j = x0; j <= x1; ++j )
338 {
339 if( m_radius[m_indexIm( j, i )] <= maxr )
340 cumPhot[m_indexIm( j, i )] += im( j, i );
341 }
342 }
343 }
344
345 // If deltaPhot is desired, output it here.
346 if( deltaPhot != nullptr )
347 {
348 deltaPhot->assign( cumPhot.begin(), cumPhot.end() );
349 }
350
351 // Now perform cumulative sum
352 for( int i = 1; i < cumPhot.size(); ++i )
353 {
354 cumPhot[i] += cumPhot[i - 1];
355 }
356
357 return 0;
358}
359
360extern template class aperturePhotometer<float>;
361
362extern template class aperturePhotometer<double>;
363
364} // namespace improc
365} // namespace mx
366
367#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.
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).
Tools for using the eigen library for image processing.
Eigen::Array< scalarT, -1, -1 > eigenImage
Definition of the eigenImage type, which is an alias for Eigen::Array.
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.
vectorT::value_type vectorMedian(const vectorT &vec, vectorT *work=0)
Calculate median of a vector, leaving the vector unaltered.
Declares and defines functions to work with image masks.
The mxlib c++ namespace.
Definition mxlib.hpp:37