# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. include include include define ADD 1 # Opcodes. define SUB 2 define MUL 3 define DIV 4 define MIN 5 define MAX 6 # T_IMARITH -- Simple image arithmetic. # # For each pixel in each image compute: # # operand1 op operand2 = result # # Do the operations as efficiently as possible. Allow operand1 or operand2 # to be a constant. Allow resultant image to have the same name as an # operand image. Allow lists for the operands and the results. # Allow one of the operands to have extra dimensions but require that the # common dimensions are of the same length. procedure t_imarith () int list1 # Operand1 list int list2 # Operand2 list int list3 # Result list int op # Operator bool verbose # Verbose option bool noact # Noact option double c1 # Constant for operand1 double c2 # Constant for operand2 double divzero # Zero divide replacement int pixtype # Output pixel datatype int calctype # Datatype for calculations int i, j, pixtype1, pixtype2 short sc1, sc2, sdz int hlist double dval1, dval2 pointer im1, im2, im3 pointer sp, operand1, operand2, result, imtemp pointer opstr, dtstr, field, title, hparams int imtopenp(), imtgetim(), imtlen(), imofnlu(), imgnfn() double clgetd(), imgetd() bool clgetb(), streq() int clgwrd() int gctod(), lexnum() pointer immap() errchk immap, imgetd, imputd begin # Allocate memory for strings. call smark (sp) call salloc (operand1, SZ_FNAME, TY_CHAR) call salloc (operand2, SZ_FNAME, TY_CHAR) call salloc (result, SZ_FNAME, TY_CHAR) call salloc (imtemp, SZ_FNAME, TY_CHAR) call salloc (opstr, SZ_FNAME, TY_CHAR) call salloc (dtstr, SZ_FNAME, TY_CHAR) call salloc (field, SZ_FNAME, TY_CHAR) call salloc (title, SZ_IMTITLE, TY_CHAR) call salloc (hparams, SZ_LINE, TY_CHAR) # Get the operands and the operator. list1 = imtopenp ("operand1") op = clgwrd ("op", Memc[opstr], SZ_FNAME, ",+,-,*,/,min,max,") list2 = imtopenp ("operand2") list3 = imtopenp ("result") # Get the rest of the options. call clgstr ("hparams", Memc[hparams], SZ_LINE) verbose = clgetb ("verbose") noact = clgetb ("noact") if (op == DIV) divzero = clgetd ("divzero") # Check the number of elements. if (((imtlen (list1) != 1) && (imtlen (list1) != imtlen (list3))) || ((imtlen (list2) != 1) && (imtlen (list2) != imtlen (list3)))) { call imtclose (list1) call imtclose (list2) call imtclose (list3) call error (1, "Wrong number of elements in the operand lists") } # Do each operation. while (imtgetim (list3, Memc[result], SZ_FNAME) != EOF) { if (imtgetim (list1, Memc[imtemp], SZ_FNAME) != EOF) call strcpy (Memc[imtemp], Memc[operand1], SZ_FNAME) if (imtgetim (list2, Memc[imtemp], SZ_FNAME) != EOF) call strcpy (Memc[imtemp], Memc[operand2], SZ_FNAME) # Image sections in the output are not allowed. call imgsection (Memc[result], Memc[field], SZ_FNAME) if (Memc[field] != EOS) { call eprintf ( "imarith: image sections in the output are not allowed (%s)\n") call pargstr (Memc[result]) next } # To allow purely numeric file names first test if the operand # is a file. If it is not then attempt to interpret the operand # as a numerical constant. Otherwise it is an error. iferr { im1 = immap (Memc[operand1], READ_ONLY, 0) pixtype1 = IM_PIXTYPE(im1) } then { i = 1 j = gctod (Memc[operand1], i, c1) if ((Memc[operand1+i-1]!=EOS) && (Memc[operand1+i-1]!=' ')) { call eprintf ("%s is not an image or a number\n") call pargstr (Memc[operand1]) next } i = 1 pixtype1 = lexnum (Memc[operand1], i, j) switch (pixtype1) { case LEX_REAL: pixtype1 = TY_REAL default: pixtype1 = TY_SHORT } im1 = NULL } iferr { im2 = immap (Memc[operand2], READ_ONLY, 0) pixtype2 = IM_PIXTYPE(im2) } then { i = 1 j = gctod (Memc[operand2], i, c2) if ((Memc[operand2+i-1]!=EOS) && (Memc[operand2+i-1]!=' ')) { call eprintf ("%s is not an image or a number\n") call pargstr (Memc[operand2]) if (im1 != NULL) call imunmap (im1) next } i = 1 pixtype2 = lexnum (Memc[operand2], i, j) switch (pixtype2) { case LEX_REAL: pixtype2 = TY_REAL default: pixtype2 = TY_SHORT } im2 = NULL } # Determine the output pixel datatype and calculation datatype. call ima_set (pixtype1, pixtype2, op, pixtype, calctype) # If verbose or noact print the operation. if (verbose || noact) { call printf ("IMARITH:\n Operation = %s\n") call pargstr (Memc[opstr]) call printf (" Operand1 = %s\n Operand2 = %s\n") call pargstr (Memc[operand1]) call pargstr (Memc[operand2]) call printf (" Result = %s\n Result pixel type = %s\n") call pargstr (Memc[result]) call dtstring (pixtype, Memc[dtstr], SZ_FNAME) call pargstr (Memc[dtstr]) call printf (" Calculation type = %s\n") call dtstring (calctype, Memc[dtstr], SZ_FNAME) call pargstr (Memc[dtstr]) if (op == DIV) { call printf ( " Replacement value for division by zero = %g\n") call pargd (divzero) } } # Do the operation if the no act switch is not set. if (!noact) { # Check the two operands have the same dimension lengths # over the same dimensions. if ((im1 != NULL) && (im2 != NULL)) { j = OK do i = 1, min (IM_NDIM (im1), IM_NDIM (im2)) if (IM_LEN (im1, i) != IM_LEN (im2, i)) j = ERR if (j == ERR) { call imunmap (im1) call imunmap (im2) call eprintf ( "Input images have different dimensions\n") next } } # Create a temporary output image as a copy of one of the # operand images (the one with the highest dimension). # This allows the resultant image to have # the same name as one of the operand images. if ((im1 != NULL) && (im2 != NULL)) { call xt_mkimtemp (Memc[operand1], Memc[result], Memc[imtemp], SZ_FNAME) if (streq (Memc[result], Memc[imtemp])) call xt_mkimtemp (Memc[operand2], Memc[result], Memc[imtemp], SZ_FNAME) if (IM_NDIM(im1) >= IM_NDIM(im2)) im3 = immap (Memc[result], NEW_COPY, im1) else im3 = immap (Memc[result], NEW_COPY, im2) } else if (im1 != NULL) { call xt_mkimtemp (Memc[operand1], Memc[result], Memc[imtemp], SZ_FNAME) im3 = immap (Memc[result], NEW_COPY, im1) } else if (im2 != NULL) { call xt_mkimtemp (Memc[operand2], Memc[result], Memc[imtemp], SZ_FNAME) im3 = immap (Memc[result], NEW_COPY, im2) } else call error (0, "No operand images") # Set the result image title and pixel datatype. call clgstr ("title", Memc[title], SZ_IMTITLE) if (Memc[title] != EOS) call strcpy (Memc[title], IM_TITLE (im3), SZ_IMTITLE) IM_PIXTYPE (im3) = pixtype # Call the appropriate procedure to do the arithmetic # efficiently. switch (calctype) { case TY_SHORT: sc1 = c1 sc2 = c2 switch (op) { case ADD: call ima_adds (im1, im2, im3, sc1, sc2) case SUB: call ima_subs (im1, im2, im3, sc1, sc2) case MUL: call ima_muls (im1, im2, im3, sc1, sc2) case DIV: sdz = divzero call ima_divs (im1, im2, im3, sc1, sc2, sdz) case MIN: call ima_mins (im1, im2, im3, sc1, sc2) case MAX: call ima_maxs (im1, im2, im3, sc1, sc2) } case TY_INT: switch (op) { case ADD: call ima_addi (im1, im2, im3, int (c1), int (c2)) case SUB: call ima_subi (im1, im2, im3, int (c1), int (c2)) case MUL: call ima_muli (im1, im2, im3, int (c1), int (c2)) case DIV: call ima_divi (im1, im2, im3, int (c1), int (c2), int (divzero)) case MIN: call ima_mini (im1, im2, im3, int (c1), int (c2)) case MAX: call ima_maxi (im1, im2, im3, int (c1), int (c2)) } case TY_LONG: switch (op) { case ADD: call ima_addl (im1, im2, im3, long (c1), long (c2)) case SUB: call ima_subl (im1, im2, im3, long (c1), long (c2)) case MUL: call ima_mull (im1, im2, im3, long (c1), long (c2)) case DIV: call ima_divl (im1, im2, im3, long (c1), long (c2), long (divzero)) case MIN: call ima_minl (im1, im2, im3, long (c1), long (c2)) case MAX: call ima_maxl (im1, im2, im3, long (c1), long (c2)) } case TY_REAL: switch (op) { case ADD: call ima_addr (im1, im2, im3, real (c1), real (c2)) case SUB: call ima_subr (im1, im2, im3, real (c1), real (c2)) case MUL: call ima_mulr (im1, im2, im3, real (c1), real (c2)) case DIV: call ima_divr (im1, im2, im3, real (c1), real (c2), real (divzero)) case MIN: call ima_minr (im1, im2, im3, real (c1), real (c2)) case MAX: call ima_maxr (im1, im2, im3, real (c1), real (c2)) } case TY_DOUBLE: switch (op) { case ADD: call ima_addd (im1, im2, im3, double(c1), double(c2)) case SUB: call ima_subd (im1, im2, im3, double(c1), double(c2)) case MUL: call ima_muld (im1, im2, im3, double(c1), double(c2)) case DIV: call ima_divd (im1, im2, im3, double(c1), double(c2), double(divzero)) case MIN: call ima_mind (im1, im2, im3, double(c1), double(c2)) case MAX: call ima_maxd (im1, im2, im3, double(c1), double(c2)) } } # Do the header parameters. iferr { ifnoerr (dval1 = imgetd (im3, "CCDMEAN")) call imdelf (im3, "CCDMEAN") hlist = imofnlu (im3, Memc[hparams]) while (imgnfn (hlist, Memc[field], SZ_FNAME) != EOF) { if (im1 != NULL) dval1 = imgetd (im1, Memc[field]) else dval1 = c1 if (im2 != NULL) dval2 = imgetd (im2, Memc[field]) else dval2 = c2 switch (op) { case ADD: call imputd (im3, Memc[field], dval1 + dval2) case SUB: call imputd (im3, Memc[field], dval1 - dval2) case MUL: call imputd (im3, Memc[field], dval1 * dval2) case DIV: if (dval2 == 0.) { call eprintf ( "WARNING: Division by zero in header keyword (%s)\n") call pargstr (Memc[field]) } else call imputd (im3, Memc[field], dval1 / dval2) case MIN: call imputd (im3, Memc[field], min (dval1, dval2)) case MAX: call imputd (im3, Memc[field], max (dval1, dval2)) } } call imcfnl (hlist) } then call erract (EA_WARN) } # Unmap images and release the temporary output image. if (im1 != NULL) call imunmap (im1) if (im2 != NULL) call imunmap (im2) if (!noact) { call imunmap (im3) call xt_delimtemp (Memc[result], Memc[imtemp]) } } call imtclose (list1) call imtclose (list2) call imtclose (list3) call sfree (sp) end # IMA_SET -- Determine the output image pixel type and the calculation # datatype. The default pixel types are based on the highest arithmetic # precendence of the input images or constants. Division requires # a minimum of real. procedure ima_set (pixtype1, pixtype2, op, pixtype, calctype) int pixtype1 # Pixel datatype of operand 1 int pixtype2 # Pixel datatype of operand 2 int pixtype # Pixel datatype of resultant image int op # Operation int calctype # Pixel datatype for calculations char line[1] int max_type begin # Determine maximum precedence datatype. switch (pixtype1) { case TY_SHORT: if (op == DIV) max_type = TY_REAL else if (pixtype2 == TY_USHORT) max_type = TY_LONG else max_type = pixtype2 case TY_USHORT: if (op == DIV) max_type = TY_REAL else if ((pixtype2 == TY_SHORT) || (pixtype2 == TY_USHORT)) max_type = TY_LONG else max_type = pixtype2 case TY_INT: if (op == DIV) max_type = TY_REAL else if ((pixtype2 == TY_SHORT) || (pixtype2 == TY_USHORT)) max_type = pixtype1 else max_type = pixtype2 case TY_LONG: if (op == DIV) max_type = TY_REAL else if ((pixtype2 == TY_SHORT) || (pixtype2 == TY_USHORT) || (pixtype2 == TY_INT)) max_type = pixtype1 else max_type = pixtype2 case TY_REAL: if (pixtype2 == TY_DOUBLE) max_type = pixtype2 else max_type = pixtype1 case TY_DOUBLE: max_type = pixtype1 } # Set calculation datatype. call clgstr ("calctype", line, 1) switch (line[1]) { case '1': if (pixtype1 == TY_USHORT) calctype = TY_LONG else calctype = pixtype1 case '2': if (pixtype2 == TY_USHORT) calctype = TY_LONG else calctype = pixtype2 case EOS: calctype = max_type case 's': calctype = TY_SHORT case 'u': calctype = TY_LONG case 'i': calctype = TY_INT case 'l': calctype = TY_LONG case 'r': calctype = TY_REAL case 'd': calctype = TY_DOUBLE default: call error (6, "Unrecognized datatype") } # Set output pixel datatype. call clgstr ("pixtype", line, 1) switch (line[1]) { case '1': pixtype = pixtype1 case '2': pixtype = pixtype2 case EOS: pixtype = calctype case 's': pixtype = TY_SHORT case 'u': pixtype = TY_USHORT case 'i': pixtype = TY_INT case 'l': pixtype = TY_LONG case 'r': pixtype = TY_REAL case 'd': pixtype = TY_DOUBLE default: call error (6, "Unrecognized dataype") } end