#ifndef IP_SYM_CONVOLVE #define IP_SYM_CONVOLVE 1 //////////////////////////////////////////////////////////////////////////// //! docentry="Image.Image Processing.Spatial_Filters" //! example=exIPConv.cc //! file="amma/Image/IPStream/IPLinear/IPConvSym.hh" //! lib=IPLinear //! rcsid="$Id: IPConvSym.hh,v 1.1 2000/10/18 10:13:02 ees1wc Exp $" //! author="Bill Christmas" //! date="01/12/99" #include "amma/DP/Process.hh" #include "amma/NumImage.hh" #include "amma/Image/IPSpatFilter.hh" #include "amma/SArray1d.hh" using namespace IPSpatFilterN; // -------------------------------------------------------------------------- // ********** IPConvSymBodyC ******************************************** // -------------------------------------------------------------------------- //! userlevel=Develop //: Body class for IPConvSymC. template class IPConvSymBodyC : public DPProcessBodyC,NumImageC >, private IPSpatFilterC { public: IPConvSymBodyC (const SArray1dC & Coeffs, DirnT Dirn, ResizeT Resize, PadT Pad); //: Constructor // (See handle class IPConvSymC) virtual NumImageC Apply (const NumImageC &im); //: Apply convolution to "im" // Uses mask specified in constructor. protected: const SArray1dC mask; // filter coefficients }; // -------------------------------------------------------------------------- // ********** IPConvSymC ******************************************** // -------------------------------------------------------------------------- //! userlevel=Normal //: Convolves an image with a 1-D odd-order symmetrical mask // //

Similar to IPConvolveC, but with these // differences: // //

    //
  • The centre of the mask is used to align the input and output images //
  • It is faster (hopefully) //
// //

Convolution can be vertical, horizontal or both. Because the mask is // symmetrical, you only have to specify the right-hand ½ of it: the // central coefficient of the mask is element 0 of the array. // //

The mask type is separately templated, so that you can use any // combination of pixel and mask types, provided multiplication between them is // supported. // //

See namespace IPSpatFilterN for enumerated // parameter values. template class IPConvSymC : public DPProcessC,NumImageC > { public: IPConvSymC(); //: Default constructor. // Creates an invalid handle. IPConvSymC (const SArray1dC & Coeffs, DirnT Direction, ResizeT Resize=Erode, PadT Pad = PBRescale); //: Constructor with all params // // See IPSpatFilterN for explanation of parameter values // //!param: Coeffs - array of filter coefficients //!param: Otherwise - see IPSpatFilterC }; ///////////////////////////////////////////////////////////////////////// // Implementation: template IPConvSymBodyC::IPConvSymBodyC (const SArray1dC & Coeffs, DirnT Dirn, ResizeT Resize, PadT Pad) : IPSpatFilterC(((Dirn==Horizontal) ? 1 : 2*Coeffs.Size()-1), ((Dirn==Vertical) ? 1 : 2*Coeffs.Size()-1), Dirn, Resize, Pad, ShiftUL), mask(Coeffs) {} template NumImageC IPConvSymBodyC::Apply (const NumImageC &im) { if (mask.Size() < 1) { errAMMA << "bad mask size: " << mask.Size(); errAMMA.Function("NumImageC IPConvSymBodyC::Apply (const NumImageC &im)").Exit(-1); } if ((pad_method != PadBlack) && (pad_method != PBRescale)) { errAMMA << "Pad method " << pad_method << " not yet implemented"; errAMMA.Function("NumImageC IPConvSymBodyC::Apply (const NumImageC &im)").Exit(-1); } NumImageC current; ImageRectangleC im_rect(im.Rectangle()); PixelT Zero; // create general-purpose zero value for mask coeff template StdMath::SetToZero(Zero); switch (resize) { case Erode: current = NumImageC(im); break; case Original: current = NumImageC(im_rect.Expand((rows-1)/2, (rows-1)/2, (cols-1)/2, (cols-1)/2)); current.Fill(Zero).Copy(im); break; case Expand: current = NumImageC(im_rect.Expand(rows-1, rows-1, cols-1, cols-1)); current.Fill(Zero).Copy(im); break; } if ((direction == Horizontal) || (direction == TwoD)) { NumImageC op(ImageRectangleC(current.TRow(), current.BRow(), current.LCol()+mask.Size()-1, current.RCol()-mask.Size()+1)); if (op.IsValid()) { FOREACH_PIXEL (op, p) { op[p] = current[p] * mask[0]; for (IndexC i=1; i= op.LCol(); --c) { norm-= mask[abs(c+1)]; // one more coeff falls outside o/p image if (c < (IntT) im.Cnum()/2) { FOREACH_ROW(op, r) op[r][im.LCol()+c] *= tot/norm; FOREACH_ROW(op, r) op[r][im.RCol()-c] *= tot/norm; } } } current = op; } } if ((direction == Vertical) || (direction == TwoD)) { NumImageC op(ImageRectangleC(current.TRow()+mask.Size()-1, current.BRow()-mask.Size()+1, current.LCol(), current.RCol())); if (op.IsValid()) { FOREACH_PIXEL (op, p) { op[p] = current[p] * mask[0]; for (IndexC i=1; i= op.TRow(); --r) { norm-= mask[abs(r+1)]; // one more coeff falls outside o/p image if (r < (IntT) im.Rnum()/2) { FOREACH_COL(op, c) op[im.TRow()+r][c] *= tot/norm; FOREACH_COL(op, c) op[im.BRow()-r][c] *= tot/norm; } } } current = op; } } return current; } template IPConvSymC::IPConvSymC() {} template IPConvSymC:: IPConvSymC (const SArray1dC & Coeffs, DirnT Direction, ResizeT Resize, PadT Pad) : DPProcessC,NumImageC > (*new IPConvSymBodyC(Coeffs, Direction, Resize, Pad)) {} #endif