8#ifndef __imageFilters_hpp__
9#define __imageFilters_hpp__
71template <
typename _arrayT,
size_t _kernW = 4,
class _verboseT = verbose::d>
74 typedef _arrayT arrayT;
75 typedef typename _arrayT::Scalar arithT;
76 static const int kernW = _kernW;
78 typedef _verboseT verboseT;
84 explicit gaussKernel( arithT fwhm )
88 int w = kernW * _fwhm;
93 kernel.resize( w, w );
95 arithT kcen = 0.5 * ( w - 1.0 );
97 arithT sig2 = _fwhm / 2.354820045030949327;
101 for(
int i = 0; i < w; ++i )
103 for(
int j = 0; j < w; ++j )
105 r2 = pow( i - kcen, 2 ) + pow( j - kcen, 2 );
106 kernel( i, j ) = exp( -r2 / ( 2.0 * sig2 ) );
110 kernel /= kernel.sum();
115 return _kernW * _fwhm;
124 static_cast<void>( x );
125 static_cast<void>( y );
127 kernelArray = kernel;
138template <
typename _arrayT,
size_t _kernW = 2,
class _verboseT = verbose::d>
141 typedef _arrayT arrayT;
142 typedef typename _arrayT::Scalar arithT;
144 inline static constexpr int kernW =
static_cast<int>( _kernW );
146 typedef _verboseT verboseT;
179 maxAz = fabs( maxAz );
197 const arithT maximumDimension =
200 if( !
math::isFinite( maximumDimension ) || maximumDimension > std::numeric_limits<int>::max() )
205 m_maxWidth =
static_cast<int>( maximumDimension /
static_cast<arithT
>( 2 ) );
220 kernel.resize( 0, 0 );
226 "kernel widths and maxAz must be finite" );
236 kernel.resize( 1, 1 );
241 const arithT rad0 = std::hypot( x, y );
255 q = std::atan2( y, x );
260 const arithT height =
264 height > std::numeric_limits<int>::max() )
267 "kernel dimensions exceed the supported size" );
270 int w =
static_cast<int>( width );
271 int h =
static_cast<int>( height );
290 std::format(
"Width half-width bigger than maxWidth. "
291 "This is a bug. Details: "
292 "|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|",
309 std::format(
"Height half-width bigger than maxWidth. "
310 "This is a bug. Details: "
311 "|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|{}|",
325 kernel.resize( w, h );
327 const arithT xcen = 0.5 * ( w - 1.0 );
328 const arithT ycen = 0.5 * ( h - 1.0 );
330 for(
int j = 0; j < h; ++j )
332 for(
int i = 0; i < w; ++i )
334 const arithT dx = i - xcen;
335 const arithT dy = j - ycen;
336 const arithT sampleX = x + dx;
337 const arithT sampleY = y + dy;
338 const arithT radP = std::hypot( sampleX, sampleY );
346 const arithT tangentialOffset = dy * cosq - dx * sinq;
347 if( std::fabs( tangentialOffset ) <=
m_azWidth )
354 q2 = std::atan2( sampleY, sampleX );
358 if( std::fabs( dq ) >
m_maxAz )
371 const arithT ksum = kernel.sum();
374 kernel.resize( 0, 0 );
376 std::format(
"kernel sum 0 at {},{}", x, y ) );
389template <
class kernelT>
392 typedef kernelT::arrayT arrayT;
393 typedef kernelT::arrayT::Scalar arithT;
394 typedef kernelT::verboseT verboseT;
424 for( uint32_t cc = 0; cc <
m_cols; ++cc )
426 for( uint32_t rr = 0; rr <
m_rows; ++rr )
433 std::format(
"failed to pre-calculate kernel at row {}, column {}", rr, cc ) );
457 const arithT row = x +
m_xcen;
458 const arithT column = y +
m_ycen;
461 column >=
m_cols || std::floor( row ) != row || std::floor( column ) != column )
466 const size_t n =
static_cast<size_t>( column ) *
m_rows +
static_cast<size_t>( row );
483template <
typename imageOutT,
typename imageInT,
typename kernelT>
486 const kernelT &kernel,
492 typedef typename kernelT::verboseT verboseT;
494 fim.resize( im.rows(), im.cols() );
496 float xcen = 0.5 * ( im.rows() - 1 );
497 float ycen = 0.5 * ( im.cols() - 1 );
501 maxr = 0.5 * std::min( im.rows(), im.cols() ) - kernel.maxWidth();
504 int mini = 0.5 * im.rows() - maxr;
505 int maxi = 0.5 * im.rows() + maxr;
506 int minj = 0.5 * im.cols() - maxr;
507 int maxj = 0.5 * im.cols() + maxr;
509 typename kernelT::arrayT kernelArray;
514 #pragma omp parallel private( kernelArray )
516 int im_i, im_j, im_p, im_q;
517 int kern_i, kern_j, kern_p, kern_q;
518 typename imageOutT::Scalar norm;
524 for(
int i = 0; i < im.rows(); ++i )
531 for(
int j = 0; j < im.cols(); ++j )
538 if( ( i >= mini && i < maxi ) && ( j >= minj && j < maxj ) )
540 errc = kernel.setKernel( i - xcen, j - ycen, kernelArray );
542 fim( i, j ) = ( im.block( i - 0.5 * ( kernelArray.rows() - 1 ),
543 j - 0.5 * ( kernelArray.cols() - 1 ),
545 kernelArray.cols() ) *
551 errc = kernel.setKernel( i - xcen, j - ycen, kernelArray );
553 im_i = i - 0.5 * ( kernelArray.rows() - 1 );
557 im_j = j - 0.5 * ( kernelArray.cols() - 1 );
561 im_p = im.rows() - im_i;
562 if( im_p > kernelArray.rows() )
563 im_p = kernelArray.rows();
565 im_q = im.cols() - im_j;
566 if( im_q > kernelArray.cols() )
567 im_q = kernelArray.cols();
569 kern_i = 0.5 * ( kernelArray.rows() - 1 ) - i;
573 kern_j = 0.5 * ( kernelArray.cols() - 1 ) - j;
577 kern_p = kernelArray.rows() - kern_i;
578 if( kern_p > kernelArray.rows() )
579 kern_p = kernelArray.rows();
581 kern_q = kernelArray.cols() - kern_j;
582 if( kern_q > kernelArray.cols() )
583 kern_q = kernelArray.cols();
591 norm = kernelArray.block( kern_i, kern_j, kern_p, kern_q ).sum();
594 ( im.block( im_i, im_j, kern_p, kern_q ) * kernelArray.block( kern_i, kern_j, kern_p, kern_q ) )
597 if( !std::isfinite( fim( i, j ) ) )
628template <
typename imageOutT,
typename imageInT,
typename kernelT>
631 const kernelT &kernel,
636 fim.resize( im.rows(), im.cols() );
638 float xcen = 0.5 * ( im.rows() - 1 );
639 float ycen = 0.5 * ( im.cols() - 1 );
642 maxr = 0.5 * std::min( im.rows(), im.cols() ) - kernel.maxWidth();
644 int mini = 0.5 * im.rows() - maxr;
645 int maxi = 0.5 * im.rows() + maxr;
646 int minj = 0.5 * im.cols() - maxr;
647 int maxj = 0.5 * im.cols() + maxr;
649 typename kernelT::arrayT kernelArray;
652 #pragma omp parallel private( kernelArray )
654 int im_i, im_j, im_p, im_q;
655 int kern_i, kern_j, kern_p, kern_q;
656 typename imageOutT::Scalar norm;
658 std::vector<typename imageOutT::Scalar> pixels;
662 for(
int i = 0; i < im.rows(); ++i )
664 for(
int j = 0; j < im.cols(); ++j )
666 if( ( i >= mini && i < maxi ) && ( j >= minj && j < maxj ) )
668 kernel.setKernel( i - xcen, j - ycen, kernelArray );
671 for(
int cc = 0; cc < kernelArray.cols(); ++cc )
673 for(
int rr = 0; rr < kernelArray.rows(); ++rr )
675 if( kernelArray( rr, cc ) != 0 )
676 pixels.push_back( im.block( i - 0.5 * ( kernelArray.rows() - 1 ),
677 j - 0.5 * ( kernelArray.cols() - 1 ),
679 kernelArray.cols() )( rr, cc ) );
692 kernel.setKernel( i - xcen, j - ycen, kernelArray );
694 im_i = i - 0.5 * ( kernelArray.rows() - 1 );
698 im_j = j - 0.5 * ( kernelArray.cols() - 1 );
702 im_p = im.rows() - im_i;
703 if( im_p > kernelArray.rows() )
704 im_p = kernelArray.rows();
706 im_q = im.cols() - im_j;
707 if( im_q > kernelArray.cols() )
708 im_q = kernelArray.cols();
710 kern_i = 0.5 * ( kernelArray.rows() - 1 ) - i;
714 kern_j = 0.5 * ( kernelArray.cols() - 1 ) - j;
718 kern_p = kernelArray.rows() - kern_i;
719 if( kern_p > kernelArray.rows() )
720 kern_p = kernelArray.rows();
722 kern_q = kernelArray.cols() - kern_j;
723 if( kern_q > kernelArray.cols() )
724 kern_q = kernelArray.cols();
732 norm = kernelArray.block( kern_i, kern_j, kern_p, kern_q ).sum();
735 for(
int cc = 0; cc < kern_q; ++cc )
737 for(
int rr = 0; rr < kern_p; ++rr )
739 if( kernelArray.block( kern_i, kern_j, kern_p, kern_q )( rr, cc ) != 0 )
741 pixels.push_back( im.block( im_i, im_j, kern_p, kern_q )( rr, cc ) );
777template <
typename imageTout,
typename imageTin>
780 const imageTin &imIn,
782 bool rejectMinMax =
false
785 typedef typename imageTout::Scalar scalarT;
787 if( meanFullWidth <= 0 || meanFullWidth > imIn.rows() || meanFullWidth > imIn.cols() ||
788 imOut.rows() != imIn.rows() || imOut.cols() != imIn.cols() )
793 const int before = meanFullWidth / 2;
794 const int after = meanFullWidth - before - 1;
795 int nPix = meanFullWidth * meanFullWidth;
797 if( rejectMinMax && nPix <= 2 )
805 for(
int jj = before; jj < imIn.cols() - after; ++jj )
807 for(
int ii = before; ii < imIn.rows() - after; ++ii )
810 scalarT max = std::numeric_limits<scalarT>::lowest();
811 scalarT min = std::numeric_limits<scalarT>::max();
812 for(
int ll = 0; ll < meanFullWidth; ++ll )
814 for(
int kk = 0; kk < meanFullWidth; ++kk )
816 const scalarT value = imIn( ii - before + kk, jj - before + ll );
824 imOut( ii, jj ) = ( sum - max - min ) / nPix;
830 for(
int jj = before; jj < imIn.cols() - after; ++jj )
832 for(
int ii = before; ii < imIn.rows() - after; ++ii )
835 for(
int ll = 0; ll < meanFullWidth; ++ll )
837 for(
int kk = 0; kk < meanFullWidth; ++kk )
839 sum += imIn( ii - before + kk, jj - before + ll );
842 imOut( ii, jj ) = sum / nPix;
876template <
typename imageTout,
typename imageTin>
881 typename imageTout::Scalar &pMax,
882 const imageTin &imIn,
884 bool rejectMinMax =
false
887 typedef typename imageTout::Scalar scalarT;
891 pMax = std::numeric_limits<scalarT>::lowest();
893 if( meanFullWidth <= 0 || meanFullWidth > imIn.rows() || meanFullWidth > imIn.cols() ||
894 imOut.rows() != imIn.rows() || imOut.cols() != imIn.cols() )
899 const int before = meanFullWidth / 2;
900 const int after = meanFullWidth - before - 1;
901 int nPix = meanFullWidth * meanFullWidth;
903 if( rejectMinMax && nPix <= 2 )
911 for(
int jj = before; jj < imIn.cols() - after; ++jj )
913 for(
int ii = before; ii < imIn.rows() - after; ++ii )
916 scalarT max = std::numeric_limits<scalarT>::lowest();
917 scalarT min = std::numeric_limits<scalarT>::max();
918 for(
int ll = 0; ll < meanFullWidth; ++ll )
920 for(
int kk = 0; kk < meanFullWidth; ++kk )
922 const scalarT value = imIn( ii - before + kk, jj - before + ll );
930 imOut( ii, jj ) = ( sum - max - min ) / nPix;
931 if( imOut( ii, jj ) > pMax )
933 pMax = imOut( ii, jj );
942 for(
int jj = before; jj < imIn.cols() - after; ++jj )
944 for(
int ii = before; ii < imIn.rows() - after; ++ii )
947 for(
int ll = 0; ll < meanFullWidth; ++ll )
949 for(
int kk = 0; kk < meanFullWidth; ++kk )
951 sum += imIn( ii - before + kk, jj - before + ll );
954 imOut( ii, jj ) = sum / nPix;
955 if( imOut( ii, jj ) > pMax )
957 pMax = imOut( ii, jj );
990template <
typename imageTout,
typename imageTin>
995 typename imageTout::Scalar &pMax,
996 const imageTin &imIn,
1000 typedef typename imageTout::Scalar scalarT;
1004 pMax = std::numeric_limits<scalarT>::lowest();
1006 if( medianFullWidth <= 0 || medianFullWidth > imIn.rows() || medianFullWidth > imIn.cols() ||
1007 imOut.rows() != imIn.rows() || imOut.cols() != imIn.cols() )
1012 const int before = medianFullWidth / 2;
1013 const int after = medianFullWidth - before - 1;
1014 const size_t sampleCount =
static_cast<size_t>( medianFullWidth ) *
static_cast<size_t>( medianFullWidth );
1015 std::vector<scalarT> pixs( sampleCount );
1017 for(
int jj = before; jj < imIn.cols() - after; ++jj )
1019 for(
int ii = before; ii < imIn.rows() - after; ++ii )
1022 for(
int ll = 0; ll < medianFullWidth; ++ll )
1024 for(
int kk = 0; kk < medianFullWidth; ++kk )
1026 pixs[n] = imIn( ii - before + kk, jj - before + ll );
1032 if( imOut( ii, jj ) > pMax )
1034 pMax = imOut( ii, jj );
1061template <
typename imageTout,
typename imageTin>
1064 const imageTin &imIn,
1069 typename imageTout::Scalar pMax;
1070 return medianSmooth( imOut, xMax, yMax, pMax, imIn, medianFullWidth );
1073template <
typename eigenImT>
1078 typedef typename eigenImT::Scalar realT;
1080 std::vector<realT> edge( 2 * ncols );
1081 for(
int rr = 0; rr < im.rows(); ++rr )
1083 for(
int cc = 0; cc < ncols; ++cc )
1085 edge[cc] = im( rr, cc );
1088 for(
int cc = 0; cc < ncols; ++cc )
1090 edge[ncols + cc] = im( rr, im.cols() - ncols + cc );
1094 im.row( rr ) -= med;
1100template <
typename eigenImT>
1105 typedef typename eigenImT::Scalar realT;
1107 std::vector<realT> edge( 2 * nrows );
1108 for(
int cc = 0; cc < im.cols(); ++cc )
1110 for(
int rr = 0; rr < nrows; ++rr )
1112 edge[rr] = im( rr, cc );
1115 for(
int rr = 0; rr < nrows; ++rr )
1117 edge[nrows + rr] = im( im.rows() - nrows + rr, cc );
1121 im.col( cc ) -= med;
1129template <
typename floatT>
1136template <
typename floatT>
1139 bool operator()( radval<floatT> rv1, radval<floatT> rv2 )
1141 return ( rv1.r < rv2.r );
1145template <
typename floatT>
1148 bool operator()( radval<floatT> rv1, radval<floatT> rv2 )
1150 return ( rv1.v < rv2.v );
1165template <
typename vecT,
typename eigenImT1,
typename eigenImT2,
typename eigenImT3>
1169 const eigenImT1 &im,
1170 const eigenImT2 &radim,
1171 const eigenImT3 *mask,
1174 typename eigenImT1::Scalar minr = 0 )
1176 typedef typename eigenImT1::Scalar floatT;
1178 int dim1 = im.rows();
1179 int dim2 = im.cols();
1195 std::vector<radval<floatT>> rv( nPix );
1199 for(
int c = 0; c < im.cols(); ++c )
1201 for(
int r = 0; r < im.rows(); ++r )
1205 if( ( *mask )( r, c ) == 0 )
1209 rv[i].r = radim( r, c );
1210 rv[i].v = im( r, c );
1215 sort( rv.begin(), rv.end(), radvalRadComp<floatT>() );
1231 floatT r1 = minr + dr;
1238 while( rv[i1].r < r0 )
1241 while( rv[i2].r <= r1 )
1247 for(
int in = i1; in < i2; ++in )
1253 n = 0.5 * ( i2 - i1 );
1255 std::nth_element( rv.begin() + i1, rv.begin() + i1 + n, rv.begin() + i2, radvalValComp<floatT>() );
1257 med = ( rv.begin() + i1 + n )->v;
1260 if( ( i2 - i1 ) % 2 == 0 )
1264 ( med + ( *std::max_element( rv.begin() + i1, rv.begin() + i1 + n, radvalValComp<floatT>() ) ).v );
1268 rad.push_back( .5 * ( r0 + r1 ) );
1269 prof.push_back( med );
1289template <
typename vecT,
typename eigenImT1,
typename eigenImT2>
1293 const eigenImT1 &im,
1294 const eigenImT2 &mask,
1299 radim.resize( im.cols(), im.rows() );
1303 radprof( rad, prof, im, radim, &mask, mean );
1317template <
typename vecT,
typename eigenImT1>
1321 const eigenImT1 &im,
1326 radim.resize( im.cols(), im.rows() );
1344template <
typename radprofT,
typename eigenImT1,
typename eigenImT2,
typename eigenImT3>
1347 const eigenImT2 &rad,
1348 const eigenImT3 *mask,
1356 std::vector<double> med_r, med_v;
1358 radprof( med_r, med_v, im, rad, mask );
1361 radprofIm.resize( im.rows(), im.cols() );
1365 for(
int c = 0; c < im.cols(); ++c )
1367 for(
int r = 0; r < im.rows(); ++r )
1371 if( ( *mask )( r, c ) == 0 )
1373 radprofIm( r, c ) = 0;
1378 radprofIm( r, c ) = interp( ( (
double)rad( r, c ) ) );
1380 im( r, c ) -= radprofIm( r, c );
1394template <
typename radprofT,
typename eigenImT>
1398 bool subtract =
false,
1403 rad.resize( im.rows(), im.cols() );
1421template <
typename eigenImT,
typename eigenImT1,
typename eigenImT2,
typename eigenImT3>
1423 const eigenImT1 &im,
1424 const eigenImT2 &rad,
1425 const eigenImT3 &mask,
1426 typename eigenImT::Scalar minRad,
1427 typename eigenImT::Scalar maxRad,
1432 typedef typename eigenImT::Scalar floatT;
1434 int dim1 = im.cols();
1435 int dim2 = im.rows();
1437 floatT mr = rad.maxCoeff();
1440 std::vector<radval<floatT>> rv;
1441 rv.reserve( dim1 * dim2 );
1443 for(
int i = 0; i < im.size(); ++i )
1445 if( mask( i ) == 0 )
1448 rv.push_back( { rad( i ), im( i ) } );
1451 sort( rv.begin(), rv.end(), radvalRadComp<floatT>() );
1459 std::vector<double> std_r, std_v, mean_v;
1463 while( i1 < rv.size() && rv[i1].r < r0 )
1467 if( i1 == rv.size() )
1473 while( i2 < rv.size() && rv[i2].r <= r1 )
1476 std::vector<double> vals;
1478 for(
int i = i1; i < i2; ++i )
1480 vals.push_back( rv[i].v );
1484 std_r.push_back( .5 * ( r0 + r1 ) );
1485 mean_v.push_back( mean );
1493 stdIm.resize( dim1, dim2 );
1497 for(
int i = 0; i < dim1; ++i )
1499 for(
int j = 0; j < dim2; ++j )
1501 if( rad( i, j ) < minRad || rad( i, j ) > maxRad )
1507 stdIm( i, j ) = stdInterp( ( (
double)rad( i, j ) ) );
1509 stdIm( i, j ) = ( im( i, j ) - meanInterp( ( (
double)rad( i, j ) ) ) ) / stdIm( i, j );
1526template <
typename eigenImT,
typename eigenImT1,
typename eigenImT2>
1529 const eigenImT1 &im,
1530 const eigenImT2 &mask,
1531 typename eigenImT::Scalar minRad,
1532 typename eigenImT::Scalar maxRad,
1537 int dim1 = im.cols();
1538 int dim2 = im.rows();
1541 rad.resize( dim1, dim2 );
1544 stddevImage( stdIm, im, rad, mask, minRad, maxRad, divide );
1556template <
typename eigenCubeT,
typename eigenCubeT1,
typename eigenCubeT2,
typename radT1,
typename radT2>
1559 const eigenCubeT1 &imc,
1560 const eigenCubeT2 &maskCube,
1567 int dim1 = imc.cols();
1568 int dim2 = imc.rows();
1570 typename eigenCubeT::Scalar minRadF = minRad;
1571 typename eigenCubeT::Scalar maxRadF = maxRad;
1574 rad.resize( dim1, dim2 );
1578 stdImc.resize( imc.rows(), imc.cols(), imc.planes() );
1581 for(
int i = 0; i < imc.planes(); ++i )
1585 im = imc.image( i );
1586 mask = maskCube.image( i );
1588 stddevImage( stdIm, im, rad, mask, minRadF, maxRadF, divide );
1590 stdImc.image( i ) = stdIm;
Class to manage interpolation using the GSL interpolation library.
Floating-point classification utilities that remain reliable under fast-math optimization.
Utilities for working with angles.
Eigen::Array< scalarT, -1, -1 > eigenImage
Definition of the eigenImage type, which is an alias for Eigen::Array.
error_t
The mxlib error codes.
@ noerror
No error has occurred.
@ sizeerr
A size was invalid or calculated incorrectly.
@ exception
An exception was thrown.
@ invalidconfig
A config setting was invalid.
@ invalidarg
An argument was invalid.
error_t mxlib_error_report(const error_t &code, const std::string &expl, const std::source_location &loc=std::source_location::current())
Print a report to stderr given an mxlib error_t code and explanation and return the code.
bool isFinite(realT value)
Test whether a floating-point value is finite, including under finite-math-only optimization.
angleT::realT angleDiff(typename angleT::realT q1, typename angleT::realT q2)
Calculate the difference between two angles, correctly across 0/360.
realT dtor(realT q)
Convert from degrees to radians.
int meanSmooth(imageTout &imOut, const imageTin &imIn, int meanFullWidth, bool rejectMinMax=false)
Smooth an image using the mean in a rectangular box, optionally rejecting the highest and lowest valu...
int medianSmooth(imageTout &imOut, int &xMax, int &yMax, typename imageTout::Scalar &pMax, const imageTin &imIn, int medianFullWidth)
error_t filterImage(imageOutT &fim, imageInT im, const kernelT &kernel, int maxr=0)
Filter an image with a mean kernel.
void medianFilterImage(imageOutT &fim, imageInT im, const kernelT &kernel, int maxr=0, int maxrproc=1)
Filter an image with a median kernel.
void radiusImage(eigenT &m, typename eigenT::Scalar xc, typename eigenT::Scalar yc, typename eigenT::Scalar scale=1)
Fills in the cells of an Eigen 2D Array with their radius from the center.
void radprof(vecT &rad, vecT &prof, const eigenImT1 &im, const eigenImT2 &radim, const eigenImT3 *mask, bool mean=false, typename eigenImT1::Scalar minr=0)
Calculate the the radial profile.
void radprofim(radprofT &radprofIm, eigenImT1 &im, const eigenImT2 &rad, const eigenImT3 *mask, bool subtract, bool mean=false)
Form a radial profile image, and optionally subtract it from the input.
void stddevImage(eigenImT &stdIm, const eigenImT1 &im, const eigenImT2 &rad, const eigenImT3 &mask, typename eigenImT::Scalar minRad, typename eigenImT::Scalar maxRad, bool divide)
Form a standard deviation image, and optionally normalize the input relative to the local mean to for...
void stddevImageCube(eigenCubeT &stdImc, const eigenCubeT1 &imc, const eigenCubeT2 &maskCube, radT1 minRad, radT2 maxRad, bool divide=false)
vectorT::value_type vectorMedianInPlace(vectorT &vec)
Calculate median of a vector in-place, altering the vector.
valueT vectorMean(const valueT *vec, size_t sz)
Calculate the mean of a vector.
valueT vectorVariance(const valueT *vec, size_t sz, valueT mean)
Calculate the variance of a vector relative to a supplied mean value.
vectorT::value_type vectorMedian(const vectorT &vec, vectorT *work=0)
Calculate median of a vector, leaving the vector unaltered.
Class for managing 1-D interpolation using the GNU Scientific Library.
void colEdgeMedSubtract(eigenImT &im, int nrows)
void rowEdgeMedSubtract(eigenImT &im, int ncols)
Declares and defines functions to work with image masks.
azBoxKernel(arithT radWidth, arithT azWidth, arithT maxAz)
Construct a kernel with an optional angular-position limit.
arithT m_radWidth
the half-width of the averaging box, in the radial direction, in pixels.
int m_maxWidth
maximum kernel half-width needed to keep every generated kernel in bounds.
void setMaxWidth()
Sets the max width based on the configured az and rad widths.
int maxWidth() const
Get the maximum kernel half-width in either image dimension.
arithT m_maxAz
maximum azimuthal half-width in radians; 0 means no angular limit.
azBoxKernel(arithT radWidth, arithT azWidth)
Construct a kernel without an angular-position limit.
error_t setKernel(arithT x, arithT y, arrayT &kernel) const
Generate a normalized kernel at the requested image-relative coordinate.
static constexpr int kernW
kernel sampling factor.
arithT m_azWidth
the half-width of the averaging box, in the azimuthal direction, in pixels.
error_t setKernel(arithT x, arithT y, arrayT &kernelArray) const
arithT m_xcen
pixel x-coordinate of the image center.
precalcKernel(const kernelT &kernel, uint32_t rows, uint32_t cols, arithT xcen, arithT ycen)
Pre-calculate a production kernel for every coordinate in an image.
int m_maxWidth
maximum half-width reported by the copied production kernel.
uint32_t m_cols
number of image columns represented by the cache.
error_t setKernel(arithT x, arithT y, arrayT &kernel) const
Retrieve the cached kernel at an integral image-relative coordinate.
arithT m_ycen
pixel y-coordinate of the image center.
std::vector< arrayT > m_kernels
generated kernels in column-major image-coordinate order.
uint32_t m_rows
number of image rows represented by the cache.
int maxWidth() const
Get the maximum half-width reported by the cached production kernel.
precalcKernel()=delete
Disallow construction without a production kernel and image geometry.
kernelT m_kernel
copied production kernel used to populate the cache.
Header for the std::vector utilities.