27#ifndef improc_imageUtils_hpp
28#define improc_imageUtils_hpp
47template <
typename realT =
double>
50 return 0.5 * ( 1.0 * rows_cols - 1 );
57template <
typename realT =
double,
typename imT>
67template <
typename realT =
double,
typename imT>
84template <
typename realT>
87 static_assert( std::is_floating_point_v<realT>,
"invalidNumber requires a floating-point type" );
89#ifdef MXLIB_INVALID_NUMBER_VALUE
90 return static_cast<realT
>( MXLIB_INVALID_NUMBER_VALUE );
92 return std::numeric_limits<realT>::quiet_NaN();
102template <
typename realT>
105 static_assert( std::is_floating_point_v<realT>,
"isInvalidPixel requires a floating-point type" );
107#ifdef MXLIB_INVALID_NUMBER_VALUE
117template <
typename realT>
126 x1 = xc - ( x0 - xc );
127 y1 = yc - ( y0 - yc );
140template <
class imageT,
typename valueT>
145 for(
int c = 0; c < im.cols(); ++c )
147 for(
int r = 0; r < im.rows(); ++r )
161template <
class imageT>
164 typename imageT::Scalar zero = 0;
173template <
class cubeT,
class maskCubeT>
180 mask->resize( imc.rows(), imc.cols(), imc.planes() );
184 for(
int p = 0; p < imc.planes(); ++p )
186 for(
int c = 0; c < imc.cols(); ++c )
188 for(
int r = 0; r < imc.rows(); ++r )
192 imc.image( p )( r, c ) = 0;
195 ( *mask ).image( p )( r, c ) = 1;
207template <
class cubeT>
220template <
class calcT,
class imageT>
223 return static_cast<calcT
>( im.sum() ) / ( im.rows() * im.cols() );
232template <
class calcT,
class imageT,
class maskT>
236 return static_cast<calcT
>( ( im * mask ).sum() ) / ( mask.sum() );
246template <
typename calcT,
class imageT>
251 return ( im.template cast<calcT>() - mn ).square().sum() / ( im.rows() * im.cols() );
261template <
typename calcT,
class imageT,
class maskT>
267 return ( im.template cast<calcT>() * mask - mn ).square().sum() / ( mask.sum() );
282template <
typename imageT,
typename maskT = imageT>
283typename imageT::Scalar
286 std::vector<typename imageT::Scalar> *work = 0
291 typename imageT::Scalar med;
293 bool localWork =
false;
296 work =
new std::vector<typename imageT::Scalar>;
312 for(
int i = 0; i < mat.rows(); ++i )
314 for(
int j = 0; j < mat.cols(); ++j )
316 if( ( *mask )( i, j ) == 0 )
320 ( *work )[ii] = mat( i, j );
328 for(
int i = 0; i < mat.rows(); ++i )
330 for(
int j = 0; j < mat.cols(); ++j )
332 ( *work )[ii] = mat( i, j );
359template <
typename imageT>
361 std::vector<typename imageT::Scalar> *work = 0
365 return imageMedian( mat,
static_cast<Eigen::Array<typename imageT::Scalar, -1, -1
> *>(
nullptr ), work );
373template <
typename imageT>
375 typename imageT::Scalar &y,
382 typename imageT::Scalar sum = im.sum();
386 x = 0.5 * ( im.rows() - 1.0 );
387 y = 0.5 * ( im.cols() - 1.0 );
391 for(
int j = 0; j < im.cols(); ++j )
393 for(
int i = 0; i < im.rows(); ++i )
395 x += ( i + 1 ) * im( i, j );
396 y += ( j + 1 ) * im( i, j );
413template <
typename floatT,
typename imageT,
typename magImageT,
typename transformT>
425 floatT magSize_x = ceil( ( im.rows() - 1.0 ) / scale_x ) + 1;
426 floatT magSize_y = ceil( ( im.cols() - 1.0 ) / scale_y ) + 1;
428 floatT mag_x = ( (floatT)magSize_x - 1.0 ) / ( (floatT)im.rows() - 1.0 );
429 floatT mag_y = ( (floatT)magSize_y - 1.0 ) / ( (floatT)im.cols() - 1.0 );
431 scale_x = 1.0 / mag_x;
432 scale_y = 1.0 / mag_y;
434 magIm.resize( magSize_x, magSize_y );
439 magIm.maxCoeff( &ix, &iy );
453template <
typename floatT,
typename imageT,
typename magImageT>
482template <
typename imageT,
typename imageT1,
typename imageT2,
typename imageT3,
typename imageT4>
485 const imageT2 &mask1,
490 combo.resize( im1.rows(), im2.cols() );
492 for(
int c = 0; c < combo.cols(); ++c )
494 for(
int r = 0; r < combo.rows(); ++r )
496 if( mask1( r, c ) == 1 && mask2( r, c ) == 0 )
497 combo( r, c ) = im1( r, c );
498 else if( mask2( r, c ) == 1 & mask1( r, c ) == 0 )
499 combo( r, c ) = im2( r, c );
500 else if( mask1( r, c ) == 1 && mask2( r, c ) == 1 )
501 combo( r, c ) = 0.5 * ( im1( r, c ) + im2( r, c ) );
512template <
typename eigenT,
typename eigenTin>
515 out.resize( in.rows() - w, in.cols() - w );
517 out.topLeftCorner( st, st ) = in.topLeftCorner( st, st );
519 out.bottomLeftCorner( in.rows() - ( st + w ), st ) = in.bottomLeftCorner( in.rows() - ( st + w ), st );
521 out.topRightCorner( st, in.cols() - ( st + w ) ) = in.topRightCorner( st, in.cols() - ( st + w ) );
523 out.bottomRightCorner( in.rows() - ( st + w ), in.cols() - ( st + w ) ) =
524 in.bottomRightCorner( in.rows() - ( st + w ), in.cols() - ( st + w ) );
531template <
typename eigenT,
typename eigenTin>
532void removeRows( eigenT &out,
const eigenTin &in,
int st,
int w )
534 out.resize( in.rows() - w, in.cols() );
536 out.topLeftCorner( st, in.cols() ) = in.topLeftCorner( st, in.cols() );
538 out.bottomLeftCorner( in.rows() - ( st + w ), in.cols() ) =
539 in.bottomLeftCorner( in.rows() - ( st + w ), in.cols() );
546template <
typename eigenT,
typename eigenTin>
547void removeCols( eigenT &out,
const eigenTin &in,
int st,
int w )
549 out.resize( in.rows(), in.cols() - w );
551 out.topLeftCorner( in.rows(), st ) = in.topLeftCorner( in.rows(), st );
553 out.topRightCorner( in.rows(), in.cols() - ( st + w ) ) = in.topRightCorner( in.rows(), in.cols() - ( st + w ) );
565void *
imcpy(
void *dest,
Floating-point classification utilities that remain reliable under fast-math optimization.
void removeCols(eigenT &out, const eigenTin &in, int st, int w)
Remove columns.
void removeRows(eigenT &out, const eigenTin &in, int st, int w)
Remove rows.
void removeRowsAndCols(eigenT &out, const eigenTin &in, int st, int w)
Remove rows and columns.
int imageMaxInterp(floatT &x, floatT &y, floatT &scale_x, floatT &scale_y, magImageT &magIm, const imageT &im, transformT trans)
Find the maximum in an image at sub-pixel resolution by interpolation.
imageT::Scalar imageMedian(const imageT &mat, const maskT *mask, std::vector< typename imageT::Scalar > *work=0)
Calculate the median of an Eigen-like array.
calcT imageVariance(imageT &im, calcT mn)
Calculate the variance of an image given its mean.
int imageCenterOfLight(typename imageT::Scalar &x, typename imageT::Scalar &y, const imageT &im)
Calculate the center of light of an image.
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.
calcT imageMean(imageT &im)
Calculate the mean value of an image.
void zeroNaNs(imageT &im, valueT val)
Zero any NaNs in an image.
void zeroNaNCube(cubeT &imc, maskCubeT *mask)
Zero any NaNs in an image cube.
bool isFinite(realT value)
Test whether a floating-point value is finite, including under finite-math-only optimization.
void * imcpy(void *dest, void *src, size_t width, size_t height, size_t szof)
Copy one image to another, with no transformation.
constexpr realT invalidNumber()
Return the configured invalid image-pixel value.
bool isInvalidPixel(realT value)
Check whether a value represents an invalid image pixel.
void * imcpy_flipLR(void *dest, void *src, size_t width, size_t height, size_t szof)
Copy one image to another, flipping left-right.
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.
void * imcpy_flipUD(void *dest, void *src, size_t width, size_t height, size_t szof)
Copy one image to another, flipping up-down.
int reflectImageCoords(int &x1, int &y1, int x0, int y0, realT xc, realT yc)
Reflect pixel coordinates across the given center pixel.
vectorT::value_type vectorMedianInPlace(vectorT &vec)
Calculate median of a vector in-place, altering the vector.
realT imCen(int rows_cols)
Get the mxlib standard center coordinate of an image.
realT imCenX(const imT &im)
Get the mxlib standard center x-coordinate of an image.
realT imCenY(const imT &im)
Get the mxlib standard center y-coordinate of an image.