예제 #1
0
/**
 * im_mattrn:
 * @in: input matrix 
 * @filename: name for output matrix
 *
 * Transposes the input matrix.
 * Pass the filename to set for the output.
 *
 * See also: im_matmul(), im_matinv().
 *
 * Returns: the result matrix on success, or %NULL on error.
 */
DOUBLEMASK *
im_mattrn( DOUBLEMASK *in, const char *name )
{	
	int xc, yc;
	DOUBLEMASK *mat;
	double *out, *a, *b;

	/* Allocate output matrix.
	 */
	if( !(mat = im_create_dmask( name, in->ysize, in->xsize )) ) 
		return( NULL );
	mat->scale = in->scale;
	mat->offset = in->offset;

	/* Transpose.
	 */
	out = mat->coeff;
	a = in->coeff;

	for( yc = 0; yc < mat->ysize; yc++ ) {
		b = a;

		for( xc = 0; xc < mat->xsize; xc++ ) {
			*out++ = *b;
			b += in->xsize;
		}

		a++;
	}

	return( mat );
}
예제 #2
0
/**
 * im_matcat:
 * @top: input matrix
 * @bottom: input matrix
 * @filename: filename for output
 *
 * Matrix catenations. Returns a new matrix which is the two source matrices
 * joined together top-bottom. They must be the same width.
 *
 * See also: im_mattrn(), im_matmul(), im_matinv().
 *
 * Returns: the joined mask on success, or NULL on error.
 */
DOUBLEMASK *
im_matcat( DOUBLEMASK *top, DOUBLEMASK *bottom, const char *filename )
{
	int newxsize, newysize;
	DOUBLEMASK *mat;
	double *out;

	/* matrices must be same width
	 */
	if( top->xsize != bottom->xsize ) {
		im_error( "im_matcat", "%s", 
			_( "matrices must be same width" ) );
		return( NULL );
	}

	newxsize = top->xsize;
	newysize = top->ysize + bottom->ysize;

	/* Allocate output matrix.
	 */
	if( !(mat = im_create_dmask( filename, newxsize, newysize )) ) 
		return( NULL );

	/* copy first matrix then add second on the end
	 */
	memcpy( mat->coeff, top->coeff, 
		top->xsize * top->ysize * sizeof( double ) );
	out = mat->coeff + top->xsize * top->ysize;
	memcpy( out, bottom->coeff, 
		bottom->xsize * bottom->ysize * sizeof( double ) );

	return( mat );
}
예제 #3
0
/* Rotate a dmask with a set of offsets.
 */
static DOUBLEMASK *
rotdmask( offset_fn fn, DOUBLEMASK *m, const char *name )
{
	DOUBLEMASK *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_dmask( 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 );
}
예제 #4
0
/* MATRIX concatenate (join columns ie add mask to bottom of another)
 */
DOUBLEMASK *
im_matcat( DOUBLEMASK *in1, DOUBLEMASK *in2, const char *name )
{
	int newxsize, newysize;
	DOUBLEMASK *mat;
	double *out;
	
	/* matrices must be same width
	 */
	if( in1->xsize != in2->xsize ) {
		im_error( "im_matcat", "%s", _( "matrices must be same width" ) );
		return( NULL );
	}

	newxsize = in1->xsize;
	newysize = in1->ysize + in2->ysize;

	/* Allocate output matrix.
	 */
	if( !(mat = im_create_dmask( name, newxsize, newysize )) ) {
		im_error( "im_matcat", "%s", _( "unable to allocate output matrix" ) );
		return( NULL );
	}

	/* copy first matrix then add second on the end
	 */
	memcpy( mat->coeff, in1->coeff, 
		in1->xsize * in1->ysize * sizeof( double ) );
	out = mat->coeff + in1->xsize * in1->ysize;
	memcpy( out, in2->coeff, 
		in2->xsize * in2->ysize * sizeof( double ) );

	return( mat );
}
예제 #5
0
/**
 * im_matmul:
 * @in1: input matrix 
 * @in2: input matrix
 * @filename: name for output matrix
 *
 * Multiplies two DOUBLEMASKs. Result matrix is made and returned.
 * Pass the filename to set for the output.
 *
 * The scale and offset members of @in1 and @in2 are ignored.
 *
 * See also: im_mattrn(), im_matinv().
 *
 * Returns: the result matrix on success, or %NULL on error.
 */
