LCOV - code coverage report
Current view: top level - include/improc - imagePads.hpp (source / functions) Coverage Total Hit
Test: mxlib Lines: 0.0 % 6 0
Test Date: 2026-08-30 22:23:37 Functions: 0.0 % 1 0

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

Generated by: LCOV version 2.0-1