/* Rotate an imask with a set of offsets. */ static INTMASK * rotimask( offset_fn fn, INTMASK *m, const char *name ) { INTMASK *out; int size = m->xsize * m->ysize; int *offsets; int i; if( m->xsize != m->ysize || (m->xsize % 2) == 0 ) { im_errormsg( "im_rotate_*mask*: mask should " "be square of even size" ); return( NULL ); } if( !(offsets = fn( m->xsize )) ) return( NULL ); if( !(out = im_create_imask( name, m->xsize, m->ysize )) ) { im_free( offsets ); return( NULL ); } out->scale = m->scale; out->offset = m->offset; for( i = 0; i < size; i++ ) out->coeff[i] = m->coeff[offsets[i]]; im_free( offsets ); return( out ); }
/** * im_scale_dmask: * @in: mask to scale * @filename: filename for returned mask * * Scale the dmask to make an imask with a maximum value of 20. * * See also: im_norm_dmask(). * * Returns: the converted mask, or NULL on error. */ INTMASK * im_scale_dmask( DOUBLEMASK *in, const char *filename ) { const int size = in->xsize * in->ysize; INTMASK *out; double maxval, dsum; int i; int isum; if( im_check_dmask( "im_scale_dmask", in ) || !(out = im_create_imask( filename, in->xsize, in->ysize )) ) return( NULL ); /* Find mask max. */ maxval = in->coeff[0]; for( i = 0; i < size; i++ ) if( in->coeff[i] > maxval ) maxval = in->coeff[i]; /* Copy and scale, setting max to 20. */ for( i = 0; i < size; i++ ) out->coeff[i] = IM_RINT( in->coeff[i] * 20.0 / maxval ); out->offset = in->offset; /* Set the scale to match the adjustment to max. */ isum = 0; dsum = 0.0; for( i = 0; i < size; i++ ) { isum += out->coeff[i]; dsum += in->coeff[i]; } if( dsum == in->scale ) out->scale = isum; else if( dsum == 0.0 ) out->scale = 1.0; else out->scale = IM_RINT( in->scale * isum / dsum ); return( out ); }
/** * im_dup_imask: * @in: mask to duplicate * @filename: filename to set for the new mask * * Duplicate an imask. * * See also: im_dup_dmask(). * * Returns: the mask copy, or NULL on error. */ INTMASK * im_dup_imask( INTMASK *in, const char *filename ) { INTMASK *out; int i; if( im_check_imask( "im_dup_imask", in ) || !(out = im_create_imask( filename, in->xsize, in->ysize )) ) return( NULL ); out->offset = in->offset; out->scale = in->scale; for( i = 0; i < in->xsize * in->ysize; i++ ) out->coeff[i] = in->coeff[i]; return( out ); }
/** * im_create_imaskv: * @filename: set mask filename to this * @xsize: mask width * @ysize: mask height * @...: values to set for the mask * * Create an imask and initialise it from the function parameter list. * * See also: im_create_imask(). * * Returns: The newly-allocated mask. */ INTMASK * im_create_imaskv( const char *filename, int xsize, int ysize, ... ) { va_list ap; INTMASK *out; int i; if( !(out = im_create_imask( filename, xsize, ysize )) ) return( NULL ); va_start( ap, ysize ); for( i = 0; i < xsize * ysize; i++ ) out->coeff[i] = va_arg( ap, int ); va_end( ap ); return( out ); }
/** * im_read_imask: * @filename: read matrix from this file * * Reads an integer matrix from a file. * * This function works exactly as im_read_dmask(), but the loaded matrix is * checked for 'int-ness'. All coefficients must be integers, and scale and * offset must be integers. * * See also: im_read_dmask(). * * Returns: the loaded mask on success, or NULL on error. */ INTMASK * im_read_imask( const char *filename ) { DOUBLEMASK *dmask; INTMASK *imask; int i; if( !(dmask = im_read_dmask( filename )) ) return( NULL ); if( ceil( dmask->scale ) != dmask->scale || ceil( dmask->offset ) != dmask->offset ) { im_error( "im_read_imask", "%s", _( "scale and offset should be int" ) ); im_free_dmask( dmask ); return( NULL ); } for( i = 0; i < dmask->xsize * dmask->ysize; i++ ) if( ceil( dmask->coeff[i] ) != dmask->coeff[i] ) { im_error( "im_read_imask", _( "ceofficient at " "position (%d, %d) is not int" ), i % dmask->xsize, i / dmask->xsize ); im_free_dmask( dmask ); return( NULL ); } if( !(imask = im_create_imask( filename, dmask->xsize, dmask->ysize )) ) { im_free_dmask( dmask ); return( NULL ); } imask->scale = dmask->scale; imask->offset = dmask->offset; for( i = 0; i < dmask->xsize * dmask->ysize; i++ ) imask->coeff[i] = dmask->coeff[i]; im_free_dmask( dmask ); return( imask ); }
/** * im_dmask2imask: * @in: mask to convert * @filename: filename for returned mask * * Make an imask from the dmask, rounding to nearest. * * See also: im_scale_dmask(). * * Returns: the converted mask, or NULL on error. */ INTMASK * im_dmask2imask( DOUBLEMASK *in, const char *filename ) { const int size = in->xsize * in->ysize; INTMASK *out; int i; if( im_check_dmask( "im_dmask2imask", in ) || !(out = im_create_imask( filename, in->xsize, in->ysize )) ) return( NULL ); for( i = 0; i < size; i++ ) out->coeff[i] = IM_RINT( in->coeff[i] ); out->offset = IM_RINT( in->offset ); out->scale = IM_RINT( in->scale ); return( out ); }
INTMASK * im_vips2imask( IMAGE *in, const char *filename ) { int width, height; INTMASK *out; double *data; int x, y; double double_result; int int_result; /* double* only: cast if necessary. */ if( in->BandFmt != IM_BANDFMT_DOUBLE ) { IMAGE *t; if( !(t = im_open( "im_vips2imask", "p" )) ) return( NULL ); if( im_clip2fmt( in, t, IM_BANDFMT_DOUBLE ) || !(out = im_vips2imask( t, filename )) ) { im_close( t ); return( NULL ); } im_close( t ); return( out ); } /* Check the image. */ if( im_incheck( in ) || im_check_uncoded( "im_vips2imask", in ) ) return( NULL ); if( in->Bands == 1 ) { width = in->Xsize; height = in->Ysize; } else if( in->Xsize == 1 ) { width = in->Bands; height = in->Ysize; } else if( in->Ysize == 1 ) { width = in->Xsize; height = in->Bands; } else { im_error( "im_vips2imask", "%s", _( "one band, nx1, or 1xn images only" ) ); return( NULL ); } data = (double *) in->data; if( !(out = im_create_imask( filename, width, height )) ) return( NULL ); /* We want to make an intmask which has the same input to output ratio * as the double image. * * Imagine convolving with the double image, what's the ratio of * brightness between input and output? We want the same ratio for the * int version, if we can. * * Imaging an input image where every pixel is 1, what will the output * be? */ double_result = 0; for( y = 0; y < height; y++ ) for( x = 0; x < width; x++ ) double_result += data[x + width * y]; double_result /= vips_image_get_scale( in ); for( y = 0; y < height; y++ ) for( x = 0; x < width; x++ ) if( in->Bands > 1 && in->Ysize == 1 ) /* Need to transpose: the image is RGBRGBRGB, * we need RRRGGGBBB. */ out->coeff[x + y * width] = VIPS_RINT( data[x * height + y] ); else out->coeff[x + y * width] = VIPS_RINT( data[x + y * width] ); out->scale = VIPS_RINT( vips_image_get_scale( in ) ); if( out->scale == 0 ) out->scale = 1; out->offset = VIPS_RINT( vips_image_get_offset( in ) ); /* Now convolve a 1 everywhere image with the int version we've made, * what do we get? */ int_result = 0; for( y = 0; y < height; y++ ) for( x = 0; x < width; x++ ) int_result += out->coeff[x + width * y]; int_result /= out->scale; /* And adjust the scale to get as close to a match as we can. */ out->scale = VIPS_RINT( out->scale + (int_result - double_result) ); if( out->scale == 0 ) out->scale = 1; return( out ); }