mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
imageUtils.hpp
Go to the documentation of this file.
1 /** \file imageUtils.hpp
2  * \author Jared R. Males
3  * \brief Header for the image processing utilities
4  * \ingroup image_processing_files
5  *
6  */
7 
8 //***********************************************************************//
9 // Copyright 2020 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_imageUtils_hpp
28 #define improc_imageUtils_hpp
29 
30 
31 #include "imageTransforms.hpp"
32 
33 namespace mx
34 {
35 namespace improc
36 {
37 
38 /** \ingroup image_utils
39  *@{
40  */
41 
42 /// Reflect pixel coordinates across the given center pixel.
43 /**
44  */
45 template<typename realT>
46 int reflectImageCoords( int & x1, ///< [out] the reflected x coordinate
47  int & y1, ///< [out] the reflected y coordinate
48  int x0, ///< [in] the input x coordinate
49  int y0, ///< [in] the input y coordinate
50  realT xc, ///< [in] the center pixel x coordinate
51  realT yc ///< [in] the center pixel y coordinate
52  )
53 {
54  x1 = xc - (x0 - xc);
55  y1 = yc - (y0 - yc);
56 
57  return 0;
58 }
59 
60 
61 
62 /// Zero any NaNs in an image
63 /**
64  * \overload
65  */
66 template<class imageT, typename valueT>
67 void zeroNaNs( imageT & im, ///< [in.out] image which will have any NaN pixels set to zero
68  valueT val ///< [in] [optional] The value to set NaN pixels too. Default is 0.
69  )
70 {
71  for(int c=0; c< im.cols(); ++c)
72  {
73  for(int r=0; r< im.rows(); ++r)
74  {
75  if( !std::isnormal( im(r,c) ) )
76  {
77  im(r,c) = val;
78  }
79  }
80  }
81 }
82 
83 /// Zero any NaNs in an image
84 template<class imageT>
85 void zeroNaNs( imageT & im /**< [in.out] image which will have any NaN pixels set to zero */ )
86 {
87  typename imageT::Scalar zero = 0;
88  zeroNaNs<imageT, typename imageT::Scalar> (im, zero);
89 }
90 
91 /// Zero any NaNs in an image cube
92 template<class cubeT>
93 void zeroNaNCube( cubeT & imc /**< [in.out] cube which will have any NaN pixels set to zero */)
94 {
95  for(int p=0; p< imc.planes(); ++p)
96  {
97  for(int c=0; c< imc.cols(); ++c)
98  {
99  for(int r=0; r< imc.rows(); ++r)
100  {
101  if( !std::isnormal( imc.image(p)(r,c) ) )
102  {
103  imc.image(p)(r,c) = 0;
104  }
105  }
106  }
107  }
108 }
109 
110 /// Calculate the mean value of an image
111 /**
112  *
113  * \returns the mean of the input image
114  */
115 template< class imageT>
116 typename imageT::Scalar imageMean(imageT & im /**< [in] the image of which to calculate the mean*/)
117 {
118  typename imageT::Scalar m = 0;
119 
120  for(int c=0;c<im.cols();++c)
121  {
122  for(int r=0;r<im.rows();++r)
123  {
124  m += im(r,c);
125  }
126  }
127 
128  m/=(im.rows()*im.cols());
129 
130  return m;
131 }
132 
133 /// Calculate the variance of an image w.r.t. a given value
134 /**
135  *
136  * \returns the variance of the input image
137  */
138 template< class imageT>
139 typename imageT::Scalar imageVariance( imageT & im, ///< [in] the image of which to calculate the variance
140  typename imageT::Scalar mean ///< [in] the value to calculate the variance with respect to
141  )
142 {
143  typename imageT::Scalar v = 0;
144 
145  for(int c=0;c<im.cols();++c)
146  {
147  for(int r=0;r<im.rows();++r)
148  {
149  v += pow(im(r,c)-mean,2);
150  }
151  }
152 
153  v /= (im.rows()*im.cols());
154 
155  return v;
156 }
157 
158 /// Calculate the center of light of an image
159 /** Note that the sum of the image should be > 0.
160  *
161  */
162 template<typename imageT>
163 int imageCenterOfLight( typename imageT::Scalar & x, ///< [out] the x coordinate of the center of light [pixels]
164  typename imageT::Scalar & y, ///< [out] the y coordinate of hte center of light [pixels]
165  const imageT & im ///< [in] the image to centroid
166  )
167 {
168  x =0;
169  y= 0;
170 
171  typename imageT::Scalar sum = im.sum();
172 
173  if(sum == 0)
174  {
175  x = 0.5*(im.rows()-1.0);
176  y = 0.5*(im.cols()-1.0);
177  return 0;
178  }
179 
180  for(int j=0; j < im.cols(); ++j)
181  {
182  for(int i=0; i< im.rows(); ++i)
183  {
184  x += (i+1)*im(i,j);
185  y += (j+1)*im(i,j);
186  }
187  }
188 
189  x = x/sum - 1;
190  y = y/sum - 1;
191 
192  return 0;
193 }
194 
195 /// Find the maximum in an image at sub-pixel resolution by interpolation
196 /** Uses imageMagnify() to expand the image to the desired scale. Because of the
197  * scaling used in imageMagnify, the desired scale may not be exact. As a result
198  * the actual scale is returned in scale_x and scale_y.
199  *
200  */
201 template<typename floatT, typename imageT, typename magImageT, typename transformT>
202 int imageMaxInterp( floatT & x, ///< [out] the x-position of the maximum, in pixels of the input image
203  floatT & y, ///< [out] the y-position of the maximum, in pixels of the input image
204  floatT & scale_x, ///< [in.out] the desired scale or resolution, in pixels < 1, in the x direction. On output contains the actual scale calculated.
205  floatT & scale_y, ///< [in.out] the desired scale or resolution, in pixels < 1, in the y direction. On output contains the actual scale calculated.
206  magImageT & magIm, ///< [in] the magnified image. This is used as working memory, will be resized.
207  const imageT & im, ///< [in] the image to find the maximum of
208  transformT trans ///< [in] the transform to use for interpolation
209  )
210 {
211  floatT magSize_x = ceil( (im.rows() - 1.0)/ scale_x) + 1;
212  floatT magSize_y = ceil( (im.cols() - 1.0)/ scale_y) + 1;
213 
214  floatT mag_x = ((floatT) magSize_x-1.0)/((floatT) im.rows() - 1.0);
215  floatT mag_y = ((floatT) magSize_y-1.0)/((floatT) im.cols() - 1.0);
216 
217  scale_x = 1.0/mag_x;
218  scale_y = 1.0/mag_y;
219 
220  magIm.resize(magSize_x, magSize_y);
221 
222  imageMagnify(magIm, im, trans);
223 
224  int ix, iy;
225  magIm.maxCoeff(&ix,&iy);
226  x = ix*scale_x;
227  y = iy*scale_y;
228 
229  return 0;
230 }
231 
232 /// Find the maximum in an image at sub-pixel resolution by cubic convolution interpolation
233 /** Uses imageMagnify() to expand the image to the desired scale. Because of the
234  * scaling used in imageMagnify, the desired scale may not be exact. As a result
235  * the actual scale is returned in scale_x and scale_y.
236  *
237  */
238 template<typename floatT, typename imageT, typename magImageT>
239 int imageMaxInterp( floatT & x, ///< [out] the x-position of the maximum, in pixels of the input image
240  floatT & y, ///< [out] the y-position of the maximum, in pixels of the input image
241  floatT & scale_x, ///< [in.out] the desired scale or resolution, in pixels < 1, in the x direction. On output contains the actual scale calculated.
242  floatT & scale_y, ///< [in.out] the desired scale or resolution, in pixels < 1, in the y direction. On output contains the actual scale calculated.
243  magImageT & magIm, ///< [in] the magnified image. This is used as working memory, will be resized.
244  const imageT & im ///< [in] the image to find the maximum of
245  )
246 {
247  return imageMaxInterp(x,y,scale_x,scale_y, magIm, im, cubicConvolTransform<typename imageT::Scalar>());
248 }
249 
250 
251 
252 
253 /// Combine two images, each with their own mask defining good pixels.
254 /** The combined image is made up of the pixels in im1 where mask1 is 1, and the pixels of im2 where mask2 is 1.
255  * If a pixel in both mask1 and mask2 has a value of 1, that pixel in the combo is the average of im1 and im2.
256  * All other pixels are set to 0 in the combined image.
257  *
258  * Separate template types are used for each argument to allow references, etc.
259  *
260  * \tparam imageT the eigen-like array type of the combined image
261  * \tparam imageT1 the eigen-like array type of image 1
262  * \tparam imageT2 the eigen-like array type of mask 1
263  * \tparam imageT3 the eigen-like array type of image 2
264  * \tparam imageT4 the eigen-like array type of mask 2
265  */
266 template<typename imageT, typename imageT1, typename imageT2, typename imageT3, typename imageT4>
267 void combine2ImagesMasked( imageT & combo, ///< [out] the combined image. will be resized.
268  const imageT1 & im1, ///< [in] the first image
269  const imageT2 & mask1, ///< [in] the mask for the first image
270  const imageT3 & im2, ///< [in] the second image
271  const imageT4 & mask2 ///< [in] the mask for the second image
272  )
273 {
274  combo.resize(im1.rows(), im2.cols());
275 
276  for(int c=0; c < combo.cols(); ++c)
277  {
278  for(int r=0;r<combo.rows();++r)
279  {
280  if(mask1(r,c) == 1 && mask2(r,c) == 0) combo(r,c) = im1(r,c);
281  else if(mask2(r,c) == 1 & mask1(r,c) == 0) combo(r,c) = im2(r,c);
282  else if(mask1(r,c) == 1 && mask2(r,c) == 1) combo(r,c) = 0.5*(im1(r,c) + im2(r,c));
283  else combo(r,c) = 0;
284  }
285  }
286 }
287 
288 template<typename eigenT, typename eigenTin>
289 void removeRowsAndCols(eigenT & out, const eigenTin & in, int st, int w)
290 {
291 
292  out.resize(in.rows() - w, in.cols() - w);
293 
294  out.topLeftCorner(st,st) = in.topLeftCorner(st,st);
295 
296  out.bottomLeftCorner(in.rows()-(st+w), st) = in.bottomLeftCorner(in.rows()-(st+w), st);
297 
298  out.topRightCorner(st, in.cols()-(st+w)) = in.topRightCorner(st, in.cols()-(st+w));
299 
300  out.bottomRightCorner(in.rows()-(st+w),in.cols()-(st+w)) = in.bottomRightCorner(in.rows()-(st+w),in.cols()-(st+w));
301 }
302 
303 
304 template<typename eigenT, typename eigenTin>
305 void removeRows(eigenT & out, const eigenTin & in, int st, int w)
306 {
307 
308  out.resize(in.rows() - w, in.cols());
309 
310  out.topLeftCorner(st,in.cols()) = in.topLeftCorner(st,in.cols());
311 
312  out.bottomLeftCorner(in.rows()-(st+w), in.cols()) = in.bottomLeftCorner(in.rows()-(st+w), in.cols());
313 
314 }
315 
316 template<typename eigenT, typename eigenTin>
317 void removeCols(eigenT & out, const eigenTin & in, int st, int w)
318 {
319 
320  out.resize(in.rows(), in.cols() - w);
321 
322  out.topLeftCorner(in.rows(), st) = in.topLeftCorner(in.rows(), st);
323 
324  out.topRightCorner(in.rows(),in.cols()-(st+w)) = in.topRightCorner(in.rows(),in.cols()-(st+w));
325 
326 }
327 
328 /// Copy one image to another, with no transformation
329 /** This is merely memcpy
330  *
331  * \returns dest
332  */
333 void * imcpy( void * dest, ///< [out] the address of the first pixel in the destination image
334  void * src, ///< [in] the address of the first pixel in the source image
335  size_t width, ///< [in] the width in pixels of size szof
336  size_t height, ///< [in] the height in pixels of size szof
337  size_t szof ///< [in] the size in bytes of a one pixel
338  );
339 
340 /// Copy one image to another, flipping up-down
341 /** This is a reversed row-by-row memcpy
342  *
343  * \returns dest
344  */
345 void * imcpy_flipUD( void * dest, ///< [out] the address of the first pixel in the destination image
346  void * src, ///< [in] the address of the first pixel in the source image
347  size_t width, ///< [in] the width in pixels of size szof
348  size_t height, ///< [in] the height in pixels of size szof
349  size_t szof ///< [in] the size in bytes of a one pixel
350  );
351 
352 /// Copy one image to another, flipping left-right
353 /**
354  *
355  * \returns dest
356  */
357 void * imcpy_flipLR( void * dest, ///< [out] the address of the first pixel in the destination image
358  void * src, ///< [in] the address of the first pixel in the source image
359  size_t width, ///< [in] the width in pixels of size szof
360  size_t height, ///< [in] the height in pixels of size szof
361  size_t szof ///< [in] the size in bytes of a one pixel
362  );
363 
364 /// Copy one image to another, flipping up-down and left-right
365 /**
366  *
367  * \returns dest
368  */
369 void * imcpy_flipUDLR( void * dest, ///< [out] the address of the first pixel in the destination image
370  void * src, ///< [in] the address of the first pixel in the source image
371  size_t width, ///< [in] the width in pixels of size szof
372  size_t height, ///< [in] the height in pixels of size szof
373  size_t szof ///< [in] the size in bytes of a one pixel
374  );
375 
376 ///@}
377 
378 } //namespace math
379 } //namespace mx
380 
381 
382 
383 #endif // improc_imageUtils_hpp
constexpr units::realT c()
The speed of light.
Definition: constants.hpp:60
void imageMagnify(arrOutT &transim, const arrInT &im, transformT trans)
Magnify an image.
int imageMaxInterp(floatT &x, floatT &y, floatT &scale_x, floatT &scale_y, magImageT &magIm, const imageT &im)
Find the maximum in an image at sub-pixel resolution by cubic convolution interpolation.
Definition: imageUtils.hpp:239
void * imcpy(void *dest, void *src, size_t width, size_t height, size_t szof)
Copy one image to another, with no transformation.
Definition: imageUtils.cpp:35
void zeroNaNs(imageT &im)
Zero any NaNs in an image.
Definition: imageUtils.hpp:85
imageT::Scalar imageMean(imageT &im)
Calculate the mean value of an image.
Definition: imageUtils.hpp:116
int imageCenterOfLight(typename imageT::Scalar &x, typename imageT::Scalar &y, const imageT &im)
Calculate the center of light of an image.
Definition: imageUtils.hpp:163
void combine2ImagesMasked(imageT &combo, const imageT1 &im1, const imageT2 &mask1, const imageT3 &im2, const imageT4 &mask2)
Combine two images, each with their own mask defining good pixels.
Definition: imageUtils.hpp:267
void zeroNaNCube(cubeT &imc)
Zero any NaNs in an image cube.
Definition: imageUtils.hpp:93
void * imcpy_flipLR(void *dest, void *src, size_t width, size_t height, size_t szof)
Copy one image to another, flipping left-right.
Definition: imageUtils.cpp:60
void * imcpy_flipUDLR(void *dest, void *src, size_t width, size_t height, size_t szof)
Copy one image to another, flipping up-down and left-right.
Definition: imageUtils.cpp:133
void * imcpy_flipUD(void *dest, void *src, size_t width, size_t height, size_t szof)
Copy one image to another, flipping up-down.
Definition: imageUtils.cpp:45
imageT::Scalar imageVariance(imageT &im, typename imageT::Scalar mean)
Calculate the variance of an image w.r.t. a given value.
Definition: imageUtils.hpp:139
int reflectImageCoords(int &x1, int &y1, int x0, int y0, realT xc, realT yc)
Reflect pixel coordinates across the given center pixel.
Definition: imageUtils.hpp:46
Image interpolation and transformation.
The mxlib c++ namespace.
Definition: mxError.hpp:107
Transformation by cubic convolution interpolation.