include include "ccdred.h" .help proc Feb87 noao.imred.ccdred .nf ---------------------------------------------------------------------------- proc -- Process CCD images These are the main CCD reduction procedures. There is one for each readout axis (lines or columns) and one for short and real image data. They apply corrections for bad pixels, overscan levels, zero levels, dark counts, flat field response, illumination response, and fringe effects. The image is also trimmed if it was mapped with an image section. The mean value for the output image is computed when the flat field or illumination image is processed to form the scale factor for these calibrations in order to avoid reading through these image a second time. The processing information and parameters are specified in the CCD structure. The processing operations to be performed are specified by the correction array CORS in the ccd structure. There is one array element for each operation with indices defined symbolically by macro definitions (see ccdred.h); i.e. FLATCOR. The value of the array element is an integer bit field in which the bit set is the same as the array index; i.e element 3 will have the third bit set for an operation with array value 2**(3-1)=4. If an operation is not to be performed the bit is not set and the array element has the numeric value zero. Note that the addition of several correction elements gives a unique bit field describing a combination of operations. For efficiency the most common combinations are implemented as separate units. The CCD structure also contains the correction or calibration data consisting either pointers to data, IMIO pointers for the calibration images, and scale factors. The processing is performed line-by-line. The procedure CORINPUT is called to get an input line. This procedure trims and fixes bad pixels by interpolation. The output line and lines from the various calibration images are read. The image vectors as well as the overscan vector and the scale factors are passed to the procedure COR (which also dereferences the pointer data into simple arrays and variables). That procedure does the actual corrections apart from bad pixel corrections. The final optional step is to add each corrected output line to form a mean. This adds efficiency since the operation is done only if desired and the output image data is already in memory so there is no I/O penalty. SEE ALSO ccdred.h, cor, fixpix, setfixpix, setoverscan, settrim, setzero, setdark, setflat, setillum, setfringe .endhelp ---------------------------------------------------------------------- $for (sr) # PROC1 -- Process CCD images with readout axis 1 (lines). procedure proc1$t (ccd) pointer ccd # CCD structure int line, ncols, nlines, findmean, rep int overscan_type, overscan_c1, noverscan real overscan, darkscale, flatscale, illumscale, frgscale, mean PIXEL minrep pointer in, out, zeroim, darkim, flatim, illumim, fringeim, overscan_vec pointer inbuf, outbuf, zerobuf, darkbuf, flatbuf, illumbuf, fringebuf $if (datatype == csir) real asum$t() $else $if (datatype == ld) double asum$t() $else PIXEL asum$t() $endif $endif real find_overscan$t() pointer imgl2$t(), impl2$t(), ccd_gl$t(), xt_fps$t() begin # Initialize. If the correction image is 1D then just get the # data once. in = IN_IM(ccd) out = OUT_IM(ccd) ncols = OUT_C2(ccd) - OUT_C1(ccd) + 1 nlines = OUT_L2(ccd) - OUT_L1(ccd) + 1 findmean = CORS(ccd, FINDMEAN) if (findmean == YES) mean = 0. rep = CORS(ccd, MINREP) if (rep == YES) minrep = MINREPLACE(ccd) if (CORS(ccd, OVERSCAN) == 0) overscan_type = 0 else { overscan_type = OVERSCAN_TYPE(ccd) overscan_vec = OVERSCAN_VEC(ccd) overscan_c1 = BIAS_C1(ccd) - 1 noverscan = BIAS_C2(ccd) - overscan_c1 } if (CORS(ccd, ZEROCOR) == 0) { zeroim = NULL zerobuf = 1 } else if (IM_LEN(ZERO_IM(ccd),2) == 1) { zeroim = NULL zerobuf = ccd_gl$t (ZERO_IM(ccd), ZERO_C1(ccd), ZERO_C2(ccd), 1) } else zeroim = ZERO_IM(ccd) if (CORS(ccd, DARKCOR) == 0) { darkim = NULL darkbuf = 1 } else if (IM_LEN(DARK_IM(ccd),2) == 1) { darkim = NULL darkbuf = ccd_gl$t (DARK_IM(ccd), DARK_C1(ccd), DARK_C2(ccd), 1) darkscale = FLATSCALE(ccd) } else { darkim = DARK_IM(ccd) darkscale = DARKSCALE(ccd) } if (CORS(ccd, FLATCOR) == 0) { flatim = NULL flatbuf = 1 } else if (IM_LEN(FLAT_IM(ccd),2) == 1) { flatim = NULL flatbuf = ccd_gl$t (FLAT_IM(ccd), FLAT_C1(ccd), FLAT_C2(ccd), 1) flatscale = FLATSCALE(ccd) } else { flatim = FLAT_IM(ccd) flatscale = FLATSCALE(ccd) } if (CORS(ccd, ILLUMCOR) == 0) { illumim = NULL illumbuf = 1 } else { illumim = ILLUM_IM(ccd) illumscale = ILLUMSCALE(ccd) } if (CORS(ccd, FRINGECOR) == 0) { fringeim = NULL fringebuf = 1 } else { fringeim = FRINGE_IM(ccd) frgscale = FRINGESCALE(ccd) } # For each line read lines from the input. Procedure XT_FPS replaces # bad pixels by interpolation. The trimmed region is copied to the # output. Get lines from the output image and from the zero level, # dark count, flat field, illumination, and fringe images. Call COR1 # to do the actual pixel corrections. Finally, add the output pixels # to a sum for computing the mean. We must copy data outside of the # output data section. do line = 2 - OUT_L1(ccd), 0 call amov$t ( Mem$t[imgl2$t(in,IN_L1(ccd)+line-1)+IN_C1(ccd)-OUT_C1(ccd)], Mem$t[impl2$t(out,OUT_L1(ccd)+line-1)], IM_LEN(out,1)) do line = 1, nlines { outbuf = impl2$t (out, OUT_L1(ccd)+line-1) inbuf = xt_fps$t (MASK_FP(ccd), in, IN_L1(ccd)+line-1, IN_C1(ccd), IN_C2(ccd), IN_L1(ccd), IN_L2(ccd), NULL) call amov$t (Mem$t[inbuf+IN_C1(ccd)-OUT_C1(ccd)], Mem$t[outbuf], IM_LEN(out,1)) outbuf = outbuf + OUT_C1(ccd) - 1 if (overscan_type != 0) { if (overscan_type < OVERSCAN_FIT) overscan = find_overscan$t (Mem$t[inbuf+overscan_c1], noverscan, overscan_type) else overscan = Memr[overscan_vec+line-1] } if (zeroim != NULL) zerobuf = ccd_gl$t (zeroim, ZERO_C1(ccd), ZERO_C2(ccd), ZERO_L1(ccd)+line-1) if (darkim != NULL) darkbuf = ccd_gl$t (darkim, DARK_C1(ccd), DARK_C2(ccd), DARK_L1(ccd)+line-1) if (flatim != NULL) flatbuf = ccd_gl$t (flatim, FLAT_C1(ccd), FLAT_C2(ccd), FLAT_L1(ccd)+line-1) if (illumim != NULL) illumbuf = ccd_gl$t (illumim, ILLUM_C1(ccd), ILLUM_C2(ccd), ILLUM_L1(ccd)+line-1) if (fringeim != NULL) fringebuf = ccd_gl$t (fringeim, FRINGE_C1(ccd), FRINGE_C2(ccd), FRINGE_L1(ccd)+line-1) call cor1$t (CORS(ccd,1), Mem$t[outbuf], overscan, Mem$t[zerobuf], Mem$t[darkbuf], Mem$t[flatbuf], Mem$t[illumbuf], Mem$t[fringebuf], ncols, darkscale, flatscale, illumscale, frgscale) if (rep == YES) call amaxk$t (Mem$t[outbuf], minrep, Mem$t[outbuf], ncols) if (findmean == YES) mean = mean + asum$t (Mem$t[outbuf], ncols) } do line = nlines+1, IM_LEN(out,2)-OUT_L1(ccd)+1 call amov$t ( Mem$t[imgl2$t(in,IN_L1(ccd)+line-1)+IN_C1(ccd)-OUT_C1(ccd)], Mem$t[impl2$t(out,OUT_L1(ccd)+line-1)], IM_LEN(out,1)) # Compute the mean from the sum of the output pixels. if (findmean == YES) MEAN(ccd) = mean / ncols / nlines end # PROC2 -- Process CCD images with readout axis 2 (columns). procedure proc2$t (ccd) pointer ccd # CCD structure int line, ncols, nlines, findmean, rep real darkscale, flatscale, illumscale, frgscale, mean PIXEL minrep pointer in, out, zeroim, darkim, flatim, illumim, fringeim, overscan_vec pointer inbuf, outbuf, zerobuf, darkbuf, flatbuf, illumbuf, fringebuf $if (datatype == csir) real asum$t() $else $if (datatype == ld) double asum$t() $else PIXEL asum$t() $endif $endif pointer imgl2$t(), impl2$t(), imgs2$t(), ccd_gl$t(), xt_fps$t() begin # Initialize. If the correction image is 1D then just get the # data once. in = IN_IM(ccd) out = OUT_IM(ccd) ncols = OUT_C2(ccd) - OUT_C1(ccd) + 1 nlines = OUT_L2(ccd) - OUT_L1(ccd) + 1 findmean = CORS(ccd, FINDMEAN) if (findmean == YES) mean = 0. rep = CORS(ccd, MINREP) if (rep == YES) minrep = MINREPLACE(ccd) overscan_vec = OVERSCAN_VEC(ccd) if (CORS(ccd, ZEROCOR) == 0) { zeroim = NULL zerobuf = 1 } else if (IM_LEN(ZERO_IM(ccd),1) == 1) { zeroim = NULL zerobuf = imgs2$t (ZERO_IM(ccd), 1, 1, ZERO_L1(ccd), ZERO_L2(ccd)) } else zeroim = ZERO_IM(ccd) if (CORS(ccd, DARKCOR) == 0) { darkim = NULL darkbuf = 1 } else if (IM_LEN(DARK_IM(ccd),1) == 1) { darkim = NULL darkbuf = imgs2$t (DARK_IM(ccd), 1, 1, DARK_L1(ccd), DARK_L2(ccd)) darkscale = DARKSCALE(ccd) } else { darkim = DARK_IM(ccd) darkscale = DARKSCALE(ccd) } if (CORS(ccd, FLATCOR) == 0) { flatim = NULL flatbuf = 1 } else if (IM_LEN(FLAT_IM(ccd),1) == 1) { flatim = NULL flatbuf = imgs2$t (FLAT_IM(ccd), 1, 1, FLAT_L1(ccd), FLAT_L2(ccd)) flatscale = FLATSCALE(ccd) } else { flatim = FLAT_IM(ccd) flatscale = FLATSCALE(ccd) } if (CORS(ccd, ILLUMCOR) == 0) { illumim = NULL illumbuf = 1 } else { illumim = ILLUM_IM(ccd) illumscale = ILLUMSCALE(ccd) } if (CORS(ccd, FRINGECOR) == 0) { fringeim = NULL fringebuf = 1 } else { fringeim = FRINGE_IM(ccd) frgscale = FRINGESCALE(ccd) } # For each line read lines from the input. Procedure CORINPUT # replaces bad pixels by interpolation and applies a trim to the # input. Get lines from the output image and from the zero level, # dark count, flat field, illumination, and fringe images. # Call COR2 to do the actual pixel corrections. Finally, add the # output pixels to a sum for computing the mean. # We must copy data outside of the output data section. do line = 2 - OUT_L1(ccd), 0 call amov$t ( Mem$t[imgl2$t(in,IN_L1(ccd)+line-1)+IN_C1(ccd)-OUT_C1(ccd)], Mem$t[impl2$t(out,OUT_L1(ccd)+line-1)], IM_LEN(out,1)) do line = 1, nlines { outbuf = impl2$t (out, OUT_L1(ccd)+line-1) inbuf = xt_fps$t (MASK_FP(ccd), in, IN_L1(ccd)+line-1, IN_C1(ccd), IN_C2(ccd), IN_L1(ccd), IN_L2(ccd), NULL) call amov$t (Mem$t[inbuf+IN_C1(ccd)-OUT_C1(ccd)], Mem$t[outbuf], IM_LEN(out,1)) outbuf = outbuf + OUT_C1(ccd) - 1 if (zeroim != NULL) zerobuf = ccd_gl$t (zeroim, ZERO_C1(ccd), ZERO_C2(ccd), ZERO_L1(ccd)+line-1) if (darkim != NULL) darkbuf = ccd_gl$t (darkim, DARK_C1(ccd), DARK_C2(ccd), DARK_L1(ccd)+line-1) if (flatim != NULL) flatbuf = ccd_gl$t (flatim, FLAT_C1(ccd), FLAT_C2(ccd), FLAT_L1(ccd)+line-1) if (illumim != NULL) illumbuf = ccd_gl$t (illumim, ILLUM_C1(ccd), ILLUM_C2(ccd), ILLUM_L1(ccd)+line-1) if (fringeim != NULL) fringebuf = ccd_gl$t (fringeim, FRINGE_C1(ccd), FRINGE_C2(ccd), FRINGE_L1(ccd)+line-1) call cor2$t (line, CORS(ccd,1), Mem$t[outbuf], Memr[overscan_vec], Mem$t[zerobuf], Mem$t[darkbuf], Mem$t[flatbuf], Mem$t[illumbuf], Mem$t[fringebuf], ncols, zeroim, flatim, darkscale, flatscale, illumscale, frgscale) if (rep == YES) call amaxk$t (Mem$t[outbuf], minrep, Mem$t[outbuf], ncols) if (findmean == YES) mean = mean + asum$t (Mem$t[outbuf], ncols) } do line = nlines+1, IM_LEN(out,2)-OUT_L1(ccd)+1 call amov$t ( Mem$t[imgl2$t(in,IN_L1(ccd)+line-1)+IN_C1(ccd)-OUT_C1(ccd)], Mem$t[impl2$t(out,OUT_L1(ccd)+line-1)], IM_LEN(out,1)) # Compute the mean from the sum of the output pixels. if (findmean == YES) MEAN(ccd) = mean / ncols / nlines end # FIND_OVERSCAN -- Find the overscan value for a line. # No check is made on the number of pixels. # The median is the (npix+1)/2 element. real procedure find_overscan$t (data, npix, type) PIXEL data[npix] #I Overscan data int npix #I Number of overscan points int type #I Type of overscan calculation int i real overscan, d, dmin, dmax PIXEL asok$t() begin if (type == OVERSCAN_MINMAX) { overscan = data[1] dmin = data[1] dmax = data[1] do i = 2, npix { d = data[i] overscan = overscan + d if (d < dmin) dmin = d else if (d > dmax) dmax = d } overscan = (overscan - dmin - dmax) / (npix - 2) } else if (type == OVERSCAN_MEDIAN) overscan = asok$t (data, npix, (npix + 1) / 2) else { overscan = data[1] do i = 2, npix overscan = overscan + data[i] overscan = overscan / npix } return (overscan) end $endfor