27#ifndef improc_imageMasks_hpp
28#define improc_imageMasks_hpp
30#include "../math/constants.hpp"
31#include "../math/geo.hpp"
47template <
class eigenT>
49 typename eigenT::Scalar xc,
50 typename eigenT::Scalar yc,
51 typename eigenT::Scalar scale = 1
54 typedef typename eigenT::Scalar arithT;
58 size_t dim1 = m.rows();
59 size_t dim2 = m.cols();
61 for(
size_t i = 0; i < dim1; i++ )
63 f_x = ( i - xc ) * ( i - xc );
65 for(
size_t j = 0; j < dim2; j++ )
67 f_y = ( j - yc ) * ( j - yc );
69 m( i, j ) = sqrt( f_x + f_y ) * scale;
81template <
class eigenT>
84 typename eigenT::Scalar scale = 1
87 typedef typename eigenT::Scalar arithT;
91 xc = 0.5 * ( m.rows() - 1 );
92 yc = 0.5 * ( m.cols() - 1 );
103template <
class angleT,
class eigenT>
106 typename angleT::realT xc,
107 typename angleT::realT yc )
109 typedef typename angleT::realT realT;
111 for(
size_t j = 0; j < m.cols(); j++ )
113 realT f_y = (
static_cast<realT
>( j ) - yc );
115 for(
size_t i = 0; i < m.rows(); i++ )
117 realT f_x = (
static_cast<realT
>( i ) - xc );
132template <
class angleT,
class eigenT>
135 typedef typename angleT::realT realT;
137 realT xc = 0.5 * ( m.rows() - 1 );
138 realT yc = 0.5 * ( m.cols() - 1 );
140 angleImage<angleT>( m, xc, yc );
151template <
class angleT,
class eigenT1,
class eigenT2>
156 typename angleT::realT xc,
157 typename angleT::realT yc,
158 typename angleT::realT rscale = 1
161 typedef typename angleT::realT realT;
163 qIm.resize( rIm.rows(), rIm.cols() );
165 for(
int cc = 0; cc < rIm.cols(); ++cc )
167 realT f_y = ( (
static_cast<realT
>( cc ) ) - yc );
169 for(
int rr = 0; rr < rIm.rows(); ++rr )
171 realT f_x = ( (
static_cast<realT
>( rr ) ) - xc );
173 rIm( rr, cc ) = std::sqrt( f_x * f_x + f_y * f_y ) * rscale;
179template <
typename vecT>
180struct maskCoordFormat;
183struct maskCoordFormat<std::vector<size_t>>
185 static size_t coord(
int i,
int j,
int rows )
192struct maskCoordFormat<std::vector<std::vector<int>>>
194 static std::vector<int> coord(
int i,
int j,
int rows )
196 return std::vector<int>( { i, j } );
213template <
typename vecT,
typename angleT,
typename eigenT1,
typename eigenT2,
typename eigenT3 = eigenT1>
218 typename angleT::realT xcen,
219 typename angleT::realT ycen,
220 typename angleT::realT min_r,
221 typename angleT::realT max_r,
222 typename angleT::realT min_q,
223 typename angleT::realT max_q,
227 typename angleT::realT pixbuf = 0
238 int x0 = xcen + min_x;
242 int x1 = xcen + max_x + 1;
243 if( x1 > rIm.rows() )
246 int y0 = ycen + min_y;
250 int y1 = ycen + max_y + 1;
251 if( y1 > rIm.cols() )
257 if( fabs( max_q - angleT::full ) > 100 * std::numeric_limits<typename angleT::realT>::epsilon() )
263 typename angleT::realT mid_q;
266 mid_q = 0.5 * ( min_q + max_q );
270 mid_q = 0.5 * ( ( min_q - angleT::full ) + max_q );
273 for(
int j = y0; j < y1; ++j )
275 for(
int i = x0; i < x1; ++i )
277 if( rIm( i, j ) < min_r - pixbuf )
281 if( rIm( i, j ) >= max_r + pixbuf )
295 if( ( *mask )( i, j ) == 0 )
301 idx.push_back( maskCoordFormat<vecT>::coord( i, j, rIm.rows() ) );
320template <
typename angleT,
typename eigenT1,
typename eigenT2,
typename eigenT3 = eigenT1>
325 typename angleT::realT xcen,
326 typename angleT::realT ycen,
327 typename angleT::realT min_r,
328 typename angleT::realT max_r,
329 typename angleT::realT min_q,
330 typename angleT::realT max_q,
334 typename angleT::realT pixbuf = 0
339 return annulusCoordsWorker<std::vector<std::vector<int>>, angleT, eigenT1, eigenT2, eigenT3>( rIm,
362template <
typename angleT,
typename eigenT1,
typename eigenT2,
typename eigenT3 = eigenT1>
367 typename angleT::realT xcen,
368 typename angleT::realT ycen,
369 typename angleT::realT min_r,
370 typename angleT::realT max_r,
371 typename angleT::realT min_q,
372 typename angleT::realT max_q,
376 typename angleT::realT pixbuf = 0
381 return annulusCoordsWorker<std::vector<size_t>, angleT, eigenT1, eigenT2, eigenT3>( rIm,
400template <
typename angleT>
405 typename angleT::realT xcen,
406 typename angleT::realT ycen,
407 typename angleT::realT min_r,
408 typename angleT::realT max_r,
409 typename angleT::realT min_q,
410 typename angleT::realT max_q,
411 typename angleT::realT pixbuf = 0
415 typedef typename angleT::realT realT;
418 realT x00 = xcen + ( min_r - pixbuf ) * cos( min_q * angleT::radians );
419 realT y00 = ycen + ( min_r - pixbuf ) * sin( min_q * angleT::radians );
420 realT x01 = xcen + ( max_r + pixbuf ) * cos( min_q * angleT::radians );
421 realT y01 = ycen + ( max_r + pixbuf ) * sin( min_q * angleT::radians );
423 realT x10 = xcen + ( min_r - pixbuf ) * cos( max_q * angleT::radians );
424 realT y10 = ycen + ( min_r - pixbuf ) * sin( max_q * angleT::radians );
425 realT x11 = xcen + ( max_r + pixbuf ) * cos( max_q * angleT::radians );
426 realT y11 = ycen + ( max_r + pixbuf ) * sin( max_q * angleT::radians );
436 x0 = std::ceil( std::min( { x00, x01, x10, x11, x20, x21 } ) );
437 y0 = std::ceil( std::min( { y00, y01, y10, y11, y20, y21 } ) );
438 x1 = std::ceil( std::max( { x00, x01, x10, x11, x20, x21 } ) );
439 y1 = std::ceil( std::max( { y00, y01, y10, y11, y20, y21 } ) );
446template <
typename realT>
454 std::vector<size_t> idxr;
455 idxr.reserve( idxi.size() );
458 for(
size_t n = 0; n < idxi.size(); ++n )
460 int y0 = idxi[n] / w;
461 int x0 = idxi[n] - y0 * w;
465 if( x1 < w && y1 < h )
466 idxr.push_back( y1 * w + x1 );
472template <
typename sizeT>
473void rectangleIndices( std::vector<sizeT> &idx, sizeT rows, sizeT cols, sizeT xmin, sizeT xmax, sizeT ymin, sizeT ymax )
477 if( xmax > rows - 1 )
481 if( ymax > cols - 1 )
484 idx.reserve( ( xmax - xmin + 1 ) * ( ymax - ymin + 1 ) );
486 for( sizeT i = xmin; i <= xmax; ++i )
488 for( sizeT j = ymin; j <= ymax; ++j )
490 idx.push_back( j * rows + i );
495template <
class eigenT>
496void rectangleIndices( std::vector<size_t> &idx, eigenT &mask,
size_t xmin,
size_t xmax,
size_t ymin,
size_t ymax )
498 rectangleIndices<size_t>( idx, (
size_t)mask.rows(), (
size_t)mask.cols(), xmin, xmax, ymin, ymax );
509template <
class eigenT>
511 const std::vector<size_t> &idx,
512 typename eigenT::Scalar maskval
515 for(
size_t i = 0; i < idx.size(); ++i )
517 maskedIm( idx[i] ) = maskval;
529template <
class eigenT>
531 const std::vector<std::vector<int>> &coord,
532 typename eigenT::Scalar maskval
535 for(
size_t i = 0; i < coord.size(); ++i )
537 maskedIm( coord[i][0], coord[i][1] ) = maskval;
549template <
class arrayT>
551 typename arrayT::Scalar xcen,
552 typename arrayT::Scalar ycen,
553 typename arrayT::Scalar rad,
554 typename arrayT::Scalar val,
555 typename arrayT::Scalar pixbuf = 0.5
559 size_t l0 = m.rows();
560 size_t l1 = m.cols();
562 typename arrayT::Scalar rr;
564 for(
size_t c = 0; c < m.cols(); c++ )
566 for(
size_t r = 0; r < m.rows(); r++ )
568 rr = sqrt( pow( r - xcen, 2 ) + pow( c - ycen, 2 ) );
570 if( rr <= rad + pixbuf )
584template <
class arrayT>
587 typename arrayT::Scalar rad,
588 typename arrayT::Scalar val,
589 typename arrayT::Scalar pixbuf = 0.5
592 return maskCircle( m, 0.5 * ( m.rows() - 1.0 ), 0.5 * ( m.cols() - 1.0 ), rad, val, pixbuf );
603template <
class arrayT>
605 typename arrayT::Scalar xcen,
606 typename arrayT::Scalar ycen,
607 typename arrayT::Scalar xrad,
608 typename arrayT::Scalar yrad,
609 typename arrayT::Scalar ang,
610 typename arrayT::Scalar val = 0,
611 typename arrayT::Scalar pixbuf = 0.5
615 typedef typename arrayT::Scalar realT;
617 size_t l0 = m.rows();
618 size_t l1 = m.cols();
626 realT cq = cos( ang );
627 realT sq = sin( ang );
631 for(
size_t i = 0; i < l0; i++ )
634 for(
size_t j = 0; j < l1; j++ )
638 if( x == 0 && y == 0 )
644 xr = x * cq - y * sq;
645 yr = x * sq + y * cq;
648 xe = ( pow( xrad * yrad, 2 ) / ( pow( yrad, 2 ) + pow( xrad * yr / xr, 2 ) ) );
649 ye = ( pow( yrad, 2 ) - xe * pow( yrad / xrad, 2 ) );
651 rad = sqrt( xe + ye );
653 r = sqrt( pow( xr, 2 ) + pow( yr, 2 ) );
655 if( r <= rad + pixbuf )
672template <
class arrayT>
674 typename arrayT::Scalar xcen,
675 typename arrayT::Scalar ycen,
676 typename arrayT::Scalar angCen,
677 typename arrayT::Scalar angHW,
678 typename arrayT::Scalar val = 0
681 size_t l0 = m.rows();
682 size_t l1 = m.cols();
684 typedef typename arrayT::Scalar angleT;
688 for(
size_t c = 0; c < m.cols(); c++ )
690 for(
size_t r = 0; r < m.rows(); r++ )
695 if( dang > -angHW && dang <= angHW )
711template <
typename realT>
720 if( fabs( x1 - x0 ) <= 1 && fabs( y1 - y0 ) <= 1 )
723 realT xa = 0.5 * ( x0 + x1 ) + 0.5;
724 realT ya = 0.5 * ( y0 + y1 ) + 0.5;
725 if( xa >= 0 && xa < mask.rows() && ya >= 0 && ya < mask.cols() )
726 mask( (
int)xa, (int)ya ) = val;
730 realT _x0, _x1, _y0, _y1;
732 realT length = sqrt( pow( x1 - x0, 2 ) + pow( y1 - y0, 2 ) );
735 if( fabs( x1 - x0 ) <= 1 )
752 realT m = ( _x1 - _x0 ) / ( _y1 - _y0 );
753 realT b = _x0 - m * _y0;
755 realT dy = ( _y1 - _y0 ) / ( 2 * length + 1 );
756 for( realT y = _y0; y <= _y1; y += dy )
760 if( x + 0.5 >= 0 && x + 0.5 < mask.rows() && y + 0.5 >= 0 && y + 0.5 < mask.cols() )
761 mask( (
int)( x + 0.5 ), (
int)( y + 0.5 ) ) = val;
783 realT m = ( _y1 - _y0 ) / ( _x1 - _x0 );
784 realT b = _y0 - m * _x0;
786 realT dx = ( _x1 - _x0 ) / ( 2 * length + 1 );
787 for( realT x = _x0; x <= _x1; x += dx )
791 if( x + 0.5 >= 0 && x + 0.5 < mask.rows() && y + 0.5 >= 0 && y + 0.5 < mask.cols() )
792 mask( (
int)( x + 0.5 ), (
int)( y + 0.5 ) ) = val;
805template <
typename realT>
821 return drawLine( mask, x0, y0, x1, y1, val );
823 realT _x0, _x1, _y0, _y1;
826 if( fabs( x1 - x0 ) <= 1 )
843 realT m = ( _x1 - _x0 ) / ( _y1 - _y0 );
844 realT b = _x0 - m * _y0;
846 realT dy = ( _y1 - _y0 ) / ( mask.cols() + 1 );
847 for( realT y = _y0; y <= _y1; y += dy )
851 realT xs, ys, xe, ye;
854 realT cq = cos( q1 );
855 realT sq = sin( q1 );
857 xs = x + 0.5 * width * cq;
858 ys = y + 0.5 * width * sq;
860 xe = x - 0.5 * width * cq;
861 ye = y - 0.5 * width * sq;
863 drawLine( mask, xs, ys, xe, ye, val );
885 realT m = ( _y1 - _y0 ) / ( _x1 - _x0 );
886 realT b = _y0 - m * _x0;
888 realT dx = ( _x1 - _x0 ) / ( mask.rows() + 1 );
889 for( realT x = _x0; x <= _x1; x += dx )
893 realT xs, ys, xe, ye;
896 realT cq = cos( q1 );
897 realT sq = sin( q1 );
899 xs = x + 0.5 * width * cq;
900 ys = y + 0.5 * width * sq;
902 xe = x - 0.5 * width * cq;
903 ye = y - 0.5 * width * sq;
905 drawLine( mask, xs, ys, xe, ye, val );
918template <
typename imT>
920 typename imT::Scalar x0,
921 typename imT::Scalar y0,
922 typename imT::Scalar rad,
923 typename imT::Scalar height,
924 typename imT::Scalar lwidth,
925 typename imT::Scalar rwidth
928 typename imT::Scalar x, y;
930 for(
int i = 0; i < im.rows(); ++i )
933 for(
int j = 0; j < im.cols(); ++j )
937 if( sqrt( pow( x - x0, 2 ) + pow( y - y0, 2 ) ) <= rad )
941 else if( fabs( y - y0 ) <= height && x >= x0 - lwidth && x <= x0 + rwidth )
963template <
typename imageTout,
typename imageTin>
965 const imageTin &imin,
966 const std::vector<size_t> &idx,
972 imout.resize( idx.size(), 1 );
976 for(
size_t i = 0; i < idx.size(); ++i )
978 imout( i ) = imin( idx[i] );
990template <
typename imageTout,
typename imageTin>
993 const imageTin &imin,
995 const std::vector<size_t> &idx
999 for(
size_t i = 0; i < idx.size(); ++i )
1001 imout( idx[i], 0 ) = imin( i, 0 );
1008template <
typename imageT,
typename transformT = cubicConvolTransform<
typename imageT::Scalar>>
1009void rotateMask( imageT &rotMask, imageT &mask,
typename imageT::Scalar angle )
1011 imageRotate( rotMask, mask, angle, transformT() );
1013 for(
int jj = 0; jj < rotMask.cols(); ++jj )
1015 for(
int ii = 0; ii < rotMask.rows(); ++ii )
1017 if( rotMask( ii, jj ) < 0.5 )
1018 rotMask( ii, jj ) = 0;
1020 rotMask( ii, jj ) = 1;
Tools for using the eigen library for image processing.
Eigen::Array< scalarT, -1, -1 > eigenImage
Definition of the eigenImage type, which is an alias for Eigen::Array.
constexpr floatT six_fifths()
Return 6/5 in the specified precision.
realT rtod(realT q)
Convert from radians to degrees.
vecT annulusCoordsWorker(const eigenT1 &rIm, const eigenT2 &qIm, typename angleT::realT xcen, typename angleT::realT ycen, typename angleT::realT min_r, typename angleT::realT max_r, typename angleT::realT min_q, typename angleT::realT max_q, eigenT3 *mask=0, typename angleT::realT pixbuf=0)
Get the coordinates of an annular region in an image.
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 maskCircle(arrayT &m, typename arrayT::Scalar xcen, typename arrayT::Scalar ycen, typename arrayT::Scalar rad, typename arrayT::Scalar val, typename arrayT::Scalar pixbuf=0.5)
Mask a circle in an image.
void cutImageRegion(imageTout &imout, const imageTin &imin, const std::vector< size_t > &idx, bool resize=true)
Cut out a region of an image specified by an index-mask.
void annulusBoundingRect(int &x0, int &y0, int &x1, int &y1, typename angleT::realT xcen, typename angleT::realT ycen, typename angleT::realT min_r, typename angleT::realT max_r, typename angleT::realT min_q, typename angleT::realT max_q, typename angleT::realT pixbuf=0)
Get the coordinates of the bounding rectangle of an annulus.
void maskEllipse(arrayT &m, typename arrayT::Scalar xcen, typename arrayT::Scalar ycen, typename arrayT::Scalar xrad, typename arrayT::Scalar yrad, typename arrayT::Scalar ang, typename arrayT::Scalar val=0, typename arrayT::Scalar pixbuf=0.5)
Mask an ellipse in an image.
int drawLine(eigenImage< realT > &mask, realT x0, realT y0, realT x1, realT y1, realT val)
Draw a thin (1-pixel) line from one point to another.
void applyMask(eigenT &maskedIm, const std::vector< size_t > &idx, typename eigenT::Scalar maskval)
Apply a mask to an image.
int ccdBleedMask(imT &im, typename imT::Scalar x0, typename imT::Scalar y0, typename imT::Scalar rad, typename imT::Scalar height, typename imT::Scalar lwidth, typename imT::Scalar rwidth)
Populate a mask based on a typical CCD bleeding pattern.
void insertImageRegion(imageTout imout, const imageTin &imin, const std::vector< size_t > &idx)
Insert a region of an image specified by an index-mask.
void angleImage(eigenT &m, typename angleT::realT xc, typename angleT::realT yc)
Fills in the cells of an Eigen-like 2D Array with their angle relative to the center.
void maskWedge(arrayT &m, typename arrayT::Scalar xcen, typename arrayT::Scalar ycen, typename arrayT::Scalar angCen, typename arrayT::Scalar angHW, typename arrayT::Scalar val=0)
Mask a wedge in an image.
std::vector< std::vector< int > > annulusCoords(const eigenT1 &rIm, const eigenT2 &qIm, typename angleT::realT xcen, typename angleT::realT ycen, typename angleT::realT min_r, typename angleT::realT max_r, typename angleT::realT min_q, typename angleT::realT max_q, eigenT3 *mask=0, typename angleT::realT pixbuf=0)
Get the array coordinates of an annular region in an image.
void radAngImage(eigenT1 &rIm, eigenT2 &qIm, typename angleT::realT xc, typename angleT::realT yc, typename angleT::realT rscale=1)
Fills in the cells of Eigen-like arrays with their radius amd angle relative to the center.
std::vector< size_t > annulusIndices(const eigenT1 &rIm, const eigenT2 &qIm, typename angleT::realT xcen, typename angleT::realT ycen, typename angleT::realT min_r, typename angleT::realT max_r, typename angleT::realT min_q, typename angleT::realT max_q, eigenT3 *mask=0, typename angleT::realT pixbuf=0)
Get the vector indices of an annular region in an image.
int reflectImageCoords(int &x1, int &y1, int x0, int y0, realT xc, realT yc)
Reflect pixel coordinates across the given center pixel.
std::vector< size_t > reflectImageIndices(const std::vector< size_t > &idxi, int w, int h, realT xc, realT yc)
Reflect vector indices across the given center pixel.
void rotateMask(imageT &rotMask, imageT &mask, typename imageT::Scalar angle)
Rotate a binary mask.