mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
imagingUtils.hpp
Go to the documentation of this file.
1 /** \file imagingUtils.hpp
2  * \brief Utilities for modeling image formation
3  * \ingroup imaging
4  * \author Jared R. Males (jaredmales@gmail.com)
5  *
6  */
7 
8 //***********************************************************************//
9 // Copyright 2015, 2016, 2017 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 imagingUtils_hpp
28 #define imagingUtils_hpp
29 
30 #include <cmath>
31 
32 #include "../math/constants.hpp"
33 #include "../mxError.hpp"
34 
35 #include "imagingArray.hpp"
36 
37 
38 namespace mx
39 {
40 
41 namespace wfp
42 {
43 
44 ///Calculate the angular plate scale (radians per pixel) of an image after propagation by FFT.
45 /**
46  *
47  * \returns the platescale of the wavefront after propagation by FFT, in radians per pixel.
48  *
49  * \tparam realT a real floating point type
50  *
51  * \ingroup imaging
52  */
53 template<typename realT>
54 realT fftPlateScale( size_t pixels, ///< [in] the linear dimension of the FFT (including 0 pad, etc.)
55  realT metersPerPixel, ///< [in] the scale of the input wavefront [m/pix]
56  realT lambda ///< [in] the wavelength of the wavefront [m]
57  )
58 {
59  return (lambda/metersPerPixel) * (1./pixels);
60 }
61 
62 /// Fill in an Eigen-like array with a circular pupil mask.
63 /** Sets any pixel which is at rad <= r < rad+(1.0/overscan) pixels to rho = 1,
64  *
65  *
66  * \retval 0 on success
67  * \retval -1 on error
68  *
69  * \ingroup imaging
70  */
71 template<class arrayT>
72 int circularPupil( arrayT & m, ///< [in.out] is the allocated Array. Dimensions are used to create the pupil.
73  typename arrayT::Scalar eps=0, ///< [in] [optional] is the central obscuration. 0-1, default is 0.
74  typename arrayT::Scalar rad=0, ///< [in] [optional] is the desired radius. If rad <= 0, then the maximum radius based on dimensions of m is used. Default is 0.
75  typename arrayT::Scalar overscan = 0 ///< [in] [optional] overscan in fractional pixels, to include partial pixels on the edge. Default is 0.
76  )
77 {
78 
79  if( eps < 0)
80  {
81  mxError("circularPupil", MXE_INVALIDARG, "Central obscuration can not be < 0." );
82  return -1;
83  }
84 
85  if(eps > 1)
86  {
87  mxError("circularPupil", MXE_INVALIDARG, "Central obscuration can not be > 1." );
88  return -1;
89  }
90 
91  size_t l0 = m.rows();
92  size_t l1 = m.cols();
93 
94  typename arrayT::Scalar r;
95  typename arrayT::Scalar xc = 0.5*(l0-1);
96  typename arrayT::Scalar yc = 0.5*(l1-1);
97 
98  if(rad <= 0) rad = 0.5*std::min(l0-1, l1-1);
99 
100  for(size_t i=0; i < l0; i++)
101  {
102  for(size_t j=0; j < l1; j++)
103  {
104  r = std::sqrt( std::pow(i-xc, 2) + std::pow(j-yc, 2) );
105 
106  if(r <= rad+( overscan ) && r >= eps*rad) m(i,j) = 1;
107  else m(i,j) = 0;
108  }
109  }
110 
111  return 0;
112 }
113 
114 ///Draw a line in an image
115 /** \todo should handle width much more intelligently, this only works for ~45 degree lines.
116  *
117  * \tparam arrayT is an Eigen-like array with public typedef Scalar
118  */
119 template<class arrayT>
120 void drawLine( arrayT & im, ///< [in.out] The input image, modified.
121  typename arrayT::Scalar x0, ///< [in] the x value, relative to image center, of the starting point
122  typename arrayT::Scalar y0, ///< [in] the y value, relative to image center, of the starting point
123  typename arrayT::Scalar x1, ///< [in] the x value, relative to image center, of the end point
124  typename arrayT::Scalar y1, ///< [in] the y value, relative to image center, of the end point
125  typename arrayT::Scalar halfWidth ///< [in] the half-width of the line.
126  )
127 {
128 
129  int d1 = im.rows();
130  int d2 = im.cols();
131 
132  typename arrayT::Scalar xc, yc;
133 
134  xc = 0.5*(im.rows()-1);
135  yc = 0.5*(im.cols()-1);
136 
137 
138  typename arrayT::Scalar m = (y1-y0)/(x1-x0);
139  int y;
140 
141  if(x1 > x0)
142  {
143  for(int x = x0; x<=x1; ++x)
144  {
145  y = y0 + (x-x0)*m;
146 
147  for(int i=0; i<= halfWidth; ++i)
148  {
149  if( x+xc >= 0 && x+xc < d1 && y+yc+i >= 0 && y+yc+i < d2) im(x+xc,y+yc+i) = 0;
150  if( x+xc >= 0 && x+xc < d1 && y+yc-i >= 0 && y+yc-i < d2) im(x+xc,y+yc-i) = 0;
151  }
152  }
153  }
154  else
155  {
156  for(int x = x1; x<=x0; ++x)
157  {
158  y = y0 + (x-x0)*m;
159 
160  for(int i=0; i<= halfWidth; ++i)
161  {
162  if( x+xc >= 0 && x+xc < d1 && y+yc+i >= 0 && y+yc+i < d2) im(x+xc,y+yc+i) = 0;
163  if( x+xc >= 0 && x+xc < d1 && y+yc-i >= 0 && y+yc-i < d2) im(x+xc,y+yc-i) = 0;
164  }
165  }
166 
167  }
168 
169 }
170 
171 
172 
173 ///Create a complex pupil plane wavefront from a real amplitude mask.
174 /** The input real amplitude mask is placed in the center of a 0-padded complex array.
175  *
176  * \param [out] complexPupil the complex pupil plane wavefront
177  * \param [in] realPupil a real amplitude mask.
178  * \param [in] wavefrontSizePixels the desired size of the ouput wavefront, should be at least as big as realPupil
179  *
180  * \ingroup imaging
181  */
182 template<typename arrayOutT, typename arrayInT>
183 void makeComplexPupil( arrayOutT & complexPupil,
184  const arrayInT & realPupil,
185  int wavefrontSizePixels)
186 {
187 
188  complexPupil.resize(wavefrontSizePixels, wavefrontSizePixels);
189  complexPupil.set(typename arrayOutT::Scalar(0,0));
190 
191  //Lower-left corner of insertion region
192  int bl = 0.5*(complexPupil.rows()-1) - 0.5*(realPupil.rows()-1.);
193 
194  for(int i=0; i< realPupil.cols(); ++i)
195  {
196  for(int j=0; j < realPupil.rows(); ++j)
197  {
198  complexPupil(bl+i, bl+j) = typename arrayOutT::Scalar(realPupil(i,j),0); //*exp( typename arrayOutT::Scalar(0,1));
199  }
200  }
201  //complexPupil.block(bl, bl, realPupil.rows(), realPupil.rows()) = realPupil*std::complex<realT>(1,0);
202 
203 }
204 
205 
206 ///Create a complex wavefront from a real amplitude and a real phase.
207 /** The wavefront is placed in the center of a 0-padded complex array.
208  *
209  * \param [out] complexWavefront the complex pupil plane wavefront
210  * \param [in] realAmplitude is the real-valued amplitude.
211  * \param [in] realPhase is the real-valued phase in radians, same size as realAmplitude
212  * \param [in] wavefrontSizePixels the desired size of the ouput wavefront, should be at least as big as the real arrays
213  *
214  * \ingroup imaging
215  */
216 template<typename arrayOutT, typename arrayInT>
217 void makeComplexPupil( arrayOutT & complexWavefront,
218  const arrayInT & realAmplitude,
219  const arrayInT & realPhase,
220  int wavefrontSizePixels)
221 {
222 
223  complexWavefront.resize(wavefrontSizePixels, wavefrontSizePixels);
224  complexWavefront.set(typename arrayOutT::Scalar(0,0));
225 
226  //Lower-left corner of insertion region
227  int bl = 0.5*(complexWavefront.rows()-1) - 0.5*(realAmplitude.rows()-1.);
228 
229  for(int i=0; i< realAmplitude.cols(); ++i)
230  {
231  for(int j=0; j < realAmplitude.rows(); ++j)
232  {
233  complexWavefront(bl+j, bl+i) = realAmplitude(j,i)*exp( (typename arrayOutT::Scalar(0,1)) * realPhase(j,i));
234  }
235  }
236 }
237 
238 
239 ///Apply a tilt to a wavefront
240 /**
241  * \param complexWavefront [in.out] the complex wavefront to tilt, will be modified on output
242  * \param xTilt [input] the amount of tilt in the x direction, in pixels
243  * \param yTilt [input] the amount of tilt in the y direction, in pixels
244  *
245  * \ingroup imaging
246  */
247 template<typename wavefrontT>
248 void tiltWavefront( wavefrontT & complexWavefront,
249  typename wavefrontT::Scalar::value_type xTilt,
250  typename wavefrontT::Scalar::value_type yTilt)
251 {
252  typedef typename wavefrontT::Scalar complexT;
253  typedef typename wavefrontT::Scalar::value_type realT;
254 
255  realT pi = math::pi<realT>();
256 
257  int wfsSizeX = complexWavefront.cols();
258  int wfsSizeY = complexWavefront.rows();
259 
260  realT xCen = 0.5*(wfsSizeX-1);
261  realT yCen = 0.5*(wfsSizeY-1);
262 
263  realT argX = 2.0*pi/(wfsSizeX-1.0);
264  realT argY = 2.0*pi/(wfsSizeY-1.0);
265 
266  for(int ii=0; ii < wfsSizeX; ++ii)
267  {
268  for(int jj=0; jj < wfsSizeY; ++jj)
269  {
270  complexWavefront(ii,jj) = complexWavefront(ii,jj)*exp( complexT( (realT)0., argX*xTilt*(ii-xCen)+argY*yTilt*(jj-yCen)));
271  }
272  }
273 }
274 
275 template< typename imageT1, typename imageT2>
276 void extractBlock(imageT1 & im,
277  int imX0,
278  int imXsz,
279  int imY0,
280  int imYsz,
281  imageT2 & wf,
282  int wfX0,
283  int wfY0)
284 {
285  int im_rows = im.cols();
286 
287  int wf_rows = wf.cols();
288 
289  typedef typename imageT1::Scalar dataT;
290 
291  dataT * im_data;
292  dataT * wf_data;
293 
294 
295 
296  for(int j =0; j< imYsz; ++j)
297  {
298  im_data = &im.data()[imX0 + (imY0+j)*im_rows];
299  wf_data = &wf.data()[wfX0 + (wfY0+j)*wf_rows];
300 
301  memcpy( im_data, wf_data, sizeof(dataT)*imXsz);
302  }
303 }
304 
305 template< typename realImageT,
306  typename complexImageT>
307 void extractIntensityImage(realImageT & im,
308  int imX0,
309  int imXsz,
310  int imY0,
311  int imYsz,
312  complexImageT & wf,
313  int wfX0,
314  int wfY0)
315 {
316  int im_rows = im.cols();
317 
318  int wf_rows = wf.cols();
319 
320  typename realImageT::Scalar * im_data;
321  typename complexImageT::Scalar * wf_data;
322 
323  for(int j =0; j< imXsz; ++j)
324  {
325  im_data = &im.data()[imX0 + (imY0+j)*im_rows];
326  wf_data = &wf.data()[wfX0 + (wfY0+j)*wf_rows];
327  for(int i=0; i<imYsz; ++i)
328  {
329  im_data[i] = norm(wf_data[i]);
330  }
331  }
332 }
333 
334 template< typename realImageT,
335  typename complexImageT>
336 void extractIntensityImageAccum(realImageT & im,
337  int imX0,
338  int imXsz,
339  int imY0,
340  int imYsz,
341  complexImageT & wf,
342  int wfX0,
343  int wfY0)
344 {
345  int im_rows = im.cols();
346 
347  int wf_rows = wf.cols();
348 
349  typename realImageT::Scalar * im_data;
350  typename complexImageT::Scalar * wf_data;
351 
352  for(int j =0; j< imXsz; ++j)
353  {
354  im_data = &im.data()[imX0 + (imY0+j)*im_rows];
355  wf_data = &wf.data()[wfX0 + (wfY0+j)*wf_rows];
356  for(int i=0; i<imYsz; ++i)
357  {
358  im_data[i] += norm(wf_data[i]);
359  }
360  }
361 }
362 
363 } //namespace wfp
364 } //namespace mx
365 
366 #endif //__imagingUtils_hpp__
367 
constexpr T pi()
Get the value of pi.
Definition: constants.hpp:52
void makeComplexPupil(arrayOutT &complexWavefront, const arrayInT &realAmplitude, const arrayInT &realPhase, int wavefrontSizePixels)
Create a complex wavefront from a real amplitude and a real phase.
void tiltWavefront(wavefrontT &complexWavefront, typename wavefrontT::Scalar::value_type xTilt, typename wavefrontT::Scalar::value_type yTilt)
Apply a tilt to a wavefront.
realT fftPlateScale(size_t pixels, realT metersPerPixel, realT lambda)
Calculate the angular plate scale (radians per pixel) of an image after propagation by FFT.
int circularPupil(arrayT &m, typename arrayT::Scalar eps=0, typename arrayT::Scalar rad=0, typename arrayT::Scalar overscan=0)
Fill in an Eigen-like array with a circular pupil mask.
Declares and defines a class for managing images.
The mxlib c++ namespace.
Definition: mxError.hpp:107