| // Object part of VMask class |
| |
| /* |
| |
| Copyright (C) 1991-2001 The National Gallery |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU Lesser General Public License as published by |
| the Free Software Foundation; either version 2 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU Lesser General Public License for more details. |
| |
| You should have received a copy of the GNU Lesser General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| |
| */ |
| |
| /* |
| |
| These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk |
| |
| */ |
| |
| #ifdef HAVE_CONFIG_H |
| #include <config.h> |
| #endif /*HAVE_CONFIG_H*/ |
| #include <vips/intl.h> |
| |
| #include <cstdlib> |
| #include <cmath> |
| |
| #include <vips/vips.h> |
| |
| #include <vips/vipscpp.h> |
| |
| #ifdef WITH_DMALLOC |
| #include <dmalloc.h> |
| #endif /*WITH_DMALLOC*/ |
| |
| VIPS_NAMESPACE_START |
| |
| /* Functions for VMask - refcounting layer over VPMask. |
| */ |
| |
| VMask::~VMask() |
| { |
| ref->nrefs--; |
| if( !ref->nrefs ) |
| delete ref; |
| } |
| |
| VMask &VMask::operator=( const VMask &a ) |
| { |
| // Loosing ref to LHS |
| ref->nrefs--; |
| |
| if( ref->nrefs > 0 ) |
| // Need fresh refblock |
| ref = new refblock; |
| else |
| // Recycle old refblock |
| delete ref->pmask; |
| |
| // LHS now points to RHS |
| ref = a.ref; |
| ref->nrefs++; |
| |
| return( *this ); |
| } |
| |
| // Make sure this is a private copy of pmask --- dup if nrefs != 1 |
| void VMask::make_private() |
| { |
| if( ref->nrefs > 1 ) { |
| // Make fresh refblock |
| refblock *ref2 = new refblock; |
| |
| // And copy the mask |
| ref2->pmask = ref->pmask->dup(); |
| ref->nrefs--; |
| ref = ref2; |
| } |
| } |
| |
| void VMask::ostream_print( std::ostream &file ) const |
| { |
| file << *(ref->pmask); |
| } |
| |
| // Embed INTMASK in VIMask |
| void VIMask::embed( INTMASK *i ) throw( VError ) |
| { |
| if( ref->pmask ) |
| verror( "embed: VIMask not empty" ); |
| ref->pmask = new _private_detail::VPIMask( i ); |
| } |
| |
| // Type conversions: implicit INTMASK to DOUBLEMASK |
| VIMask::operator VDMask() |
| { |
| VDMask out( xsize(), ysize() ); |
| |
| out.mask().dptr->scale = scale(); |
| out.mask().dptr->offset = offset(); |
| |
| for( int i = 0; i < size(); i++ ) |
| out[i] = (*this)[i]; |
| |
| return( out ); |
| } |
| |
| |
| // Forward ref of VImage class |
| class VImage; |
| |
| // Type conversions: implicit DOUBLEMASK to INTMASK |
| VDMask::operator VIMask() |
| { |
| VIMask out( xsize(), ysize() ); |
| |
| out.mask().iptr->scale = int( scale() ); |
| out.mask().iptr->offset = int( offset() ); |
| |
| for( int i = 0; i < size(); i++ ) |
| out[i] = (int) rint( (*this)[i] ); |
| |
| return( out ); |
| } |
| |
| // Type conversions: implicit DOUBLEMASK to VImage |
| VDMask::operator VImage() throw( VError ) |
| { |
| VImage out; |
| |
| if( im_mask2vips( mask().dptr, out.image() ) ) |
| verror(); |
| |
| return( out ); |
| } |
| |
| // ... and INTMASK to VImage |
| VIMask::operator VImage() { return( VImage( VDMask( *this ) ) ); } |
| |
| // Embed DOUBLEMASK in VDMask |
| void VDMask::embed( DOUBLEMASK *i ) throw( VError ) |
| { |
| if( ref->pmask ) |
| verror( "embed: VDMask not empty" ); |
| ref->pmask = new _private_detail::VPDMask( i ); |
| } |
| |
| /* Functions for P*Mask - layer over im_*_*mask() functions. |
| */ |
| |
| // Create empty imask |
| _private_detail::VPIMask::VPIMask( int xsize, int ysize ) throw( VError ) |
| { |
| if( !(data.iptr = im_create_imask( "VPIMask::VPIMask", xsize, ysize )) ) |
| verror(); |
| type = _private_detail::VPMask::INT; |
| } |
| |
| // Init from vector |
| _private_detail::VPIMask::VPIMask( int xsize, int ysize, |
| int scale, int offset, std::vector<int> coeff ) |
| throw( VError ) |
| { |
| int i; |
| |
| if( !(data.iptr = im_create_imask( "VPIMask::VPIMask", xsize, ysize )) ) |
| verror(); |
| type = _private_detail::VPMask::INT; |
| |
| data.iptr->scale = scale; |
| data.iptr->offset = offset; |
| for( i = 0; i < xsize * ysize; i++ ) |
| data.iptr->coeff[i] = coeff[i]; |
| } |
| |
| // Create from filename |
| _private_detail::VPIMask::VPIMask( const char *name ) throw( VError ) |
| { |
| if( !(data.iptr = im_read_imask( (char *) name )) ) |
| verror(); |
| type = _private_detail::VPMask::INT; |
| } |
| |
| // Create from existing INTMASK |
| _private_detail::VPIMask::VPIMask( INTMASK *imask ) |
| { |
| data.iptr = imask; |
| type = _private_detail::VPMask::INT; |
| } |
| |
| // Create empty |
| _private_detail::VPIMask::VPIMask() |
| { |
| data.iptr = 0; |
| type = _private_detail::VPMask::UNASSIGNED; |
| } |
| |
| _private_detail::VPIMask::~VPIMask() |
| { |
| if( data.iptr ) { |
| im_free_imask( data.iptr ); |
| data.iptr = 0; |
| type = _private_detail::VPMask::UNASSIGNED; |
| } |
| } |
| |
| // Duplicate -- we are a VPIMask, return a new VPIMask which is a copy of us. |
| // Return as a VPMask tho'. |
| _private_detail::VPMask *_private_detail::VPIMask::dup() const throw( VError ) |
| { |
| _private_detail::VPIMask *out = new _private_detail::VPIMask(); |
| |
| INTMASK *msk; |
| if( !(msk = im_dup_imask( data.iptr, "VPIMask::dup" )) ) { |
| delete out; |
| verror(); |
| } |
| out->embed( msk ); |
| |
| return( out ); |
| } |
| |
| // Insert INTMASK pointer |
| void _private_detail::VPIMask::embed( INTMASK *msk ) throw( VError ) |
| { |
| if( type != _private_detail::VPMask::UNASSIGNED ) |
| verror( "VPIMask::embed: VPIMask not empty" ); |
| |
| data.iptr = msk; |
| type = _private_detail::VPMask::INT; |
| } |
| |
| int _private_detail::VPIMask::xsize() const throw( VError ) |
| { |
| if( !data.iptr ) |
| verror( "xsize: mask not set" ); |
| |
| return( data.iptr->xsize ); |
| } |
| |
| int _private_detail::VPIMask::ysize() const throw( VError ) |
| { |
| if( !data.iptr ) |
| verror( "ysize: mask not set" ); |
| |
| return( data.iptr->ysize ); |
| } |
| |
| int _private_detail::VPIMask::scale() const throw( VError ) |
| { |
| if( !data.iptr ) |
| verror( "scale: mask not set" ); |
| |
| return( data.iptr->scale ); |
| } |
| |
| int _private_detail::VPIMask::offset() const throw( VError ) |
| { |
| if( !data.iptr ) |
| verror( "offset: mask not set" ); |
| |
| return( data.iptr->offset ); |
| } |
| |
| const char *_private_detail::VPIMask::filename() const throw( VError ) |
| { |
| if( !data.iptr ) |
| verror( "filename: mask not set" ); |
| |
| return( data.iptr->filename ); |
| } |
| |
| void _private_detail::VPIMask::ostream_print( std::ostream &file ) const |
| throw( VError ) |
| { |
| if( !data.iptr ) |
| verror( "internal error #7447234" ); |
| |
| int i, j; |
| int *p = data.iptr->coeff; |
| |
| file << this->xsize() << "\t" << this->ysize() << "\t"; |
| file << this->scale() << "\t" << this->offset() << "\n"; |
| |
| for( i = 0; i < this->ysize(); i++ ) { |
| for( j = 0; j < this->xsize(); j++ ) |
| file << *p++ << "\t"; |
| |
| file << "\n"; |
| } |
| } |
| |
| // Extract start of int array |
| int *_private_detail::VPIMask::array() const |
| { |
| return( data.iptr->coeff ); |
| } |
| |
| // Create empty dmask |
| _private_detail::VPDMask::VPDMask( int xsize, int ysize ) throw( VError ) |
| { |
| if( !(data.dptr = im_create_dmask( "VPDMask::VPDMask", xsize, ysize )) ) |
| verror(); |
| type = _private_detail::VPMask::DOUBLE; |
| } |
| |
| // Create from vector |
| _private_detail::VPDMask::VPDMask( int xsize, int ysize, |
| double scale, double offset, std::vector<double> coeff ) throw( VError ) |
| { |
| int i; |
| |
| if( !(data.dptr = im_create_dmask( "VPDMask::VPDMask", xsize, ysize )) ) |
| verror(); |
| type = _private_detail::VPMask::DOUBLE; |
| |
| data.dptr->scale = scale; |
| data.dptr->offset = offset; |
| for( i = 0; i < xsize * ysize; i++ ) |
| data.dptr->coeff[i] = coeff[i]; |
| } |
| |
| // Create from filename |
| _private_detail::VPDMask::VPDMask( const char *name ) throw( VError ) |
| { |
| if( !(data.dptr = im_read_dmask( (char *) name )) ) |
| verror(); |
| type = _private_detail::VPMask::DOUBLE; |
| } |
| |
| // Create empty |
| _private_detail::VPDMask::VPDMask() |
| { |
| data.dptr = 0; |
| type = _private_detail::VPMask::UNASSIGNED; |
| } |
| |
| // Create from existing DOUBLEMASK |
| _private_detail::VPDMask::VPDMask( DOUBLEMASK *dmask ) |
| { |
| data.dptr = dmask; |
| type = _private_detail::VPMask::DOUBLE; |
| } |
| |
| _private_detail::VPDMask::~VPDMask() |
| { |
| if( data.dptr ) { |
| im_free_dmask( data.dptr ); |
| data.dptr = 0; |
| type = _private_detail::VPMask::UNASSIGNED; |
| } |
| } |
| |
| // Duplicate -- we are a VPIMask, return a new VPIMask which is a copy of us. |
| // Return as a VPMask tho'. |
| _private_detail::VPMask *_private_detail::VPDMask::dup() const throw( VError ) |
| { |
| _private_detail::VPDMask *out = new _private_detail::VPDMask(); |
| |
| DOUBLEMASK *msk; |
| if( !(msk = im_dup_dmask( data.dptr, "VPDMask::dup" )) ) { |
| delete out; |
| verror(); |
| } |
| out->embed( msk ); |
| |
| return( out ); |
| } |
| |
| // Insert DOUBLEMASK pointer |
| void _private_detail::VPDMask::embed( DOUBLEMASK *msk ) throw( VError ) |
| { |
| if( type != _private_detail::VPMask::UNASSIGNED ) |
| verror( "VPDMask::embed: VPDMask not empty" ); |
| |
| data.dptr = msk; |
| type = _private_detail::VPMask::DOUBLE; |
| } |
| |
| int _private_detail::VPDMask::xsize() const throw( VError ) |
| { |
| if( !data.dptr ) |
| verror( "xsize: mask not set" ); |
| |
| return( data.dptr->xsize ); |
| } |
| |
| int _private_detail::VPDMask::ysize() const throw( VError ) |
| { |
| if( !data.dptr ) |
| verror( "ysize: mask not set" ); |
| |
| return( data.dptr->ysize ); |
| } |
| |
| double _private_detail::VPDMask::scale() const throw( VError ) |
| { |
| if( !data.dptr ) |
| verror( "scale: mask not set" ); |
| |
| return( data.dptr->scale ); |
| } |
| |
| double _private_detail::VPDMask::offset() const throw( VError ) |
| { |
| if( !data.dptr ) |
| verror( "offset: mask not set" ); |
| |
| return( data.dptr->offset ); |
| } |
| |
| const char *_private_detail::VPDMask::filename() const throw( VError ) |
| { |
| if( !data.dptr ) |
| verror( "filename: mask not set" ); |
| |
| return( data.dptr->filename ); |
| } |
| |
| void _private_detail::VPDMask::ostream_print( std::ostream &file ) const |
| throw( VError ) |
| { |
| if( !data.dptr ) |
| verror( "internal error #7447234" ); |
| |
| int i, j; |
| double *p = data.dptr->coeff; |
| |
| file << this->xsize() << "\t" << this->ysize() << "\t"; |
| file << this->scale() << "\t" << this->offset() << "\n"; |
| |
| for( i = 0; i < this->ysize(); i++ ) { |
| for( j = 0; j < this->xsize(); j++ ) |
| file << *p++ << "\t"; |
| |
| file << "\n"; |
| } |
| } |
| |
| // Extract data pointer |
| double *_private_detail::VPDMask::array() const |
| { |
| return( data.dptr->coeff ); |
| } |
| |
| // Build functions |
| VIMask VIMask::gauss( double sig, double minamp ) throw( VError ) |
| { |
| VIMask out; |
| INTMASK *msk; |
| |
| if( !(msk = im_gauss_imask( "VIMask::gauss", sig, minamp )) ) |
| verror(); |
| out.embed( msk ); |
| |
| return( out ); |
| } |
| |
| VIMask VIMask::gauss_sep( double sig, double minamp ) throw( VError ) |
| { |
| VIMask out; |
| INTMASK *msk; |
| |
| if( !(msk = im_gauss_imask_sep( "VIMask::gauss", sig, minamp )) ) |
| verror(); |
| out.embed( msk ); |
| |
| return( out ); |
| } |
| |
| VDMask VDMask::gauss( double sig, double minamp ) throw( VError ) |
| { |
| VDMask out; |
| DOUBLEMASK *msk; |
| |
| if( !(msk = im_gauss_dmask( "VDMask::gauss", sig, minamp )) ) |
| verror(); |
| out.embed( msk ); |
| |
| return( out ); |
| } |
| |
| VIMask VIMask::log( double sig, double minamp ) throw( VError ) |
| { |
| VIMask out; |
| INTMASK *msk; |
| |
| if( !(msk = im_log_imask( "VIMask::log", sig, minamp )) ) |
| verror(); |
| out.embed( msk ); |
| |
| return( out ); |
| } |
| |
| VDMask VDMask::log( double sig, double minamp ) throw( VError ) |
| { |
| VDMask out; |
| DOUBLEMASK *msk; |
| |
| if( !(msk = im_log_dmask( "VDMask::log", sig, minamp )) ) |
| verror(); |
| out.embed( msk ); |
| |
| return( out ); |
| } |
| |
| // Manipulation functions |
| VIMask VIMask::rotate45() throw( VError ) |
| { |
| VIMask out; |
| INTMASK *msk; |
| |
| if( !(msk = im_rotate_imask45( mask().iptr, "VIMask::rotate45" )) ) |
| verror(); |
| out.embed( msk ); |
| |
| return( out ); |
| } |
| |
| VIMask VIMask::rotate90() throw( VError ) |
| { |
| VIMask out; |
| INTMASK *msk; |
| |
| if( !(msk = im_rotate_imask90( mask().iptr, "VIMask::rotate90" )) ) |
| verror(); |
| out.embed( msk ); |
| |
| return( out ); |
| } |
| |
| VDMask VDMask::rotate45() throw( VError ) |
| { |
| VDMask out; |
| DOUBLEMASK *msk; |
| |
| if( !(msk = im_rotate_dmask45( mask().dptr, "VDMask::rotate45" )) ) |
| verror(); |
| out.embed( msk ); |
| |
| return( out ); |
| } |
| |
| VDMask VDMask::rotate90() throw( VError ) |
| { |
| VDMask out; |
| DOUBLEMASK *msk; |
| |
| if( !(msk = im_rotate_dmask90( mask().dptr, "VDMask::rotate90" )) ) |
| verror(); |
| out.embed( msk ); |
| |
| return( out ); |
| } |
| |
| VDMask VDMask::trn() throw( VError ) |
| { |
| VDMask out; |
| DOUBLEMASK *msk; |
| |
| if( !(msk = im_mattrn( mask().dptr, "VDMask::trn" )) ) |
| verror(); |
| out.embed( msk ); |
| |
| return( out ); |
| } |
| |
| VDMask VDMask::inv() throw( VError ) |
| { |
| VDMask out; |
| DOUBLEMASK *msk; |
| |
| if( !(msk = im_matinv( mask().dptr, "VDMask::inv" )) ) |
| verror(); |
| out.embed( msk ); |
| |
| return( out ); |
| } |
| |
| VDMask VDMask::mul( VDMask m ) throw( VError ) |
| { |
| VDMask out; |
| DOUBLEMASK *msk; |
| |
| if( !(msk = im_matmul( mask().dptr, m.mask().dptr, "VDMask::mul" )) ) |
| verror(); |
| out.embed( msk ); |
| |
| return( out ); |
| } |
| |
| VDMask VDMask::cat( VDMask m ) throw( VError ) |
| { |
| VDMask out; |
| DOUBLEMASK *msk; |
| |
| if( !(msk = im_matcat( mask().dptr, m.mask().dptr, "VDMask::cat" )) ) |
| verror(); |
| out.embed( msk ); |
| |
| return( out ); |
| } |
| |
| VIMask VDMask::scalei() throw( VError ) |
| { |
| VIMask out; |
| INTMASK *msk; |
| |
| if( !(msk = im_scale_dmask( mask().dptr, "VDMask::scalei" )) ) |
| verror(); |
| out.embed( msk ); |
| |
| return( out ); |
| } |
| |
| // Arithmetic on a VIMask ... just cast and use VDMask |
| VDMask VIMask::trn() throw( VError ) |
| { return( ((VDMask)*this).trn() ); } |
| VDMask VIMask::inv() throw( VError ) |
| { return( ((VDMask)*this).inv() ); } |
| VDMask VIMask::cat( VDMask a ) throw( VError ) |
| { return( ((VDMask)*this).cat( a ) ); } |
| VDMask VIMask::mul( VDMask a ) throw( VError ) |
| { return( ((VDMask)*this).mul( a ) ); } |
| |
| // Overload [] to get linear array subscript. |
| // Our caller may write to the result, so make sure we have a private |
| // copy. |
| // Involves function call, slow anyway, so do range checking |
| int &VIMask::operator[]( int x ) throw( VError ) |
| { |
| if( ref->nrefs != 1 ) |
| make_private(); |
| |
| if( x > size() ) |
| verror( "VIMask::operator[]: subscript out of range" ); |
| |
| return( ((_private_detail::VPIMask *)ref->pmask)->array()[x] ); |
| } |
| |
| double &VDMask::operator[]( int x ) throw( VError ) |
| { |
| if( ref->nrefs != 1 ) |
| make_private(); |
| |
| if( x > size() ) |
| verror( "VDMask::operator[]: subscript out of range" ); |
| |
| return( ((_private_detail::VPDMask *)ref->pmask)->array()[x] ); |
| } |
| |
| VIPS_NAMESPACE_END |