b085908558
You must now include vips7 support explicitly with #include <vips/vips7compat.h> in your code just after including `vips.h`. The old vips7 names, such as `Rect`, were starting to cause problems with other packages like opencv.
1089 lines
23 KiB
C
1089 lines
23 KiB
C
/* read and write masks
|
|
*/
|
|
|
|
/* Copyright: 1990, N. Dessipris.
|
|
*
|
|
* Author: Nicos Dessipris
|
|
* Written on: 29/04/1991
|
|
* Modified on: 10/8/1992, J.Cupitt
|
|
* - Mask reading routines no longer fail if scale and offset are missing.
|
|
* Instead, they set default values of scale=1, offset=0.
|
|
* - Code tidied up, better error recovery.
|
|
* - Bugs fixed in im_dup_*mask. No longer coredump.
|
|
* - Bugs fixed in im_write_*mask. Now work for non-square matricies.
|
|
* - im_copy_*mask_matrix, im_copy_matrix_*mask added: copy VIPS mask
|
|
* structures into Numerical Recipies in C style matricies and vice
|
|
* versa. Both structures should have been built before copy attempted.
|
|
* See im_create_*mask, im_*mat_alloc. The matrix should be indexed by 0
|
|
* to size-1.
|
|
* 9/7/93 JC
|
|
* - some ANSIfication and tidies
|
|
* - im_free_*mask() now return zero, so they can be used as close
|
|
* callbacks.
|
|
* 7/10/94 JC
|
|
* - new IM_NEW(), IM_ARRAY() macros added
|
|
* 27/4/95 JC
|
|
* - oops! forgot to init IM_ARRAY() memory to zero
|
|
* 7/8/96 JC
|
|
* - im_scale_dmask() rewritten
|
|
* 7/5/98 JC
|
|
* - im_read_*mask() rewritten, now more robust
|
|
* - im_write_*mask() rewritten
|
|
* - new functions im_write_*mask_name()
|
|
* 28/7/99 JC
|
|
* - im_create_imaskv(), im_create_dmaskv() make masks and init from
|
|
* varargs
|
|
* - tabs allowed as column separators
|
|
* 9/2/05
|
|
* - "," allowed as column separator ... helps CSV read
|
|
* 31/5/06
|
|
* - use g_ascii_strtod() and friends
|
|
* 2006-09-08 tcv
|
|
* - add im_norm_dmask()
|
|
* 1/9/09
|
|
* - move im_print_*mask() here
|
|
* 12/11/09
|
|
* - reading a float mask with im_read_imask() produced an incorrect
|
|
* error messagge
|
|
* 21/10/10
|
|
* - gtk-doc
|
|
* - you can use commas to separate header fields
|
|
* - small cleanups
|
|
* 30/11/10
|
|
* - im_scale_dmask() normalises to 20, not 100 ... we hit the fast
|
|
* conv path more often
|
|
* 24/1/10
|
|
* - oops, missing braces in write dmask removed spaces between items
|
|
*/
|
|
|
|
/*
|
|
|
|
This file is part of VIPS.
|
|
|
|
VIPS 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
02110-1301 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 <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
|
|
#include <vips/vips.h>
|
|
#include <vips/vips7compat.h>
|
|
|
|
/**
|
|
* INTMASK:
|
|
* @xsize: mask width
|
|
* @ysize: mask height
|
|
* @scale: mask scale factor
|
|
* @offset: mask offset
|
|
* @coeff: array of mask elements
|
|
* @filename: the file this mask was read from, or should be written to
|
|
*
|
|
* An integer mask.
|
|
*
|
|
* @scale lets the mask represent fractional values: for
|
|
* example, in integer convolution (see im_conv()) the result of the
|
|
* convolution is divided by @scale and then added to @offset before being
|
|
* written to the output image.
|
|
*
|
|
* @scale and @offset default to 1 and 0. Various functions, such as
|
|
* im_conv(), will fail if @scale is zero.
|
|
*
|
|
* You can read and write the matrix elements in @coeff.
|
|
*/
|
|
|
|
/**
|
|
* DOUBLEMASK:
|
|
* @xsize: mask width
|
|
* @ysize: mask height
|
|
* @scale: mask scale factor
|
|
* @offset: mask offset
|
|
* @coeff: array of mask elements
|
|
* @filename: the file this mask was read from, or should be written to
|
|
*
|
|
* A floating-point mask.
|
|
*
|
|
* As with #INTMASK, in convolution (see im_convf()) the result of the
|
|
* convolution is divided by @scale and then added to @offset before being
|
|
* written to the output image.
|
|
*
|
|
* @scale and @offset default to 1.0 and 0.0. Various functions, such as
|
|
* im_conv(), will fail if @scale is zero.
|
|
*
|
|
* You can read and write the matrix elements in @coeff.
|
|
*/
|
|
|
|
/* Size of line buffer for reading.
|
|
*/
|
|
#define MAX_LINE (32768)
|
|
|
|
/**
|
|
* im_free_imask:
|
|
* @in: mask to free
|
|
*
|
|
* Free mask structure and any attached arrays. Return zero, so we can use
|
|
* these functions as close callbacks.
|
|
*
|
|
* See also: im_free_dmask().
|
|
*
|
|
* Returns: zero.
|
|
*/
|
|
int
|
|
im_free_imask( INTMASK *in )
|
|
{
|
|
if( !in )
|
|
return( 0 );
|
|
|
|
IM_FREE( in->coeff );
|
|
IM_FREE( in->filename );
|
|
IM_FREE( in );
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
/**
|
|
* im_free_dmask:
|
|
* @in: mask to free
|
|
*
|
|
* Free mask structure and any attached arrays. Return zero, so we can use
|
|
* these functions as close callbacks.
|
|
*
|
|
* See also: im_free_dmask().
|
|
*
|
|
* Returns: zero.
|
|
*/
|
|
int
|
|
im_free_dmask( DOUBLEMASK *in )
|
|
{
|
|
if( !in )
|
|
return( 0 );
|
|
|
|
IM_FREE( in->coeff );
|
|
IM_FREE( in->filename );
|
|
IM_FREE( in );
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
/**
|
|
* im_create_imask:
|
|
* @filename: set mask filename to this
|
|
* @xsize: mask width
|
|
* @ysize: mask height
|
|
*
|
|
* Create an empty imask. You need to loop over @coeff to set the values.
|
|
*
|
|
* See also: im_create_imaskv().
|
|
*
|
|
* Returns: The newly-allocated mask.
|
|
*/
|
|
INTMASK *
|
|
im_create_imask( const char *filename, int xsize, int ysize )
|
|
{
|
|
INTMASK *out;
|
|
int size = xsize * ysize;
|
|
|
|
/* Check args.
|
|
*/
|
|
if( xsize <= 0 || ysize <= 0 || filename == NULL ) {
|
|
im_error( "im_create_imask", "%s", _( "bad arguments" ) );
|
|
return( NULL );
|
|
}
|
|
|
|
/* Allocate and initialise structure.
|
|
*/
|
|
if( !(out = IM_NEW( NULL, INTMASK )) )
|
|
return( NULL );
|
|
out->coeff = NULL;
|
|
out->filename = NULL;
|
|
out->scale = 1;
|
|
out->offset = 0;
|
|
out->xsize = 0;
|
|
out->ysize = 0;
|
|
|
|
if( !(out->coeff = IM_ARRAY( NULL, size, int )) ) {
|
|
im_free_imask( out );
|
|
return( NULL );
|
|
}
|
|
(void) memset( (char *) out->coeff, 0, size * sizeof( int ) );
|
|
if( !(out->filename = im_strdup( NULL, filename )) ) {
|
|
im_free_imask( out );
|
|
return( NULL );
|
|
}
|
|
out->xsize = xsize;
|
|
out->ysize = ysize;
|
|
|
|
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_create_dmask:
|
|
* @filename: set mask filename to this
|
|
* @xsize: mask width
|
|
* @ysize: mask height
|
|
*
|
|
* Create an empty dmask. You need to loop over @coeff to set the values.
|
|
*
|
|
* See also: im_create_dmaskv(), im_vips2mask().
|
|
*
|
|
* Returns: The newly-allocated mask.
|
|
*/
|
|
DOUBLEMASK *
|
|
im_create_dmask( const char *filename, int xsize, int ysize )
|
|
{
|
|
DOUBLEMASK *out;
|
|
int size = xsize * ysize;
|
|
|
|
/* Check args.
|
|
*/
|
|
if( xsize <= 0 || ysize <= 0 || filename == NULL ) {
|
|
im_error( "im_create_dmask", "%s", _( "bad arguments" ) );
|
|
return( NULL );
|
|
}
|
|
|
|
/* Allocate and initialise structure.
|
|
*/
|
|
if( !(out = IM_NEW( NULL, DOUBLEMASK )) )
|
|
return( NULL );
|
|
out->coeff = NULL;
|
|
out->filename = NULL;
|
|
out->scale = 1.0;
|
|
out->offset = 0.0;
|
|
out->xsize = 0;
|
|
out->ysize = 0;
|
|
|
|
if( !(out->coeff = IM_ARRAY( NULL, size, double )) ) {
|
|
im_free_dmask( out );
|
|
return( NULL );
|
|
}
|
|
(void) memset( (char *) out->coeff, 0, size * sizeof( double ) );
|
|
if( !(out->filename = im_strdup( NULL, filename )) ) {
|
|
im_free_dmask( out );
|
|
return( NULL );
|
|
}
|
|
out->xsize = xsize;
|
|
out->ysize = ysize;
|
|
|
|
return( out );
|
|
}
|
|
|
|
/**
|
|
* im_create_dmaskv:
|
|
* @filename: set mask filename to this
|
|
* @xsize: mask width
|
|
* @ysize: mask height
|
|
* @...: values to set for the mask
|
|
*
|
|
* Create a dmask and initialise it from the function parameter list.
|
|
*
|
|
* See also: im_create_dmask().
|
|
*
|
|
* Returns: The newly-allocated mask.
|
|
*/
|
|
DOUBLEMASK *
|
|
im_create_dmaskv( const char *filename, int xsize, int ysize, ... )
|
|
{
|
|
va_list ap;
|
|
|
|
DOUBLEMASK *out;
|
|
int i;
|
|
|
|
if( !(out = im_create_dmask( filename, xsize, ysize )) )
|
|
return( NULL );
|
|
|
|
va_start( ap, ysize );
|
|
for( i = 0; i < xsize * ysize; i++ )
|
|
out->coeff[i] = va_arg( ap, double );
|
|
va_end( ap );
|
|
|
|
return( out );
|
|
}
|
|
|
|
/* Read a line from a file!
|
|
*/
|
|
static int
|
|
get_line( FILE *fp, char *buf )
|
|
{
|
|
if( !fgets( buf, MAX_LINE, fp ) ) {
|
|
im_error( "read_mask", "%s", _( "unexpected EOF" ) );
|
|
return( -1 );
|
|
}
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
/* width, height, optional scale, optional offset.
|
|
*/
|
|
static int
|
|
read_header( FILE *fp, int *xs, int *ys, double *scale, double *offset )
|
|
{
|
|
char buf[MAX_LINE];
|
|
char *p, *q;
|
|
double v[4];
|
|
int i;
|
|
|
|
/* Read the first line: should contain size and optional
|
|
* scale + offset.
|
|
*/
|
|
if( get_line( fp, buf ) )
|
|
return( -1 );
|
|
|
|
/* Read as space separated doubles. \n is in the break list because
|
|
* our line will (usually) have a trailing \n which we want to count
|
|
* as whitespace.
|
|
*/
|
|
p = buf;
|
|
for( i = 0, p = buf;
|
|
i < 4 && (q = im_break_token( p, " \";,\t\n" ));
|
|
i++, p = q )
|
|
v[i] = g_ascii_strtod( p, NULL );
|
|
|
|
if( (i != 2 && i != 4) ||
|
|
ceil( v[0] ) != v[0] ||
|
|
ceil( v[1] ) != v[1] ||
|
|
v[0] <= 0 ||
|
|
v[1] <= 0 ) {
|
|
im_error( "read_header",
|
|
"%s", _( "error reading matrix header" ) );
|
|
return( -1 );
|
|
}
|
|
if( i == 4 && v[2] == 0 ) {
|
|
im_error( "read_header",
|
|
"%s", _( "scale should be non-zero" ) );
|
|
return( -1 );
|
|
}
|
|
|
|
*xs = v[0];
|
|
*ys = v[1];
|
|
if( i == 2 ) {
|
|
*scale = 1.0;
|
|
*offset = 0.0;
|
|
}
|
|
else {
|
|
*scale = v[2];
|
|
*offset = v[3];
|
|
}
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
/**
|
|
* im_read_dmask:
|
|
* @filename: read matrix from this file
|
|
*
|
|
* Reads a matrix from a file.
|
|
*
|
|
* Matrix files have a simple format that's supposed to be easy to create with
|
|
* a text editor or a spreadsheet.
|
|
*
|
|
* The first line has four numbers for width, height, scale and
|
|
* offset (scale and offset may be omitted, in which case they default to 1.0
|
|
* and 0.0). Scale must be non-zero. Width and height must be positive
|
|
* integers. The numbers are separated by any mixture of spaces, commas,
|
|
* tabs and quotation marks ("). The scale and offset fields may be
|
|
* floating-point, and must use '.'
|
|
* as a decimal separator.
|
|
*
|
|
* Subsequent lines each hold one line of matrix data, with numbers again
|
|
* separated by any mixture of spaces, commas,
|
|
* tabs and quotation marks ("). The numbers may be floating-point, and must
|
|
* use '.'
|
|
* as a decimal separator.
|
|
*
|
|
* Extra characters at the ends of lines or at the end of the file are
|
|
* ignored.
|
|
*
|
|
* See also: im_read_imask(), im_gauss_dmask().
|
|
*
|
|
* Returns: the loaded mask on success, or NULL on error.
|
|
*/
|
|
DOUBLEMASK *
|
|
im_read_dmask( const char *filename )
|
|
{
|
|
FILE *fp;
|
|
double sc, off;
|
|
int xs, ys;
|
|
DOUBLEMASK *out;
|
|
int x, y, i;
|
|
char buf[MAX_LINE];
|
|
|
|
if( !(fp = im__file_open_read( filename, NULL, TRUE )) )
|
|
return( NULL );
|
|
|
|
if( read_header( fp, &xs, &ys, &sc, &off ) ) {
|
|
fclose( fp );
|
|
return( NULL );
|
|
}
|
|
|
|
if( !(out = im_create_dmask( filename, xs, ys )) ) {
|
|
fclose( fp );
|
|
return( NULL );
|
|
}
|
|
out->scale = sc;
|
|
out->offset = off;
|
|
|
|
for( i = 0, y = 0; y < ys; y++ ) {
|
|
char *p;
|
|
|
|
if( get_line( fp, buf ) ) {
|
|
im_free_dmask( out );
|
|
fclose( fp );
|
|
return( NULL );
|
|
}
|
|
|
|
for( p = buf, x = 0; p && x < xs;
|
|
x++, i++, p = im_break_token( p, " \t,\";" ) )
|
|
out->coeff[i] = g_ascii_strtod( p, NULL );
|
|
}
|
|
fclose( fp );
|
|
|
|
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_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_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 );
|
|
}
|
|
|
|
/**
|
|
* im_imask2dmask:
|
|
* @in: mask to convert
|
|
* @filename: filename for returned mask
|
|
*
|
|
* Make a dmask from the imask.
|
|
*
|
|
* See also: im_dmask2imask().
|
|
*
|
|
* Returns: the converted mask, or NULL on error.
|
|
*/
|
|
DOUBLEMASK *
|
|
im_imask2dmask( INTMASK *in, const char *filename )
|
|
{
|
|
const int size = in->xsize * in->ysize;
|
|
|
|
DOUBLEMASK *out;
|
|
int i;
|
|
|
|
if( im_check_imask( "im_imask2dmask", in ) ||
|
|
!(out = im_create_dmask( filename, in->xsize, in->ysize )) )
|
|
return( NULL );
|
|
|
|
for( i = 0; i < size; i++ )
|
|
out->coeff[i] = in->coeff[i];
|
|
out->offset = in->offset;
|
|
out->scale = in->scale;
|
|
|
|
return( out );
|
|
}
|
|
|
|
/**
|
|
* im_norm_dmask:
|
|
* @mask: mask to scale
|
|
*
|
|
* Normalise the dmask. Apply the scale and offset to each element to make
|
|
* a mask with scale 1, offset zero.
|
|
*
|
|
* See also: im_scale_dmask().
|
|
*
|
|
* Returns: 0 on success, or -1 on error.
|
|
*/
|
|
void
|
|
im_norm_dmask( DOUBLEMASK *mask )
|
|
{
|
|
const int n = mask->xsize * mask->ysize;
|
|
const double scale = (mask->scale == 0) ? 0 : (1.0 / mask->scale);
|
|
|
|
int i;
|
|
|
|
if( im_check_dmask( "im_norm_dmask", mask ) ||
|
|
(1.0 == scale && 0.0 == mask->offset) )
|
|
return;
|
|
|
|
for( i = 0; i < n; i++ )
|
|
mask->coeff[i] = mask->coeff[i] * scale + mask->offset;
|
|
|
|
mask->scale = 1.0;
|
|
mask->offset = 0.0;
|
|
}
|
|
|
|
/**
|
|
* 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_dup_dmask:
|
|
* @in: mask to duplicate
|
|
* @filename: filename to set for the new mask
|
|
*
|
|
* Duplicate a dmask.
|
|
*
|
|
* See also: im_dup_imask().
|
|
*
|
|
* Returns: the mask copy, or NULL on error.
|
|
*/
|
|
DOUBLEMASK *
|
|
im_dup_dmask( DOUBLEMASK *in, const char *filename )
|
|
{
|
|
DOUBLEMASK *out;
|
|
int i;
|
|
|
|
if( im_check_dmask( "im_dup_dmask", in ) ||
|
|
!(out = im_create_dmask( 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 );
|
|
}
|
|
|
|
/* Write to file.
|
|
*/
|
|
static int
|
|
write_line( FILE *fp, const char *fmt, ... )
|
|
{
|
|
va_list ap;
|
|
|
|
va_start( ap, fmt );
|
|
if( !vfprintf( fp, fmt, ap ) ) {
|
|
im_error( "write_mask", "%s", _( "write error, disc full?" ) );
|
|
return( -1 );
|
|
}
|
|
va_end( ap );
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
static int
|
|
write_double( FILE *fp, double d )
|
|
{
|
|
char buf[G_ASCII_DTOSTR_BUF_SIZE];
|
|
|
|
fprintf( fp, "%s", g_ascii_dtostr( buf, sizeof( buf ), d ) );
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
/**
|
|
* im_write_imask_name:
|
|
* @in: mask to write
|
|
* @filename: filename to write to
|
|
*
|
|
* Write an imask to a file. See im_read_dmask() for a description of the mask
|
|
* file format.
|
|
*
|
|
* See also: im_write_imask().
|
|
*
|
|
* Returns: 0 on success, or -1 on error.
|
|
*/
|
|
int
|
|
im_write_imask_name( INTMASK *in, const char *filename )
|
|
{
|
|
FILE *fp;
|
|
int x, y, i;
|
|
|
|
if( im_check_imask( "im_write_imask_name", in ) ||
|
|
!(fp = im__file_open_write( filename, TRUE )) )
|
|
return( -1 );
|
|
|
|
if( write_line( fp, "%d %d", in->xsize, in->ysize ) ) {
|
|
fclose( fp );
|
|
return( -1 );
|
|
}
|
|
if( in->scale != 1 || in->offset != 0 )
|
|
write_line( fp, " %d %d", in->scale, in->offset );
|
|
write_line( fp, "\n" );
|
|
|
|
for( i = 0, y = 0; y < in->ysize; y++ ) {
|
|
for( x = 0; x < in->xsize; x++, i++ )
|
|
write_line( fp, "%d ", in->coeff[i] );
|
|
|
|
if( write_line( fp, "\n" ) ) {
|
|
fclose( fp );
|
|
return( -1 );
|
|
}
|
|
}
|
|
fclose( fp );
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
/**
|
|
* im_write_imask:
|
|
* @in: mask to write
|
|
*
|
|
* Write an imask to a file.
|
|
*
|
|
* See also: im_write_imask_name().
|
|
*
|
|
* Returns: 0 on success, or -1 on error.
|
|
*/
|
|
int
|
|
im_write_imask( INTMASK *in )
|
|
{
|
|
if( !in->filename ) {
|
|
im_error( "im_write_imask", "%s", _( "filename not set" ) );
|
|
return( -1 );
|
|
}
|
|
|
|
return( im_write_imask_name( in, in->filename ) );
|
|
}
|
|
|
|
/**
|
|
* im_write_dmask_name:
|
|
* @in: mask to write
|
|
* @filename: filename to write to
|
|
*
|
|
* Write a dmask to a file. See im_read_dmask() for a description of the mask
|
|
* file format.
|
|
*
|
|
* See also: im_write_dmask().
|
|
*
|
|
* Returns: 0 on success, or -1 on error.
|
|
*/
|
|
int
|
|
im_write_dmask_name( DOUBLEMASK *in, const char *filename )
|
|
{
|
|
FILE *fp;
|
|
int x, y, i;
|
|
|
|
if( im_check_dmask( "im_write_dmask_name", in ) ||
|
|
!(fp = im__file_open_write( filename, TRUE )) )
|
|
return( -1 );
|
|
|
|
if( write_line( fp, "%d %d", in->xsize, in->ysize ) ) {
|
|
fclose( fp );
|
|
return( -1 );
|
|
}
|
|
if( in->scale != 1.0 || in->offset != 0.0 ) {
|
|
write_line( fp, " " );
|
|
write_double( fp, in->scale );
|
|
write_line( fp, " " );
|
|
write_double( fp, in->offset );
|
|
}
|
|
write_line( fp, "\n" );
|
|
|
|
for( i = 0, y = 0; y < in->ysize; y++ ) {
|
|
for( x = 0; x < in->xsize; x++, i++ ) {
|
|
write_double( fp, in->coeff[i] );
|
|
write_line( fp, " " );
|
|
}
|
|
|
|
if( write_line( fp, "\n" ) ) {
|
|
fclose( fp );
|
|
return( -1 );
|
|
}
|
|
}
|
|
fclose( fp );
|
|
|
|
return( 0 );
|
|
}
|
|
|
|
/**
|
|
* im_write_dmask:
|
|
* @in: mask to write
|
|
*
|
|
* Write a dmask to a file. See im_read_dmask() for a description of the mask
|
|
* file format.
|
|
*
|
|
* See also: im_write_dmask_name().
|
|
*
|
|
* Returns: 0 on success, or -1 on error.
|
|
*/
|
|
int
|
|
im_write_dmask( DOUBLEMASK *in )
|
|
{
|
|
if( !in->filename ) {
|
|
im_error( "im_write_dmask", "%s", _( "filename not set" ) );
|
|
return( -1 );
|
|
}
|
|
|
|
return( im_write_dmask_name( in, in->filename ) );
|
|
}
|
|
|
|
/* Copy an imask into a matrix. Only used internally by matrix package for
|
|
* invert.
|
|
*/
|
|
void
|
|
im_copy_imask_matrix( INTMASK *mask, int **matrix )
|
|
{
|
|
int x, y;
|
|
int *p = mask->coeff;
|
|
|
|
for( y = 0; y < mask->ysize; y++ )
|
|
for( x = 0; x < mask->xsize; x++ )
|
|
matrix[x][y] = *p++;
|
|
}
|
|
|
|
|
|
/* Copy a matrix into an imask.
|
|
*/
|
|
void
|
|
im_copy_matrix_imask( int **matrix, INTMASK *mask )
|
|
{
|
|
int x, y;
|
|
int *p = mask->coeff;
|
|
|
|
for( y = 0; y < mask->ysize; y++ )
|
|
for( x = 0; x < mask->xsize; x++ )
|
|
*p++ = matrix[x][y];
|
|
}
|
|
|
|
/* Copy a dmask into a matrix.
|
|
*/
|
|
void
|
|
im_copy_dmask_matrix( DOUBLEMASK *mask, double **matrix )
|
|
{
|
|
int x, y;
|
|
double *p = mask->coeff;
|
|
|
|
for( y = 0; y < mask->ysize; y++ )
|
|
for( x = 0; x < mask->xsize; x++ )
|
|
matrix[x][y] = *p++;
|
|
}
|
|
|
|
/* Copy a matrix to a dmask.
|
|
*/
|
|
void
|
|
im_copy_matrix_dmask( double **matrix, DOUBLEMASK *mask )
|
|
{
|
|
int x, y;
|
|
double *p = mask->coeff;
|
|
|
|
for( y = 0; y < mask->ysize; y++ )
|
|
for( x = 0; x < mask->xsize; x++ )
|
|
*p++ = matrix[x][y];
|
|
}
|
|
|
|
/**
|
|
* im_print_imask:
|
|
* @in: mask to print
|
|
*
|
|
* Print an imask to stdout.
|
|
*
|
|
* See also: im_print_dmask().
|
|
*/
|
|
void
|
|
im_print_imask( INTMASK *in )
|
|
{
|
|
int i, j, k;
|
|
|
|
printf( "%s: %d %d %d %d\n",
|
|
in->filename, in->xsize, in->ysize, in->scale, in->offset );
|
|
|
|
for( k = 0, j = 0; j < in->ysize; j++ ) {
|
|
for( i = 0; i < in->xsize; i++, k++ )
|
|
printf( "%d\t", in->coeff[k] );
|
|
|
|
printf( "\n" );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* im_print_dmask:
|
|
* @in: mask to print
|
|
*
|
|
* Print a dmask to stdout.
|
|
*
|
|
* See also: im_print_imask().
|
|
*/
|
|
void
|
|
im_print_dmask( DOUBLEMASK *in )
|
|
{
|
|
int i, j, k;
|
|
|
|
printf( "%s: %d %d %f %f\n",
|
|
in->filename, in->xsize, in->ysize, in->scale, in->offset );
|
|
|
|
for( k = 0, j = 0; j < in->ysize; j++ ) {
|
|
for( i = 0; i < in->xsize; i++, k++ )
|
|
printf( "%f\t", in->coeff[k] );
|
|
|
|
printf( "\n" );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* im_local_dmask:
|
|
* @out: image to make the mask local to
|
|
* @mask: mask to local-ize
|
|
*
|
|
* @out takes ownership of @mask: when @out is closed, @mask will be closed
|
|
* for you. If im_local_dmask() itself fails, the mask is also freed.
|
|
*
|
|
* See also: im_local_imask().
|
|
*
|
|
* Returns: the mask, or NULL on error.
|
|
*/
|
|
DOUBLEMASK *
|
|
im_local_dmask( VipsImage *out, DOUBLEMASK *mask )
|
|
{
|
|
if( im_check_dmask( "im_local_dmask", mask ) )
|
|
return( NULL );
|
|
|
|
if( im_add_close_callback( out,
|
|
(im_callback_fn) im_free_dmask, mask, NULL ) ) {
|
|
im_free_dmask( mask );
|
|
return( NULL );
|
|
}
|
|
|
|
return( mask );
|
|
}
|
|
|
|
/**
|
|
* im_local_imask:
|
|
* @out: image to make the mask local to
|
|
* @mask: mask to local-ize
|
|
*
|
|
* @out takes ownership of @mask: when @out is closed, @mask will be closed
|
|
* for you. If im_local_imask() itself fails, the mask is also freed.
|
|
*
|
|
* See also: im_local_dmask().
|
|
*
|
|
* Returns: the mask, or NULL on error.
|
|
*/
|
|
INTMASK *
|
|
im_local_imask( VipsImage *out, INTMASK *mask )
|
|
{
|
|
if( im_check_imask( "im_local_dmask", mask ) )
|
|
return( NULL );
|
|
|
|
if( im_add_close_callback( out,
|
|
(im_callback_fn) im_free_imask, mask, NULL ) ) {
|
|
im_free_imask( mask );
|
|
return( NULL );
|
|
}
|
|
|
|
return( mask );
|
|
}
|