8 #ifndef __imageFilters_hpp__
9 #define __imageFilters_hpp__
13 #include "../math/gslInterpolator.hpp"
14 #include "../math/vectorUtils.hpp"
15 #include "../math/geo.hpp"
29 template<
typename _arrayT,
size_t _kernW=4>
32 typedef _arrayT arrayT;
33 typedef typename _arrayT::Scalar arithT;
34 static const int kernW = _kernW;
50 arithT kcen = 0.5*(w-1.0);
52 arithT sig2 = _fwhm/2.354820045030949327;
56 for(
int i=0; i < w; ++i)
58 for(
int j=0; j < w; ++j)
60 r2 = pow(i-kcen,2) + pow(j-kcen,2) ;
61 kernel(i,j) = exp(-r2/(2.0*sig2));
65 kernel /= kernel.sum();
73 void setKernel(arithT x, arithT y, arrayT & kernelArray)
89 template<
typename _arrayT,
size_t _kernW=2>
92 typedef _arrayT arrayT;
93 typedef typename _arrayT::Scalar arithT;
95 static const int kernW = _kernW;
118 if(maxAz >= 180) maxAz = 0;
130 arithT mx1 = kernW*( (int) ( fabs(
m_azWidth*sin(qmax)) + fabs(
m_radWidth*cos(qmax)) ) + 1 );
133 arithT mx2 = kernW*( (int) ( fabs(
m_azWidth*cos(qmax)) + fabs(
m_radWidth*sin(qmax)) ) + 1 );
135 m_maxWidth = 0.5*std::max(mx1, mx2);
143 void setKernel(arithT x, arithT y, arrayT & kernel)
145 arithT rad0 = sqrt((arithT) (x*x + y*y));
147 arithT sinq = y/rad0;
148 arithT cosq = x/rad0;
152 if(
m_maxAz > 0) q = atan2(sinq, cosq);
159 std::stringstream errs;
160 errs <<
"|" << kernW <<
"|" <<
m_radWidth <<
"|" <<
m_azWidth <<
"|" << m_maxWidth <<
"|" << x <<
"|" << y <<
"|" << rad0 <<
"|" << sinq <<
"|" << cosq;
161 errs <<
"|" << w <<
"|" <<
h <<
"|";
162 mxThrowException(
err::sizeerr,
"azBoxKernel::setKernel",
"width bigger than 2*maxWidth. This is a bug. Details: " + errs.str());
167 std::stringstream errs;
168 errs <<
"|" << kernW <<
"|" <<
m_radWidth <<
"|" <<
m_azWidth <<
"|" << m_maxWidth <<
"|" << x <<
"|" << y <<
"|" << rad0 <<
"|" << sinq <<
"|" << cosq;
169 errs <<
"|" << w <<
"|" <<
h <<
"|";
170 mxThrowException(err::sizeerr,
"azBoxKernel::setKernel",
"height bigger than 2*maxWidth. This is a bug. Details: " + errs.str());
175 arithT xcen = 0.5*(w-1.0);
176 arithT ycen = 0.5*(
h-1.0);
180 arithT sinq2, cosq2, sindq, q2, dq;
181 for(
int j=0; j <
h; ++j)
184 for(
int i=0; i < w; ++i)
187 rad = sqrt( pow(xP-xcen,2) + pow(yP-ycen,2) );
188 radP = sqrt( pow(x+xP-xcen,2) + pow(y+yP-ycen,2) );
196 sinq2 = (yP-ycen)/rad;
197 cosq2 = (xP-xcen)/rad;
199 sindq = sinq2*cosq - cosq2*sinq;
204 q2 = atan2(y+yP-ycen, x+xP-xcen);
205 dq = math::angleDiff<math::radiansT<arithT>>(q,q2);
214 else kernel(i,j) = 0;
218 arithT ksum = kernel.sum();
221 mxThrowException(err::invalidconfig,
"azBoxKernel::setKernel",
"kernel sum 0 at " + std::to_string(x) +
"," + std::to_string(y));
276 template<
typename imageOutT,
typename imageInT,
typename kernelT>
277 void filterImage(imageOutT & fim, imageInT im, kernelT kernel,
int maxr= 0)
279 fim.resize(im.rows(), im.cols());
281 float xcen = 0.5*(im.rows()-1);
282 float ycen = 0.5*(im.cols()-1);
284 if(maxr == 0) maxr = 0.5*im.rows() - kernel.maxWidth();
286 int mini = 0.5*im.rows() - maxr;
287 int maxi = 0.5*im.rows() + maxr;
288 int minj = 0.5*im.cols() - maxr;
289 int maxj = 0.5*im.cols() + maxr;
292 typename kernelT::arrayT kernelArray;
294 #pragma omp parallel private(kernelArray)
296 int im_i, im_j, im_p,im_q;
297 int kern_i, kern_j, kern_p,kern_q;
298 typename imageOutT::Scalar norm;
301 for(
int i=0; i< im.rows(); ++i)
303 for(
int j=0; j<im.cols(); ++j)
305 if((i >= mini && i< maxi) && (j>= minj && j<maxj))
307 kernel.setKernel(i-xcen, j-ycen, kernelArray);
308 fim(i,j) = (im.block(i-0.5*(kernelArray.rows()-1), j-0.5*(kernelArray.cols()-1), kernelArray.rows(), kernelArray.cols())*kernelArray).sum();
312 kernel.setKernel(i-xcen, j-ycen, kernelArray);
314 im_i = i - 0.5*(kernelArray.rows()-1);
315 if(im_i < 0) im_i = 0;
317 im_j = j - 0.5*(kernelArray.cols()-1);
318 if(im_j < 0) im_j = 0;
320 im_p = im.rows() - im_i;
321 if(im_p > kernelArray.rows()) im_p = kernelArray.rows();
323 im_q = im.cols() - im_j;
324 if(im_q > kernelArray.cols()) im_q = kernelArray.cols();
326 kern_i = 0.5*(kernelArray.rows()-1) - i;
327 if(kern_i < 0) kern_i = 0;
329 kern_j = 0.5*(kernelArray.cols()-1) - j;
330 if(kern_j < 0) kern_j = 0;
332 kern_p = kernelArray.rows() - kern_i;
333 if(kern_p > kernelArray.rows()) kern_p = kernelArray.rows();
335 kern_q = kernelArray.cols() - kern_j;
336 if(kern_q > kernelArray.cols()) kern_q = kernelArray.cols();
339 if(im_p < kern_p) kern_p = im_p;
340 if(im_q < kern_q) kern_q = im_q;
342 norm = kernelArray.block(kern_i, kern_j, kern_p, kern_q ).sum();
344 fim(i,j) = ( im.block(im_i, im_j, kern_p, kern_q) * kernelArray.block(kern_i, kern_j, kern_p, kern_q )).sum()/norm;
345 if( !std::isfinite(fim(i,j))) fim(i,j) = 0.0;
352 template<
typename imageOutT,
typename imageInT,
typename kernelT>
353 void medianFilterImage( imageOutT & fim,
359 fim.resize(im.rows(), im.cols());
361 float xcen = 0.5*(im.rows()-1);
362 float ycen = 0.5*(im.cols()-1);
364 if(maxr == 0) maxr = 0.5*im.rows() - kernel.maxWidth();
366 int mini = 0.5*im.rows() - maxr;
367 int maxi = 0.5*im.rows() + maxr;
368 int minj = 0.5*im.cols() - maxr;
369 int maxj = 0.5*im.cols() + maxr;
372 typename kernelT::arrayT kernelArray;
374 #pragma omp parallel private(kernelArray)
376 int im_i, im_j, im_p,im_q;
377 int kern_i, kern_j, kern_p,kern_q;
378 typename imageOutT::Scalar norm;
380 std::vector<typename imageOutT::Scalar> pixels;
383 for(
int i=0; i< im.rows(); ++i)
385 for(
int j=0; j<im.cols(); ++j)
387 if((i >= mini && i< maxi) && (j>= minj && j<maxj))
389 kernel.setKernel(i-xcen, j-ycen, kernelArray);
392 for(
int cc=0; cc<kernelArray.cols(); ++cc)
394 for(
int rr=0; rr<kernelArray.rows(); ++rr)
396 if(kernelArray(rr,cc) != 0) pixels.push_back(im.block(i-0.5*(kernelArray.rows()-1), j-0.5*(kernelArray.cols()-1), kernelArray.rows(), kernelArray.cols())(rr,cc));
409 kernel.setKernel(i-xcen, j-ycen, kernelArray);
411 im_i = i - 0.5*(kernelArray.rows()-1);
412 if(im_i < 0) im_i = 0;
414 im_j = j - 0.5*(kernelArray.cols()-1);
415 if(im_j < 0) im_j = 0;
417 im_p = im.rows() - im_i;
418 if(im_p > kernelArray.rows()) im_p = kernelArray.rows();
420 im_q = im.cols() - im_j;
421 if(im_q > kernelArray.cols()) im_q = kernelArray.cols();
423 kern_i = 0.5*(kernelArray.rows()-1) - i;
424 if(kern_i < 0) kern_i = 0;
426 kern_j = 0.5*(kernelArray.cols()-1) - j;
427 if(kern_j < 0) kern_j = 0;
429 kern_p = kernelArray.rows() - kern_i;
430 if(kern_p > kernelArray.rows()) kern_p = kernelArray.rows();
432 kern_q = kernelArray.cols() - kern_j;
433 if(kern_q > kernelArray.cols()) kern_q = kernelArray.cols();
436 if(im_p < kern_p) kern_p = im_p;
437 if(im_q < kern_q) kern_q = im_q;
439 norm = kernelArray.block(kern_i, kern_j, kern_p, kern_q ).sum();
442 for(
int cc=0; cc<kern_q; ++cc)
444 for(
int rr=0; rr<kern_p; ++rr)
446 if( kernelArray.block(kern_i, kern_j, kern_p, kern_q )(rr,cc) != 0)
448 pixels.push_back( im.block(im_i, im_j, kern_p, kern_q)(rr,cc));
484 template<
typename imageTout,
typename imageTin>
486 const imageTin & imIn,
488 bool rejectMinMax =
false
491 typedef typename imageTout::Scalar scalarT;
493 int buff = 0.5*meanFullWidth;
495 int nPix = meanFullWidth*meanFullWidth;
500 for(
int jj=buff; jj< imIn.cols()-buff; ++jj)
502 for(
int ii=buff; ii < imIn.rows()-buff; ++ii)
507 for(
int ll = jj-buff; ll < jj+buff+1; ++ll)
509 for(
int kk = ii-buff; kk < ii+buff+1; ++kk)
513 if(imIn(kk,ll) > max) max = imIn(kk,ll);
514 if(imIn(kk,ll) < min) min = imIn(kk,ll);
517 imOut(ii,jj) = (sum-max-min)/nPix;
523 for(
int jj=buff; jj< imIn.cols()-buff; ++jj)
525 for(
int ii=buff; ii < imIn.rows()-buff; ++ii)
528 for(
int ll = jj-buff; ll < jj+buff+1; ++ll)
530 for(
int kk = ii-buff; kk < ii+buff+1; ++kk)
535 imOut(ii,jj) = sum/nPix;
565 template<
typename imageTout,
typename imageTin>
569 typename imageTout::Scalar & pMax,
570 const imageTin & imIn,
572 bool rejectMinMax =
false
575 typedef typename imageTout::Scalar scalarT;
577 int buff = 0.5*meanFullWidth;
579 int nPix = meanFullWidth*meanFullWidth;
581 pMax = std::numeric_limits<scalarT>::lowest();
586 for(
int jj=buff; jj< imIn.cols()-buff; ++jj)
588 for(
int ii=buff; ii < imIn.rows()-buff; ++ii)
593 for(
int ll = jj-buff; ll < jj+buff+1; ++ll)
595 for(
int kk = ii-buff; kk < ii+buff+1; ++kk)
599 if(imIn(kk,ll) > max) max = imIn(kk,ll);
600 if(imIn(kk,ll) < min) min = imIn(kk,ll);
603 imOut(ii,jj) = (sum-max-min)/nPix;
604 if(imOut(ii,jj) > pMax)
615 for(
int jj=buff; jj< imIn.cols()-buff; ++jj)
617 for(
int ii=buff; ii < imIn.rows()-buff; ++ii)
620 for(
int ll = jj-buff; ll < jj+buff+1; ++ll)
622 for(
int kk = ii-buff; kk < ii+buff+1; ++kk)
627 imOut(ii,jj) = sum/nPix;
628 if(imOut(ii,jj) > pMax)
660 template<
typename imageTout,
typename imageTin>
664 typename imageTout::Scalar & pMax,
665 const imageTin & imIn,
669 typedef typename imageTout::Scalar scalarT;
671 int buff = 0.5*medianFullWidth;
673 std::vector<scalarT> pixs(medianFullWidth*medianFullWidth);
675 pMax = std::numeric_limits<scalarT>::lowest();
677 for(
int jj=buff; jj< imIn.cols()-buff; ++jj)
679 for(
int ii=buff; ii < imIn.rows()-buff; ++ii)
682 for(
int ll = jj-buff; ll < jj+buff+1; ++ll)
684 for(
int kk = ii-buff; kk < ii+buff+1; ++kk)
686 pixs[n] = imIn(kk,ll);
692 if(imOut(ii,jj) > pMax)
721 template<
typename imageTout,
typename imageTin>
723 const imageTin & imIn,
728 typename imageTout::Scalar pMax;
729 return medianSmooth(imOut, xMax, yMax, pMax, imIn, medianFullWidth);
732 template<
typename eigenImT>
737 typedef typename eigenImT::Scalar realT;
739 std::vector<realT> edge(2*ncols);
740 for(
int rr=0; rr<im.rows(); ++rr)
742 for(
int cc=0; cc< ncols; ++cc)
744 edge[cc] = im(rr,cc);
747 for(
int cc=0; cc< ncols; ++cc)
749 edge[ncols+cc] = im(rr,im.cols()-ncols + cc);
759 template<
typename eigenImT>
764 typedef typename eigenImT::Scalar realT;
766 std::vector<realT> edge(2*nrows);
767 for(
int cc=0; cc<im.cols(); ++cc)
769 for(
int rr=0; rr< nrows; ++rr)
771 edge[rr] = im(rr,cc);
774 for(
int rr=0; rr< nrows; ++rr)
776 edge[nrows+rr] = im(im.rows()-nrows + rr, cc);
788 template<
typename floatT>
795 template<
typename floatT>
798 bool operator()(radval<floatT> rv1, radval<floatT> rv2)
800 return (rv1.r < rv2.r);
804 template<
typename floatT>
807 bool operator()(radval<floatT> rv1, radval<floatT> rv2)
809 return (rv1.v < rv2.v);
825 template<
typename vecT,
typename eigenImT1,
typename eigenImT2,
typename eigenImT3>
828 const eigenImT1 & im,
829 const eigenImT2 & radim,
830 const eigenImT3 * mask,
832 typename eigenImT1::Scalar minr = 0
835 typedef typename eigenImT1::Scalar floatT;
837 int dim1 = im.rows();
838 int dim2 = im.cols();
854 std::vector<radval<floatT> > rv(nPix);
858 for(
int c=0;
c<im.cols();++
c)
860 for(
int r=0;r<im.rows();++r)
864 if( (*mask)(r,
c) == 0)
continue;
867 rv[i].r = radim(r,
c);
873 sort(rv.begin(), rv.end(), radvalRadComp<floatT>());
883 if(minr == 0) minr = rv[0].r;
889 floatT r1 = minr + dr;
896 while(rv[i1].r < r0) ++i1;
898 while(rv[i2].r <= r1) ++i2;
903 for(
int in=i1; in<i2; ++in) med += rv[in].v;
910 std::nth_element(rv.begin()+i1, rv.begin()+i1+n, rv.begin()+i2, radvalValComp<floatT>());
912 med = (rv.begin()+i1+n)->v;
917 med = 0.5*(med + (*std::max_element(rv.begin()+i1, rv.begin()+i1+n, radvalValComp<floatT>())).v);
921 rad.push_back(.5*(r0+r1));
945 template<
typename vecT,
typename eigenImT1,
typename eigenImT2>
948 const eigenImT1 & im,
949 const eigenImT2 & mask,
954 radim.resize(im.cols(), im.rows());
958 radprof(rad, prof, im, radim, &mask, mean);
972 template<
typename vecT,
typename eigenImT1>
975 const eigenImT1 & im,
981 radim.resize(im.cols(), im.rows());
999 template<
typename radprofT,
typename eigenImT1,
typename eigenImT2,
typename eigenImT3>
1002 const eigenImT2 & rad,
1003 const eigenImT3 * mask,
1010 std::vector<double> med_r, med_v;
1012 radprof(med_r, med_v, im, rad, mask);
1015 radprofIm.resize(im.rows(), im.cols() );
1019 for(
int c=0;
c<im.cols();++
c)
1021 for(
int r=0;r<im.rows();++r)
1025 if( (*mask)(r,
c) == 0)
1032 radprofIm(r,
c) = interp( ((
double) rad(r,
c)) );
1033 if(subtract) im(r,
c) -= radprofIm(r,
c);
1051 template<
typename radprofT,
typename eigenImT>
1054 bool subtract =
false,
1059 rad.resize(im.rows(), im.cols());
1078 template<
typename eigenImT,
typename eigenImT1,
typename eigenImT2,
typename eigenImT3>
1080 const eigenImT1 & im,
1081 const eigenImT2 & rad,
1082 const eigenImT3 & mask,
1083 typename eigenImT::Scalar minRad,
1084 typename eigenImT::Scalar maxRad,
1088 typedef typename eigenImT::Scalar floatT;
1090 int dim1 = im.cols();
1091 int dim2 = im.rows();
1093 floatT mr = rad.maxCoeff();
1096 std::vector<radval<floatT> > rv(dim1*dim2);
1098 for(
int i=0;i<rv.size();++i)
1100 if(mask(i) == 0)
continue;
1106 sort(rv.begin(), rv.end(), radvalRadComp<floatT>());
1116 std::vector<double> std_r, std_v;
1120 while(rv[i1].r < r0 && i1 < rv.size())
1130 while(rv[i2].r <= r1 && i2 < rv.size()) ++i2;
1133 std::vector<double> vals;
1135 for(
int i=i1; i< i2; ++i)
1137 vals.push_back( rv[i].v);
1140 std_r.push_back(.5*(r0+r1));
1148 std::cerr << std_r.size() <<
" " << std_v.size() <<
"\n";
1151 stdIm.resize(dim1, dim2);
1154 for(
int i=0;i<dim1;++i)
1156 for(
int j=0;j<dim2;++j)
1158 if(rad(i,j) < minRad || rad(i,j) > maxRad)
1164 stdIm(i,j) = interp( ((
double) rad(i,j)) );
1165 if(divide) stdIm(i,j) = im(i,j) / stdIm(i,j);
1183 template<
typename eigenImT,
typename eigenImT1,
typename eigenImT2>
1185 const eigenImT1 & im,
1186 const eigenImT2 & mask,
1187 typename eigenImT::Scalar minRad,
1188 typename eigenImT::Scalar maxRad,
1192 int dim1 = im.cols();
1193 int dim2 = im.rows();
1196 rad.resize(dim1, dim2);
1199 stddevImage(stdIm, im, rad, mask, minRad, maxRad, divide );
1211 template<
typename eigenCubeT,
typename eigenCubeT1,
typename eigenImT>
1213 const eigenCubeT1 & imc,
1214 const eigenImT & mask,
1215 typename eigenImT::Scalar minRad,
1216 typename eigenImT::Scalar maxRad,
1220 int dim1 = imc.cols();
1221 int dim2 = imc.rows();
1224 rad.resize(dim1, dim2);
1228 stdImc.resize(imc.rows(), imc.cols(), imc.planes());
1231 for(
int i=0; i< imc.planes(); ++i)
1237 stddevImage(stdIm, im, rad, mask, minRad, maxRad, divide );
1239 stdImc.image(i) = stdIm;
mxException for a size error
Class to manage interpolation using the GSL interpolation library.
constexpr units::realT c()
The speed of light.
constexpr units::realT h()
Planck Constant.
Eigen::Array< scalarT, -1, -1 > eigenImage
Definition of the eigenImage type, which is an alias for Eigen::Array.
realT dtor(realT q)
Convert from degrees to radians.
int medianSmooth(imageTout &imOut, const imageTin &imIn, int medianFullWidth)
Smooth an image using the median in a rectangular box.
int meanSmooth(imageTout &imOut, int &xMax, int &yMax, typename imageTout::Scalar &pMax, 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...
void filterImage(imageOutT &fim, imageInT im, kernelT kernel, int maxr=0)
Filter an image with a mean 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, bool mean=false, double dr=1)
Calculate the the radial profile.
void radprofim(radprofT &radprof, eigenImT &im, bool subtract=false, bool mean=false)
Form a radial profile image, and optionally subtract it from the input.
void stddevImage(eigenImT &stdIm, const eigenImT1 &im, const eigenImT2 &mask, typename eigenImT::Scalar minRad, typename eigenImT::Scalar maxRad, bool divide=false)
Form a standard deviation image, and optionally divide the input by it to form a S/N map.
void stddevImageCube(eigenCubeT &stdImc, const eigenCubeT1 &imc, const eigenImT &mask, typename eigenImT::Scalar minRad, typename eigenImT::Scalar maxRad, bool divide=false)
Form a standard deviation image for each imamge in a cube, and optionally divide the input by it form...
vectorT::value_type vectorMedianInPlace(vectorT &vec)
Calculate median of a vector in-place, altering the 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.
void colEdgeMedSubtract(eigenImT &im, int nrows)
void rowEdgeMedSubtract(eigenImT &im, int ncols)
Declares and defines functions to work with image masks.
Azimuthally variable boxcare kernel.
void setMaxWidth()
Sets the max width based on the configured az and rad widths.
arithT m_maxAz
the maximum half-width of the averging box in the azimuthal direction, in degrees....
azBoxKernel(arithT radWidth, arithT azWidth, arithT maxAz)
arithT m_radWidth
the half-width of the averaging box, in the radial direction, in pixels.
arithT m_azWidth
the half-width of the averaging box, in the azimuthal direction, in pixels.
azBoxKernel(arithT radWidth, arithT azWidth)
Symetric Gaussian smoothing kernel.