DOUBLEMASK *
im_matmul( DOUBLEMASK *in1, DOUBLEMASK *in2, const char *name )
{	
	int xc, yc, col;
	double sum;
	DOUBLEMASK *mat;
	double *out, *a, *b;
	double *s1, *s2;

	/* Check matrix sizes.
	 */
	if( in1->xsize != in2->ysize ) {
		im_error( "im_matmul", "%s", _( "bad sizes" ) );
		return( NULL );
	}

	/* Allocate output matrix.
	 */
	if( !(mat = im_create_dmask( name, in2->xsize, in1->ysize )) ) 
		return( NULL );

	/* Multiply.
	 */
	out = mat->coeff;
	s1 = in1->coeff;

	for( yc = 0; yc < in1->ysize; yc++ ) {
		s2 = in2->coeff;

		for( col = 0; col < in2->xsize; col++ ) {
			/* Get ready to sweep a row.
			 */
			sum = 0.0;
			a = s1;
			b = s2;

			for( sum = 0.0, xc = 0; xc < in1->xsize; xc++ ) {
				sum += *a++ * *b;
				b += in2->xsize;
			}

			*out++ = sum;
			s2++;
		}

		s1 += in1->xsize;
	}

	return( mat );
}
예제 #6
0
/* Given a pair of points, return scale, angle, dx, dy to resample the 2nd
 * image with.
 */
int 
im__coeff( int xr1, int yr1, int xs1, int ys1, 
	int xr2, int yr2, int xs2, int ys2, 
	double *a, double *b, double *dx, double *dy )
{	
	DOUBLEMASK *in, *out;

	if( !(in = im_create_dmask( "in", 4, 4 )) ) {
		im_errormsg( "im__coeff: unable to allocate matrix" );
		return( -1 );
	}

	in->coeff[0] = (double)xs1;
	in->coeff[1] = (double)-ys1;
	in->coeff[2] = 1.0;
	in->coeff[3] = 0.0;
	in->coeff[4] = (double)ys1;
	in->coeff[5] = (double)xs1;
	in->coeff[6] = 0.0;
	in->coeff[7] = 1.0;
	in->coeff[8] = (double)xs2;
	in->coeff[9] = (double)-ys2;
	in->coeff[10] = 1.0;
	in->coeff[11] = 0.0;
	in->coeff[12] = (double)ys2;
	in->coeff[13] = (double)xs2;
	in->coeff[14] = 0.0;
	in->coeff[15] = 1.0;

	if( !(out = im_matinv( in, "out" )) ) {
		im_free_dmask( in );
		im_errormsg( "im__coeff: unable to invert matrix" );
		return( -1 );
	}

	*a = out->coeff[0]*xr1 + out->coeff[1]*yr1 + 
		out->coeff[2]*xr2 + out->coeff[3]*yr2;
	*b = out->coeff[4]*xr1 + out->coeff[5]*yr1 + 
		out->coeff[6]*xr2 + out->coeff[7]*yr2;
	*dx= out->coeff[8]*xr1 + out->coeff[9]*yr1 + 	
		out->coeff[10]*xr2 + out->coeff[11]*yr2;
	*dy= out->coeff[12]*xr1 + out->coeff[13]*yr1 + 
		out->coeff[14]*xr2 + out->coeff[15]*yr2;

	im_free_dmask( in );
	im_free_dmask( out );

	return( 0 );
}
예제 #7
0
/**
 * 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 );
}
예제 #8
0
/**
 * 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 );
}
예제 #9
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 );
}
예제 #10
0
/**
 * im_vips2mask:
 * @in: input image
 * @filename: name for output mask 
 *
 * Make a mask from an image. All images are cast to %IM_BANDFMT_DOUBLE
 * before processing. There are two cases for handling bands:
 *
 * If the image has a single band, im_vips2mask() will write a mask the same
 * size as the image.
 *
 * If the image has more than one band, it must be one pixel high or wide. In
 * this case the output mask uses that axis to represent band values.
 *
 * See also: im_mask2vips(), im_measure_area().
 *
 * Returns: a #DOUBLEMASK with @outname set as the name, or NULL on error
 */
