/* -*-C-*- $Id: image.c,v 9.34 1999/01/02 06:11:34 cph Exp $ Copyright (c) 1987-1999 Massachusetts Institute of Technology This program is free software; you can redistribute it and/or modify it under the terms of the GNU 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "scheme.h" #include "prims.h" #include "array.h" #include void arg_image (arg_number, nrows, ncols, array) int arg_number; long * nrows; long * ncols; REAL ** array; { fast SCHEME_OBJECT argument = (ARG_REF (arg_number)); fast SCHEME_OBJECT rest; fast SCHEME_OBJECT first; fast SCHEME_OBJECT second; fast SCHEME_OBJECT third; if (! (PAIR_P (argument))) goto loser; first = (PAIR_CAR (argument)); if (! (UNSIGNED_FIXNUM_P (first))) goto loser; rest = (PAIR_CDR (argument)); if (! (PAIR_P (rest))) goto loser; second = (PAIR_CAR (rest)); if (! (UNSIGNED_FIXNUM_P (second))) goto loser; rest = (PAIR_CDR (rest)); if (! (PAIR_P (rest))) goto loser; third = (PAIR_CAR (rest)); if (! (ARRAY_P (third))) goto loser; if ((PAIR_CDR (rest)) != EMPTY_LIST) goto loser; (*nrows) = (UNSIGNED_FIXNUM_TO_LONG (first)); (*ncols) = (UNSIGNED_FIXNUM_TO_LONG (second)); (*array) = (ARRAY_CONTENTS (third)); return; loser: error_bad_range_arg (arg_number); /* NOTREACHED */ } #define MAKE_IMAGE(nrows, ncols, array) \ (cons ((LONG_TO_UNSIGNED_FIXNUM (nrows)), \ (cons ((LONG_TO_UNSIGNED_FIXNUM (ncols)), \ (cons ((array), EMPTY_LIST)))))) static int read_byte (fp) fast FILE * fp; { int result = (getc (fp)); if (ferror (fp)) error_external_return (); return (result); } static int read_word (fp) fast FILE * fp; { int result = (getw (fp)); if (ferror (fp)) error_external_return (); return (result); } static void write_word (fp, datum) fast FILE * fp; int datum; { if ((putw (datum, fp)) != 0) error_external_return (); return; } static int read_2bint (fp) fast FILE * fp; { int msd = (getc (fp)); if (ferror (fp)) error_external_return (); { int lsd = (getc (fp)); if (ferror (fp)) error_external_return (); { int result = ((msd << 8) | lsd); return (((result & (1 << 15)) == 0) ? result : ((-1 << 16) | result)); } } } static void write_2bint (fp, datum) fast FILE * fp; int datum; { if (((putc (((datum >> 8) & 0xFF), fp)) == EOF) || ((putc ((datum & 0xFF), fp)) == EOF)) error_external_return (); return; } DEFINE_PRIMITIVE ("IMAGE-READ-ASCII", Prim_read_image_ascii, 1, 1, 0) { fast FILE * fp; long nrows, ncols; PRIMITIVE_HEADER (1); CHECK_ARG (1, STRING_P); if ( (fp = fopen((STRING_ARG (1)), "r")) == NULL) error_bad_range_arg (1); fscanf (fp, "%d %d \n", (&nrows), (&ncols)); if ((ferror (fp)) || ((ncols > 512) || (nrows > 512))) { printf("read-image-ascii-file: problem with rows,cols \n"); error_bad_range_arg (1); } { fast long length = (nrows * ncols); SCHEME_OBJECT array = (allocate_array (length)); fast REAL * scan = (ARRAY_CONTENTS (array)); while ((length--) > 0) { long number; fscanf (fp, "%d", (&number)); if (ferror (fp)) error_external_return (); (*scan++) = ((REAL) number); } if ((fclose (fp)) != 0) error_external_return (); PRIMITIVE_RETURN (MAKE_IMAGE (nrows, ncols, array)); } } DEFINE_PRIMITIVE ("IMAGE-READ-2BINT", Prim_read_image_2bint, 1, 1, 0) { FILE *fp, *fopen(); PRIMITIVE_HEADER (1); CHECK_ARG (1, STRING_P); if ( ( fp = (fopen((STRING_ARG (1)), "r")) ) == NULL) error_bad_range_arg (1); { int nrows = (read_word (fp)); int ncols = (read_word (fp)); fast long length = (nrows * ncols); SCHEME_OBJECT array = (allocate_array (length)); fast REAL * scan = (ARRAY_CONTENTS (array)); while ((length--) > 0) (*scan++) = ((REAL) (read_2bint (fp))); if ((fclose (fp)) != 0) error_external_return (); PRIMITIVE_RETURN (MAKE_IMAGE (nrows, ncols, array)); } } DEFINE_PRIMITIVE ("IMAGE-READ-CTSCAN", Prim_read_image_ctscan, 1, 1, 0) { fast FILE * fp; PRIMITIVE_HEADER (1); CHECK_ARG (1, STRING_P); fp = (fopen((STRING_ARG (1)), "r")); if (fp == ((FILE *) 0)) error_bad_range_arg (1); Primitive_GC_If_Needed (BYTES_TO_WORDS (512 * (sizeof (int)))); { int nrows = 512; int ncols = 512; SCHEME_OBJECT array = (allocate_array (nrows * ncols)); REAL * Array = (ARRAY_CONTENTS (array)); fast int * Widths = ((int *) Free); fast int i; /* Discard header */ for (i = 0; (i < 2048); i += 1) (void) read_byte (fp); for (i = 0; (i < 512); i += 1) (Widths [i]) = (read_2bint (fp)); for (i = 0; (i < (nrows * ncols)); i += 1) (Array [i]) = 0; for (i = 0; (i < 512); i += 1) { fast int array_index = ((i * 512) + (256 - (Widths [i]))); fast int m; for (m = 0; (m < (2 * (Widths [i]))); m += 1) (Array [array_index + m]) = ((REAL) (read_2bint (fp))); } /* CTSCAN images are upside down */ #if (REAL_IS_DEFINED_DOUBLE != 0) ALIGN_FLOAT (Free); Free += 1; #endif Primitive_GC_If_Needed (512 * REAL_SIZE); Image_Mirror_Upside_Down (Array, nrows, ncols, ((REAL *) Free)); if ((fclose (fp)) != 0) error_external_return (); PRIMITIVE_RETURN (MAKE_IMAGE (nrows, ncols, array)); } } DEFINE_PRIMITIVE ("IMAGE-READ-CBIN", Prim_read_image_cbin, 1, 1, 0) { fast FILE * fp; PRIMITIVE_HEADER (1); CHECK_ARG (1, STRING_P); fp = (fopen ((STRING_ARG (1)), "r")); if (fp == ((FILE *) 0)) error_bad_range_arg (1); { int nrows = (read_word (fp)); int ncols = (read_word (fp)); long length = (nrows * ncols); SCHEME_OBJECT array = (allocate_array (length)); fast REAL * scan = (ARRAY_CONTENTS (array)); while ((length--) > 0) (*scan++) = (read_word (fp)); if ((fclose (fp)) != 0) error_external_return (); PRIMITIVE_RETURN (MAKE_IMAGE (nrows, ncols, array)); } } Image_Mirror_Upside_Down (Array,nrows,ncols,Temp_Row) REAL * Array; long nrows; long ncols; REAL * Temp_Row; { int i; REAL *M_row, *N_row; for (i=0;i<(nrows/2);i++) { M_row = Array + (i * ncols); N_row = Array + (((nrows-1)-i) * ncols); C_Array_Copy(N_row, Temp_Row, ncols); C_Array_Copy(M_row, N_row, ncols); C_Array_Copy(Temp_Row, M_row, ncols); } } /* The following does not work, to be fixed. */ DEFINE_PRIMITIVE ("IMAGE-DOUBLE-TO-FLOAT!", Prim_image_double_to_float, 1, 1, 0) { long Length; long i,j; long allocated_cells; long nrows, ncols; SCHEME_OBJECT array; double *Array, *From_Here; fast double temp_value_cell; float *To_Here; PRIMITIVE_HEADER (1); arg_image (1, (&nrows), (&ncols), (&array)); Array = ((double *) (ARRAY_CONTENTS (array))); From_Here = Array; To_Here = ((float *) (Array)); Length = nrows * ncols; for (i=0;i r1) || ((at1c + mc) > c1)) error_bad_range_arg (7); if (((at2r + mr) > r2) || ((at2c + mc) > c2)) error_bad_range_arg (9); subimage_copy (x, y, r1, c1, r2, c2, at1r, at1c, at2r, at2c, mr, mc); PRIMITIVE_RETURN (UNSPECIFIC); } void subimage_copy (x,y, r1,c1,r2,c2, at1r,at1c,at2r,at2c, mr,mc) REAL *x,*y; long r1,c1,r2,c2, at1r,at1c,at2r,at2c, mr,mc; { long i,j; REAL *xrow,*yrow; xrow = x + at1r*c1 + at1c; yrow = y + at2r*c2 + at2c; /* A(i,j)--->Array[i*ncols+j] */ for (i=0; i Array[i*ncols + j] With no knowledge outside boundary, assume laplace(edge-point)=0.0 (no wrap-around, no artificial bndry) */ void image_laplacian (x,y, nrows,ncols) REAL *x, *y; long nrows, ncols; { long i,j, nrows1, ncols1; nrows1=nrows-1; ncols1=ncols-1; /* no need todo anything for 1-point image */ if ((nrows<2)||(ncols<2)) return; /* */ i=0;j=0; y[i*ncols+j] = 0.0; /* NE corner */ i=0;j=ncols1; y[i*ncols+j] = 0.0; /* NW corner */ i=nrows1;j=0; y[i*ncols+j] = 0.0; /* SE corner */ i=nrows1;j=ncols1; y[i*ncols+j] = 0.0; /* SW corner */ i=0; for (j=1;j Array[i*ncols + j] magnification in a south-east direction (i.e. replication of pixels in South-East corner) */ C_image_double_by_interpolation (array, new_array, nrows, ncols) REAL *array, *new_array; long nrows, ncols; { long i,j, nrows1, ncols1, nrows2, ncols2; nrows1=nrows-1; ncols1=ncols-1; nrows2=2*nrows; ncols2=2*ncols; /* no need todo anything for 1-point image */ if ((nrows<2)||(ncols<2)) return(1); i=nrows1; for (j=0;jSquare_HC)) Ring_Array[i*ncols+j] = 0; else Ring_Array[i*ncols+j] = 1; }} } /* Periodic-shift without side-effects for code simplicity. */ DEFINE_PRIMITIVE ("IMAGE-PERIODIC-SHIFT", Prim_image_periodic_shift, 3, 3, 0) { long nrows; long ncols; REAL * Array; PRIMITIVE_HEADER (3); { SCHEME_OBJECT Parray; arg_image (1, (&nrows), (&ncols), (&Parray)); Array = (ARRAY_CONTENTS (Parray)); } { long ver_shift = ((arg_integer (2)) % nrows); long hor_shift = ((arg_integer (3)) % ncols); SCHEME_OBJECT array = (allocate_array (nrows * ncols)); SCHEME_OBJECT Result = (MAKE_IMAGE (nrows, ncols, array)); C_Image_Periodic_Shift (Array, (ARRAY_CONTENTS (array)), nrows, ncols, ver_shift, hor_shift); PRIMITIVE_RETURN (Result); } } /* ASSUMES ((hor_shift < nrows) && (ver_shift < ncols)) */ C_Image_Periodic_Shift(Array, New_Array, nrows, ncols, ver_shift, hor_shift) REAL *Array, *New_Array; long nrows, ncols, hor_shift, ver_shift; { long i, j, ver_index, hor_index; REAL *To_Here; To_Here = New_Array; for (i=0;i ignore argument 4 */ Image_Fast_Transpose (x, rows); else Image_Transpose (x, y, rows, cols); PRIMITIVE_RETURN (UNSPECIFIC); } DEFINE_PRIMITIVE ("IMAGE-ROTATE-90CLW!", Prim_image_rotate_90clw, 1, 1, 0) { long nrows; long ncols; REAL * Array; long Length; PRIMITIVE_HEADER (1); { SCHEME_OBJECT Parray; arg_image (1, (&nrows), (&ncols), (&Parray)); Array = (ARRAY_CONTENTS (Parray)); } Length = (nrows * ncols); #if (REAL_IS_DEFINED_DOUBLE != 0) ALIGN_FLOAT (Free); Free += 1; #endif Primitive_GC_If_Needed (Length * REAL_SIZE); { REAL * Temp_Array = ((REAL *) Free); Image_Rotate_90clw (Array, Temp_Array, nrows, ncols); C_Array_Copy (Temp_Array, Array, Length); } { SCHEME_OBJECT argument = (ARG_REF (1)); SET_PAIR_CAR (argument, (LONG_TO_UNSIGNED_FIXNUM (ncols))); SET_PAIR_CAR ((PAIR_CDR (argument)), (LONG_TO_UNSIGNED_FIXNUM (nrows))); PRIMITIVE_RETURN (argument); } } DEFINE_PRIMITIVE ("IMAGE-ROTATE-90CCLW!", Prim_image_rotate_90cclw, 1, 1, 0) { long nrows; long ncols; REAL * Array; long Length; PRIMITIVE_HEADER (1); { SCHEME_OBJECT Parray; arg_image (1, (&nrows), (&ncols), (&Parray)); Array = (ARRAY_CONTENTS (Parray)); } Length = (nrows * ncols); #if (REAL_IS_DEFINED_DOUBLE != 0) ALIGN_FLOAT (Free); Free += 1; #endif Primitive_GC_If_Needed (Length * REAL_SIZE); { REAL * Temp_Array = ((REAL *) Free); Image_Rotate_90cclw (Array, Temp_Array, nrows, ncols); C_Array_Copy (Temp_Array, Array, Length); } { SCHEME_OBJECT argument = (ARG_REF (1)); SET_PAIR_CAR (argument, (LONG_TO_UNSIGNED_FIXNUM (ncols))); SET_PAIR_CAR ((PAIR_CDR (argument)), (LONG_TO_UNSIGNED_FIXNUM (nrows))); PRIMITIVE_RETURN (argument); } } DEFINE_PRIMITIVE ("IMAGE-MIRROR!", Prim_image_mirror, 1, 1, 0) { long nrows; long ncols; REAL * Array; PRIMITIVE_HEADER (1); { SCHEME_OBJECT Parray; arg_image (1, (&nrows), (&ncols), (&Parray)); Array = (ARRAY_CONTENTS (Parray)); } C_Mirror_Image (Array, nrows, ncols); /* side-effecting... */ PRIMITIVE_RETURN (ARG_REF (1)); } /* C routines referred to above */ /* IMAGE_FAST_TRANSPOSE A(i,j) <-> A(j,i) . UNWRAP: A(i,j) ----> Array[i*ncols + j] convention:= fix row & go by columns . UNWRAP is a bijection from the compact plane to the compact interval. */ Image_Fast_Transpose (Array, nrows) /* for square images */ REAL *Array; long nrows; { long i, j; long from, to; REAL temp; for (i=0;i B(j,i) . UNWRAP: A(i,j) ----> Array[i*ncols + j] convention:= fix row & go by columns . UNWRAP is a bijection from the compact plane to the compact interval. */ Image_Transpose (Array, New_Array, nrows, ncols) REAL *Array, *New_Array; long nrows, ncols; { long i, j; for (i=0;i A(j, (nrows-1)-i) . UNWRAP: A(i,j) ----> Array[i*ncols + j] convention:= fix row & go by columns UNWRAP is a bijection from the compact plane to the compact interval. */ Image_Rotate_90clw (Array, Rotated_Array, nrows, ncols) REAL *Array, *Rotated_Array; long nrows, ncols; { long i, j; for (i=0;i A((nrows-1)-j, i) . (minus 1 because we start from 0). UNWRAP: A(i,j) ----> Array[i*ncols + j] because of convention:= fix row & go by columns UNWRAP is a bijection from the compact plane to the compact interval. */ Image_Rotate_90cclw (Array, Rotated_Array, nrows, ncols) REAL *Array, *Rotated_Array; long nrows, ncols; { long i, j; fast long from_index, to_index; long Length=nrows*ncols; for (i=0;i A(i, (ncols-1)-j) [ The -1 is there because we count from 0] . A(i,j) -------> Array[i*ncols + j] fix row, read column convention. */ C_Mirror_Image (Array, nrows, ncols) REAL *Array; long nrows, ncols; { long i, j; long ncols2=ncols/2, Length=nrows*ncols; REAL temp; long from, to; for (i=0; i A(j, i) this should be identical to image_transpose (see above). UNWRAP: A(i,j) ----> Array[i*ncols + j] because of convention:= fix row & go by columns UNWRAP is a bijection from the compact plane to the compact interval. */ C_Rotate_90clw_Mirror_Image (Array, Rotated_Array, nrows, ncols) REAL *Array, *Rotated_Array; long nrows, ncols; { long i, j; long from, to, Length=nrows*ncols; for (i=0;i