/** * 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 ); }
/** * 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 ); }
/* 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 ); }
/* 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 ); }
/** * 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 ); }
/* 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 ); }
/** * 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 ); }
/** * 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 ); }
/** * 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_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 ); }
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 ); }