DOUBLEMASK *
im_vips2mask( IMAGE *in, const char *filename )
{
	int width, height;
	DOUBLEMASK *out;

	/* double* only: cast if necessary.
	 */
	if( in->BandFmt != IM_BANDFMT_DOUBLE ) {
		IMAGE *t;

		if( !(t = im_open( "im_vips2mask", "p" )) )
			return( NULL );
		if( im_clip2fmt( in, t, IM_BANDFMT_DOUBLE ) ||
			!(out = im_vips2mask( t, filename )) ) {
			im_close( t );
			return( NULL );
		}
		im_close( t );

		return( out );
	}

	/* Check the image.
	 */
	if( im_incheck( in ) ||
		im_check_uncoded( "im_vips2mask", 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_vips2mask", 
			"%s", _( "one band, nx1, or 1xn images only" ) );
		return( NULL );
	}

	if( !(out = im_create_dmask( filename, width, height )) )
		return( NULL );
	if( in->Bands > 1 && in->Ysize == 1 ) {
		double *data = (double *) in->data;
		int x, y;

		/* Need to transpose: the image is RGBRGBRGB, we need RRRGGGBBB.
		 */
		for( y = 0; y < height; y++ )
			for( x = 0; x < width; x++ )
				out->coeff[x + y * width] =
					data[x * height + y];
	}
	else
		memcpy( out->coeff, in->data, 
			width * height * sizeof( double ) );

	out->scale = vips_image_get_scale( in );
	out->offset = vips_image_get_offset( in );

	return( out );
}
예제 #11
0
DOUBLEMASK *
im_log_dmask( const char *filename, double sigma, double min_ampl )
{
	const double sig2 = sigma * sigma;

	double last;
	int x, y, k;

	double *pt1, *pt2, *pt3, *pt4;
	int xm, ym;
	int xm2, ym2; /* xm2 = xm/2 */
	int offset;
	double *cf, *cfs, *mc;
	DOUBLEMASK *m;
	double sum;

	/* Stop used-before-set warnings.
	 */
	last = 0.0;

	/* Find the size of the mask depending on the entered data. We want to
	 * eval the mask out to the flat zero part, ie. beyond the minimum and
	 * to the point where it comes back up towards zero.
	 */
	for( x = 0; x < IM_MAXMASK; x++ ) {
		const double distance = x * x;
		double val;

		/* Handbook of Pattern Recognition and image processing
		 * by Young and Fu AP 1986 pp 220-221
		 * temp =  (1.0 / (2.0 * IM_PI * sig4)) *
			(2.0 - (distance / sig2)) * 
			exp( (-1.0) * distance / (2.0 * sig2) )

		   .. use 0.5 to normalise
		 */
		val = 0.5 * 
			(2.0 - (distance / sig2)) * 
			exp( -distance / (2.0 * sig2) );

		/* Stop when change in temp (ie. difference from the last
		 * point) and absolute value are both less than the min.
		 */
		if( x > 0 && 
			fabs( val ) < min_ampl && 
			fabs( val - last ) < min_ampl ) 
			break;

		last = val;
	}
	if( x == IM_MAXMASK ) {
		im_error( "im_log_dmask", "%s", _( "mask too large" ) );
		return( NULL );
	}

	xm2 = x; ym2 = x;
	xm = xm2 * 2 + 1; ym = ym2 * 2 + 1;

	if( !(cfs = IM_ARRAY( NULL, (xm2 + 1) * (ym2 + 1), double )) )
		return( NULL );

	/* Make 1/4 of the mask.
	 */
	for( k = 0, y = 0; y <= ym2; y++ )
		for( x = 0; x <= xm2; x++, k++ ) {
			const double distance = x * x + y * y;

			cfs[k] = 0.5 *
				(2.0 - (distance / sig2)) *
				exp( -distance / (2.0 * sig2) );
		}

#ifdef PIM_RINT
	for( k = 0, y = 0; y <= ym2; y++ ) {
		for( x = 0; x <= xm2; x++, k++ )
			fprintf( stderr, "%3.2f ", cfs[k] );
		fprintf( stderr, "\n" );
	}
#endif

	if( !(m = im_create_dmask( filename, xm, ym )) ) {
		im_free( cfs ); 
		return( NULL );
	}

	/* Copy the 1/4 cfs into the m 
	 */
	cf = cfs;
	offset = xm2 * (xm + 1);
	mc = m->coeff + offset;
	for( y = 0; y <= ym2; y++ ) {
		for( x = 0; x <= xm2; x++ ) {
			pt1 = mc + (y * xm) + x; 
			pt2 = mc - (y * xm) + x;
			pt3 = mc + (y * xm) - x; 
			pt4 = mc - (y * xm) - x;

			*pt1 = cf[x];
			*pt2 = cf[x];
			*pt3 = cf[x];
			*pt4 = cf[x];
		}

		cf += (xm2 + 1);
	}
	im_free( cfs );

	sum = 0.0;
	for( k = 0, y = 0; y < m->ysize; y++ )
		for( x = 0; x < m->xsize; x++, k++ )
			sum += m->coeff[k];
	m->scale = sum;
	m->offset = 0.0;

#ifdef PIM_RINT
	im_print_dmask( m );
#endif

	return( m );
}