27#ifndef improc_imageMasks_hpp
28#define improc_imageMasks_hpp
30#include "../math/constants.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 );
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
234 const typename angleT::realT maxBufferedRadius = max_r + pixbuf;
235 if( maxBufferedRadius <= 0 )
240 int x0 =
static_cast<int>( std::floor( xcen - maxBufferedRadius ) );
244 int x1 =
static_cast<int>( std::ceil( xcen + maxBufferedRadius ) );
245 if( x1 > rIm.rows() )
248 int y0 =
static_cast<int>( std::floor( ycen - maxBufferedRadius ) );
252 int y1 =
static_cast<int>( std::ceil( ycen + maxBufferedRadius ) );
253 if( y1 > rIm.cols() )
259 if( fabs( max_q - angleT::full ) > 100 * std::numeric_limits<typename angleT::realT>::epsilon() )
265 typename angleT::realT mid_q;
268 mid_q = 0.5 * ( min_q + max_q );
272 mid_q = 0.5 * ( ( min_q - angleT::full ) + max_q );
275 for(
int j = y0; j < y1; ++j )
277 for(
int i = x0; i < x1; ++i )
279 if( rIm( i, j ) < min_r - pixbuf )
283 if( rIm( i, j ) >= max_r + pixbuf )
297 if( ( *mask )( i, j ) == 0 )
303 idx.push_back( maskCoordFormat<vecT>::coord( i, j, rIm.rows() ) );
322template <
typename angleT,
typename eigenT1,
typename eigenT2,
typename eigenT3 = eigenT1>
327 typename angleT::realT xcen,
328 typename angleT::realT ycen,
329 typename angleT::realT min_r,
330 typename angleT::realT max_r,
331 typename angleT::realT min_q,
332 typename angleT::realT max_q,
336 typename angleT::realT pixbuf = 0
367template <
typename angleT,
typename eigenT1,
typename eigenT2,
typename eigenT3 = eigenT1>
372 typename angleT::realT xcen,
373 typename angleT::realT ycen,
374 typename angleT::realT min_r,
375 typename angleT::realT max_r,
376 typename angleT::realT min_q,
377 typename angleT::realT max_q,
381 typename angleT::realT pixbuf = 0
408template <
typename angleT>
413 typename angleT::realT xcen,
414 typename angleT::realT ycen,
415 typename angleT::realT min_r,
416 typename angleT::realT max_r,
417 typename angleT::realT min_q,
418 typename angleT::realT max_q,
419 typename angleT::realT pixbuf = 0
423 typedef typename angleT::realT realT;
426 realT x00 = xcen + ( min_r - pixbuf ) * cos( min_q * angleT::radians );
427 realT y00 = ycen + ( min_r - pixbuf ) * sin( min_q * angleT::radians );
428 realT x01 = xcen + ( max_r + pixbuf ) * cos( min_q * angleT::radians );
429 realT y01 = ycen + ( max_r + pixbuf ) * sin( min_q * angleT::radians );
431 realT x10 = xcen + ( min_r - pixbuf ) * cos( max_q * angleT::radians );
432 realT y10 = ycen + ( min_r - pixbuf ) * sin( max_q * angleT::radians );
433 realT x11 = xcen + ( max_r + pixbuf ) * cos( max_q * angleT::radians );
434 realT y11 = ycen + ( max_r + pixbuf ) * sin( max_q * angleT::radians );
444 x0 = std::ceil( std::min( { x00, x01, x10, x11, x20, x21 } ) );
445 y0 = std::ceil( std::min( { y00, y01, y10, y11, y20, y21 } ) );
446 x1 = std::ceil( std::max( { x00, x01, x10, x11, x20, x21 } ) );
447 y1 = std::ceil( std::max( { y00, y01, y10, y11, y20, y21 } ) );
454template <
typename realT>
462 std::vector<size_t> idxr;
463 idxr.reserve( idxi.size() );
466 for(
size_t n = 0; n < idxi.size(); ++n )
468 int y0 = idxi[n] / w;
469 int x0 = idxi[n] - y0 * w;
473 if( x1 < w && y1 < h )
474 idxr.push_back( y1 * w + x1 );
480template <
typename sizeT>
481void rectangleIndices( std::vector<sizeT> &idx, sizeT rows, sizeT cols, sizeT xmin, sizeT xmax, sizeT ymin, sizeT ymax )
485 if( xmax > rows - 1 )
489 if( ymax > cols - 1 )
492 idx.reserve( ( xmax - xmin + 1 ) * ( ymax - ymin + 1 ) );
494 for( sizeT i = xmin; i <= xmax; ++i )
496 for( sizeT j = ymin; j <= ymax; ++j )
498 idx.push_back( j * rows + i );
503template <
class eigenT>
504void rectangleIndices( std::vector<size_t> &idx, eigenT &mask,
size_t xmin,
size_t xmax,
size_t ymin,
size_t ymax )
506 rectangleIndices<size_t>( idx, (
size_t)mask.rows(), (
size_t)mask.cols(), xmin, xmax, ymin, ymax );
517template <
class eigenT>
519 const std::vector<size_t> &idx,
520 typename eigenT::Scalar maskval
523 for(
size_t i = 0; i < idx.size(); ++i )
525 maskedIm( idx[i] ) = maskval;
537template <
class eigenT>
539 const std::vector<std::vector<int>> &coord,
540 typename eigenT::Scalar maskval
543 for(
size_t i = 0; i < coord.size(); ++i )
545 maskedIm( coord[i][0], coord[i][1] ) = maskval;
557template <
class arrayT>
559 typename arrayT::Scalar xcen,
560 typename arrayT::Scalar ycen,
561 typename arrayT::Scalar rad,
562 typename arrayT::Scalar val,
563 typename arrayT::Scalar pixbuf = 0.5
567 size_t l0 = m.rows();
568 size_t l1 = m.cols();
570 typename arrayT::Scalar rr;
572 for(
size_t c = 0; c < m.cols(); c++ )
574 for(
size_t r = 0; r < m.rows(); r++ )
576 rr = sqrt( pow( r - xcen, 2 ) + pow( c - ycen, 2 ) );
578 if( rr <= rad + pixbuf )
592template <
class arrayT>
595 typename arrayT::Scalar rad,
596 typename arrayT::Scalar val,
597 typename arrayT::Scalar pixbuf = 0.5
600 return maskCircle( m, 0.5 * ( m.rows() - 1.0 ), 0.5 * ( m.cols() - 1.0 ), rad, val, pixbuf );
611template <
class arrayT>
613 typename arrayT::Scalar xcen,
614 typename arrayT::Scalar ycen,
615 typename arrayT::Scalar xrad,
616 typename arrayT::Scalar yrad,
617 typename arrayT::Scalar ang,
618 typename arrayT::Scalar val = 0,
619 typename arrayT::Scalar pixbuf = 0.5
623 typedef typename arrayT::Scalar realT;
625 size_t l0 = m.rows();
626 size_t l1 = m.cols();
634 realT cq = cos( ang );
635 realT sq = sin( ang );
639 for(
size_t i = 0; i < l0; i++ )
642 for(
size_t j = 0; j < l1; j++ )
646 if( x == 0 && y == 0 )
652 xr = x * cq - y * sq;
653 yr = x * sq + y * cq;
656 xe = ( pow( xrad * yrad, 2 ) / ( pow( yrad, 2 ) + pow( xrad * yr / xr, 2 ) ) );
657 ye = ( pow( yrad, 2 ) - xe * pow( yrad / xrad, 2 ) );
659 rad = sqrt( xe + ye );
661 r = sqrt( pow( xr, 2 ) + pow( yr, 2 ) );
663 if( r <= rad + pixbuf )
680template <
class arrayT>
682 typename arrayT::Scalar xcen,
683 typename arrayT::Scalar ycen,
684 typename arrayT::Scalar angCen,
685 typename arrayT::Scalar angHW,
686 typename arrayT::Scalar val = 0
689 size_t l0 = m.rows();
690 size_t l1 = m.cols();
692 typedef typename arrayT::Scalar angleT;
696 for(
size_t c = 0; c < m.cols(); c++ )
698 for(
size_t r = 0; r < m.rows(); r++ )
703 if( dang > -angHW && dang <= angHW )
719template <
typename realT>
728 if( fabs( x1 - x0 ) <= 1 && fabs( y1 - y0 ) <= 1 )
731 realT xa = 0.5 * ( x0 + x1 ) + 0.5;
732 realT ya = 0.5 * ( y0 + y1 ) + 0.5;
733 if( xa >= 0 && xa < mask.rows() && ya >= 0 && ya < mask.cols() )
734 mask( (
int)xa, (
int)ya ) = val;
738 realT _x0, _x1, _y0, _y1;
740 realT length = sqrt( pow( x1 - x0, 2 ) + pow( y1 - y0, 2 ) );
743 if( fabs( x1 - x0 ) <= 1 )
760 realT m = ( _x1 - _x0 ) / ( _y1 - _y0 );
761 realT b = _x0 - m * _y0;
763 realT dy = ( _y1 - _y0 ) / ( 2 * length + 1 );
764 for( realT y = _y0; y <= _y1; y += dy )
768 if( x + 0.5 >= 0 && x + 0.5 < mask.rows() && y + 0.5 >= 0 && y + 0.5 < mask.cols() )
769 mask( (
int)( x + 0.5 ), (
int)( y + 0.5 ) ) = val;
791 realT m = ( _y1 - _y0 ) / ( _x1 - _x0 );
792 realT b = _y0 - m * _x0;
794 realT dx = ( _x1 - _x0 ) / ( 2 * length + 1 );
795 for( realT x = _x0; x <= _x1; x += dx )
799 if( x + 0.5 >= 0 && x + 0.5 < mask.rows() && y + 0.5 >= 0 && y + 0.5 < mask.cols() )
800 mask( (
int)( x + 0.5 ), (
int)( y + 0.5 ) ) = val;
813template <
typename realT>
829 return drawLine( mask, x0, y0, x1, y1, val );
831 realT _x0, _x1, _y0, _y1;
834 if( fabs( x1 - x0 ) <= 1 )
851 realT m = ( _x1 - _x0 ) / ( _y1 - _y0 );
852 realT b = _x0 - m * _y0;
854 realT dy = ( _y1 - _y0 ) / ( mask.cols() + 1 );
855 for( realT y = _y0; y <= _y1; y += dy )
859 realT xs, ys, xe, ye;
862 realT cq = cos( q1 );
863 realT sq = sin( q1 );
865 xs = x + 0.5 * width * cq;
866 ys = y + 0.5 * width * sq;
868 xe = x - 0.5 * width * cq;
869 ye = y - 0.5 * width * sq;
871 drawLine( mask, xs, ys, xe, ye, val );
893 realT m = ( _y1 - _y0 ) / ( _x1 - _x0 );
894 realT b = _y0 - m * _x0;
896 realT dx = ( _x1 - _x0 ) / ( mask.rows() + 1 );
897 for( realT x = _x0; x <= _x1; x += dx )
901 realT xs, ys, xe, ye;
904 realT cq = cos( q1 );
905 realT sq = sin( q1 );
907 xs = x + 0.5 * width * cq;
908 ys = y + 0.5 * width * sq;
910 xe = x - 0.5 * width * cq;
911 ye = y - 0.5 * width * sq;
913 drawLine( mask, xs, ys, xe, ye, val );
926template <
typename imT>
928 typename imT::Scalar x0,
929 typename imT::Scalar y0,
930 typename imT::Scalar rad,
931 typename imT::Scalar height,
932 typename imT::Scalar lwidth,
933 typename imT::Scalar rwidth
936 typename imT::Scalar x, y;
938 for(
int i = 0; i < im.rows(); ++i )
941 for(
int j = 0; j < im.cols(); ++j )
945 if( sqrt( pow( x - x0, 2 ) + pow( y - y0, 2 ) ) <= rad )
949 else if( fabs( y - y0 ) <= height && x >= x0 - lwidth && x <= x0 + rwidth )
971template <
typename imageTout,
typename imageTin>
973 const imageTin &imin,
974 const std::vector<size_t> &idx,
980 imout.resize( idx.size(), 1 );
984 for(
size_t i = 0; i < idx.size(); ++i )
986 imout( i ) = imin( idx[i] );
998template <
typename imageTout,
typename imageTin>
1001 const imageTin &imin,
1003 const std::vector<size_t> &idx
1007 for(
size_t i = 0; i < idx.size(); ++i )
1009 imout( idx[i], 0 ) = imin( i, 0 );
1016template <
typename imageT,
typename transformT = cubicConvolTransform<
typename imageT::Scalar>>
1017void rotateMask( imageT &rotMask, imageT &mask,
typename imageT::Scalar angle )
1019 imageRotate( rotMask, mask, angle, transformT() );
1021 for(
int jj = 0; jj < rotMask.cols(); ++jj )
1023 for(
int ii = 0; ii < rotMask.rows(); ++ii )
1025 if( rotMask( ii, jj ) < 0.5 )
1026 rotMask( ii, jj ) = 0;
1028 rotMask( ii, jj ) = 1;
Tools for using the eigen library for image processing.
Utilities for working with angles.
Eigen::Array< scalarT, -1, -1 > eigenImage
Definition of the eigenImage type, which is an alias for Eigen::Array.
constexpr T pi()
Get the value of pi.
constexpr T two_pi()
Get the value of 2pi.
angleT::realT angleDiff(typename angleT::realT q1, typename angleT::realT q2)
Calculate the difference between two angles, correctly across 0/360.
angleT::realT angleMod(typename angleT::realT q)
Calculate the angle modulo full-circle, normalizing to a positive value.
realT rtod(realT q)
Convert from radians to degrees.
angleT::realT angleMean(const std::vector< typename angleT::realT > &q)
Calculate the mean of a set of angles, correctly across 0/360.
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.