mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
imagePads.hpp
Go to the documentation of this file.
1 /** \file imagePads.hpp
2  * \brief Image padding
3  * \ingroup image_processing_files
4  * \author Jared R. Males (jaredmales@gmail.com)
5  *
6  */
7 
8 //***********************************************************************//
9 // Copyright 2015, 2016, 2017, 2018 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_imagePads_hpp
28 #define improc_imagePads_hpp
29 
30 #include <vector>
31 
32 #include "../mxError.hpp"
33 
34 namespace mx
35 {
36 namespace improc
37 {
38 
39 /** \addtogroup image_padding
40  * These functions pad an image by adding rows and columns, and filling in the new pixels with appropriate values. This can be a constant, or nearest neighbor. A version
41  * is also provided which expands an aribtrary 1/0 mask, which is useful when working with, say, circular regions of an image.
42  */
43 
44 /** \ingroup image_padding
45  * @{
46  */
47 
48 /// Pad an image with a constant value
49 /**
50  * \retval 0 on success
51  * \retval -1 on error
52  *
53  * \tparam imOutT is an Eigen-like array
54  * \tparam imInT is an Eigen-like array
55  */
56 template<typename imOutT, typename imInT>
57 int padImage( imOutT & imOut, ///< [out] On return contains the padded image. This will be resized.
58  imInT & imIn, ///< [in] The image to be padded.
59  unsigned int padSz, ///< [in] The size of the pad. The padded image (imOut) will be 2*padSz rows and cols larger than the input.
60  typename imOutT::Scalar value ///< [in] the value to use for padding.
61  )
62 {
63  int nRows = imIn.rows() + 2*padSz;
64  int nCols = imIn.cols() + 2*padSz;
65 
66  imOut = imOutT::Constant(nRows, nCols, value);
67 
68  imOut.block(padSz, padSz, imIn.rows(),imIn.cols()) = imIn;
69 
70  return 0;
71 }
72 
73 /// Pad an image with a constant value for reference types.
74 /** This version can be used with Eigen reference types.
75  *
76  * \retval 0 on success
77  * \retval -1 on error
78  *
79  * \tparam imOutT is an Eigen-like array reference
80  * \tparam imInT is an Eigen-like array reference
81  */
82 template<typename imOutT, typename imInT>
83 int padImageRef( imOutT imOut, ///< [out] On return contains the padded image. This will be resized.
84  imInT imIn, ///< [in] The image to be padded.
85  unsigned int padSz, ///< [in] The size of the pad. The padded image (imOut) will be 2*padSz rows and cols larger than the input.
86  typename imOutT::Scalar value ///< [in] the value to use for padding.
87  )
88 {
89  int nRows = imIn.rows() + 2*padSz;
90  int nCols = imIn.cols() + 2*padSz;
91 
92 
93  imOut = imOutT::Constant(nRows, nCols, value);
94 
95  imOut.block(padSz, padSz, imIn.rows(),imIn.cols()) = imIn;
96 
97  return 0;
98 }
99 
100 /// Pad an image by repeating the values in the edge rows and columns
101 /** Allocates imOut to hold 2*padSz more rows and columns, and copies imIn to the center. Then fills in the new pixels
102  * by copying the edge pixels outward.
103  *
104  * \retval 0 on success
105  * \retval -1 on error
106  *
107  * \tparam imOutT is an Eigen-like array
108  * \tparam imInT is an Eigen-like array
109  */
110 template<typename imOutT, typename imInT>
111 int padImage( imOutT & imOut, ///< [out] On return contains the padded image. This will be resized.
112  imInT & imIn, ///< [in] The image to be padded.
113  unsigned int padSz ///< [in] The size of the pad. The padded image (imOut) will be 2*padSz rows and cols larger than the input.
114  )
115 {
116  int dim1 = imIn.rows();
117  int dim2 = imIn.cols();
118 
119  imOut.resize(dim1+2*padSz, dim2 + 2*padSz);
120 
121  imOut.block(padSz, padSz, dim1, dim2) = imIn;
122 
123  //First do the left and right edge columns and corners
124  for(int i = 0; i< padSz; ++i)
125  {
126  for(int j=0; j < imOut.cols(); ++j)
127  {
128  if( j < padSz )
129  {
130  imOut(i,j) = imIn(0, 0);
131  imOut( imOut.rows()-1-i, j) = imIn( dim1-1, 0);
132  }
133  else if( j >= dim2 + padSz)
134  {
135  imOut(i,j) = imIn(0, dim2-1);
136  imOut( imOut.rows()-1-i, j) = imIn( dim1-1, dim2-1);
137  }
138  else
139  {
140  imOut( i, j ) = imOut( padSz, j );
141  imOut( imOut.rows() - padSz + i, j ) = imOut( padSz + dim1-1, j );
142  }
143  }
144  }
145 
146  //Now do the top and bottom rows.
147  for(int i=padSz; i < dim1+padSz; ++i)
148  {
149  for(int j=0; j< padSz; ++j)
150  {
151  imOut(i,j) = imOut(i, padSz);
152  imOut(i, imOut.cols()-1-j) = imOut(i, imOut.cols()-1-padSz);
153  }
154  }
155 
156 
157  return 0;
158 }
159 
160 /// Pad an image by repeating the values at the edge of a 1/0 mask
161 /** Allocates imOut to match imMask, and copies imIn to the center multiplied by the mask. Then fills in the new pixels
162  * by copying the edge pixels outward. For each pixel on the edge of the mask (touching at least one 1-valued pixel
163  * in the mask), the value is chosen as the value of the nearest pixel with a 1 in the mask. If the closest pixels are more than one equidistant pixels,
164  * their mean value is used.
165  *
166  *
167  * \retval 0 on success
168  * \retval -1 on error
169  *
170  * \tparam imOutT is an Eigen-like array
171  * \tparam imInT is an Eigen-like array
172  */
173 template<typename imOutT, typename imInT>
174 int padImage( imOutT & imOut, ///< [out] On return contains the padded image. This will be resized.
175  imInT & imIn, ///< [in] The image to be padded.
176  imInT & imMask, ///< [in] The 1/0 mask image.
177  unsigned int padSz ///< [in] The number of iterations of the padding loop.
178  )
179 {
180 
181  typedef imInT imMaskT;
182 
183  int dim1 = imMask.rows();
184  int dim2 = imMask.cols();
185 
186  imOut.resize(dim1, dim2);
187 
188  int stR = 0.5*(dim1 - imIn.rows());
189  int stC = 0.5*(dim2 - imIn.cols());
190 
191 
192  if(stR < 0)
193  {
194  mxError("padImage", MXE_INVALIDARG, "imMask must have at least as many rows as imIn.");
195  return -1;
196  }
197  if(stC < 0)
198  {
199  mxError("padImage", MXE_INVALIDARG, "imMask must have at least as many columns as imIn.");
200  return -1;
201  }
202 
203  imOut.block(stR, stC, imIn.rows(), imIn.cols()) = imIn;
204 
205  imOut *= imMask;
206 
207  imMaskT tMask = imMask; //Need a modifiable mask, which grows as the image is extended
208 
209  std::vector<int> nmi, nmj; //Used to track which pixels of the mask need to be updated
210 
211  for(unsigned int n=0; n < padSz; ++n)
212  {
213  nmi.clear();
214  nmj.clear();
215  for(int ii =0; ii< dim1; ++ii)
216  {
217  for(int jj =0; jj<dim2; ++jj)
218  {
219  if(tMask(ii,jj) == 1) continue;
220 
221  typename imOutT::Scalar mv = 0;
222  //int r, minr;// = 3;
223  int nv = 0;
224 
225  //Loop over the neighboring pixels
226  for(int i=-1; i<=1; ++i)
227  {
228  for(int j=-1; j<=1; ++j)
229  {
230  if(i==0 && j==0) continue;
231  if( ii + i < 0 || ii + i >= dim1) continue;
232  if( jj + j < 0 || jj + j >= dim2) continue;
233 
234  if( tMask( ii+i, jj+j) == 1)
235  {
236  mv += imOut( ii+i, jj+j);
237  ++nv;
238 
239  }
240  }
241  }
242 
243  //Found at least 1 neighboring pixel in the 1's part of the mask
244  if(nv > 0)
245  {
246  imOut(ii, jj) = mv/nv;
247  nmi.push_back(ii);
248  nmj.push_back(jj);
249  }
250  }
251  }
252 
253  for(size_t i=0; i< nmi.size(); ++i)
254  {
255  tMask( nmi[i], nmj[i]) = 1;
256  }
257 
258  }
259 
260  return 0;
261 
262 }
263 
264 ///Cut down a padded image
265 /**
266  * \retval 0 on success
267  * \retval -1 on error
268  *
269  * \tparam imOutT is an Eigen-like array
270  * \tparam imInT is an Eigen-like array
271  */
272 template<typename imOutT, typename imInT>
273 int cutPaddedImage( imOutT & imOut, ///< [out] On return contains the cut image. This will be resized.
274  const imInT & imIn, ///< [in] The image to be cut down.
275  unsigned int padSz ///< [in] The size of the pad. The output image will be smaller by 2*padSz rows and cols.
276  )
277 {
278  if(2*padSz > imIn.rows())
279  {
280  mxError("cutPaddedImage", MXE_INVALIDARG, "padSz too large, must be < imIn.rows()/2");
281  return -1;
282  }
283 
284  if(2*padSz > imIn.cols())
285  {
286  mxError("cutPaddedImage", MXE_INVALIDARG, "padSz too large, must be < imIn.cols()/2");
287  return -1;
288  }
289 
290  int nRows = imIn.rows() - 2*padSz;
291  int nCols = imIn.cols() - 2*padSz;
292 
293  imOut = imIn.block(padSz, padSz, nRows, nCols);
294 
295  return 0;
296 }
297 
298 ///@}
299 
300 
301 }// namespace improc
302 }// namespace mx
303 
304 #endif //improc_imagePads_hpp
int padImageRef(imOutT imOut, imInT imIn, unsigned int padSz, typename imOutT::Scalar value)
Pad an image with a constant value for reference types.
Definition: imagePads.hpp:83
int cutPaddedImage(imOutT &imOut, const imInT &imIn, unsigned int padSz)
Cut down a padded image.
Definition: imagePads.hpp:273
int padImage(imOutT &imOut, imInT &imIn, imInT &imMask, unsigned int padSz)
Pad an image by repeating the values at the edge of a 1/0 mask.
Definition: imagePads.hpp:174
The mxlib c++ namespace.
Definition: mxError.hpp:107