diff options
author | Joseph Hunkeler <jhunkeler@gmail.com> | 2015-07-08 20:46:52 -0400 |
---|---|---|
committer | Joseph Hunkeler <jhunkeler@gmail.com> | 2015-07-08 20:46:52 -0400 |
commit | fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4 (patch) | |
tree | bdda434976bc09c864f2e4fa6f16ba1952b1e555 /noao/nproto/ace | |
download | iraf-linux-fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4.tar.gz |
Initial commit
Diffstat (limited to 'noao/nproto/ace')
63 files changed, 15317 insertions, 0 deletions
diff --git a/noao/nproto/ace/Notes b/noao/nproto/ace/Notes new file mode 100644 index 00000000..3cdd5b07 --- /dev/null +++ b/noao/nproto/ace/Notes @@ -0,0 +1,12 @@ +o Evaluate centroid in detection phase so that evaluation can + include quantities based on distance from centroid. +o Kron magnitudes +o Add partial pixel +o What to do about contaminating objects in the apertures. + +TODO + +o MapIO - match coordinates for sky fit +o match object mask as part of aceall when outobjmask is given +o reorganize to remove xap,yap,etc from detection phase +o errors in ra/dec and mags diff --git a/noao/nproto/ace/Revisions b/noao/nproto/ace/Revisions new file mode 100644 index 00000000..df309bd9 --- /dev/null +++ b/noao/nproto/ace/Revisions @@ -0,0 +1,89 @@ + +convolve.x + An amovki() call was mistakenly used as amovi() (6/3/13, MJF) + +convolve.x + The 'bpbuf' pointer was declared as TY_REAL instead of TY_INT (5/4/13) + +objs.h + Added P2R for 64-bit systems. + +skyfit.x + If a complete line is exceptionally deviant from the true sky it + will bias the sky surface. As a quick fix for the possibly common + case that the first or last lines are high due to charge transfer + effects, the lines to use was changed to start and end a half step + from the ends. This is only a quick fix and a more sophisticated + solutions is needed. (10/17/02, Valdes) + +skyblock.x + There was another bug in interp2. (10/17/02, Valdes) + +skyblock.x + There was a bug in interp2. (9/30/02, Valdes) + +convolve.x + Fixed error when reference image does not overlap target image on + the right. (9/23/02, Valdes) + +detect.x + The flux comparison in difference detection used sigma normalized + fluxes. This was changed to unnormalized fluxes which is done + by using the same sigmas for the target and reference images. + (9/23/02, Valdes) + +t_acedetect.x +pars.x +diffdetect.pars + Made changes for diffdetect. (9/23/02, Valdes) + +t_acedetect.x + Switched over to the xtools version of xt_pmmap. + (9/10/02, Valdes) + +t_acedetect.x +skyblock.x +omwrite.x + If DATASEC is present then it is automatically applied to the + image. It is also deleted from the output sky and mask since + they will be the size of the data section. (9/10/02, Valdes) + +skyfit.x + The sigma fit is now always a constant. (8/6/02, Valdes) + +skyblock.x + Fixed a type mismatch in a min() function. (6/13/02, Valdes) + +===== +V2.12 +===== + +skyblock.x + Changed algorithm for updating sky to do in place updates so that + extensions might be used. (12/21/01, Valdes) + +detect.x + The number of sky block lines was being wrong in using nc instead of nl. + (12/21/01, Valdes) + +t_acedetect.x + The check on the number of catalog definitions files did not allow + just one file when there was input list. (12/20/01, Valdes) + +t_acedetect.x + The default catalog output is now STSDAS. (5/7/01, Valdes) + +mim.x + When deleting the image name returned from imstats any image section + needed to be stripped. (5/7/01, Valdes) + +mim.x +convolve.x +skyfit.x +skyimages.x + Added error checking for calls to mim_glr. (5/7/01, Valdes) + +catdefine.x + The reference to acesrc$ was replaced with ace$src/ in order to run + standalone without additional environment definitions. (5/7/01, Valdes) + diff --git a/noao/nproto/ace/ace.h b/noao/nproto/ace/ace.h new file mode 100644 index 00000000..988ffd05 --- /dev/null +++ b/noao/nproto/ace/ace.h @@ -0,0 +1,32 @@ +define NUMSTART 11 # First object number + +# Header structure. +define HDR_SZFNAME 99 # Length of filename strings. +define HDR_LEN 101 +define HDR_MAGZERO Memr[P2R($1)] # Magnitude zero point +define HDR_IMAGE Memc[P2C($1+1)] # Image name +define HDR_MASK Memc[P2C($1+51)] # Object mask name + +# Mask Flags. +define MASK_NUM 0077777777B # Mask number +define MASK_BNDRY 0100000000B # Boundary flag +define MASK_SPLIT 0200000000B # Split flag +define MASK_DARK 0400000000B # Dark flag + +define MSETFLAG ori($1,$2) +define MUNSETFLAG andi($1,noti($2)) + +define MNUM (andi($1,MASK_NUM)) +define MNOTDARK (andi($1,MASK_DARK)==0) +define MDARK (andi($1,MASK_DARK)!=0) +define MNOTSPLIT (andi($1,MASK_SPLIT)==0) +define MSPLIT (andi($1,MASK_SPLIT)!=0) +define MNOTBNDRY (andi($1,MASK_BNDRY)==0) +define MBNDRY (andi($1,MASK_BNDRY)!=0) + +# Output object masks types. +define OM_TYPES "|boolean|numbers|colors|all|" +define OM_BOOL 1 # Boolean (0=sky, 1=object+bad) +define OM_ONUM 2 # Object number only +define OM_COLORS 3 # Bad=1, Objects=2-9 +define OM_ALL 4 # All values diff --git a/noao/nproto/ace/acedetect.h b/noao/nproto/ace/acedetect.h new file mode 100644 index 00000000..111d324e --- /dev/null +++ b/noao/nproto/ace/acedetect.h @@ -0,0 +1,27 @@ +# ACEDETECT parameter structure. +define PAR_SZSTR 199 # Length of strings in par structure +define PAR_LEN 128 # Length of parameter structure + +define PAR_IMLIST Memi[$1+$2-1] # List of images (2) +define PAR_BPMLIST Memi[$1+$2+1] # List of bad pixel masks (2) +define PAR_SKYLIST Memi[$1+$2+3] # List of skys (2) +define PAR_SIGLIST Memi[$1+$2+5] # List of sigmas (2) +define PAR_EXPLIST Memi[$1+$2+7] # List of sigmas (2) +define PAR_GAINLIST Memi[$1+$2+9] # List of measurement gain maps (2) +define PAR_SCALELIST Memi[$1+$2+11] # List of scales (2) +define PAR_OMLIST Memi[$1+14] # List of object masks +define PAR_INCATLIST Memi[$1+15] # List of input catalogs +define PAR_OUTCATLIST Memi[$1+16] # List of output catalogs +define PAR_CATDEFLIST Memi[$1+17] # List of catalog definitions +define PAR_LOGLIST Memi[$1+18] # List of log files +define PAR_OUTSKYLIST Memi[$1+19] # List of output sky images +define PAR_OUTSIGLIST Memi[$1+20] # List of output sigma images + +define PAR_SKY Memi[$1+21] # Sky parameters +define PAR_DET Memi[$1+22] # Detection parameters +define PAR_SPT Memi[$1+23] # Split parameters +define PAR_GRW Memi[$1+24] # Grow parameters +define PAR_EVL Memi[$1+25] # Evaluate parameters + +define PAR_OMTYPE Memi[$1+26] # Output object mask type +define PAR_EXTNAMES Memc[P2C($1+27)] # Extensions names diff --git a/noao/nproto/ace/aceoverlay.x b/noao/nproto/ace/aceoverlay.x new file mode 100644 index 00000000..d8622568 --- /dev/null +++ b/noao/nproto/ace/aceoverlay.x @@ -0,0 +1,76 @@ +include <error.h> +include <imhdr.h> +include <imset.h> +include <pmset.h> +include "ace.h" + + +pointer procedure overlay (ovrly, im) + +char ovrly[ARB] #I Overlay name +pointer im #I Reference image +pointer ovr #O Overlay pointer + +int i, j, nc, nl, val +long v[2] +pointer sp, fname, pm, buf + +int nowhite(), andi() +bool pm_linenotempty() +pointer ods_pmmap(), imstati() + +begin + call smark (sp) + call salloc (fname, SZ_FNAME, TY_CHAR) + + if (nowhite (ovrly, Memc[fname], SZ_FNAME) == 0) { + call sfree (sp) + return (NULL) + } + + if (Memc[fname] == '!') { + iferr (call imgstr (im, Memc[fname+1], Memc[fname], SZ_FNAME)) { + call sfree (sp) + return (NULL) + } + } + + iferr (ovr = ods_pmmap (Memc[fname], im)) { + call sfree (sp) + call erract (EA_WARN) + return (NULL) + } + + nc = IM_LEN(ovr,1) + nl = IM_LEN(ovr,2) + pm = imstati (ovr, IM_PMDES) + + call salloc (buf, nc, TY_INT) + + v[1] = 1 + do i = 1, nl { + v[2] = i + if (!pm_linenotempty(pm, v)) + next + call pmglpi (pm, v, Memi[buf], 0, nc, 0) + do j = 0, nc-1 { + val = Memi[buf+j] + if (val == 0) + next + else if (val < NUMSTART) + val = 1 + else { + val = andi (val, MASK_BNDRY) + if (val != 0) + val = mod (andi (Memi[buf+j], MASK_NUM), 9) + 2 + #val = 1 + } + Memi[buf+j] = val + } + call pmplpi (pm, v, Memi[buf], 0, nc, PIX_SRC) + } + + call sfree (sp) + + return (ovr) +end diff --git a/noao/nproto/ace/acesky.h b/noao/nproto/ace/acesky.h new file mode 100644 index 00000000..5773f1a7 --- /dev/null +++ b/noao/nproto/ace/acesky.h @@ -0,0 +1,21 @@ +# Sky parameter structure. +define SKY_LEN 5 # Length of parameter structure + +define SKY_TYPE Memi[$1] # Type of sky algorithm +define SKY_NEWSKY Memi[$1+1] # Determine a new sky sigma? +define SKY_NEWSIG Memi[$1+2] # Determine a new sky sigma? +define SKY_SURPARS Memi[$1+3] # Pointer to parameters for surface fit +define SKY_BLKPARS Memi[$1+4] # Pointer to parameters for block stat + +define SKY_TYPES "|surface|block|" +define SKY_SURFACE 1 # Surface fitting +define SKY_BLOCK 2 # Block statistics + +define SKY_SURPARSLEN 7 # Length of parameter structure +define SKY_NSKYLINES Memi[$1] # Number of sky lines to sample +define SKY_SKYBLK1D Memi[$1+1] # Sky block size for 1D averages +define SKY_SKYHCLIP Memr[P2R($1+2)] # Sky fitting high sigma clip +define SKY_SKYLCLIP Memr[P2R($1+3)] # Sky fitting low sigma clip +define SKY_SKYXORDER Memi[$1+4] # Sky fitting x order +define SKY_SKYYORDER Memi[$1+5] # Sky fitting y order +define SKY_SKYXTERMS Memi[$1+6] # Sky fitting cross terms diff --git a/noao/nproto/ace/bndry.x b/noao/nproto/ace/bndry.x new file mode 100644 index 00000000..0abb0acd --- /dev/null +++ b/noao/nproto/ace/bndry.x @@ -0,0 +1,194 @@ +include <pmset.h> +include "ace.h" + + +# BNDRY -- Flag boundary pixels of unsplit objects. +# Assume the boundary flag is not set. + +procedure bndry (om, logfd) + +pointer om #I Object mask +int logfd #I Logfile + +int i, c, c1, c2, l, nc, nl, num, bndryval, val, vallast +pointer sp, v, irl, irlptr, orl, orlptr, bufs, buf1, buf2, buf3 + +int andi(), ori() + +begin + call smark (sp) + call salloc (v, PM_MAXDIM, TY_LONG) + + if (logfd != NULL) + call fprintf (logfd, " Set boundary mask:\n") + + call pm_gsize (om, nc, Meml[v], nl) + nc = Meml[v]; nl = Meml[v+1] + Meml[v] = 1 + + # Allocate buffers. + call salloc (irl, 3+3*nc, TY_INT) + call salloc (orl, 3+3*nc, TY_INT) + call salloc (bufs, 3, TY_POINTER) + call salloc (Memi[bufs], nc, TY_INT) + call salloc (Memi[bufs+1], nc, TY_INT) + call salloc (Memi[bufs+2], nc, TY_INT) + + Memi[orl+1] = nc + + # First line. + l = 1 + buf2 = Memi[bufs+mod(l,3)] + buf3 = Memi[bufs+mod(2,3)] + + Meml[v+1] = l + 1 + call pmglpi (om, Meml[v], Memi[buf3], 0, nc, 0) + Meml[v+1] = l + call pmglpi (om, Meml[v], Memi[buf2], 0, nc, 0) + call pmglri (om, Meml[v], Memi[irl], 0, nc, 0) + + irlptr = irl + orlptr = orl + do i = 2, Memi[irl] { + irlptr = irlptr + 3 + num = Memi[irlptr+2] + + if (num < NUMSTART || MSPLIT(num)) { + orlptr = orlptr + 3 + Memi[orlptr] = Memi[irlptr] + Memi[orlptr+1] = Memi[irlptr+1] + Memi[orlptr+2] = num + next + } + + bndryval = MSETFLAG (num, MASK_BNDRY) + c1 = Memi[irlptr] - 1 + c2 = c1 + Memi[irlptr+1] - 1 + do c = c1, c2 + Memi[buf2+c] = bndryval + + orlptr = orlptr + 3 + Memi[orlptr] = Memi[irlptr] + Memi[orlptr+1] = Memi[irlptr+1] + Memi[orlptr+2] = bndryval + } + Memi[orl] = 1 + (orlptr - orl) / 3 + call pmplri (om, Meml[v], Memi[orl], 0, nc, PIX_SRC) + + # Interior lines. + do l = 2, nl-1 { + buf1 = Memi[bufs+mod(l-1,3)] + buf2 = Memi[bufs+mod(l,3)] + buf3 = Memi[bufs+mod(l+1,3)] + + Meml[v+1] = l + 1 + call pmglpi (om, Meml[v], Memi[buf3], 0, nc, 0) + Meml[v+1] = l + call pmglri (om, Meml[v], Memi[irl], 0, nc, 0) + + irlptr = irl + orlptr = orl + do i = 2, Memi[irl] { + irlptr = irlptr + 3 + num = Memi[irlptr+2] + + if (num < NUMSTART || MSPLIT(num)) { + orlptr = orlptr + 3 + Memi[orlptr] = Memi[irlptr] + Memi[orlptr+1] = Memi[irlptr+1] + Memi[orlptr+2] = num + next + } + + c1 = Memi[irlptr] - 1 + c2 = c1 + Memi[irlptr+1] - 1 + bndryval = MSETFLAG (num, MASK_BNDRY) + + Memi[buf2+c1] = bndryval + + orlptr = orlptr + 3 + Memi[orlptr] = c1 + 1 + Memi[orlptr+2] = bndryval + vallast = bndryval + + do c = c1+1, c2-1 { + val = num + if (Memi[buf3+c-1] != num) + val = bndryval + else if (Memi[buf3+c] != num) + val = bndryval + else if (Memi[buf3+c+1] != num) + val = bndryval + else if (Memi[buf1+c-1] != num && Memi[buf1+c-1]!=bndryval) + val = bndryval + else if (Memi[buf1+c] != num && Memi[buf1+c] != bndryval) + val = bndryval + else if (Memi[buf1+c+1] != num && Memi[buf1+c+1]!=bndryval) + val = bndryval + + if (val == bndryval) + Memi[buf2+c] = val + + if (val != vallast) { + Memi[orlptr+1] = c - Memi[orlptr] + 1 + orlptr = orlptr + 3 + + Memi[orlptr] = c + 1 + Memi[orlptr+2] = val + vallast = val + } + } + + Memi[buf2+c2] = bndryval + + if (vallast != bndryval) { + Memi[orlptr+1] = c2 - Memi[orlptr] + 1 + orlptr = orlptr + 3 + Memi[orlptr] = c2 + 1 + Memi[orlptr+1] = 1 + Memi[orlptr+2] = bndryval + } else + Memi[orlptr+1] = c2 - Memi[orlptr] + 2 + } + + Memi[orl] = 1 + (orlptr - orl) / 3 + call pmplri (om, Meml[v], Memi[orl], 0, nc, PIX_SRC) + } + + # Last line. + l = nl + buf2 = Memi[bufs+mod(l,3)] + + Meml[v+1] = l + call pmglri (om, Meml[v], Memi[irl], 0, nc, 0) + + irlptr = irl + orlptr = orl + do i = 2, Memi[irl] { + irlptr = irlptr + 3 + num = Memi[irlptr+2] + + if (num < NUMSTART || MSPLIT(num)) { + orlptr = orlptr + 3 + Memi[orlptr] = Memi[irlptr] + Memi[orlptr+1] = Memi[irlptr+1] + Memi[orlptr+2] = num + next + } + + bndryval = MSETFLAG (num, MASK_BNDRY) + c1 = Memi[irlptr] - 1 + c2 = c1 + Memi[irlptr+1] - 1 + do c = c1, c2 + Memi[buf2+c] = bndryval + + orlptr = orlptr + 3 + Memi[orlptr] = Memi[irlptr] + Memi[orlptr+1] = Memi[irlptr+1] + Memi[orlptr+2] = bndryval + } + Memi[orl] = 1 + (orlptr - orl) / 3 + call pmplri (om, Meml[v], Memi[orl], 0, nc, PIX_SRC) + + call sfree (sp) +end diff --git a/noao/nproto/ace/cat.h b/noao/nproto/ace/cat.h new file mode 100644 index 00000000..39a7ed8a --- /dev/null +++ b/noao/nproto/ace/cat.h @@ -0,0 +1,45 @@ +# Catalog structure. +define CAT_SZSTR 99 # Length of catalog string +define CAT_LEN 160 # Length of catalog structure +define CAT_OBJS Memi[$1] # Array of objects (ptr) +define CAT_APFLUX Memi[$1+1] # Array of aperture fluxes (ptr) +define CAT_NOBJS Memi[$1+2] # Number of objects +define CAT_NUMMAX Memi[$1+3] # Maximum object number +define CAT_FLAGS Memi[$1+4] # Catalog flags +define CAT_HDR Memi[$1+5] # Header structure +define CAT_INTBL Memi[$1+6] # Input table structure +define CAT_OUTTBL Memi[$1+7] # Output table structure +define CAT_MAGZERO Memr[P2R($1+8)] # Magnitude zero +define CAT_CATALOG Memc[P2C($1+10)] # Catalog name +define CAT_OBJID Memc[P2C($1+60)] # Default ID +define CAT_STRPTR P2C($1+110) # Working string buffer +define CAT_STR Memc[CAT_STRPTR($1)] # Working string buffer + +# Table structure. +define TBL_LEN 2 +define TBL_TP Memi[$1] # Table pointer +define TBL_STP Memi[$1+1] # Symbol table of entries + +# Entry structure. +define ENTRY_ULEN 19 # Length of units string +define ENTRY_FLEN 19 # Length of format string +define ENTRY_DLEN 99 # Length of description string +define ENTRY_LEN 95 # Length of entry structure +define ENTRY_CDEF Memi[$1] # Column descriptor +define ENTRY_ID Memi[$1+1] # Entry id +define ENTRY_TYPE Memi[$1+2] # Datatype in object record +define ENTRY_CTYPE Memi[$1+3] # Datatype in catalog +define ENTRY_FUNC Memi[$1+4] # Entry function +define ENTRY_RAP Memr[P2R($1+5)] # Entry aperture radius +define ENTRY_UNITS Memc[P2C($1+6)] # Entry units (19) +define ENTRY_FORMAT Memc[P2C($1+26)] # Entry format (19) +define ENTRY_DESC Memc[P2C($1+46)] # Entry description (99) + +define FUNCS "|MAG|" +define FUNC_MAG 1 # Magnitude + +# Catalog extensions. +define CATEXTNS "|fits|tab|" + +# Catalog Parameters. +define CATPARAMS "|image|mask|objid|catalog|nobjects|magzero|" diff --git a/noao/nproto/ace/catdef.desc b/noao/nproto/ace/catdef.desc new file mode 100644 index 00000000..2c1a989c --- /dev/null +++ b/noao/nproto/ace/catdef.desc @@ -0,0 +1,73 @@ +# This describes the currently available catalog definition entries +# available and the format. + +# Comments begining with '#' are ignored. +# Order of lines determines order in catalog. +# Case is ignored though labels in catalog will be as given in file. + +ACE_NAME [OPTIONAL USER NAME FOR CATALOG] + +# There are a few functions currently available. + +MAG(ACE_NAME) +APFLUX(radius_in_pixels) +MAG(APFLUX(radius_in_pixels)) + + +# Basic quantities. +NUM Object number +PNUM Parent number (0 if original detection) +NPIX Number of pixels +NDETECT Number of detected pixels (before growing) +FLAGS Flags (currently on M for multiple object) + +# Fluxes +FLUX Isophotal flux +FRACFLUX Apportioned flux (TOTMAG) +APFLUX(radius) Aperture fluxes (radius in pixels) +SKY Mean sky +PEAK Peak pixel value above sky +ISIGAVG Average (I - sky) / sig +ISIGMAX Maximum (I - sky) / sig + +# Positions +WX X world coordinate (requires WCS in header) +WY Y world coordinate (requires WCS in header) +X1 X centroid (pixels) +Y1 Y centroid (pixels) +XAP X aperture coordinate (centroid initially then not changed) +YAP Y aperture coordinate (centroid initially then not changed) +XMIN Minimum X (pixels) +XMAX Maxium X (pixels) +YMIN Minimum Y (pixels) +YMAX Maxium Y (pixels) + +# Miscellaneous +SIG Mean sky sigma +FRAC Apportioned fraction + +X2 X 2nd moment (pixels) +Y2 Y 2nd moment (pixels) +XY X 2nd cross moment (pixels) + +# Derived quantities. +A Semimajor axis +B Semiminor axis +THETA Position angle (degrees) +ELONG Elongation = A/B +ELLIP Ellipticity = 1 - B/A +R Second moment radius (pixels) +CXX Second moment ellipse (pixels) +CYY Second moment ellipse (pixels) +CXY Second moment ellipse (pixels) + +# Error estimates. +FLUXERR Error in flux +XERR Error in X centroid (pixels) +YERR Error in Y centroid (pixels) +AERR Error in A +BERR Error in B +THETAERR Error in THETA (degrees) +CXXERR Error in CXX (pixels) +CYYERR Error in CYY (pixels) +CXYERR Error in CXY (pixels) diff --git a/noao/nproto/ace/catdefine.x b/noao/nproto/ace/catdefine.x new file mode 100644 index 00000000..038f85d9 --- /dev/null +++ b/noao/nproto/ace/catdefine.x @@ -0,0 +1,192 @@ +include "ace.h" +include "cat.h" +include "objs.h" + + +define CATDEF "ace$lib/catdef.dat" + +# CATDEF -- Read catalog definition file and create symbol table. + +procedure catdefine (tbl, mode, catdef) + +pointer tbl #I Table pointer +int mode #I Table access mode +char catdef[ARB] #I Catalog definition file + +int i, n, fd, args, func, ncols +pointer sp, fname, name, label, str, entry, sym +pointer stp1, stp2, tp + +bool strne() +int open(), fscan(), nscan(), strncmp(), ctoi(), ctor() +int stridxs(), strldxs(), strdic() +pointer stopen(), stenter(), stfind(), sthead(), stnext(), stname() +errchk open, stopen, tbcdef1, tbcfnd1 + +define err_ 10 + +begin + call smark (sp) + call salloc (fname, SZ_FNAME, TY_CHAR) + call salloc (name, SZ_FNAME, TY_CHAR) + call salloc (label, SZ_LINE, TY_CHAR) + call salloc (str, SZ_LINE, TY_CHAR) + call salloc (entry, ENTRY_LEN, TY_STRUCT) + call aclri (Memi[entry], ENTRY_LEN) + + # Build a symbol table from ace$objs.h. + fd = open ("ace$src/objs.h", READ_ONLY, TEXT_FILE) + stp1 = stopen ("catdefine", 100, ENTRY_LEN, SZ_LINE) + while (fscan(fd) != EOF) { + Memc[fname] = EOS + call gargwrd (Memc[fname], SZ_FNAME) + if (strne (Memc[fname], "define")) + next + call gargwrd (Memc[name], SZ_FNAME) + if (strncmp (Memc[name], "ID_", 3) != 0) + next + call gargi (ENTRY_ID(entry)) + call gargwrd (Memc[label], SZ_LINE) + if (Memc[label] != '#') + next + call gargwrd (Memc[label], SZ_LINE) + call gargwrd (ENTRY_UNITS(entry), ENTRY_ULEN) + call gargwrd (ENTRY_FORMAT(entry), ENTRY_FLEN) + call gargstr (ENTRY_DESC(entry), ENTRY_DLEN) + if (nscan() < 7) + next + switch (Memc[label]) { + case 'i': + ENTRY_TYPE(entry) = TY_INT + case 'r': + ENTRY_TYPE(entry) = TY_REAL + case 'd': + ENTRY_TYPE(entry) = TY_DOUBLE + default: + i = 1 + if (ctoi (Memc[label], i, ENTRY_TYPE(entry)) == 0) + next + ENTRY_TYPE(entry) = -ENTRY_TYPE(entry) + } + ENTRY_CTYPE(entry) = ENTRY_TYPE(entry) + sym = stenter (stp1, Memc[name+3], ENTRY_LEN) + call amovi (Memi[entry], Memi[sym], ENTRY_LEN) + } + call close (fd) + + if (tbl != NULL) + tp = TBL_TP(tbl) + + # Read the definition file. + if (catdef[1] == EOS) + call strcpy (CATDEF, Memc[fname], SZ_FNAME) + else + call strcpy (catdef, Memc[fname], SZ_FNAME) + fd = open (Memc[fname], READ_ONLY, TEXT_FILE) + stp2 = stopen ("catdefine", 100, ENTRY_LEN, SZ_LINE) + ncols = 0 + while (fscan(fd) != EOF) { + call gargwrd (Memc[name], SZ_FNAME) + call gargwrd (Memc[label], SZ_LINE) + n = nscan() + if (n == 0) + next + if (Memc[name] == '#') + next + + # Parse the name. + call strcpy (Memc[name], Memc[str], SZ_LINE) + call strupr (Memc[str]) + args = stridxs ("(", Memc[str]) + 1 + if (args > 1) { + i = strldxs (")", Memc[str]) + Memc[str+args-2] = EOS + Memc[str+i-1] = EOS + func = strdic (Memc[str], Memc[fname], SZ_FNAME, FUNCS) + if (func == 0) { + call strcpy (Memc[name], Memc[str], SZ_LINE) + call strupr (Memc[str]) + } else + call strcpy (Memc[str+args-1], Memc[str], SZ_LINE) + + args = stridxs ("(", Memc[str]) + 1 + if (args > 1) { + i = strldxs (")", Memc[str]) + Memc[str+args-2] = EOS + Memc[str+i-1] = EOS + sym = stfind (stp1, Memc[str]) + } else + sym = stfind (stp1, Memc[str]) + } else { + sym = stfind (stp1, Memc[str]) + func = 0 + } + + if (sym == NULL) { +err_ + call stclose (stp1) + call stclose (stp2) + call close (fd) + call sprintf (Memc[label], SZ_LINE, + "Unknown or ambiguous catalog quantity `%s' in definition file `%s'") + call pargstr (Memc[name]) + call pargstr (Memc[fname]) + call error (1, Memc[label]) + } + ncols = ncols + 1 + if (tbl == NULL) + next + + if (n == 1) + call strcpy (Memc[name], Memc[label], SZ_LINE) + + entry = stenter (stp2, Memc[label], ENTRY_LEN) + call amovi (Memi[sym], Memi[entry], ENTRY_LEN) + ENTRY_FUNC(entry) = func + + switch (ENTRY_FUNC(entry)) { + case FUNC_MAG: + ENTRY_CTYPE(entry) = TY_REAL + call strcpy ("magnitudes", ENTRY_UNITS(entry), ENTRY_ULEN) + ENTRY_FORMAT(entry) = EOS + } + + if (mode == NEW_FILE) + call tbcdef1 (tp, ENTRY_CDEF(entry), Memc[label], + ENTRY_UNITS(sym), ENTRY_FORMAT(sym), ENTRY_CTYPE(sym), 1) + else + call tbcfnd1 (tp, Memc[label], ENTRY_CDEF(entry)) + + # Get arguments. + switch (ENTRY_ID(entry)) { + case ID_APFLUX: + if (ctor (Memc[name], args, ENTRY_RAP(entry)) == 0) + goto err_ + } + } + call close (fd) + call stclose (stp1) + + if (tbl == NULL) + return + + if (ncols == 0) { + call stclose (stp2) + call sprintf (Memc[label], SZ_LINE, + "No catalog quantity definitions in file `%s'") + call pargstr (Memc[fname]) + call error (1, Memc[label]) + } + + # Reverse order of symbol table. + stp1 = stopen ("catdef", ncols, ENTRY_LEN, SZ_LINE) + for (sym=sthead(stp2); sym!=NULL; sym=stnext(stp2,sym)) { + entry = stenter (stp1, Memc[stname(stp2,sym)], ENTRY_LEN) + call amovi (Memi[sym], Memi[entry], ENTRY_LEN) + } + call stclose (stp2) + + TBL_STP(tbl) = stp1 + + call sfree (sp) +end diff --git a/noao/nproto/ace/catio.x b/noao/nproto/ace/catio.x new file mode 100644 index 00000000..1fbae947 --- /dev/null +++ b/noao/nproto/ace/catio.x @@ -0,0 +1,931 @@ +include <imset.h> +#include <tbset.h> +define TBL_NROWS 0 +include <math.h> +include "ace.h" +include "cat.h" +include "objs.h" + + +# CATOPEN -- Open a catalog. +# This may be used just to allocate the structure or to actually open +# a catalog file. It does not read the objects. Use catrobjs. + +procedure catopen (cat, input, output, catdef) + +pointer cat #U Catalog structure +char input[ARB] #I Input catalog name +char output[ARB] #I Output catalog name +char catdef[ARB] #I Catalog definition file + +pointer tbl + +bool streq() +pointer tbtopn() + +begin + if (cat == NULL) + call calloc (cat, CAT_LEN, TY_STRUCT) + + if (input[1] == EOS && output[1] == EOS) + return + + if (streq (input, output)) { # READ_WRITE + call calloc (tbl, TBL_LEN, TY_STRUCT) + CAT_INTBL(cat) = tbl + CAT_OUTTBL(cat) = tbl + + TBL_TP(tbl) = tbtopn (input, READ_WRITE, 0) + call catdefine (tbl, READ_ONLY, catdef) + call catrhdr (cat) + } else if (output[1] == EOS) { # READ_ONLY + call calloc (tbl, TBL_LEN, TY_STRUCT) + CAT_INTBL(cat) = tbl + CAT_OUTTBL(cat) = NULL + + TBL_TP(tbl) = tbtopn (input, READ_ONLY, 0) + call catdefine (tbl, READ_ONLY, catdef) + call catrhdr (cat) + } else if (input[1] == EOS) { # NEW_FILE + call calloc (tbl, TBL_LEN, TY_STRUCT) + CAT_INTBL(cat) = NULL + CAT_OUTTBL(cat) = tbl + + TBL_TP(tbl) = tbtopn (output, NEW_FILE, 0) + call catdefine (tbl, NEW_FILE, catdef) + } else { # NEW_COPY + call calloc (tbl, TBL_LEN, TY_STRUCT) + CAT_INTBL(cat) = tbl + + TBL_TP(tbl) = tbtopn (input, READ_ONLY, 0) + call catdefine (tbl, NEW_COPY, catdef) + call catrhdr (cat) + + call calloc (tbl, TBL_LEN, TY_STRUCT) + CAT_OUTTBL(cat) = tbl + TBL_TP(tbl) = tbtopn (output, NEW_COPY, TBL_TP(CAT_INTBL(cat))) + call catdefine (tbl, NEW_COPY, catdef) + } +end + + +procedure catcreate (cat) + +pointer cat #I Catalog structure + +pointer tbl, tp + +begin + if (cat == NULL) + return + tbl = CAT_OUTTBL(cat) + if (tbl == NULL) + return + tp = TBL_TP(tbl) + if (tp == NULL) + return + if (CAT_INTBL(cat) != NULL) { + if (tp == TBL_TP(CAT_INTBL(cat))) + return + } + call tbtcre (tp) +end + + +# CATCLOSE -- Close a catalog. + +procedure catclose (cat) + +pointer cat #I Catalog pointer + +int i +pointer tbl, objs + +begin + if (cat == NULL) + return + + tbl = CAT_INTBL(cat) + if (tbl != NULL) { + if (TBL_STP(tbl) != NULL) + call stclose (TBL_STP(tbl)) + if (tbl == CAT_OUTTBL(cat)) + CAT_OUTTBL(cat) = NULL + call tbtclo (TBL_TP(tbl)) + } + tbl = CAT_OUTTBL(cat) + if (tbl != NULL) { + if (TBL_STP(tbl) != NULL) + call stclose (TBL_STP(tbl)) + call tbtclo (TBL_TP(tbl)) + } + + objs = CAT_OBJS(cat) + if (objs != NULL) { + do i = 0, CAT_NUMMAX(cat)-1 + call mfree (Memi[objs+i], TY_STRUCT) + } + + call mfree (CAT_APFLUX(cat), TY_REAL) + call mfree (CAT_OBJS(cat), TY_POINTER) + call mfree (CAT_INTBL(cat), TY_STRUCT) + call mfree (CAT_OUTTBL(cat), TY_STRUCT) + call mfree (CAT_HDR(cat), TY_STRUCT) + call mfree (cat, TY_STRUCT) +end + + +# CATGETS -- Get a string parameter from the catalog header. + +procedure catgets (cat, param, value, maxchar) + +pointer cat #I Catalog pointer +char param[ARB] #I Parameter to get +char value[ARB] #O Returned value +int maxchar #I Maximum characters in value + +int i, strdic() + +begin + value[1] = EOS + + if (cat == NULL) + return + + i = strdic (param, CAT_STR(cat), CAT_SZSTR, CATPARAMS) + switch (i) { + case 1: + if (CAT_HDR(cat) == NULL) + i = 0 + else + call strcpy (HDR_IMAGE(CAT_HDR(cat)), value, maxchar) + case 2: + if (CAT_HDR(cat) == NULL) + i = 0 + else + call strcpy (HDR_MASK(CAT_HDR(cat)), value, maxchar) + case 3: + call strcpy (CAT_OBJID(cat), value, maxchar) + case 4: + call strcpy (CAT_CATALOG(cat), value, maxchar) + default: + call sprintf (CAT_STR(cat), CAT_SZSTR, + "catgets: unknown catalog parameter `%s'") + call pargstr (param) + call error (1, CAT_STR(cat)) + } + + if (i == 0) { + call sprintf (CAT_STR(cat), CAT_SZSTR, + "catgets: parameter `%s' not found") + call pargstr (param) + call error (1, CAT_STR(cat)) + } +end + + +procedure catgeti (cat, param, value) + +pointer cat #I Catalog pointer +char param[ARB] #I Parameter to get +int value #O Returned value + +int i, strdic() + +begin + value = INDEFI + + if (cat == NULL) + return + + i = strdic (param, CAT_STR(cat), CAT_SZSTR, CATPARAMS) + switch (i) { + case 5: + value = CAT_NOBJS(cat) + default: + call sprintf (CAT_STR(cat), CAT_SZSTR, + "catgeti: unknown catalog parameter `%s'") + call pargstr (param) + call error (1, CAT_STR(cat)) + } +end + + +procedure catputs (cat, param, value) + +pointer cat #I Catalog pointer +char param[ARB] #I Parameter to get +char value[ARB] #I Value + +int i, strdic() + +begin + if (cat == NULL) + return + + i = strdic (param, CAT_STR(cat), CAT_SZSTR, CATPARAMS) + switch (i) { + case 0: + call sprintf (CAT_STR(cat), CAT_SZSTR, + "catgets: unknown catalog parameter `%s'") + call pargstr (param) + call error (1, CAT_STR(cat)) + case 1: + if (CAT_HDR(cat) == NULL) + call calloc (CAT_HDR(cat), HDR_LEN, TY_STRUCT) + call strcpy (value, HDR_IMAGE(CAT_HDR(cat)), HDR_SZFNAME) + case 2: + if (CAT_HDR(cat) == NULL) + call calloc (CAT_HDR(cat), HDR_LEN, TY_STRUCT) + call strcpy (value, HDR_MASK(CAT_HDR(cat)), HDR_SZFNAME) + case 3: + call strcpy (value, CAT_OBJID(cat), CAT_SZSTR) + case 4: + call strcpy (value, CAT_CATALOG(cat), CAT_SZSTR) + } +end + + +procedure catputr (cat, param, value) + +pointer cat #I Catalog pointer +char param[ARB] #I Parameter to get +real value #I Value + +int i, strdic() + +begin + if (cat == NULL) + return + + i = strdic (param, CAT_STR(cat), CAT_SZSTR, CATPARAMS) + switch (i) { + case 6: + if (CAT_HDR(cat) == NULL) + call calloc (CAT_HDR(cat), HDR_LEN, TY_STRUCT) + HDR_MAGZERO(CAT_HDR(cat)) = value + default: + call sprintf (CAT_STR(cat), CAT_SZSTR, + "catgetr: unknown catalog parameter `%s'") + call pargstr (param) + call error (1, CAT_STR(cat)) + } +end + + +procedure catrobjs (cat, filt) + +pointer cat #I Catalog pointer +char filt[ARB] #I Filter string + +int i, num, nrows, nobjs, nummax, nalloc, tbpsta() +pointer tbl, tp, objs, obj +bool filter() + +begin + if (cat == NULL) + return + + tbl = CAT_INTBL(cat) + if (tbl == NULL) + return + tp = TBL_TP(tbl) + + nrows = tbpsta (tp, TBL_NROWS) + nalloc = nrows + NUMSTART - 1 + call calloc (objs, nalloc, TY_POINTER) + + nobjs = 0 + nummax = 0 + obj = NULL + do i = 1, nrows { + call catrobj (cat, obj, i) + if (!filter (obj, filt)) + next + num = OBJ_NUM(obj) + if (num > nalloc) { + nalloc = nalloc + 1000 + call realloc (objs, nalloc, TY_POINTER) + call aclri (Memi[objs+nalloc-1000], 1000) + } + if (Memi[objs+num-1] == NULL) + nobjs = nobjs + 1 + nummax = max (num, nummax) + Memi[objs+num-1] = obj + obj = NULL + } + + CAT_OBJS(cat) = objs + CAT_NOBJS(cat) = nobjs + CAT_NUMMAX(cat) = nummax +end + + +procedure catrobj (cat, obj, row) + +pointer cat #I Catalog pointer +pointer obj #U Object pointer +int row #I Table row + +int id, type, ori() +pointer tbl, tp, stp, sym, cdef, sthead(), stnext() + +begin + if (cat == NULL) + return + + tbl = CAT_INTBL(cat) + if (tbl == NULL) + return + + tp = TBL_TP(tbl) + stp = TBL_STP(tbl) + + if (obj == NULL) + call calloc (obj, OBJ_LEN, TY_STRUCT) + + for (sym=sthead(stp); sym!=NULL; sym=stnext(stp,sym)) { + id = ENTRY_ID(sym) + if (id > 1000 || id == ID_APFLUX) + next + switch (id) { + case ID_FLAGS: + OBJ_FLAGS(obj) = 0 + ifnoerr (call tbegtt (tp, cdef, row, CAT_STR(cat), CAT_SZSTR)) { + if (Memc[CAT_STRPTR(cat)] == 'M') + SETFLAG(obj,OBJ_SPLIT) + } + next + } + + type = ENTRY_TYPE(sym) + cdef = ENTRY_CDEF(sym) + switch (type) { + case TY_INT: + iferr (call tbegti (tp, cdef, row, OBJI(obj,id))) + OBJI(obj,id) = INDEFI + case TY_REAL: + iferr (call tbegtr (tp, cdef, row, OBJR(obj,id))) + OBJR(obj,id) = INDEFR + case TY_DOUBLE: + iferr (call tbegtd (tp, cdef, row, OBJD(obj,id))) + OBJD(obj,id) = INDEFD + default: + iferr (call tbegtt (tp, cdef, row, OBJC(obj,id), -type)) + OBJC(obj,id) = EOS + } + } + + OBJ_ROW(obj) = row +end + + +procedure catwobj (cat, obj, row) + +pointer cat #I Catalog pointer +pointer obj #I Object pointer +int row #I Table row + +int ival +real rval +double dval +pointer sval + +int id, type, func, napr, andi() +real magzero, a, b, theta, elong, ellip, r, cxx, cyy, cxy +real aerr, berr, thetaerr, cxxerr, cyyerr, cxyerr +bool doshape +pointer tbl, tp, stp, sym, cdef, sthead(), stnext() + +begin + if (obj == NULL) + return + + tbl = CAT_OUTTBL(cat) + if (tbl == NULL) + return + tp = TBL_TP(tbl) + stp = TBL_STP(tbl) + + #call sprintf (CAT_STR(cat), CAT_SZSTR, "%s-%d") + # if (OBJ_OBJID(obj) != NULL) + # call pargstr (Memc[OBJ_OBJID(obj)]) + # else + # call pargstr (CAT_OBJID(cat)) + # call pargi (OBJ_NUM(obj)) + #call tbeptt (tp, TBL_BJID(tbl), row, CAT_STR(cat)) + #call tbeptt (tp, TBL_CLASS(tbl), row, OBJ_CLASS(obj)) + + magzero = CAT_MAGZERO(cat) + if (IS_INDEFR(magzero)) + magzero = 0. + sval = CAT_STRPTR(cat) + napr = 0 + doshape = false + for (sym=sthead(stp); sym!=NULL; sym=stnext(stp,sym)) { + id = ENTRY_ID(sym) + func = ENTRY_FUNC(sym) + type = ENTRY_TYPE(sym) + cdef = ENTRY_CDEF(sym) + if (id > 1000) { + switch (id) { + case ID_A, ID_B, ID_THETA, ID_ELONG, ID_ELLIP, ID_R, ID_CXX, + ID_CYY, ID_CXY: + if (!doshape) { + call catshape (obj, a, b, theta, elong, ellip, r, + cxx, cyy, cxy, aerr, berr, thetaerr, cxxerr, + cyyerr, cxyerr) + doshape = true + } + switch (id) { + case ID_A: + rval = a + case ID_B: + rval = b + case ID_THETA: + rval = theta + case ID_ELONG: + rval = elong + case ID_ELLIP: + rval = ellip + case ID_R: + rval = r + case ID_CXX: + rval = cxx + case ID_CYY: + rval = cyy + case ID_CXY: + rval = cxy + } + case ID_FLUXERR, ID_XERR, ID_YERR: + switch (id) { + case ID_FLUXERR: + rval = OBJ_FLUXVAR(obj) + case ID_XERR: + rval = OBJ_XVAR(obj) + case ID_YERR: + rval = OBJ_YVAR(obj) + } + if (IS_INDEFR(rval) || rval < 0.) + rval = INDEFR + else + rval = sqrt (rval) + case ID_AERR, ID_BERR, ID_THETAERR, ID_CXXERR, ID_CYYERR, + ID_CXYERR: + if (!doshape) { + call catshape (obj, a, b, theta, elong, ellip, r, + cxx, cyy, cxy, aerr, berr, thetaerr, cxxerr, + cyyerr, cxyerr) + doshape = true + } + switch (id) { + case ID_AERR: + rval = aerr + case ID_BERR: + rval = aerr + case ID_THETAERR: + rval = aerr + case ID_CXXERR: + rval = aerr + case ID_CYYERR: + rval = aerr + case ID_CXYERR: + rval = aerr + } + } + } else if (id == ID_FLAGS) { + if (SPLIT(obj)) + call strcpy ("M", Memc[sval], SZ_LINE) + else + call strcpy ("-", Memc[sval], SZ_LINE) + } else if (id == ID_APFLUX) { + if (OBJ_APFLUX(obj) == NULL) + rval = INDEFR + else { + rval = Memr[OBJ_APFLUX(obj)+napr] + napr = napr + 1 + } + } else { + switch (type) { + case TY_INT: + ival = OBJI(obj,id) + case TY_REAL: + rval = OBJR(obj,id) + case TY_DOUBLE: + dval = OBJD(obj,id) + default: + call strcpy (OBJC(obj,id), Memc[sval], SZ_LINE) + } + } + + # Apply function. + if (func > 0) { + if (ENTRY_CTYPE(sym) != type) { + # For now all function types are real. + switch (type) { + case TY_INT: + rval = ival + case TY_DOUBLE: + rval = dval + } + } + type = ENTRY_CTYPE(sym) + switch (func) { + case FUNC_MAG: + if (!IS_INDEFR(rval)) { + if (rval <= 0.) + rval = INDEFR + else + rval = -2.5 * log10 (rval) + magzero + } + } + } + + # Write to catalog. + switch (type) { + case TY_INT: + call tbepti (tp, cdef, row, ival) + case TY_REAL: + call tbeptr (tp, cdef, row, rval) + case TY_DOUBLE: + call tbeptd (tp, cdef, row, dval) + default: + call tbeptt (tp, cdef, row, Memc[sval]) + } + } + OBJ_ROW(obj) = row +end + + +# CATWCS -- Set catalog WCS information. + +procedure catwcs (cat, im) + +pointer cat #I Catalog pointer +pointer im #I IMIO pointer + +int i +pointer sp, axtype, label, units, format +pointer mw, tbl, tp, stp, sym, cdef + +bool streq() +pointer mw_openim(), sthead(), stnext(), stname() +errchk mw_openim + +begin + if (cat == NULL) + return + if (CAT_OUTTBL(cat) == NULL) + return + + call smark (sp) + call salloc (axtype, SZ_FNAME, TY_CHAR) + call salloc (label, SZ_FNAME, TY_CHAR) + call salloc (units, SZ_FNAME, TY_CHAR) + call salloc (format, SZ_FNAME, TY_CHAR) + + tbl = CAT_OUTTBL(cat) + tp = TBL_TP(tbl) + stp = TBL_STP(tbl) + + mw = mw_openim (im) + do i = 1, 2 { + iferr (call mw_gwattrs (mw, i, "axtype", Memc[axtype], SZ_FNAME)) + Memc[axtype] = EOS + iferr (call mw_gwattrs (mw, i, "label", Memc[label], SZ_FNAME)) { + if (streq (Memc[axtype], "ra")) + call strcpy ("RA", Memc[label], SZ_FNAME) + else if (streq (Memc[axtype], "dec")) + call strcpy ("DEC", Memc[label], SZ_FNAME) + else + Memc[label] = EOS + } + iferr (call mw_gwattrs (mw, i, "units", Memc[units], SZ_FNAME)) { + if (streq (Memc[axtype], "ra") || streq (Memc[axtype], "dec")) + call strcpy ("deg", Memc[units], SZ_FNAME) + else + Memc[units] = EOS + } + iferr (call mw_gwattrs (mw, i, "format", Memc[format], SZ_FNAME)) { + if (streq (Memc[axtype], "ra")) + call strcpy ("%.2H", Memc[format], SZ_FNAME) + else if (streq (Memc[axtype], "dec")) + call strcpy ("%.1h", Memc[format], SZ_FNAME) + else + Memc[format] = EOS + } + + if (i == 1) { + for (sym=sthead(stp); sym!=NULL; sym=stnext(stp,sym)) { + if (ENTRY_ID(sym) != ID_WX) + next + if (!(streq (Memc[stname(stp,sym)], "WX") || + streq (Memc[stname(stp,sym)], "wx"))) + Memc[label] = EOS + break + } + } else { + for (sym=sthead(stp); sym!=NULL; sym=stnext(stp,sym)) { + if (ENTRY_ID(sym) != ID_WY) + next + if (!(streq (Memc[stname(stp,sym)], "WY") || + streq (Memc[stname(stp,sym)], "wy"))) + Memc[label] = EOS + break + } + } + + if (sym != NULL) { + cdef = ENTRY_CDEF(sym) + if (Memc[label] != EOS) + call tbcnam (tp, cdef, Memc[label]) + if (Memc[units] != EOS) + call tbcnit (tp, cdef, Memc[units]) + if (Memc[format] != EOS) + call tbcfmt (tp, cdef, Memc[format]) + } + } + call mw_close (mw) + + call sfree (sp) +end + + +procedure catrhdr (cat) + +pointer cat #I Catalog pointer + +pointer tp, hdr + +begin + if (cat == NULL) + return + + if (CAT_HDR(cat) != NULL) + call mfree (CAT_HDR(cat), TY_STRUCT) + if (CAT_INTBL(cat) == NULL) + return + tp = TBL_TP(CAT_INTBL(cat)) + + call calloc (CAT_HDR(cat), HDR_LEN, TY_STRUCT) + hdr = CAT_HDR(cat) + + iferr (call tbhgtt (tp, "IMAGE", HDR_IMAGE(hdr), HDR_SZFNAME)) + HDR_IMAGE(hdr) = EOS + iferr (call tbhgtt (tp, "MASK", HDR_MASK(hdr), HDR_SZFNAME)) + HDR_MASK(hdr) = EOS + iferr (call tbhgtr (tp, "MAGZERO", HDR_MAGZERO(hdr))) + HDR_MAGZERO(hdr) = INDEFR +end + + +procedure catwhdr (cat, im) + +pointer cat #I Catalog pointer +pointer im #I Image pointer + +pointer tp, hdr + +begin + if (cat == NULL) + return + + tp = CAT_OUTTBL(cat) + hdr = CAT_HDR(cat) + if (tp == NULL || hdr == NULL) + return + tp = TBL_TP(tp) + + if (HDR_IMAGE(hdr) != EOS) + call tbhadt (tp, "IMAGE", HDR_IMAGE(hdr)) + if (HDR_MASK(hdr) != EOS) + call tbhadt (tp, "MASK", HDR_MASK(hdr)) + if (!IS_INDEFR(HDR_MAGZERO(hdr))) + call tbhadr (tp, "MAGZERO", HDR_MAGZERO(hdr)) +end + + +procedure catwobjs (cat) + +pointer cat #I Catalog pointer + +int i, j +pointer objs, obj + +begin + if (cat == NULL) + return + if (CAT_OUTTBL(cat) == NULL) + return + if (CAT_OBJS(cat) == NULL) + return + + objs = CAT_OBJS(cat) + j = 0 + do i = 1, CAT_NUMMAX(cat) { + obj = Memi[objs+i-1] + if (obj == NULL) + next + j = j + 1 + call catwobj (cat, obj, j) + } +end + + + +procedure catdump (cat) + +pointer cat #I Catalog pointer + +int i +pointer objs, obj + +begin + if (CAT_OBJS(cat) == NULL) + return + + objs = CAT_OBJS(cat) + do i = 1, CAT_NUMMAX(cat) { + obj = Memi[objs+i-1] + if (obj == NULL) + next + + call printf ("%d %d %g %g\n") + call pargi (OBJ_NUM(obj)) + call pargi (OBJ_NPIX(obj)) + call pargr (OBJ_XAP(obj)) + call pargr (OBJ_YAP(obj)) + } +end + + +# CATGOBJ -- Get object given the object number. +# +# Currently this relies on the object pointer array being indexed by +# object number. + +pointer procedure catgobj (cat, num) + +pointer cat #I Catalog +int num #I Object number + +begin + return (Memi[CAT_OBJS(cat)+num-1]) +end + + +# These currently work on the object number but eventually there will be +# an array of indices to allow traversing the objects in some sorted order. + +pointer procedure cathead (cat) + +pointer cat #I Catalog pointer + +int i +pointer objs, obj + +begin + objs = CAT_OBJS(cat) + do i = 0, CAT_NUMMAX(cat)-1 { + obj = Memi[objs+i] + if (obj != NULL) + return (obj) + } + return (NULL) +end + + +pointer procedure catnext (cat, obj) + +pointer cat #I Catalog pointer +pointer obj #I Input object pointer + +int i +pointer objs, objnext + +begin + if (obj == NULL) + return (NULL) + + objs = CAT_OBJS(cat) + do i = OBJ_NUM(obj), CAT_NUMMAX(cat)-1 { + objnext = Memi[objs+i] + if (objnext != NULL) + return (objnext) + } + return (NULL) +end + + +procedure catshape (obj, a, b, theta, elong, ellip, r, cxx, cyy, cxy, + aerr, berr, thetaerr, cxxerr, cyyerr, cxyerr) + +pointer obj #I Object structure +real a #O Semimajor axis based on second moments +real b #O Semiminor axis based on second moments +real theta #O Position angle based on second moments +real elong #O Elongation (A/B) +real ellip #O Ellipticity (1 - B/A) +real r #O Radius based on second moments +real cxx, cyy, cxy #O Ellipse parameters based on second moments +real aerr, berr, thetaerr #O Errors +real cxxerr, cyyerr, cxyerr #O Errors + +bool doerr +real x2, y2, xy, r2, d, f +real xvar, yvar, xycov, rvar, dvar, fvar + +begin + a = INDEFR + b = INDEFR + theta = INDEFR + elong = INDEFR + ellip = INDEFR + r = INDEFR + aerr = INDEFR + berr = INDEFR + thetaerr = INDEFR + cxxerr = INDEFR + cyyerr = INDEFR + cxyerr = INDEFR + + x2 = OBJ_X2(obj) + y2 = OBJ_Y2(obj) + xy = OBJ_XY(obj) + xvar = OBJ_XVAR(obj) + yvar = OBJ_YVAR(obj) + xycov = OBJ_XYCOV(obj) + + if (IS_INDEFR(x2) || IS_INDEFR(y2) || IS_INDEFR(xy)) + return + + r2 = x2 + y2 + if (r2 < 0.) + return + + doerr = !(IS_INDEF(xvar) || IS_INDEF(yvar) || IS_INDEF(xycov)) + if (doerr) { + rvar = xvar + yvar + if (rvar < 0.) + doerr = false + } + + r = sqrt (r2) + + d = x2 - y2 + theta = RADTODEG (atan2 (2 * xy, d) / 2.) + + if (doerr) { + dvar = xvar - yvar + thetaerr = atan2 (2 * xycov, dvar) / 2. + if (thetaerr < 0.) + thetaerr = INDEF + else + thetaerr = DEGTORAD (sqrt (thetaerr)) + } + + f = sqrt (d**2 + 4 * xy**2) + if (f > r2) + return + + if (doerr) { + fvar = sqrt (dvar**2 + 4 * xycov**2) + if (fvar > rvar) + doerr = false + } + + a = sqrt ((r2 + f) / 2) + b = sqrt ((r2 - f) / 2) + + if (doerr) { + aerr = sqrt ((rvar + fvar) / 2) + berr = sqrt ((rvar - fvar) / 2) + } + + ellip = 1 - b / a + if (b > 0.) + elong = a / b + + if (f == 0) { + cxx = 1. / (a * a) + cyy = 1. / (a * a) + cxy = 0 + } else { + cxx = y2 / f + cyy = x2 / f + cxy = -2 * xy / f + } + + if (doerr) { + if (fvar == 0) { + cxxerr = 1. / (aerr * aerr) + cyyerr = 1. / (berr * berr) + cxyerr = 0. + } else { + cxxerr = yvar / fvar + cyyerr = xvar / fvar + cxyerr = -2 * xycov / fvar + } + } + +end diff --git a/noao/nproto/ace/colors.dat b/noao/nproto/ace/colors.dat new file mode 100644 index 00000000..553ce35c --- /dev/null +++ b/noao/nproto/ace/colors.dat @@ -0,0 +1,8 @@ +black 202 +white 203 +red 204 +green 205 +blue 206 +yellow 207 +cyan 208 +magenta 209 diff --git a/noao/nproto/ace/convolve.x b/noao/nproto/ace/convolve.x new file mode 100644 index 00000000..af9734ef --- /dev/null +++ b/noao/nproto/ace/convolve.x @@ -0,0 +1,971 @@ +include <ctype.h> +include <imhdr.h> + + +# ODCNV -- Get a line of data possibly convolved. Also get the unconvolved +# data, the sky data, and the sky sigma data. +# +# This routine must be called sequentially starting with the first line. +# It is initialized when the first line. Memory is freed by using a final +# call with a line of zero. + +procedure convolve (in, bpm, sky, sig, exp, offset, scale, line, cnv, + indata, bp, cnvdata, skydata, sigdata, expdata, cnvwt, logfd) + +pointer in[2] #I Image pointers +pointer bpm[2] #I BPM pointer +pointer sky[2] #I Sky map +pointer sig[2] #I Sigma map +pointer exp[2] #I Exposure map +int offset[2] #I Offsets +real scale[2] #I Image scales +int line #I Line +char cnv[ARB] #I Convolution string +pointer indata[2] #O Pointers to unconvolved image data +pointer bp #O Bad pixel data +pointer cnvdata #O Pointer to convolved image data +pointer skydata[2] #O Pointer to sky data +pointer sigdata[2] #O Pointer to sigma data corrected by exposure map +pointer expdata[2] #O Pointer to exposure map data +real cnvwt #O Weight for convolved sigma +int logfd #I Logfile + +int i, j, k, nx, ny, nx2, ny2, nc, nl, mode, off +real wts, wts1 +pointer bpm2, kptr, ptr, symptr, symwptr +bool dobpm, overlap, fp_equalr() + +pointer kernel, sym, symbuf, symwts, buf, buf2, buf3, bpbuf, bpwts, wtsl, scales +data kernel/NULL/, sym/NULL/, symbuf/NULL/, symwts/NULL/ +data buf/NULL/, buf2/NULL/, buf3/NULL/, bpbuf/NULL/, bpwts/NULL/ +data wtsl/NULL/, scales/NULL/ + +errchk cnvparse, cnvgline2 + +begin + # If no convolution. + if (cnv[1] == EOS) { + if (line == 0) + return + + call cnvgline1 (line, offset, in, bpm, indata, bp) + call cnvgline2 (line, offset, in, sky, sig, exp, skydata, + sigdata, expdata) + cnvwt = 1 + if (in[2] == NULL) + cnvdata = indata[1] + else + call asubr_scale (Memr[indata[1]], scale[1], + Memr[indata[2]], scale[2], Memr[cnvdata], IM_LEN(in[1],1)) + return + } + + # Free memory. + if (line == 0) { + if (symbuf != NULL) { + do i = 0, ARB { + ptr = Memi[symbuf+i] + if (ptr == -1) + break + call mfree (ptr, TY_REAL) + } + } + if (symwts != NULL) { + do i = 0, ARB { + ptr = Memi[symwts+i] + if (ptr == -1) + break + call mfree (ptr, TY_REAL) + } + } + call mfree (scales, TY_REAL) + call mfree (wtsl, TY_REAL) + call mfree (kernel, TY_REAL) + call mfree (scales, TY_REAL) + call mfree (sym, TY_INT) + call mfree (symbuf, TY_POINTER) + call mfree (symwts, TY_POINTER) + call mfree (buf, TY_REAL) + call mfree (buf2, TY_REAL) + call mfree (buf3, TY_REAL) + call mfree (bpbuf, TY_INT) + call mfree (bpwts, TY_REAL) + + return + } + + # Initialize by getting the kernel coefficients, setting the + # image I/O buffers using a scrolling array, and allocate memory. + + if (line == 1 || buf == NULL) { + if (buf != NULL) { + if (symbuf != NULL) { + do i = 0, ARB { + ptr = Memi[symbuf+i] + if (ptr == -1) + break + call mfree (ptr, TY_REAL) + } + } + if (symwts != NULL) { + do i = 0, ARB { + ptr = Memi[symwts+i] + if (ptr == -1) + break + call mfree (ptr, TY_REAL) + } + } + call mfree (scales, TY_REAL) + call mfree (wtsl, TY_REAL) + call mfree (kernel, TY_REAL) + call mfree (scales, TY_REAL) + call mfree (sym, TY_INT) + call mfree (symbuf, TY_POINTER) + call mfree (symwts, TY_POINTER) + call mfree (buf, TY_REAL) + call mfree (buf2, TY_REAL) + call mfree (buf3, TY_REAL) + call mfree (bpbuf, TY_INT) + call mfree (bpwts, TY_REAL) + } + + nc = IM_LEN(in[1],1) + nl = IM_LEN(in[1],2) + + call cnvparse (cnv, kernel, nx, ny, logfd) + nx2 = nx / 2 + ny2 = ny / 2 + call malloc (scales, ny, TY_REAL) + call calloc (wtsl, ny, TY_REAL) + call amovkr (1., Memr[scales], ny) + + # Check for lines which are simple scalings of the first line. + do i = 2, ny { + kptr = kernel + (i - 1) * nx + wts = 0. + do k = 0, nx-1 { + if (Memr[kptr+k] == 0. || Memr[kernel+k] == 0.) { + wts = 0. + break + } + if (wts == 0.) + wts = Memr[kptr+k] / Memr[kernel+k] + else { + wts1 = Memr[kptr+k] / Memr[kernel+k] + if (!fp_equalr (wts, wts1)) + break + } + } + if (wts != 0. && fp_equalr (wts, wts1)) { + Memr[scales+i-1] = wts + call amovr (Memr[kernel], Memr[kptr], nx) + } + } + + wts = 0 + do i = 1, ny { + kptr = kernel + (i - 1) * nx + wts1 = 0. + do j = 1, nx { + wts1 = wts1 + Memr[kptr] + kptr = kptr + 1 + } + Memr[wtsl+i-1] = wts1 + wts = wts + wts1 + } + if (wts != 0.) { + call adivkr (Memr[wtsl], wts, Memr[wtsl], ny) + call adivkr (Memr[kernel], wts, Memr[kernel], nx*ny) + } + cnvwt = sqrt (wts) + + if (in[2] == NULL) + bpm2 = NULL + else + bpm2 = bpm[2] + if (bpm[1] == NULL && bpm2 == NULL) + dobpm = false + else + dobpm = true + if (dobpm) { + call malloc (bpbuf, nc*ny, TY_INT) + call malloc (bpwts, nc, TY_REAL) + call calloc (symwts, ny*ny+1, TY_POINTER) + Memi[symwts+ny*ny] = -1 + } + + # Check for any line symmetries in the kernel. + call malloc (sym, ny, TY_INT) + call calloc (symbuf, ny*ny+1, TY_POINTER) + Memi[symbuf+ny*ny] = -1 + do i = ny, 1, -1 { + kptr = kernel + (i - 1) * nx + do j = ny, 1, -1 { + ptr = kernel + (j - 1) * nx + do k = 0, nx-1 { + if (Memr[kptr+k] != Memr[ptr+k]) + break + } + if (k == nx) { + Memi[sym+i-1] = j + break + } + } + } + do i = ny, 1, -1 { + k = 0 + do j = ny, 1, -1 + if (Memi[sym+j-1] == i) + k = k + 1 + if (k == 1) + Memi[sym+i-1] = 0 + } + + call malloc (buf, nc*ny, TY_REAL) + if (in[2] != NULL) { + call malloc (buf2, nc*ny, TY_REAL) + call malloc (buf3, nc*ny, TY_REAL) + } + + if (in[2] != NULL) { + overlap = true + if (1-offset[1] < 1 || nc-offset[1] > IM_LEN(in[2],1)) + overlap = false + if (1-offset[2] < 1 || nl-offset[2] > IM_LEN(in[2],2)) + overlap = false + } + do i = 1, ny { + call cnvgline1 (i, offset, in, bpm, indata, bp) + off = mod (i, ny) * nc + call amovr (Memr[indata[1]], Memr[buf+off], nc) + if (in[2] != NULL) { + call amovr (Memr[indata[2]], Memr[buf2+off], nc) + call asubr_scale (Memr[buf+off], scale[1], + Memr[buf2+off], scale[2], Memr[buf3+off], nc) + } + if (dobpm) + call amovi (Memi[bp], Memi[bpbuf+off], nc) + } + } + + # Get new line. + j = line + ny2 + if (j > ny && j <= nl) { + call cnvgline1 (j, offset, in, bpm, indata, bp) + off = mod (j, ny) * nc + call amovr (Memr[indata[1]], Memr[buf+off], nc) + if (in[2] != NULL) { + call amovr (Memr[indata[2]], Memr[buf2+off], nc) + call asubr_scale (Memr[buf+off], scale[1], + Memr[buf2+off], scale[2], Memr[buf3+off], nc) + } + if (dobpm) { + ptr = bpbuf + off + call amovi (Memi[bp], Memi[ptr], nc) + } + } + + # Compute the convolution vector with boundary reflection. + # Save and reuse lines with the same kernel weights apart + # from a scale factor. + + kptr = kernel + call aclrr (Memr[cnvdata], nc) + if (dobpm) + call aclrr (Memr[bpwts], nc) + do i = 1, ny { + j = line + i - ny2 - 1 + if (j < 1) + j = 2 - j + else if (j > nl) + j = 2 * nl - j + off = mod (j, ny) * nc + if (in[2] == NULL) + ptr = buf + else + ptr = buf3 + k = Memi[sym+i-1] + if (k == 0) { + mode = 1 + symptr = ptr + symwptr = bpwts + } else { + if (k == i) + mode = 2 + else + mode = 3 + symptr = Memi[symbuf+(k-1)*ny+mod(j,ny)] + if (symptr == NULL) { + call malloc (symptr, nc, TY_REAL) + Memi[symbuf+(k-1)*ny+mod(j,ny)] = symptr + mode = 2 + } + if (dobpm) { + symwptr = Memi[symwts+(k-1)*ny+mod(j,ny)] + if (symwptr == NULL) { + call malloc (symwptr, nc, TY_REAL) + Memi[symwts+(k-1)*ny+mod(j,ny)] = symwptr + } + } + } + if (dobpm) + call convolve2 (Memr[ptr+off], Memr[cnvdata], Memr[symptr], + nc, Memr[kptr], Memr[scales+i-1], nx, Memi[bpbuf+off], + Memr[wtsl+i-1], Memr[bpwts], Memr[symwptr], mode) + else + call convolve1 (Memr[ptr+off], Memr[cnvdata], Memr[symptr], + nc, Memr[kptr], Memr[scales+i-1], nx, mode) + kptr = kptr + nx + } + if (dobpm) { + do i = 0, nc-1 + if (Memr[bpwts+i] != 0.) + Memr[cnvdata+i] = Memr[cnvdata+i] / Memr[bpwts+i] + } + + # Set the output vectors. + off = mod (line, ny) * nc + indata[1] = buf + off + if (dobpm) { + if (bpm2 == NULL) + bp = bpbuf + off + else + call amovi (Memi[bpbuf+off], Memi[bp], nc) + } + if (in[2] != NULL) { + if (overlap) + indata[2] = buf2 + off + else + call amovr (Memr[buf2+off], Memr[indata[2]], nc) + } + call cnvgline2 (line, offset, in, sky, sig, exp, skydata, sigdata, + expdata) +end + + + +# ODCNV1 -- One dimensional convolution with boundary reflection. +# +# The convolution is added to the output so that it might be used +# as part of a 2D convolution. + +procedure convolve1 (in, out, save, nc, xkernel, scale, nx, mode) + +real in[nc] #I Input data to be convolved +real out[nc] #O Output convolved data +real save[nc] #U Output saved data +int nc #I Number of data points +real xkernel[nx] #I Convolution weights +real scale #I Scale for saved vector +int nx #I Number of convolution points (must be odd) +int mode #I Mode (1=no save, 2=save, 3=use save) + +int i, j, k, nx2 +real val +bool fp_equalr() + +begin + if (mode == 1) { + nx2 = nx / 2 + do i = 1, nx2 { + val = 0 + do j = 1, nx { + k = i + j - nx2 - 1 + if (k < 1) + k = 2 - k + val = val + in[k] * xkernel[j] + } + out[i] = out[i] + val + } + do i = nx2+1, nc-nx2 { + k = i - nx2 + val = 0 + do j = 1, nx { + val = val + in[k] * xkernel[j] + k = k + 1 + } + out[i] = out[i] + val + } + do i = nc-nx2+1, nc { + val = 0 + do j = 1, nx { + k = i + j - nx2 - 1 + if (k > nc) + k = 2 * nc - k + val = val + in[k] * xkernel[j] + } + out[i] = out[i] + val + } + } else if (mode == 2) { + nx2 = nx / 2 + do i = 1, nx2 { + val = 0 + do j = 1, nx { + k = i + j - nx2 - 1 + if (k < 1) + k = 2 - k + val = val + in[k] * xkernel[j] + } + out[i] = out[i] + val + save[i] = val + } + do i = nx2+1, nc-nx2 { + k = i - nx2 + val = 0 + do j = 1, nx { + val = val + in[k] * xkernel[j] + k = k + 1 + } + out[i] = out[i] + val + save[i] = val + } + do i = nc-nx2+1, nc { + val = 0 + do j = 1, nx { + k = i + j - nx2 - 1 + if (k > nc) + k = 2 * nc - k + val = val + in[k] * xkernel[j] + } + out[i] = out[i] + val + save[i] = val + } + } else { + if (fp_equalr (1., scale)) { + do i = 1, nc + out[i] = out[i] + save[i] + } else { + do i = 1, nc + out[i] = out[i] + scale * save[i] + } + } +end + + +# ODCNV2 -- One dimensional convolution with boundary reflection and masking. +# +# The convolution is added to the output so that it might be used +# as part of a 2D convolution. + +procedure convolve2 (in, out, save, nc, xkernel, scale, nx, bp, + wtssum, wts, wtsave, mode) + +real in[nc] #I Input data to be convolved +real out[nc] #O Output convolved data +real save[nc] #U Output saved data +int nc #I Number of data points +real xkernel[nx] #I Convolution weights +real scale #I Scale for saved vector +int nx #I Number of convolution points (must be odd) +int bp[nc] #I Bad pixel data +real wtssum #I Sum of weights +real wts[nc] #I Weights +real wtsave[nc] #U Output saved weight data +int mode #I Mode (1=no save, 2=save, 3=use save) + +int i, j, k, nx2 +real val, wt +bool fp_equalr() + +begin + if (mode == 1) { + nx2 = nx / 2 + do i = 1, nx2 { + val = 0 + wt = wtssum + do j = 1, nx { + k = i + j - nx2 - 1 + if (k < 1) + k = 2 - k + if (bp[k] == 0) + val = val + in[k] * xkernel[j] + else + wt = wt - xkernel[j] + } + out[i] = out[i] + val + wts[i] = wts[i] + wt + } + do i = nx2+1, nc-nx2 { + k = i - nx2 + val = 0 + wt = wtssum + do j = 1, nx { + if (bp[k] == 0) + val = val + in[k] * xkernel[j] + else + wt = wt - xkernel[j] + k = k + 1 + } + out[i] = out[i] + val + wts[i] = wts[i] + wt + } + do i = nc-nx2+1, nc { + val = 0 + wt = wtssum + do j = 1, nx { + k = i + j - nx2 - 1 + if (k > nc) + k = 2 * nc - k + if (bp[k] == 0) + val = val + in[k] * xkernel[j] + else + wt = wt - xkernel[j] + } + out[i] = out[i] + val + wts[i] = wts[i] + wt + } + } else if (mode == 2) { + nx2 = nx / 2 + do i = 1, nx2 { + val = 0 + wt = wtssum + do j = 1, nx { + k = i + j - nx2 - 1 + if (k < 1) + k = 2 - k + if (bp[k] == 0) + val = val + in[k] * xkernel[j] + else + wt = wt - xkernel[j] + } + out[i] = out[i] + val + wts[i] = wts[i] + wt + save[i] = val + wtsave[i] = wt + } + do i = nx2+1, nc-nx2 { + k = i - nx2 + val = 0 + wt = wtssum + do j = 1, nx { + if (bp[k] == 0) + val = val + in[k] * xkernel[j] + else + wt = wt - xkernel[j] + k = k + 1 + } + out[i] = out[i] + val + wts[i] = wts[i] + wt + save[i] = val + wtsave[i] = wt + } + do i = nc-nx2+1, nc { + val = 0 + wt = wtssum + do j = 1, nx { + k = i + j - nx2 - 1 + if (k > nc) + k = 2 * nc - k + if (bp[k] == 0) + val = val + in[k] * xkernel[j] + else + wt = wt - xkernel[j] + } + out[i] = out[i] + val + wts[i] = wts[i] + wt + save[i] = val + wtsave[i] = wt + } + } else { + if (fp_equalr (1., scale)) { + do i = 1, nc { + out[i] = out[i] + save[i] + wts[i] = wts[i] + wtsave[i] + } + } else { + do i = 1, nc { + out[i] = out[i] + scale * save[i] + wts[i] = wts[i] + scale * wtsave[i] + } + } + } +end + + +# ASUBR_SCALE -- out = in1 * scale1 - in2 * scale2 + +procedure asubr_scale (in1, scale1, in2, scale2, out, n) + +real in1[n] #I Input vector +real scale1 #I Scale +real in2[n] #I Input vector +real scale2 #I Scale +real out[n] #O Output vector +int n #I Number of points + +int i + +begin + if (scale1 == 1. && scale2 == 1.) + call asubr (in1, in2, out, n) + else if (scale1 == 1.) { + do i = 1, n + out[i] = in1[i] - in2[i] * scale2 + } else if (scale2 == 1.) { + do i = 1, n + out[i] = in1[i] * scale1 - in2[i] + } else { + do i = 1, n + out[i] = in1[i] * scale1 - in2[i] * scale2 + } +end + + +procedure cnvgline1 (line, offset, im, bpm, imdata, bp) + +int line #I Line to be read +int offset[2] #I Offsets +pointer im[2] #I Image pointers +pointer bpm[2] #I Bad pixel mask pointers +pointer imdata[2] #U Image data +pointer bp #U Bad pixel data + +bool overlap +int nl1, nl2, loff, l2 +int nc1, nc2, nc3, off1, off2, off3, c1, c2 +pointer imgl2r(), imgl2i() + + +begin + # Get data for first image. Use IMIO buffers except the + # bad pixel buffer is not used if there is a second image. + + imdata[1] = imgl2r (im[1], line) + if (bpm[1] != NULL) { + if (im[2] == NULL) + bp = imgl2i (bpm[1], line) + else + call amovi (Memi[imgl2i(bpm[1],line)], Memi[bp], + IM_LEN(bpm[1],1)) + } + if (im[2] == NULL) + return + + # Initialize. + if (line == 1) { + nc1 = IM_LEN(im[1],1) + nc2 = IM_LEN(im[2],1) + nl1 = IM_LEN(im[1],2) + nl2 = IM_LEN(im[2],2) + + overlap = true + if (1-offset[1] < 1 || nc1-offset[1] > nc2) + overlap = false + if (1-offset[2] < 1 || nl1-offset[2] > nl2) + overlap = false + + off2 = -offset[1] + c1 = max (1, 1+off2) + c2 = min (nc2, nc1+off2) + nc2 = c2 - c1 + 1 + off1 = c1 - off2 - 1 + off3 = c2 - off2 + off2 = max (0, off2) + nc3 = nc1 - off3 + if (off1 > 0) { + call aclrr (Memr[imdata[2]], off1) + if (bpm[1] == NULL) + call amovki (1, Memi[bp], off1) + } + if (nc3 > 0) { + call aclrr (Memr[imdata[2]+off3], nc3) + if (bpm[1] == NULL) + call amovki (1, Memi[bp+off3], nc3) + } + + loff = -offset[2] + if (loff < 0) + call aclrr (Memr[imdata[2]], nc1) + } + + l2 = line + loff + if (l2 < 1 || l2 > nl2) { + call amovki (1, Memi[bp], nc1) + return + } + + if (overlap) { + imdata[2] = imgl2r (im[2], l2) + off2 + if (bpm[1] != NULL && bpm[2] != NULL) + call amaxi (Memi[imgl2i(bpm[2],l2)+off2], Memi[bp], Memi[bp], + nc1) + else if (bpm[2] != NULL) + call amovi (Memi[imgl2i(bpm[2],l2)+off2], Memi[bp], nc1) + } else { + # Copy the overlapping parts of the second image to the output + # buffers which must be allocated externally. Use the bad pixel + # mask to flag regions where there is no overlap. + + call amovr (Memr[imgl2r(im[2],l2)+off2], Memr[imdata[2]+off1], nc2) + if (bpm[1] != NULL && bpm[2] != NULL) { + call amaxi (Memi[imgl2i(bpm[2],l2)+off2], Memi[bp+off1], + Memi[bp+off1], nc2) + if (off1 > 0) + call amovki (1, Memi[bp], off1) + if (nc3 > 0) + call amovki (1, Memi[bp+off3], nc3) + } else if (bpm[2] != NULL) + call amovi (Memi[imgl2i(bpm[2],l2)+off2], Memi[bp+off1], nc2) + } +end + + +procedure cnvgline2 (line, offset, im, skymap, sigmap, expmap, + skydata, sigdata, expdata) + +int line #I Line to be read +int offset[2] #I Offsets +pointer im[2] #I Image pointers +pointer skymap[2] #I Sky map +pointer sigmap[2] #I Sky sigma map +pointer expmap[2] #I Exposure map +pointer skydata[2] #U Sky data +pointer sigdata[2] #U Sky sigma data +pointer expdata[2] #U Exposure map data + +bool overlap +int nl1, nl2, loff, l2 +int nc1, nc2, nc3, off1, off2, off3, c1, c2 +pointer ptr + +pointer map_glr() +errchk map_glr + +begin + # Get data for first image. + + skydata[1] = map_glr (skymap[1], line, READ_ONLY) + if (expmap[1] == NULL) + sigdata[1] = map_glr (sigmap[1], line, READ_ONLY) + else { + sigdata[1] = map_glr (sigmap[1], line, READ_WRITE) + expdata[1] = map_glr (expmap[1], line, READ_ONLY) + call expsigma (Memr[sigdata[1]], Memr[expdata[1]], + IM_LEN(im[1],1), 0) + } + if (im[2] == NULL) + return + + # Initialize. + if (line == 1) { + nc1 = IM_LEN(im[1],1) + nc2 = IM_LEN(im[2],1) + nl1 = IM_LEN(im[1],2) + nl2 = IM_LEN(im[2],2) + + overlap = true + if (1-offset[1] < 1 || nc1-offset[1] > nc2) + overlap = false + if (1-offset[2] < 1 || nl1-offset[2] > nl2) + overlap = false + + off2 = -offset[1] + c1 = max (1, 1+off2) + c2 = min (nc2, nc1+off2) + nc2 = c2 - c1 + 1 + off1 = c1 - off2 - 1 + off3 = c2 - off2 + nc3 = nc1 - off3 + if (off1 > 0) { + call aclrr (Memr[skydata[2]], off1) + call aclrr (Memr[sigdata[2]], off1) + if (expmap[2] != NULL) + call aclrr (Memr[expdata[2]], off1) + } + if (nc3 > 0) { + call aclrr (Memr[skydata[2]+off3], nc3) + call aclrr (Memr[sigdata[2]+off3], nc3) + if (expmap[2] != NULL) + call aclrr (Memr[expdata[2]+off3], nc3) + } + + loff = -offset[2] + if (loff < 0) { + call aclrr (Memr[skydata[2]], nc1) + call aclrr (Memr[sigdata[2]], nc1) + if (expmap[2] != NULL) + call aclrr (Memr[expdata[2]], nc1) + } + } + + l2 = line + loff + if (l2 < 1 || l2 > nl2) + return + + if (overlap) { + skydata[2] = map_glr (skymap[2], l2, READ_ONLY) + off2 + if (expmap[2] == NULL) + sigdata[2] = map_glr (sigmap[2], l2, READ_ONLY) + off2 + else { + sigdata[2] = map_glr (sigmap[2], l2, READ_WRITE) + off2 + expdata[2] = map_glr (expmap[2], l2, READ_ONLY) + off2 + call expsigma (Memr[sigdata[2]], Memr[expdata[2]], nc2, 0) + } + } else { + # Copy the overlapping parts of the second image to the output + # buffers which must be allocated externally. + + ptr = map_glr(skymap[2],l2,READ_ONLY) + call amovr (Memr[ptr+off2], Memr[skydata[2]+off1], nc2) + ptr = map_glr(sigmap[2],l2,READ_ONLY) + call amovr (Memr[ptr+off2], Memr[sigdata[2]+off1], nc2) + if (expmap[2] != NULL) { + ptr = map_glr(expmap[2],l2,READ_ONLY) + call amovr (Memr[ptr+off2], Memr[expdata[2]+off1], nc2) + call expsigma (Memr[sigdata[2]], Memr[expdata[2]], nc2, 0) + } + } +end + + +# CNVPARSE -- Parse convolution string. + +procedure cnvparse (cnvstr, kernel, nx, ny, logfd) + +char cnvstr[ARB] #I Convolution string +pointer kernel #O Pointer to convolution kernel elements +int nx, ny #O Convolution size +int logfd #I Log file descriptor + +int i, j, nx2, ny2 +int ip, fd, open(), fscan(), nscan(), ctor(), ctoi(), strncmp() +real val, sx, sy +pointer ptr +errchk open + +define unknown_ 10 + +begin + kernel = NULL + + for (ip=1; IS_WHITE(cnvstr[ip]); ip=ip+1) + ; + + if (cnvstr[ip] == EOS) { + nx = 1 + ny = 1 + call malloc (kernel, 1, TY_REAL) + Memr[kernel] = 1 + } else if (cnvstr[ip] == '@') { + fd = open (cnvstr[ip+1], READ_ONLY, TEXT_FILE) + call malloc (kernel, 100, TY_REAL) + i = 0 + nx = 0 + ny = 0 + while (fscan (fd) != EOF) { + do j = 1, ARB { + call gargr (val) + if (nscan() < j) + break + Memr[kernel+i] = val + i = i + 1 + if (mod (i, 100) == 0) + call realloc (kernel, i+100, TY_REAL) + } + j = j - 1 + if (nx == 0) + nx = j + else if (j != nx) { + call close (fd) + call error (1, + "Number of convolution elements inconsistent") + } + ny = ny + 1 + } + call close (fd) + } else if (IS_ALPHA(cnvstr[ip])) { + if (strncmp ("block", cnvstr[ip], 5) == 0) { + i = 6 + if (ctoi (cnvstr[ip], i, nx) == 0 || + ctoi (cnvstr[ip], i, ny) == 0) + goto unknown_ + call malloc (kernel, nx*ny, TY_REAL) + call amovkr (1., Memr[kernel], nx*ny) + } else if (strncmp ("bilinear", cnvstr[ip], 8) == 0) { + i = 9 + if (ctoi (cnvstr[ip], i, nx) == 0 || + ctoi (cnvstr[ip], i, ny) == 0) + goto unknown_ + call malloc (kernel, nx*ny, TY_REAL) + + nx2 = nx / 2 + ny2 = ny / 2 + ptr = kernel + do j = 0, ny-1 { + do i = 0, nx-1 { + Memr[ptr] = (nx2-abs(nx2-i)+1) * (ny2-abs(ny2-j)+1) + ptr = ptr + 1 + } + } + } else if (strncmp ("gauss", cnvstr[ip], 5) == 0) { + i = 6 + if (ctoi (cnvstr[ip], i, nx) == 0 || + ctoi (cnvstr[ip], i, ny) == 0) + goto unknown_ + if (ctor (cnvstr[ip], i, sx) == 0 || + ctor (cnvstr[ip], i, sy) == 0) + goto unknown_ + call malloc (kernel, nx*ny, TY_REAL) + + nx2 = nx / 2 + ny2 = ny / 2 + val = 2 * sx * sy + ptr = kernel + do j = 0, ny-1 { + do i = 0, nx-1 { + Memr[ptr] = exp (-((i-nx2)**2+(j-ny2)**2) / val) + ptr = ptr + 1 + } + } + } + } else { + call malloc (kernel, 100, TY_REAL) + i = 0 + nx = 0 + ny = 0 + while (cnvstr[ip] != EOS) { + do j = 1, ARB { + if (ctor (cnvstr, ip, val) == 0) + break + Memr[kernel+i] = val + i = i + 1 + if (mod (i, 100) == 0) + call realloc (kernel, i+100, TY_REAL) + } + j = j - 1 + if (nx == 0) + nx = j + else if (j != nx) + call error (1, + "Number of convolution elements inconsistent") + ny = ny + 1 + if (cnvstr[ip] != EOS) + ip = ip + 1 + for (; IS_WHITE(cnvstr[ip]); ip=ip+1) + ; + } + } + + if (kernel == NULL) +unknown_ call error (1, "Unrecognized convolution") + + if (mod (nx, 2) != 1 || mod (ny, 2) != 1) { + call mfree (kernel, TY_REAL) + call error (1, "Convolution size must be odd") + } + + if (logfd != NULL) { + ptr = kernel + call eprintf (" Convolution:\n") + do j = 1, ny { + call eprintf (" ") + do i = 1, nx { + call eprintf (" %7.3g") + call pargr (Memr[ptr]) + ptr = ptr + 1 + } + call eprintf ("\n") + } + } + +end diff --git a/noao/nproto/ace/detect.h b/noao/nproto/ace/detect.h new file mode 100644 index 00000000..1c807e7c --- /dev/null +++ b/noao/nproto/ace/detect.h @@ -0,0 +1,16 @@ +# Detection parameter structure. +define DET_LEN 62 # Length of parameter structure +define DET_STRLEN 99 # Length of strings in structure + +define DET_CNV P2C($1) # Convolution string +define DET_HSIG Memr[P2R($1+51)] # High detection sigma +define DET_LSIG Memr[P2R($1+52)] # Low detection sigma +define DET_HDETECT Memi[$1+53] # Detect above sky? +define DET_LDETECT Memi[$1+54] # Detect below sky? +define DET_NEIGHBORS Memi[$1+55] # Neighbor type +define DET_MINPIX Memi[$1+56] # Minimum number of pixels +define DET_SIGAVG Memr[P2R($1+57)] # Minimum average above sky in sigma +define DET_SIGPEAK Memr[P2R($1+58)] # Minimum peak above sky in sigma +define DET_FRAC2 Memr[P2R($1+59)] # Fraction of difference relative to 2 +define DET_BPVAL Memi[$1+60] # Output bad pixel value +define DET_SKB Memi[$1+61] # Parameters for sky update diff --git a/noao/nproto/ace/detect.par b/noao/nproto/ace/detect.par new file mode 100644 index 00000000..fd39b83f --- /dev/null +++ b/noao/nproto/ace/detect.par @@ -0,0 +1,65 @@ +# ACEDETECT + +images,f,a,,,,"List of images" +masks,s,h,"!BPM",,,"List of bad pixel masks" +skys,s,h,"",,,"List of sky maps" +sigmas,s,h,"",,,"List of sigma maps" +exps,s,h,"",,,"List of exposure maps" +gains,s,h,"",,,"List of gain maps" +objmasks,s,h,"",,,"List of object masks" +omtype,s,h,"all","boolean|numbers|colors|all",,"Object mask type" +catalogs,s,h,"",,,"List of catalogs" +extnames,s,h,"",,,"Extension names" +catdefs,s,h,"ace$lib/catdef.dat",,,"List of catalog definitions" +logfiles,s,h,"STDOUT",,,"List of log files + +# Steps" +dodetect,b,h,yes,,,"Detect objects?" +dosplit,b,h,yes,,,"Split merged objects?" +dogrow,b,h,yes,,,"Grow object regions?" +doevaluate,b,h,yes,,,"Evaluate objects? + +# Sky" +skytype,s,h,"block","fit|block",,"Type of sky estimation + +# Sky Fitting" +fitstep,i,h,100,1,,"Line step for sky sampling" +fitblk1d,i,h,10,,,"Block average for line fitting" +fithclip,r,h,2.,,,"High sky clipping during 1D sky estimation" +fitlclip,r,h,3.,,,"Low sky clippling during 1D sky estimation" +fitxorder,i,h,1,1,,"Sky fitting x order" +fityorder,i,h,1,1,,"Sky fitting y order" +fitxterms,s,h,"half","none|full|half",,"Sky fitting cross terms + +# Sky Blocks" +blkstep,i,h,1,1,,"Line step for sky sampling" +blksize,i,h,-10,,,"Block size (+=pixels, -=blocks)" +blknsubblks,i,h,2,1,,"Number of subblocks per axis + +# Detection" +updatesky,b,h,yes,,,"Update sky during detection?" +convolve,s,h,"block 3 3",,,"Convolution kernel" +hsigma,r,h,3.,.1,,"Sigma threshold above sky" +lsigma,r,h,10.,.1,,"Sigma threshold below sky" +hdetect,b,h,yes,,,"Detect objects above sky?" +ldetect,b,h,no,,,"Detect objects below sky?" +neighbors,s,h,"8","4|8",,Neighbor type +minpix,i,h,6,1,,"Minimum number of pixels in detected objects" +sigavg,r,h,4.,0.,,"Sigma of mean flux cutoff" +sigmax,r,h,4.,0.,,"Sigma of maximum pixel" +bpval,i,h,INDEF,,,"Output bad pixel value + +# Splitting" +splitmax,r,h,INDEF,,,"Maximum sigma above sky for splitting" +splitstep,r,h,0.4,,,"Splitting steps in convolved sigma" +splitthresh,r,h,5.,,,"Splitting threshold in sigma" +sminpix,i,h,8,1,,"Minimum number of pixels in split objects" +ssigavg,r,h,10.,0.,,"Sigma of mean flux cutoff" +ssigmax,r,h,5.,0.,,"Sigma of maximum pixel + +# Growing" +ngrow,i,h,2,0,,"Number of grow rings" +agrow,r,h,2.,0,,"Area grow factor + +# Evaluate" +magzero,s,h,"INDEF",,,"Magnitude zero point" diff --git a/noao/nproto/ace/detect.x b/noao/nproto/ace/detect.x new file mode 100644 index 00000000..681951db --- /dev/null +++ b/noao/nproto/ace/detect.x @@ -0,0 +1,795 @@ +include <imhdr.h> +include <pmset.h> +include <mach.h> +include "ace.h" +include "cat.h" +include "objs.h" +include "skyblock.h" +include "detect.h" +include "split.h" + + +# DETECT - Object detection. +# +# Get input image data (possibly convolved) and compare to sky using sky +# sigma and threshold factors. Catagorize as bad pixel, sky, above sky, and +# below sky. Write catagories to output mask. + +procedure detect (det, spt, dosky, dosig, skyname, signame, im, bpm, + skymap, sigmap, expmap, scale, offset, out, siglevmap, siglevels, + logfd, cat) + +pointer det #I Detection parameter structure +pointer spt #I Split parameter structure +bool dosky #I Do sky update? +bool dosig #I Do sigma update? +char skyname[ARB] #I Sky name for updating sky +char signame[ARB] #I Sigma name for updating sigma +pointer im[2] #I Input image pointers +pointer bpm[2] #I Bad pixel mask pointer +pointer skymap[2] #U Sky map +pointer sigmap[2] #U Sigma map +pointer expmap[2] #I Exposure map +real scale[2] #I Image scales +int offset[2] #I Offsets of second image +pointer out #I Output pixel mask (PMIO) pointer +pointer siglevmap #I Mask for sigma levels +pointer siglevels #O Sigma levels for mask +int logfd #I Verbose? +pointer cat #O Catalog of objects + +pointer cnv # Convolution string pointer +real hsig # Detection threshold +real splitstep # Minimum split step in convolved sigma +real splitthresh # Transition convolved sigma +bool hdetect # Detection above sky +bool ldetect # Detection below sky + +bool dosky1, dosig1, overlap +int i, c, l, nc, nl, nc2, siglevmax +int nobjs, nalloc, navail +long v[2] +real z, cnvwt +pointer sp, str, iptr, rptr, outdata, lastdata, orl, srl +pointer skb, objs, ids, links +pointer indata[2], bp, skydata[2], sigdata[2], expdata[2], cnvdata + +errchk convolve, drenum +errchk detect, salloc, malloc, calloc, realloc + + +begin + # Initialize parameters. + call det_pars ("open", "", det) + + # The sky update requires the doxxx parameter to be true, a filename + # to be specified and the skb pointer to be non-null. The skb + # pointer is set depending on the "updatesky" task parameter. + + dosky1 = (dosky && skyname[1] != EOS) + dosig1 = (dosig && signame[1] != EOS) + if (dosky1 || dosig1) + skb = DET_SKB(det) + else + skb = NULL + + cnv = DET_CNV(det) + hsig = DET_HSIG(det) + if (spt != NULL) { + splitstep = SPT_SPLITSTEP(spt) + splitthresh = SPT_SPLITTHRESH(spt) + } + hdetect = (DET_HDETECT(det) == YES) + ldetect = (DET_LDETECT(det) == YES) + + # Set sizes. + nc = IM_LEN(im[1],1) + nl = IM_LEN(im[1],2) + if (ldetect) + nc2 = 2 * (nc + 2) + else + nc2 = nc + 2 + + # Allocate memory. + call smark (sp) + call salloc (str, SZ_LINE, TY_CHAR) + call salloc (outdata, nc2, TY_INT) + call salloc (lastdata, nc2, TY_INT) + call salloc (orl, 3+3*nc, TY_INT) + call salloc (iptr, 1, TY_REAL) + call salloc (rptr, 1, TY_REAL) + + Memr[iptr] = INDEFI + Memr[rptr] = INDEFR + + if (siglevmap != NULL) + call salloc (srl, 3+3*nc, TY_INT) + else + srl = iptr + + if (expmap[1] == NULL) + expdata[1] = rptr + if (expmap[2] == NULL) + expdata[2] = rptr + + if (im[2] == NULL) { + indata[2] = rptr + skydata[2] = rptr + sigdata[2] = rptr + expdata[2] = rptr + if (bpm[1] == NULL) { + call salloc (bp, nc, TY_INT) + call aclri (Memi[bp], nc) + } + if (Memc[cnv] != EOS) + call salloc (cnvdata, nc, TY_REAL) + } else { + overlap = true + if (1-offset[1] < 1 || nc-offset[1] > IM_LEN(im[2],1)) + overlap = false + if (1-offset[2] < 1 || nl-offset[2] > IM_LEN(im[2],2)) + overlap = false + if (!overlap) { + call salloc (indata[2], nc, TY_REAL) + call salloc (skydata[2], nc, TY_REAL) + call salloc (sigdata[2], nc, TY_REAL) + call salloc (expdata[2], nc, TY_REAL) + } + call salloc (bp, nc, TY_INT) + call aclri (Memi[bp], nc) + call salloc (cnvdata, nc, TY_REAL) + } + + navail = (nc * nl) / 100 + call calloc (ids, navail, TY_INT) + call calloc (links, navail, TY_INT) + call calloc (objs, navail, TY_POINTER) + nalloc = 0 + + # Setup sky updating. + if (skb!=NULL && !overlap) { + l = 1 + call skb_iminit (skb, im[1], expmap, l, NULL) + } + + if (logfd != NULL) + call fprintf (logfd, " Detect objects:\n") + + # Go through image. + nobjs = NUMSTART - 1 + call aclri (Memi[outdata], nc2) + if (siglevmap == NULL) + siglevmax = INDEFI + else + siglevmax = 0 + + v[1] = 1 + do l = 1, nl { + # Get data. + call convolve (im, bpm, skymap, sigmap, expmap, offset, + scale, l, Memc[cnv], indata, bp, cnvdata, skydata, + sigdata, expdata, cnvwt, logfd) + call amovi (Memi[outdata], Memi[lastdata], nc2) + + call detect1 (det, spt, skb, Memr[indata[1]], Memr[skydata[1]], + Memr[sigdata[1]], Memr[expdata[1]], Memr[indata[2]], + Memr[skydata[2]], Memr[sigdata[2]], Memr[expdata[2]], + scale, Memi[bp], Memr[cnvdata], cnvwt, Memi[outdata], + Memi[lastdata], nc, nl, l, objs, ids, links, nobjs, + nalloc, navail, Memi[orl], Memi[srl], siglevmax) + + # Write to output masks. + v[2] = l + call pmplri (out, v, Memi[orl], 0, nc, PIX_SRC) + if (siglevmap != NULL) + call pmplri (siglevmap, v, Memi[srl], 0, nc, PIX_SRC) + } + + # Free convolution memory. + call convolve (im, bpm, skymap, sigmap, expmap, offset, + scale, 0, Memc[cnv], indata, bp, cnvdata, skydata, + sigdata, expdata, cnvwt, logfd) + + # Free extra object structures. + do c = nobjs, nalloc-1 + call mfree (Memi[objs+c], TY_STRUCT) + + # Renumber and reject objects with less than a minimum area. + call drenum (det, out, Memi[ids], Memi[objs], nobjs) + + call mfree (ids, TY_INT) + call mfree (links, TY_INT) + call realloc (objs, nobjs, TY_POINTER) + + CAT_NOBJS(cat) = nobjs + CAT_NUMMAX(cat) = nobjs + CAT_OBJS(cat) = objs + + # Set sigma levels if needed. + if (spt != NULL) { + call calloc (siglevels, siglevmax+1, TY_REAL) + do i = 1, siglevmax { + z = i * splitstep + if (z > splitthresh) { + z = z / splitthresh + z = (z + 3) / 4 + z = z * z * z * z + z = z * splitthresh + } + if (z > hsig) + Memr[siglevels+i-1] = z + } + Memr[siglevels+siglevmax] = MAX_REAL + } else + siglevels = NULL + + if (logfd != NULL) { + call fprintf (logfd, " %d objects detected\n") + call pargi (nobjs - NUMSTART + 1) + } + + if (skb != NULL) { + call skb_update (skb, dosky1, dosig1, im[1], skyname, signame, + skymap, sigmap, logfd) + call skb_imfree (skb) + } + + call sfree (sp) +end + + +procedure detect1 (det, spt, skb, in, sky, sig, exp, in2, sky2, sig2, exp2, + scale, bp, cnv, cnvwt, out, lastout, nc, nl, line, objs, ids, + links, nobjs, nalloc, navail, orl, srl, siglevmax) + +pointer det #I Parameters +pointer spt #I Parameters +pointer skb #I Sky block pointer +real in[nc] #I Image data +real sky[nc] #I Sky data +real sig[nc] #I Sky sigma data +real exp[nc] #I Exposure map data +real in2[nc] #I Image data +real sky2[nc] #I Sky data +real sig2[nc] #I Sky sigma data +real exp2[nc] #I Exposure map data +real scale[2] #I Image scales +int bp[nc] #I Bad pixel values +real cnv[nc] #I Convolved image data +real cnvwt #I Sigma weight +int out[ARB] #I Output data (extra pixel on each end) +int lastout[ARB] #I Last output data (extra pixel on each end) +int nc #I Number of columns +int nl #I Number of lines +int line #I Current line + +pointer objs #I Pointer to array of object pointers +pointer ids #I Pointer to array of IDs +pointer links #I Pointer to array links to other IDs +int nobjs #I Number of objects pointers +int nalloc #I Number of object pointers allocated +int navail #I Size of allocated arrays + +int orl[3,ARB] #O Output object mask range list +int srl[3,ARB] #O Output sigma level range list +int siglevmax #O Maximum sigma level (INDEF if not used) + +real hsig # High detection sigma +real lsig # Low detection sigma +int bpval # Output bad pixel value +real splitstep # Minimum split step in convolved sigma +real splitthresh # Transition convolved sigma +bool hdetect # Detection above sky +bool ldetect # Detection below sky +int neighbors # Neighbor type + +int i, j, c, c1, c2, clast, nc2, nc3, num, numlast, bin, binlast +int n, ncmax, nlmax, nbins, csky +real z, s, t, z1, s1, t1, z2, s2, t2, zcnv, rcnv, tcnv, low, high, binscale +real explast +bool dodiff, dosrl + +real a, b +pointer bins, skys, sigs, exps, nsky + +errchk dadd, realloc + +begin + # Parameters + hsig = DET_HSIG(det) + lsig = DET_LSIG(det) + bpval = DET_BPVAL(det) + hdetect = (DET_HDETECT(det) == YES) + ldetect = (DET_LDETECT(det) == YES) + neighbors = DET_NEIGHBORS(det) + + # Do sky updating? + nlmax = 0 + if (skb != NULL) { + ncmax = min (nc, SKB_NCSBLK(skb) * SKB_NCSPIX(skb)) + nlmax = min (nl, SKB_NLSBLK(skb) * SKB_NLSPIX(skb)) + + a = SKB_A(skb) + b = SKB_B(skb) + n = SKB_NCSPIX(skb) + nbins = SKB_NBINS(skb) + bins = SKB_BINS(skb) + skys = SKB_SKY(skb) + sigs = SKB_SIG(skb) + exps = SKB_EXP(skb) + nsky = SKB_NSKY(skb) + } + + # Do difference detection? + if (IS_INDEFR(in2[1])) { + dodiff = false + z1 = 0; s1 = 0; t1 = 1 + z2 = 0; s2 = 0; t2 = 1 + } else + dodiff = true + + # Initialize output mask range lists. + i = 1 + orl[1,i] = 0 + if (spt != NULL) { + splitstep = SPT_SPLITSTEP(spt) + splitthresh = SPT_SPLITTHRESH(spt) + binscale = splitthresh / splitstep + + j = 1 + srl[1,j] = 0 + dosrl = true + } else + dosrl = false + clast = 0 + + nc2 = nc + 2 + if (ldetect) + nc3 = nc2 + 1 + else + nc3 = 1 + + explast = INDEFR + + # Find pixels which are masked, sky, above sky, and below sky. + do c = 1, nc { + c1 = c + 1 + c2 = c + nc3 + out[c1] = 0 + out[c2] = 0 + + # Mark masked pixels if any. + if (bp[c] != 0) { + if (IS_INDEFI(bpval)) + num = min (bp[c], NUMSTART-1) + else + num = min (bpval, NUMSTART-1) + + if (num > 0) { + out[c1] = num + out[c2] = num + + if (num != numlast || c != clast) { + orl[2,i] = clast - orl[1,i] + i = i + 1 + + numlast = num + orl[1,i] = c + orl[3,i] = numlast + } + clast = c1 + } + + next + } + + # Find sky and object pixels. + if (dodiff) { + z1 = in[c] + s1 = sky[c] + t1 = sig[c] + z2 = in2[c] + s2 = sky2[c] + t2 = sig2[c] + z = scale[1] * z1 - scale[2] * z2 + s = scale[1] * s1 - scale[2] * s2 + t = sqrt ((scale[1]*t1)**2 + (scale[2]*t2)**2) + } else { + z = in[c] + s = sky[c] + t = sig[c] + } + zcnv = cnv[c] + rcnv = zcnv - s + tcnv = t / cnvwt + low = -lsig * tcnv + high = hsig * tcnv + + if (rcnv > high) { + if (hdetect) { + call dadd (c1, line, out, lastout, nc2, + Memi[ids], Memi[links], Memi[objs], nobjs, nalloc, + z, s, t, z2, s2, t2, neighbors, 0, num) + + if (nalloc == navail) { + navail = max (100*nalloc*(nl+1)/line/100, nalloc+10000) + call realloc (ids, navail, TY_INT) + call realloc (links, navail, TY_INT) + call realloc (objs, navail, TY_POINTER) + } + + # Add to output masks. + if (num != numlast || c != clast) { + orl[2,i] = clast - orl[1,i] + i = i + 1 + + numlast = num + orl[1,i] = c + orl[3,i] = numlast + } + + if (dosrl) { + rcnv = rcnv / tcnv / splitthresh + if (rcnv > 1.) + rcnv = (4 * rcnv**0.25 - 3) + bin = nint (rcnv * binscale) + if (bin != binlast || c != clast) { + srl[2,j] = clast - srl[1,j] + j = j + 1 + + binlast = bin + srl[1,j] = c + srl[3,j] = binlast + + siglevmax = max (bin, siglevmax) + } + } + clast = c1 + } + } else if (rcnv < low) { + if (ldetect) { + call dadd (c1, line, out[nc3], lastout[nc3], nc2, + Memi[ids], Memi[links], Memi[objs], nobjs, nalloc, + 2*s-z, s, t, z1, s1, t1, neighbors, OBJ_DARK, num) + + if (nalloc == navail) { + navail = max (100*nalloc*(nl+1)/line/100, nalloc+10000) + call realloc (ids, navail, TY_INT) + call realloc (links, navail, TY_INT) + call realloc (objs, navail, TY_POINTER) + } + + # Add to output masks. + if (num != numlast || c != clast) { + orl[2,i] = clast - orl[1,i] + i = i + 1 + + numlast = num + orl[1,i] = c + orl[3,i] = numlast + } + clast = c1 + } + } + + if (line <= nlmax && c <= ncmax) { + bin = a * (z - s) / t + b + if (bin >= 1 && bin <= nbins) { + csky = (c-1) / n + bin = bins + csky * nbins + bin - 1 + Memi[bin] = Memi[bin] + 1 + Memr[skys+csky] = Memr[skys+csky] + s + Memr[sigs+csky] = Memr[sigs+csky] + t + Memi[nsky+csky] = Memi[nsky+csky] + 1 + if (!IS_INDEFR(Memr[exps])) + Memr[exps+csky] = Memr[exps+csky] + exp[c] + } + } + } + + # Finish up range lists. + orl[2,i] = clast - orl[1,i] + orl[1,1] = i + orl[2,1] = nc + if (dosrl) { + srl[2,j] = clast - srl[1,j] + srl[1,1] = j + srl[2,1] = nc + } + + # Evaluate histogram sky values if all lines have been accumulated. + if (line <= nlmax) { + if (mod (line, SKB_NLSPIX(skb)) == 0) { + n = SKB_NCSBLK(skb) + call skb_blkeval (Memi[bins], nbins, a, b, Memr[skys], + Memr[sigs], Memr[exps], Memi[nsky], n, + SKB_NSKYMIN(skb), SKB_NAV(skb), SKB_HISTWT(skb), + SKB_SIGFAC(skb)) + + # Initialize for accumulation of next line of blocks. + SKB_SKY(skb) = skys + n + SKB_SIG(skb) = sigs + n + if (!IS_INDEFR(Memr[exps])) + call aclrr (Memr[exps], n) + call aclri (Memi[nsky], n) + call aclri (Memi[bins], n*nbins) + } + } +end + + +# OBJADD -- Add a pixel to the object list and set the mask value. + +procedure dadd (c, l, z, zlast, nc, ids, links, objs, nobjs, nalloc, + data, sky, sigma, data2, sky2, sigma2, neighbors, flags, num) + +int c, l #I Pixel coordinate +int z[nc] #I Pixel values for current line +int zlast[nc] #I Pixel values for last line +int nc #I Number of pixels in a line +int ids[ARB] #I Mask ids +int links[ARB] #I Link to other mask ids with same number +pointer objs[ARB] #I Objects +int nobjs #U Number of objects +int nalloc #U Number of allocated objects +real data #I Data value (not sky subtracted) +real sky #I Sky value +real sigma #I Sky sigma value +real data2 #I Data value (not sky subtracted) +real sky2 #I Sky value +real sigma2 #I Sky sigma value +int neighbors #I Neighbor type +int flags #I Flags +int num #O Object number assigned + +int i, num1, c1, c2 +real val +bool merge +pointer obj, obj1 + +begin + # Inherit number of a neighboring pixel. + num = INDEFI + merge = false + if (neighbors == 4) { + c1 = c - 1 + c2 = c + if (z[c1] >= NUMSTART) { + num = z[c1] + merge = true + } else if (zlast[c] >= NUMSTART) + num = ids[zlast[c]] + } else { + c1 = c - 1 + c2 = c + 1 + if (z[c1] >= NUMSTART) { + num = z[c1] + merge = true + } else if (zlast[c1] >= NUMSTART) + num = ids[zlast[c1]] + else if (zlast[c] >= NUMSTART) + num = ids[zlast[c]] + else if (zlast[c2] >= NUMSTART) + num = ids[zlast[c2]] + } + + # If no number assign a new number. + if (num == INDEFI) { + nobjs = nobjs + 1 + num = nobjs + ids[num] = num + links[num] = 0 + if (nalloc < nobjs) { + call calloc (objs[num], OBJ_DETLEN, TY_STRUCT) + nalloc = nobjs + } + obj = objs[num] + OBJ_XAP(obj) = 0. + OBJ_YAP(obj) = 0. + OBJ_FLUX(obj) = 0. + OBJ_NPIX(obj) = 0 + OBJ_ISIGMAX(obj) = 0. + OBJ_ISIGAVG(obj) = 0. + OBJ_ISIGAVG2(obj) = 0. + OBJ_FLAGS(obj) = flags + } + obj = objs[num] + + # Merge overlapping objects from previous line. + if (merge) { + i = zlast[c2] + if (i >= NUMSTART && num != ids[i]) { + num1 = ids[i] + + obj1 = objs[num1] + OBJ_XAP(obj) = OBJ_XAP(obj) + OBJ_XAP(obj1) + OBJ_YAP(obj) = OBJ_YAP(obj) + OBJ_YAP(obj1) + OBJ_FLUX(obj) = OBJ_FLUX(obj) + OBJ_FLUX(obj1) + OBJ_NPIX(obj) = OBJ_NPIX(obj) + OBJ_NPIX(obj1) + OBJ_ISIGMAX(obj) = max (OBJ_ISIGMAX(obj), OBJ_ISIGMAX(obj1)) + OBJ_ISIGAVG(obj) = OBJ_ISIGAVG(obj) + OBJ_ISIGAVG(obj1) + OBJ_ISIGAVG2(obj) = OBJ_ISIGAVG2(obj) + OBJ_ISIGAVG2(obj1) + + i = num + while (links[i] != 0) + i = links[i] + links[i] = num1 + repeat { + i = links[i] + ids[i] = num + } until (links[i] == 0) + + nalloc = nalloc + 1 + objs[nalloc] = obj1 + objs[num1] = NULL + } + } + + z[c] = num + OBJ_NPIX(obj) = OBJ_NPIX(obj) + 1 + val = (data - sky) / sigma + OBJ_XAP(obj) = OBJ_XAP(obj) + val * c1 + OBJ_YAP(obj) = OBJ_YAP(obj) + val * l + OBJ_FLUX(obj) = OBJ_FLUX(obj) + val + OBJ_ISIGMAX(obj) = max (OBJ_ISIGMAX(obj), val) + OBJ_ISIGAVG(obj) = OBJ_ISIGAVG(obj) + val + #OBJ_ISIGAVG2(obj) = OBJ_ISIGAVG2(obj) + (data2 - sky2) / sigma2 + OBJ_ISIGAVG2(obj) = OBJ_ISIGAVG2(obj) + (data2 - sky2) / sigma +end + + +procedure drenum (det, out, ids, objs, nobjs) + +pointer det #I Parameters +pointer out #I Output PMIO pointer +int ids[nobjs] #I Mask IDs +pointer objs[nobjs] #U Input and output object list +int nobjs #U Number of objects + +int minpix # Minimum number of pixels +real sigavg # Cutoff of SIGAVG +real sigmax # Cutoff of SIGMAX +real frac # Fraction of sigavg2 + +int i, j, n, nc, nl +real rval +pointer sp, v, rl, buf, obj + +begin + # Parameters. + minpix = DET_MINPIX(det) + sigavg = DET_SIGAVG(det) + sigmax = DET_SIGPEAK(det) + frac = DET_FRAC2(det) + + # Assign object numbers. Eliminate objects, by setting object number + # to zero, based on selection # critera (size, peak, etc.). + + j = NUMSTART - 1 + do i = NUMSTART, nobjs { + obj = objs[i] + if (obj == NULL) + next + + n = OBJ_NPIX(obj) + if (n < minpix) { + OBJ_NUM(obj) = 0 + next + } + rval = sqrt (real(n)) + OBJ_ISIGAVG(obj) = OBJ_ISIGAVG(obj) / rval + if ((OBJ_ISIGMAX(obj) < sigmax && OBJ_ISIGAVG(obj) < sigavg)) { + OBJ_NUM(obj) = 0 + next + } + OBJ_ISIGAVG2(obj) = OBJ_ISIGAVG2(obj) / rval + if (OBJ_ISIGAVG(obj) < frac * OBJ_ISIGAVG2(obj)) { + OBJ_NUM(obj) = 0 + next + } + + rval = OBJ_FLUX(obj) + if (rval > 0.) { + OBJ_XAP(obj) = OBJ_XAP(obj) / rval + OBJ_YAP(obj) = OBJ_YAP(obj) / rval + } else { + OBJ_XAP(obj) = INDEFR + OBJ_YAP(obj) = INDEFR + } + + j = j + 1 + OBJ_NUM(obj) = j + } + + # Set object mask. + call smark (sp) + call salloc (v, PM_MAXDIM, TY_LONG) + call pm_gsize (out, i, Meml[v], j) + nc = Meml[v]; nl = Meml[v+1] + call salloc (rl, 3+3*nc, TY_INT) + call salloc (buf, nc, TY_INT) + call drenum1 (out, nc, nl, ids, objs, Meml[v], Memi[rl], Memi[buf]) + call sfree (sp) + + # Reorder the arrays and expand object structures. + j = NUMSTART - 1 + do i = NUMSTART, nobjs { + obj = objs[i] + if (obj == NULL) + next + if (OBJ_NUM(obj) == 0) { + call mfree (objs[i], TY_STRUCT) + next + } + + call newobj (obj) + + j = j + 1 + objs[j] = obj + } + nobjs = j +end + + +procedure drenum1 (om, nc, nl, ids, objs, v, rl, buf) + +pointer om #I Object mask pointer +int nc, nl #I Dimensions +int ids[ARB] #I Mask IDs +pointer objs[ARB] #I Objects +long v[PM_MAXDIM] #I Work array +int rl[3,nc] #I Work array +int buf[nc] #I Work array + +int i, j, l, id, andi(), ori() +pointer obj + +begin + v[1] = 1 + do l = 1, nl { + v[2] = l + call pmglri (om, v, rl, 0, nc, 0) + j = 1 + do i = 2, rl[1,1] { + id = rl[3,i] + if (id >= NUMSTART) { + obj = objs[ids[id]] + id = OBJ_NUM(obj) + if (DARK(obj) && id > 0) + id = MSETFLAG(id, MASK_DARK) + } + if (id > 0) { + j = j + 1 + rl[1,j] = rl[1,i] + rl[2,j] = rl[2,i] + rl[3,j] = id + } + } + rl[1,1] = j + call pmplri (om, v, rl, 0, nc, PIX_SRC) + } +end + + +procedure newobj (obj) + +pointer obj #U Object structure + +begin + if (obj == NULL) + return + + call realloc (obj, OBJ_LEN, TY_STRUCT) + OBJ_FLUX(obj) = INDEFR + OBJ_SKY(obj) = INDEFR + OBJ_SIG(obj) = INDEFR + OBJ_PEAK(obj) = INDEFR + OBJ_X1(obj) = INDEFR + OBJ_Y1(obj) = INDEFR + OBJ_WX(obj) = INDEFD + OBJ_WY(obj) = INDEFD + OBJ_XMIN(obj) = INDEFI + OBJ_XMAX(obj) = INDEFI + OBJ_YMIN(obj) = INDEFI + OBJ_YMAX(obj) = INDEFI +end diff --git a/noao/nproto/ace/diffdetect.par b/noao/nproto/ace/diffdetect.par new file mode 100644 index 00000000..6a0c0084 --- /dev/null +++ b/noao/nproto/ace/diffdetect.par @@ -0,0 +1,59 @@ +images,f,a,,,,"List of images" +masks,s,h,"!BPM",,,"List of bad pixel masks" +skys,s,h,"",,,"List of sky maps" +sigmas,s,h,"",,,"List of sigma maps" +exps,s,h,"",,,"List of exposure maps" +gains,s,h,"",,,"List of gain maps" +scales,s,h,"",,,"List of image intensity scale factors + +# Reference Image(s)" +rimages,f,h,,,,"List of reference images" +rmasks,s,h,"!BPM",,,"List of reference bad pixel masks" +rskys,s,h,"",,,"List of reference skys" +rsigmas,s,h,"",,,"List of reference sky sigmas" +rexps,s,h,"",,,"List of reference exposure maps" +rscales,s,h,"",,,"List of reference intensity scale factors + +# Output" +objmasks,f,a,,,,"List of output object masks" +catalogs,f,a,,,,"List of output catalogs" +catdefs,s,h,"ace$lib/catdef.dat",,,"List of catalog definitions" +logfiles,s,h,"STDOUT",,,"List of log files + +# Sky" +skytype,s,h,"block","fit|block",,"Type of sky estimation + +# Sky Fitting" +fitstep,i,h,100,1,,"Line step for sky sampling" +fitblk1d,i,h,10,,,"Block average for line fitting" +fithclip,r,h,2.,,,"High sky clipping during 1D sky estimation" +fitlclip,r,h,3.,,,"Low sky clippling during 1D sky estimation" +fitxorder,i,h,1,1,,"Sky fitting x order" +fityorder,i,h,1,1,,"Sky fitting y order" +fitxterms,s,h,"half","none|full|half",,"Sky fitting cross terms + +# Sky Blocks" +blkstep,i,h,1,1,,"Line step for sky sampling" +blksize,i,h,-10,,,"Block size (+=pixels, -=blocks)" +blknsubblks,i,h,2,1,,"Number of subblocks per axis + +# Detection" +updatesky,b,h,yes,,,"Update sky during detection?" +convolve,s,h,"block 3 3",,,"Convolution kernel" +hsigma,r,h,3.,.1,,"Sigma threshold above sky" +lsigma,r,h,10.,.1,,"Sigma threshold below sky" +hdetect,b,h,yes,,,"Detect objects above sky?" +ldetect,b,h,no,,,"Detect objects below sky?" +neighbors,s,h,"8","4|8",,Neighbor type +minpix,i,h,6,1,,"Minimum number of pixels in detected objects" +sigavg,r,h,4.,0.,,"Sigma of mean flux cutoff" +sigmax,r,h,4.,0.,,"Sigma of maximum pixel" +bpval,i,h,INDEF,,,"Output bad pixel value" +rfrac,r,h,0.5,,,"Minimum fraction of reference flux in difference + +# Growing" +ngrow,i,h,2,0,,"Number of grow rings" +agrow,r,h,2.,0,,"Area grow factor + +# Evaluate" +magzero,s,h,"INDEF",,,"Magnitude zero point" diff --git a/noao/nproto/ace/display.h b/noao/nproto/ace/display.h new file mode 100644 index 00000000..fa89a479 --- /dev/null +++ b/noao/nproto/ace/display.h @@ -0,0 +1,42 @@ +# Display modes: + +define RGB 1 # True color mode +define FRAME 2 # Single frame mode + +# Color selections: + +define BLUE 1B # BLUE Select +define GREEN 2B # GREEN Select +define RED 4B # RED Select +define MONO 7B # RED + GREEN + BLUE + +# Size limiting parameters. + +define MAXCHAN 2 +define SAMPLE_SIZE 600 + +# If a logarithmic greyscale transformation is desired, the input range Z1:Z2 +# will be mapped into the range 1.0 to 10.0 ** MAXLOG before taking the log +# to the base 10. + +define MAXLOG 3 + +# The following parameter is used to compare display pixel coordinates for +# equality. It determines the maximum permissible magnification. The machine +# epsilon is not used because the computations are nontrivial and accumulation +# of error is a problem. + +define DS_TOL (1E-4) + +# These parameters are needed for user defined transfer functions. + +define U_MAXPTS 4096 +define U_Z1 0 +define U_Z2 4095 + +# BPDISPLAY options: + +define BPDISPLAY "|none|overlay|interpolate|" +define BPDNONE 1 # Ignore bad pixel mask +define BPDOVRLY 2 # Overlay bad pixels +define BPDINTERP 3 # Interpolate bad pixels diff --git a/noao/nproto/ace/doc/detect.hlp b/noao/nproto/ace/doc/detect.hlp new file mode 100644 index 00000000..ac18c675 --- /dev/null +++ b/noao/nproto/ace/doc/detect.hlp @@ -0,0 +1,470 @@ +.help detect Sep00 ace +.ih +NAME +detect -- detect and catalog objects in images +.ih +SYNOPSIS +.ih +USAGE +detect images objmasks catalogs +.ih +PARAMETERS +.ls images +List of images containing objects to be detected. The images should generally +have read and write permission to allow addition of header information. +However, the task will still run without write access with the consequence +that the header will not be updated. +.le +.ls masks = "!BPM" +List of bad pixel masks for the images. This may consist of no bad pixel +mask specified as the empty string "", a single bad pixel mask to apply to +all images or a list of bad pixel masks which must match the images list. +Mask names beginning with "!" are image header keywords which point to the +bad pixel mask. +.le +.ls skys = "SKYFIT" +List of sky images, constant values, sky fit names, or keyword +indirection. If only one value is specified then it applies to all input +images otherwise the list must match the images list. Values beginning +with "!" specify image header keywords containing the image name, constant +value, or sky fit name to be used. The value is first checked to see +if an image with that name exists, then if sky fit keywords are in the +header, and finally if it is a number. Sky fit keywords are formed from +the sky fit name with two digit sequence numbers and are interpreted as +surface fit coefficients. + +If none of these are found then the value is treated as the sky fit name +to be used to save sky fitting performed by this task. +.le +.ls sigmas = "SKYSIG" +List of sky sigma images, constant values, sigma fit names, or keyword +indirection. If only one value is specified then it applies to all input +images otherwise the list must match the images list. Values beginning +with "!" specify image header keywords containing the image name, constant +value, or sigma fit name to be used. The value is first checked to see +if an image with that name exists, then if sigma fit keywords are in the +header, and finally if it is a number. Sigma fit keywords are formed from +the sigma fit name with two digit sequence numbers and are interpreted as +surface fit coefficients. + +If none of these are found then the value is treated as the sigma fit name +to be used to save sky fitting performed by this task. +.le + +The following parameters specify the output. +.ls objmasks +List of output object masks. If no list is given then no object masks +will be created. Otherwise there must be one object mask name for each +input image. The object mask name will be recorded in the input image +header and in any output catalog. +.le +.ls catalogs +List of output catalogs. If no list is given then no catalogs will be +created. Otherwise there must be one catalog name for each input image. +The catalog name will be recorded in the input image header and in any +object mask. The catalog is created as a "table" (see \fBtables\fR +for information about the tables and general tools to interact with the +tables). If the name has an explicit ".fits" extension then a FITS binary +table is created otherwise an IRAF table (".tab" extension) is created. +.le +.ls logfiles = "STDOUT" +List of output log files. If no list is given then no output log information +will be produced. If only one file is specified it applies to all input +images otherwise the list of files must match the images list. Note that +the special name "STDOUT" corresponds to terminal output. +.le + +The following parameters define the initial sky fit determination. This is +only done if no sky image or sky constant value and sigma image or sigma +constant value are specified. +# Sky +.ls newsky = no +Determine new sky fit if one already exists? When the specified sky +corresponds to an existing sky fit (the sky fit coefficients are in the +image header) then this parameter is used to override that fit with a new +fit. Otherwise the fit is used and the initial sky fitting is skipped. +The sky fitting is also skipped if the specified sky is an image or +constant. +.le +.ls nskylines = 100 +Number of sky sample lines to use. This number of lines spread evenly +through the image are used to determine the initial sky fit. +.le +.ls skyblk1d = 10 +Sky block size for 1D sky estimation. +.le +.ls skyhclip = 2. +High sky clipping during 1D sky estimation +.le +.ls skylclip = 3. +Low sky clippling during 1D sky estimation +.le +.ls skyxorder = 4 +Sky fitting x order +.le +.ls skyyorder = 4 +Sky fitting y order +.le +.ls skyxterms = "half" (none|half|full) +Sky fitting y order +.le + +# Iterated Sky +.ls skyupdate = no +Update sky after detection iterations? +.le +.ls niterate = 1 +Maximum number of sky iterations +.le +.ls skyblk2d = 50 +Sky block size during detection +.le +.ls maxskyres = 0.2 +Maximum sky residual for iteration +.le + +# Detection +.ls convolve = "block 3 3" +Convolution kernel +.le +.ls hsigma = 3. +Sigma threshold above sky +.le +.ls lsigma = 10. +Sigma threshold below sky +.le +.ls hdetect = yes +Detect objects above sky? +.le +.ls ldetect = yes +Detect objects below sky? +.le +.ls minpix = 10 +Minimum number of pixels in detected objects +.le +.ls sigavg = 4. +Sigma of mean flux cutoff +.le +.ls sigmax = 4. +Sigma of maximum pixel +.le +.ls bpval = 1 +Output bad pixel value +.le + +# Splitting" +.ls split = yes +Split objects? +.le +.ls splitmax = INDEF +Maximum sigma above sky for splitting +.le +.ls splitstep = 0.4 +Splitting steps in convolved sigma +.le +.ls splitthresh = 5. +Splitting threshold in sigma +.le +.ls sminpix = 10 +Minimum number of pixels in split objects +.le +.ls ssigavg = 10. +Sigma of mean flux cutoff +.le +.ls ssigmax = 5. +Sigma of maximum pixel +.le + + +# Growing" +.ls ngrow = 2 +Number of grow rings +.le +.ls agrow = 2. +Area grow factor +.le +.ih +DESCRIPTION + +SKY DETERMINATION + +A critical part of detecting objects in astronomical images is determining +the background sky and sky sigma at each point in the image. In the +following discussion sky means both the mean sky level and the sky sigma. +\fBDetect\fR provides for either the user to specify the sky or for the +task to use a sky fitting algorithm. The user may specify a sky either as +another image or as a constant value. Note that the image name or +value may be specified either explicitly or with a keyword associated +with the image. + +If the sky is not specified by an image or constant value then a surface +fit to the sky is used. The surface fit is recorded in the image header as +a sequence of keywords with a specified name (the keyword prefix which may +be up to six characters) and two digit sequence number. The values of the +keywords contain the coefficients of the fit. The the surface fit +coefficients are defined in the SURFACE FIT section. + +Note that it is possible to specify the mean sky and the sky sigma in +different ways. When one is given as an image or constant and the other +as a fit. The one given as an image or constant will be kept fixed and +the fit determination and updating will be done only on the other. + +The sky surface fit is computed in two stages. There is an initial +determination using a subsample of image lines. Then there is an +optional update of the sky sample during the object detection step. +The detection step with sky updating may be iterated a specified number +of times until the maximum difference in the mean sky is less than some +amount. + +INITIAL SKY DETERMINATION + +If an existing surface fit is specified then the parameter \fInewsky\fR +selects whether a new surface fit is to be computed. If the value is "no" +then the initial sky determination is skipped though the detection update +may still be selected. + +The initial sky fit uses a combination of block averaging to reduce the +number of points in the fitting, one dimensional line fitting with sigma +clipping rejection to eliminate objects, and finally fitting a two +dimensional surface to the set of block averages over all the sample lines +which cover the image. + +The parameter \fInskylines\fR defines the number of sample lines across +the image to be used. The lines are evenly spaced starting with the +first line and ending with the last line. The number of lines affects +how fast the sky estimation is done. + +The pixels from the input line are initially all given unit weight. Bad +pixels identified by the input bad pixel mask are excluded by setting their +weights to zero. A weighted block average, with the weight of each block +being the sum of the weights, is computed. The size of the blocks is given +by the \fIskyblk1d\fR parameter. This is done to speed the fitting by +reducing the number of points. Note that when all pixels in a block have +zero weight due to the bad pixel mask or subsequent rejection the weight of +the composite block average point is zero. + +If only one of sky mean and sky sigma quantities is being determined with +the other quantity given by an input image, constant, or previous fit +then those values are simple block averaged with the same block size +to produce sample points for the mean sky or sky sigma. Note that the +sky sigma of the sample points also requires division by the square root +of the block size to give the sky sigma per block average point. The +line fitting described next is then skipped for this quantity. + +The weighted one dimensional line fitting to the block averages uses +Chebyshev polynomials of order given by the \fIskyxorder\fR. Note that +this order is the number of polynomial terms, which is one higher than the +maximum power of the polynomial so that a value of 3 corresponds to a +quadratic polynomial. + +When the mean sky is being determined, the line fitting is performed and +the fitted values at the block centers are evaluated. + +When the sky sigma is being determined, the absolute value of the residuals +relative to the mean sky divided by 0.7979 are computed. A gaussian noise +distribution will have a mean value of this quantity equal to the sigma of +the distribution. In other words, the mean of the absolute deviations of a +gaussian distribution is 0.7979 times sigma. By fitting a function to +these residual values a position variable estimate of the sky sigma is +obtained without needing to compute standard deviations over some set of +points. The fitted values at the block centers are evaluated to give the +sky sigmas for the block averaged data. + +With the set of block averaged data points and estimated mean skys and sky +sigmas points that deviate by more than the number of sigma given by the +\fIskyhclip\fR and \fIskylclip\fR parameters are rejected by setting their +weights to zero. The line fitting is then repeated until no points are +rejected with a maximum of 10 iterations. + +When the iteration completes the block average points for that image line +are accumulated for a two dimensional surface fit. Note that the weights +are used to exclude rejected averages and to weight blocks that had fewer +points due to bad pixels. The surface fit is a two dimensional Chebyshev +polynomial of orders given by the \fIskyxorder\fR and \fIskyyorder\fR. The +orders have the same meaning as in the one dimensional polynomial, namely +the number of terms in powers of x and y. There are also cross terms which +are a mixture of powers of both x and y. The \fIskyxterms\fR select +whether to use any cross terms, only cross terms whose total power does not +exceed the maximum of the pure x and y terms, or all combinations of +powers. + +After all the sample lines are completed the final surface fits are +computed. The coefficients of the fits are written to the image header +under the specified sky fit names and the fits are passed on to the +detection phase. Note that if the input image is read only then the +fit will not be written to the header but the task continues. + +UPDATED TO SKY DURING DETECTION + + +DETECTION + +The detection of objects in an image is conceptually quite simple. Each +pixel is compared against the expected sky at that point and if it is +more that a specified number of sky sigma above the sky it is a candidate +object pixels. Candidate object pixels are grouped into objects on the basis +of being connected along the eight neighboring directions. The candidate +object is then accepted if it satisfies the criteria of a minimum +number of pixels, a sufficiently significant maximum pixel, and a sufficiently +significant flux above sky. + +To detect faint objects where individual pixels are not significantly above +the sky but all pixels taken together are significant a detection filter is +applied. This consists of applying a convolution function to the image and +performing the detection described in the previous paragraph on the +convolved pixels with the sky sigma suitable adjusted for the convolution. +The convolution acts as an optimizing filter for objects with shapes +corresponding to the convolution weights. The remaining discussion +is in terms of the convolved pixel values. The case of no convolution +can be thought of as a convolution with a delta function though the +implementation is not done as a convolution for efficiency. + +Two other options to the detection are to also find pixels that are +significantly below sky (using an independent threshold to that used for +detecting pixels above sky) and form them into "dark" objects and to +take the remaining pixels that are not significantly above or below the +sky and use them to define a sky sample for output or for updating the +initial sky. + +We now go into more detail. The background sky and sky sigma against which +the detection is performed is initially set as described earlier. If desired +the sky pixels may be accumulated to update the sky. After updating the +sky the detection step may be repeated using the new sky. This is +discussed futher when we reach the end of the detection step description. + +The convolution is specified by the \fIconvolve\fR parameter. The values for +this parameter and the definition of the convolution are given in the +CONVOLUTION DETECTION FILTER section. The input pixel data is convolved +and the sky sigma is appropriately adjusted. + +When the central pixel in the convolution is flagged as a bad pixel by the +bad pixel mask (any non-zero value is a bad pixels) then the convolved +value is considered to be a bad pixel. If an output object masks is +specified the pixel will be marked with the value specified by the +\fIbpval\fR parameter. The value may be set to not show the bad pixel in +the object mask, to set all input bad pixels to some value, or to pass the +input bad pixel value to the object mask. Note that bad pixel masks in the +object mask must be between 1 and 10 to avoid confusion with the values +used to identify objects. If other pixels in the convolution are flagged +as bad pixels they are excluded from the convolution and the +convolved sky sigma is adjusted but the convolution value is still used +as a valid image pixel for detection. + +The sigma threshold for pixels to be detected as part of an object above +sky is given by the \fIhsigma\fR. This number is multiplied by the sky +sigma to get the deviation from sky. As noted earlier the sky sigma is +for the convolved pixels and the + + +CONVOLUTION DETECTION FILTER + + +The convolution detection filter is specified with the \fIconvolve\fR +parameter. There is only one convolution that can be specified and it applies +to all input images in a list. If a null string ("") is specified +then no convolution is performed. The task has been optimizations for +this case to avoid treating this as a 1x1 convolution and to avoid extra +memory allocations required when a convolution is done. + +The convolved value at pixel (i,j), denoted I(i,j), within an image of size +CxL is defined by + +.nf + I_convolved(i,j) = sum_kl{I_unconvolved(m,n)*W(k,l)} / sum_kl{W(k,l)} +.fi + +where I(m,n) is the unconvolved value at pixel (m,n), W(k,l) are the NX x +NY (both must be odd) convolution weights, sum_kl is the double sum over k +and l, and + +.nf + m' = i + k - (NX+1)/2 for k = 1 to NX + n' = j + l - (NY+1)/2 for l = 1 to NY + + m = m' (1<=m'<=C) m = 1-m' (m'<1) m = 2C-m' (m'>C) + n = n' (1<=n'<=L) n = 1-n' (n'<1) n = 2L-n' (m'>L) +.fi + +The last two lines represent boundary reflection at the edges of the image. + +The sky sigma of a convolved pixel is approximated by + +.nf + sigma_convolved(i,j) = sigma_unconvolved(i,j) / sum_kl{W(k,l)} +.fi + +In the presence of bad pixels identified by a bad pixel mask the convolution +weight applied to a bad pixel is set to zero. The sum of the weights +used to normalize the convolution is then modified from the situation with +no bad pixels. This will correct the convolved pixel value for the missing +data and the estimated sky sigma is appropriately larger. + +A convolution can be computational slow, especially for larger sizes. +The implementation of the convolution has been optimized to recognize +bilinear symmetries or lines which are scaled versions of other lines. +So if possible such symmetries should be used. The "block", "bilinear", +and "gauss" special convolutions described below have such symmetries. + +There is also an overhead in checking for bad pixels. The convolution +has an optimization to avoid such checks in the case where no bad pixel +mask is specified. + +The \fIconvolve\fR parameter is a string which can take one of the +following forms. + +.ls "" +There is no convolution or, equivalently, NX=1, NY=1. +.le +.ls @[filename] +The weights are given in the specified file. The format consists of lines +of whitespace separated values. The number of values on each line must be +the same and defines NX and the number of lines defines NY. +.le +.ls block [NX] [NY] +The weights are all the same and the convolution size is given by the +two numbers following the word "block". +.le +.ls bilinear [NX] [NY] +The weights are the bilinear matrix product of triangular one dimensional +matrices of sizes given by the two numbers following the word "bilinear". +The weights are described by the matrix product relation + +.nf + [1 ... (NX+1)/2 ... 1] * Transpose{[1 ... (NY+2)/2 ... 1]} +.fi + +For example for NX=5, and NY=3 the weights would be + +.nf + 1 2 3 2 1 + 2 4 6 4 2 + 1 2 3 2 1 +.fi +.le +.ls gauss [NX] [NY] [SX] [SY] +The weights are bidimensional gaussian values on a grid of size NX by NY +with sigma values SX and SY (real numbers) in units of pixel spacing. +.le +.ls [W(1,1)] ... [W(NX,1)], ..., [W(1,NY)] ... [W(NX,NY)] +The weights are specified as a string of real values. The values are +whitespace separated within each line and the lines are delimited by +comma. For example + +.nf + 1 2 1 + 1 2 1, 2 3 2, 1 2 1 ==> 2 3 2 + 1 2 1 +.le + +When a logfile is defined the weights are included in the log output. + + +OBJECT MASKS + +.ih +EXAMPLES +.ih +REVISIONS +.ih +SEE ALSO +.endhelp diff --git a/noao/nproto/ace/doc/installation.hlp b/noao/nproto/ace/doc/installation.hlp new file mode 100644 index 00000000..c399ad4c --- /dev/null +++ b/noao/nproto/ace/doc/installation.hlp @@ -0,0 +1,208 @@ +.help installation Jan01 ace + +.ce +\fBACE: Astronomical Cataloging Environment\fR +.ce +Release Notes and Installation Instructions + +.sh +SUMMARY +The ACE external package is used to catalog objects in images and manipulate +the catalogs. + +.sh +RELEASE INFORMATION +The following summary only highlights the major changes. There will also +be minor changes and bug fixes. + +.ls V0.2: January 27, 2001 +Alpha test version. +.le +.sh +INSTALLATION INSTRUCTIONS +Installation of this external package consists of obtaining the files, +creating a directory containing the package, compiling the executables or +installing precompiled executables, and defining the environment to load +and run the package. The package may be +installed for a site or as a personal installation. If you need help with +these installation instructions contact iraf@noao.edu or call the IRAF +HOTLINE at 520-318-8160. +.ls [arch] +In the following steps you will need to know the IRAF architecture +identifier for your IRAF installation. This identifier is similar to the +host operating system type. The identifiers are things like "ssun" for +Solaris, "alpha" for Dec Alpha, and "linux" or "redhat" for most Linux +systems. The IRAF architecture identifier is defined when you run IRAF. +Start the CL and then type + +.nf + cl> show arch + .ssun +.fi + +This is the value you need to know without the leading '.'; i.e. the +IRAF architecture is "ssun" in the above example. +.le +.ls [1-site] +If you are installing the package for site use, login as IRAF +and edit the IRAF file defining the packages. + +.nf + % cd $hlib +.fi + +Define the environment variable ace to be the pathname to +the ace package root directory. The '$' +character must be escaped in the VMS pathname and UNIX pathnames must be +terminated with a '/'. Edit extern.pkg to include the following. + +.nf + reset ace = /local/ace/ + task ace.pkg = ace$ace.cl +.fi + +Near the end of the hlib$extern.pkg file, update the definition of +helpdb so it includes the ace help database, copying the syntax +already used in the string. Add this line before the line +containing a closing quote: + +.nf + ,ace$lib/helpdb.mip\ +.fi +.le +.ls [1-personal] +If you are installing the package for personal use define a host +environment variable with the pathname of the directory where the package +will be located (needed in order to build the package from the source +code). Note that pathnames must end with '/'. For example: + +.nf + % setenv ace /local/ace/ +.fi + +In your login.cl or loginuser.cl file make the following definitions +somewhere before the "keep" statement. + +.nf + reset ace = /local/ace/ + task ace.pkg = ace$ace.cl + printf ("reset helpdb=%s,ace$lib/helpdb.mip\nkeep\n", + envget("helpdb")) | cl + flpr +.fi + +If you will be compiling the package, as opposed to installing a binary +distribution, then you need to define various environment variables. +The following is for Unix/csh which is the main supported environment. + +.nf + # Example + % setenv iraf /iraf/iraf/ # Path to IRAF root (example) + % source $iraf/unix/hlib/irafuser.csh # Define rest of environment + % setenv IRAFARCH ssun # IRAF architecture +.fi + +where you need to supply the appropriate path to the IRAF installation root +in the first step and the IRAF architecture identifier for your machine +in the last step. +.le +.ls [2] +Login into IRAF. Create a directory to contain the package files and the +instrument database files. These directory should be outside the standard +IRAF directory tree. + +.nf + cl> mkdir ace$ + cl> cd ace +.fi +.le +.ls [3] +The package is distributed as a tar archive for the +sources and, as an optional convenience, a tar archive of the executables +for select host computers. Note that IRAF includes a tar reader. The tar +file(s) are most commonly obtained via anonymous ftp. Below is an example +from a Unix machine where the compressed files have the ".Z" extension. +Files with ".gz" or ".tgz" can be handled similarly. + +.nf + cl> ftp iraf.noao.edu (140.252.1.1) + login: anonymous + password: [your email address] + ftp> cd iraf/extern + ftp> get ace.readme + ftp> binary + ftp> get ace.tar.Z + ftp> get ace-bin.<arch>.Z (optional) + ftp> quit + cl> !uncompress ace.tar + cl> !uncompress ace-bin.<arch> (optional) +.fi + +The readme file contains these instructions. The <arch> in the +optional executable distribution is replaced by the IRAF architecture +identification for your computer. + +Upon request the tar file(s) may be otained on tape for a service +charge. In this case you would mount the tape use rtar to extract +the tar files. +.le +.ls [4] +Extract the source files from the tar archive using 'rtar". + +.nf + cl> softools + so> rtar -xrf ace.tar + so> bye +.fi + +On some systems, an error message will appear ("Copy 'bin.generic' +to './bin fails") which can be ignored. +Sites should leave the symbolic link 'bin' in the package root +directory pointing to 'bin.generic' but can delete any of the +bin.<arch> directories that won't be used. If there is no binary +directory for the system you are installing it will be created +when the package is compiled later or when the binaries are installed. + +If the binary executables have been obtained these are now extracted +into the appropriate bin.<arch> directory. + +.nf + # Example of sparc installation. + cl> cd ace + cl> rtar -xrf ace-bin.sparc # Creates bin.sparc directory +.fi + +The various tar file can be deleted once they have been +successfully installed. +.ls [5] +For a source installation you now have to build the package +executable(s). The "tables" package must be installed first if not +already available. First you configure the package for the particular +architecture. + +.nf + cl> cd ace + cl> mkpkg <arch> # Substitute sparc, ssun, alpha, etc. +.fi + +This will change the bin link from bin.generic to bin.<arch>. The binary +directory will be created if not present. If an error occurs in setting +the architecture then you may need to add an entry to the file "mkpkg". +Just follow the examples in the file. + +To create the executables and move them to the binary directory + +.nf + cl> mkpkg -p ace # build executables + cl> mkpkg generic # optionally restore generic setting +.fi + +Check for errors. If the executables are not moved to the binary directory +then step [1] to define the path for the package was not done correctly. +The last step restores the package to a generic configuration. This is not +necessary if you will only have one architecture for the package. +.le + +This should complete the installation. You can now load the package +and begin testing and use. +.endhelp diff --git a/noao/nproto/ace/doc/objmasks.hlp b/noao/nproto/ace/doc/objmasks.hlp new file mode 100644 index 00000000..1c35c4c9 --- /dev/null +++ b/noao/nproto/ace/doc/objmasks.hlp @@ -0,0 +1,710 @@ +.help objmasks Jan02 nproto +.ih +NAME +objmasks -- detect objects in images and create masks and sky maps +.ih +SYNOPSIS +.ih +USAGE +objmasks images objmasks skys +.ih +PARAMETERS +.ls images +List of images or multiextension files for which object masks are desired. +.le +.ls objmasks +List of object masks to be created. This list must match the input list. +Multiextension input files will produce multiextension mask files. If the +input image is writable, the name of the created mask will recorded in the +image header. Note that it is possible to specify a null image to +not produce an output mask. This might be done if the background sky +or sky sigma maps are desired or to just see the log information. +.le + +.ls omtype = "numbers" (boolean|numbers|colors|all) +The type of encoding for the object mask values. In all cases non-object pixels +(that is background) have mask values of zero. The choices for the mask +values are "boolean", "numbers", "colors", and "all". These are described +in the \fIOutput Data\fR section. +.le +.ls skys = "", sigmas = "" +Optional lists of input or output sky and sigma maps. Maps are either +constant values or images which are interpolated to the size of the input +images. If a list is given it must match the input \fIimages\fR list. +If constant values or existing maps are specified then those are used +without change. If a new filename is given then an output file is created +with the values computed by the task. Multiextension input images create +or apply the same extension names to the specified sky or sigma files. +Constant input values apply to all extensions. The sigma values are +per single input image pixel. +.le +.ls masks = "!BPM" +List of bad pixel masks for the input images. Non-zero masks values are +ignored in the object detection and are passed on to the output object +masks based on the \fIomtype\fR parameter. An empty list applies no bad +pixel mask, a single mask applies to all input images, and a matching +list matches the masks with the input image. A mask is specified by a +filename or by reference to a filename given by the value of a header +keyword in the input image. A header keyword reference is made with the +syntax "!<keyword>" where <keyword> is the desired keyword with case +ignored. For multiextension files the input masks may be either a +multiextension file with matching extension names or a directory of +pixel list files with the extension names as filenames. +.le +.ls extnames = "" +Extensions to select from multiextension files. A null string matches all +extension names. Otherwise the parameter is a comma separated list of +patterns that match the entire extension name. Thus, an explicit list of +extension names may be specified or the pattern matching characters '?' for +any character or '[]' for a set of characters may be used. The set may +include ranges in ascii order by using hyphens; i.e. 1-3 matches the +characters 1, 2, and 3. +.le +.ls logfiles = "STDOUT" +List of output log files. If no list is given then no output log information +will be produced. If only one file is specified it applies to all input +images otherwise the list of files must match the images list. Note that +the special name "STDOUT" corresponds to terminal output. +.le + +.ls blkstep = 1 +The mean and sigma of the background or sky pixels are determined in a +first pass through the image. If \fIblkstep\fR is one all lines are used. +To skip lines in order to speed up this computation, the parameter may be +set to a larger value to define the increment between lines. However, the +task will enforce a preset minimum number to insure a sufficient sample. +.le +.ls blksize = -10 +The background mean sky and sky sigma are determined in a set of square +blocks from which the values are linearly interpolated to each point in the +input image. The size of the blocks may be specified as a number of blocks +spanning the smaller image dimension by using a negative integer value. +Or the size may be specified as the number of pixels across a block. +The task will enforce a preset minimum number of pixels per block which may +require using bigger blocks than specified. The background determination +algorithm is described further in the "Background Determination" section. +.le + +.ls convolve = "block 3 3" +Convolution filter to be applied prior to threshold detection. The +convolution filter is defined by a set of weights in a 2D array. These +may be specified in files or with certain forms given by special strings. +The options are described in the "Convolution Filter" section. +.le +.ls hsigma = 3., lsigma = 10. +Object pixels are identified by sigma thresholds about the mean background +based on the estimated background sigma at each point in the image. +The sigma factors are specified in terms of the "per pixel" sigma before +convolution. The \fIhsigma\fR value is the "high" or above background +limit and the \fIlsigma\fR value is the "low" or below background limit. +Typically detections are one-sided, such as detecting objects above +the background, and so the thresholds need not be equal. +.le +.ls hdetect = yes, ldetect = no +Identify objects as pixels which are above the background (\fIhdetect\fR) +and below the background (\fIldetect\fR)? If objects are detected but the +corresponding parameter is no then the output mask will not include those +objects. +.le +.ls neighbors = "8" (8|4) +The threshold selected pixels are associated with other neighboring pixels to +form an object. The criterion for a neighbor being part of the +same object is defined by this parameter. The choices are "8" for +pixels touching in any of the 8 directions or "4" to identify neighbors +as only horizontal or vertically adjacent. +.le +.ls minpix = 6 +The minimum number of neighboring pixels which define an acceptable object. +.le +.ls ngrow = 2, agrow = 2. +After an object is identified as a set of threshold detected pixels, +additional neighboring pixels may be added to the object. This allows +expanding the object into the faint wings of the light distribution. The +additional pixels are those which touch the boundary pixels. Pixels are +added in multiple passes, each time extending the previous boundary. The +parameter \fIngrow\fR (an integer value) defines the maximum number of +boundary extensions. The parameter \fIagrow\fR (a real value) specifies +the maximum increase in area (number of pixels) from the original +detection. +.le +.ih +DESCRIPTION +\fBOBJMASKS\fR is a task for creating masks covering objects in images. +An optional secondary product of this task is to produce background +and sigma maps. Objects are identified by threshold sigma detection. +These object masks may be used by other applications to exclude the object +data or focus on the objects. The detection consists of determining a +smooth, spatially variable mean background and background sigma (if no +input maps are provided), convolving the data by an optional filter to +optimize detection of faint sources, collecting pixels satisfying the +detection thresholds, assigning neighboring pixels to a common object, +applying a minimum number of pixels test to the objects, and growing +objects to extend into the wings of the object light distribution. +The last step is writing out the identified object pixels as a mask. + +1. Input Data + +The input data consists of one or more 2D images. The images are assumed +to contain a moderately smooth background and multiple sources or +objects. This task is most useful for images with large numbers of small +sources rather than one large object such as a nearby galaxy. The input +images, specified by the \fIimages\fR parameter, may be individual images +(which includes images selected from multiextension files as explicit +image extensions) or multiextension files specified by a root filename. In +the latter case the image extension names selected by the \fIextnames\fR +parameter are used. + +Background means and sigmas (specified per image pixels) may be specified +by "maps". These may be constant numerical values or images. The map +images will be linearly interpolated to the size of the input images. +For multi-extension input data, constant map values apply to all extensions +and maps are also multiextension files with map images having the same +extension names. + +Bad pixel masks may be associated with the input images to +exclude pixels from the background and object determinations. These +bad pixels are also included in the output object masks. The bad pixel +masks are specified by the \fImasks\fR parameter. This parameter may +identify a mask by a filename or a keyword. A single mask may be +specified to apply to all images or a matching list of masks may be +given. + +The masks are in one of the supported mask formats. As of IRAF V2.12 this +includes pixel list (.pl) files and FITS "type=mask" extensions. When the +input files are multiextension files, the selected extension names are +appended to the specified mask filename to select masks with the same +extension name. If a mask file of the form "name[ext]" is not found +the task will treat the filename as a directory of pixel list files and +select the pixel list file with the extension name; i.e. "name/ext.pl". + +2. Output Data + +The output of this task are object masks, sky maps, sigma maps, and log +information. The output object masks default to mask type extensions. If an +extension name is not specified explicitly the default extension name +"pl" is created. To select a pixel list output format an explicit ".pl" +extension must be used. + +When the input data are multiextension files, the output masks, mean sky +maps, and sky sigma maps will be multiextension files with the specified +rootnames and the same extension name as the input. + +The output mask values identify non-object pixels with zero. The non-zero +values are encoded as selected by the \fIomtype\fR parameter. The choices +are: + +.ls "boolean" +All object and bad pixels have a mask value of one; i.e. the output masks +consists only of the values 0 and 1. +.le +.ls "numbers" +Input bad pixels values between 1 and 10 preserve their value and all +other input mask values are mapped to 10. The object mask pixels have +object numbers starting with 11. The object numbers are assigned by +the task (roughly in order from the first line to the last line) and +all pixels from a single object have the same unique object number. +.le +.ls "colors" +Input bad pixels are mapped to output values of one. The object numbers +are modulo 8 plus 2; i.e. values between 2 and 9. The purpose of this +numbering is to allow mapping to the nine standard display colors for an +interesting overlay with the \fBdisplay\fR task and "ocolors='+203'". +.le +.ls "all" +This is the same as "numbers" except that bits 24 to 27 in the mask values +are used for various purposes. In particular bit 24 is set for the boundary +pixels. This numbering will be used in the future by special tasks. +.le + +Output mean sky and sky sigma maps consist of the mean and sigma values +in blocks as described in the "Background Determination" section. +Therefore, the size of the map images are smaller than the input data images. +These maps need to be interpolated to the size of the input image +to obtain the values used for particular pixels in the data images. +This interpolation expansion is done automatically by some tasks such +as \fBmscred.rmfringe\fR. + +The log output provides information about the files, the phase of the +processing, some of the parameters, and the convolution filter weights. +The output begins with the task identifier ACE. This is because this +prototype task is a first release piece of a major package called ACE +(Astronomical Cataloging Environment), which is under development. + +3. Background Determination + +Detection of sources in an image begins with determining the background. +By this we mean estimating the probability distribution of the background +pixel values at every pixel in the image. In practice we only estimate +the central value and width and assume a normal distribution for evaluating +the significance of deviations from the central value. Since we normally +won't have a sample of values at each pixel the distribution is +determined from a sample of nearby pixels. + +In this discussion the central value of a distribution is denoted by <I>. +It is estimated by the mean or mode of the sample. The width of the +distribution about <I> is denoted by <S> and is estimated by the absolute +mean residual converted to the standard deviation of a normal distribution +with the same absolute mean residual. The normal deviation of a value I +from the distribution is defined as R = (I - <I>) / <S>. + +The background may be specified by input maps for one or both of the +background quantities. The maps may be constant values which apply +to all pixels or a grid of values given in an image which are linearly +interpolated to the full size of the input data. For those quantities +which are not input the following algorithm is used for computing +a map. The maps may be output and used as a product of this task. + +The background and/or sigma are estimated in two initial passes through the +data. The first pass algorithm fits linear functions to a subsample of +lines using sigma clipping iteration to eliminate objects. The subsample +is used to speed up the algorithm and is reasonable since only linear +functions are used. Each sample line is block averaged in blocks of 10 +pixels and a linear function is fit by least squares to obtain an estimate +for <I> along the line. The fitting weights are the number of good pixels +in each block average after elimination of bad pixels specified by the +user in a bad pixel mask. The absolute values of the residuals are also +fit to produce a constant function for <S>. + +To exclude objects from affecting these estimates the fitting is iterated +using sigma clipping rejection on the normal deviations R. In the +first iteration the fitting function for <S> is a constant and in +subsequent steps a linear fit is used. When the sigma clipping iteration +rejects no more data, the remaining block averages, absolute residuals, and +weights are used to fit a 2D plane for both <I> and <S>. The <S> surface +is a constant in order to avoid potential negative sigma values. + +This first pass algorithm is fast and produces good estimates for the +planar approximation to the background. The second pass divides the image +into large, equal sized blocks, as specified by the \fIblksize\fR +parameter, and estimates <I> and <S> in each block. The size of the blocks +needs to be large enough to give good estimates of the statistics though +small enough to handle the scale of variations in the sky. Each block is +divided into four subblocks for independent estimates which are then +combined into a final value for the block. As with the first pass, the +second pass can be speeded up by using a subsample of lines (parameter +\fBblkstep\fR) provided some minimum number of lines per subblock is +maintained. + +The background estimates in each subblock are made using histograms of the +normal deviations R computed relative to the first pass estimates of <I> +and <S>. When pixels are added into the histogram the <I> and <S> used to +compute R are accumulated into means of these quantities in order +to convert estimates from the normalized deviation histogram back into data +values. The histograms are truncated at +/-2.5 and have bin widths +determined by requiring a specified average bin population based on the +number of pixels in the block. Typically the bin population is of order +500. The histogram truncation is essentially an object-background +discrimination. + +When all the pixels in a subblock have been accumulated, new estimates of +<I> and <S> are computed. If the number of pixels in the histogram is +less than two-thirds of the subblock pixels the estimates are set to be +indefinite. This flags the subblock as too contaminated by objects to be +used. All subblock neighbors, which may cross the full block boundaries, +are also rejected to minimize contamination by the wings of big galaxies +and very bright stars. + +If the histogram has enough pixels, the bin populations are squared to +emphasize the peak of the distribution and reduce the effects of the +truncated edges of the histogram. Because of noise and the fine binning of +the histogram, a simple mode cannot be used and squaring the bin numbers +helps to approach the mode with a centroid. Squaring the bin values and +then computing the centroid can also be thought of as a weighted centroid. + +Generally a mode is considered the best estimate to use for the central +value <I> of the sky distribution. But it is unclear how to best estimate +the mode without an infinite number of pixels. One could do something like +fit a parabola to the histogram peak. But instead we use the empirical +relation for a skewed distribution between the mean, mode, and median; +<I>=mean-3*(mean-median). The mean is the weighted centroid and the median +is obtained numerically from the histogram using linear interpolation to +get a subbin value. + +The <S> values are obtained from the absolute mean residual of the +unweighted histogram about the previously derived central value <I> of the +histogram. The conversion to a standard deviation is made by computing the +ratio between the standard deviation and mean absolute deviation of a +Gaussian distribution. The standard value over the entire distribution +cannot be used because the histogram is truncated. However, it is easy to +numerically compute the ratio with the same truncation. + +Once <I> and <S> are obtained in bin numbers it is converted to data +values by using the mean and sigma of the input pixel values used +to create the histogram. + +The averages of the subblock <I> and <S> values which are not indeterminate +in each block are computed. If any of the full blocks are indeterminate +when all the subblocks have been eliminated as contaminated, values are +obtained for them by interpolation from nearby blocks. The block values +are then linearly interpolated to get background values for every +pixel in the input image. + +Note that the background pixels used in the block algorithm before +detection are derived by simple sigma clipping of the histogram values +around the planar background. If an output map for either the mean +values or the sigmas is specified then during the object detection stage +the background and sigmas are updated using the detected sky pixels about +the initial block sampled background. This is a more sensitive selection +of sky pixels since convolution filtering can exclude pixels from faint +objects and the wings of all objects. The new set of sky pixels are +accumulated and used in the same way as described earlier. + +4. Convolution Filters + +In order to improve the detection of faint sources dominated by the +background noise, the input data may be convolved to produce filtered +values in which the noise has been suppressed. The threshold detection +is then performed on the filtered data values. + +The convolution detection filter is specified with the \fIconvolve\fR +parameter. There is only one convolution that can be specified and it +applies to all input images in a list. If a null string ("") is specified +then no convolution is performed. The task has been optimizations for this +case to avoid treating this as a 1x1 convolution and to avoid extra memory +allocations required when a convolution is done. + +The convolved value at pixel (i,j), denoted I'(i,j), is defined by + +.nf + I'(i,j) = sum_kl{I(m,n)*W(k,l)} / sum_kl{W(k,l)} +.fi + +where I(m,n) is the unconvolved value at pixel (m,n), W(k,l) are the NX x +NY (both must be odd) convolution weights, sum_kl is the double sum over k +and l, and + +.nf + m' = i + k - (NX+1)/2 for k = 1 to NX + n' = j + l - (NY+1)/2 for l = 1 to NY + + m = m' (1<=m'<=C) m = 1-m' (m'<1) m = 2C-m' (m'>C) + n = n' (1<=n'<=L) n = 1-n' (n'<1) n = 2L-n' (m'>L) +.fi + +The size of the image is C x L. The last two lines represent boundary +reflection at the edges of the image. + +The sky sigma of a convolved pixel is approximated by + +.nf + sigma'(i,j) = sigma(i,j) / sum_kl{W(k,l)} +.fi + +In the presence of bad pixels specified in the bad pixel mask the +convolution weight applied to a bad pixel is set to zero. If the central +pixel is bad then the convolved value is also considered to be bad. The +sum of the weights used to normalize the convolution is then modified from +the situation with no bad pixels. This will correct the convolved pixel +value for the missing data and the estimated sky sigma is appropriately +larger. Since there is an overhead in checking for bad pixels the +convolution has an optimization to avoid such checks in the case where no +bad pixel mask is specified. + +A convolution can be computational slow, especially for larger convolution +kernel sizes. The implementation of the convolution has been optimized to +recognize bilinear symmetries or lines which are scaled versions of other +lines. So if possible users should chose convolutions with such symmetries +to be most efficient. The "block", "bilinear", and "gauss" special +convolutions described below all have such symmetries. + +The \fIconvolve\fR parameter is a string with one of the following forms. + +.ls "" +There is no convolution or, equivalently, NX=1, NY=1. +.le +.ls @[filename] +The weights are given in the specified file. The format consists of lines +of whitespace separated values. The number of values on each line must be +the same and defines NX and the number of lines defines NY. +.le +.ls block [NX] [NY] +The weights are all the same and the convolution size is given by the +two numbers following the word "block". This is a moving block average +filter. +.le +.ls bilinear [NX] [NY] +The weights are the bilinear matrix product of triangular one dimensional +matrices of sizes given by the two numbers following the word "bilinear". +The weights are described by the matrix product relation + +.nf + [1 ... (NX+1)/2 ... 1] * Transpose{[1 ... (NY+2)/2 ... 1]} +.fi + +For example for NX=5, and NY=3 the weights would be + +.nf + 1 2 3 2 1 + 2 4 6 4 2 + 1 2 3 2 1 +.fi +.le +.ls gauss [NX] [NY] [SX] [SY] +The weights are bidimensional gaussian values on a grid of size NX by NY +with sigma values SX and SY (real numbers) in units of pixel spacing. +.le +.ls [W(1,1)] ... [W(NX,1)], ..., [W(1,NY)] ... [W(NX,NY)] +The weights are specified as a string of real values. The values are +whitespace separated within each line and the lines are delimited by +comma. For example + +.nf + 1 2 1 + 1 2 1, 2 3 2, 1 2 1 ==> 2 3 2 + 1 2 1 +.fi +.le + +When a logfile is defined the convolution weights are included in the +output. + +5. Object Detection + +The detection of objects in an image is conceptually quite simple once the +background is known. If an input pixel, before any convolution, is +identified in the bad pixel mask the output object mask pixel is also +identified as bad. Otherwise the input data is convolved as described +previously. + +Each convolved pixel is compared against the expected background at that +point and, if it is more that a specified number of convolution adjusted +background sigma above (\fIhsigma\fR) or below (\fIlsigma\fR) the +background, it is identified as a candidate object pixel. Candidate object +pixels, with the same sense of deviation, are grouped into objects on +the basis of being connected along the four or eight neighboring directions +as specified by the \fIneighbor\fR parameter. The candidate object is then +accepted if it satisfies the minimum number of pixels (\fIminpix\fR) in +an object and the \fIhdetect\fR or \fIldetect\fR parameter selects that +type of object. The accepted objects are assigned sequential numbers +beginning with 11. The object numbers are used, as described in the +section on the output data, to set the output object mask values. + +If an output mean sky or sigma map is requested, the output is that +updated by the sky pixels identified during the detection. + +6. Object Growing + +Astronomical objects do not have sharp edges but have light distributions +that merge into the background. This is due not only to the nature of +extended sources but to the atmospheric and instrument point spread function +effects on unresolved sources. In order to include pixels which extend +away from the threshold detection and contain some amount of light +apart from the background, the task provides options to extend or grow +the object boundaries. This is done by making multiple passes where +pixels which have not been identified as object pixels but which neighbor +object pixels are assigned to the object which they neighbor in any of +the eight directions. Each pass can be thought of as adding a ring +of new pixels following the boundary of the object from the previous +pass. + +When a non-object pixel neighbors two or more object pixels it is +assigned to the object with the greater "flux". The flux is the sum +of the pixel value deviations from the background. + +The parameter \fIngrow\fR selects the maximum number of growing iterations. +The parameter \fIagrow\fR selects the maximum fractional increase in +the number of original detected object pixels. The number of pixels +is called the "area" of the object. The growing of an object stops +when either maximum is exceedd at the end of a growing iteration. +.ih +EXAMPLES +1. The following is a test example with default parameters that can be run +by anyone. An artificial galaxy field image is generated with the task +\fBmkexample\fR (the \fBartdata\fR package is assumed to already be loaded) +and a mask is created with \fBobjmasks\fR. The image is displayed with +the object mask overlayed in colors. + +.nf + np> mkexample galfield galfield + Creating example galfield in image galfield ... + np> objmasks omtype=color + List of images or MEF files: galfield + List of output object masks: gfmask + ACE: + Image: galfield - Example artificial galaxy field + Set sky and sigma: + Determine sky and sigma by surface fits: + start line = 1, end line = 512, step = 51.1 + xorder = 2, yorder = 2, xterms = half + hclip = 2., lclip = 3. + Determine sky and sigma by block statistics: + Number of blocks: 5 5 + Number of pixels per block: 100 100 + Number of subblocks: 10 10 + Number of pixels per subblock: 50 50 + Detect objects: + Convolution: + 1. 1. 1. + 1. 1. 1. + 1. 1. 1. + 422 objects detected + Grow objects: ngrow = 2, agrow = 2. + Write object mask: gfmask[pl,type=mask] + np> display galfield 1 + z1=371.5644 z2=455.8792 + np> display galfield 2 overlay=gfmask[pl] ocolors="+203" + z1=371.5644 z2=455.8792 +.fi + +2. In the first example there was no input mask. The next example +creates a new object mask using the first object mask as an input +"bad pixel mask". While this is not the usual usage of the bad pixel +mask it does illustrate an interesting option. Note that the mask +values in the input mask are mapped to an output value of 1 in the +"colors" output. In this example the output is forced to be a pl +file by using the explicit extension. + +.nf + np> objmasks omtype=colors mask=gfmask[pl] + List of images or MEF files (galfield): + List of output object masks (gfmask): gfmask1.pl + ACE: + Image: galfield - Example artificial galaxy field + Bad pixel mask: gfmask.pl + Set sky and sigma: + Determine sky and sigma by surface fits: + start line = 1, end line = 512, step = 51.1 + xorder = 2, yorder = 2, xterms = half + hclip = 2., lclip = 3. + Determine sky and sigma by block statistics: + Number of blocks: 5 5 + Number of pixels per block: 100 100 + Number of subblocks: 10 10 + Number of pixels per subblock: 50 50 + Detect objects: + Convolution: + 1. 1. 1. + 1. 1. 1. + 1. 1. 1. + 44 objects detected + Grow objects: ngrow = 2, agrow = 2. + Write object mask: gfmask1.pl + np> display galfield 2 overlay=gfmask1 ocolors="+203" + z1=371.5644 z2=455.8792 +.fi + +3. The next example illustrates use with a multiextension file. The +example is two realizations of the galfield artificial data. + +.nf + np> mkexamples galfield mef.fits[im1] + Creating example galfield in image mef[im1] ... + np> mkexamples galfield mef[im2,append] oseed=2 + Creating example galfield in image mef[im2,append] ... + np> objmasks + List of images or MEF files (galfield): mef + List of output object masks (gfmask1.pl): mefmask + ACE: + Image: mef[im1] - Example artificial galaxy field + Set sky and sigma: + Determine sky and sigma by surface fits: + start line = 1, end line = 512, step = 51.1 + xorder = 2, yorder = 2, xterms = half + hclip = 2., lclip = 3. + Determine sky and sigma by block statistics: + Number of blocks: 5 5 + Number of pixels per block: 100 100 + Number of subblocks: 10 10 + Number of pixels per subblock: 50 50 + Detect objects: + Convolution: + 1. 1. 1. + 1. 1. 1. + 1. 1. 1. + 422 objects detected + Grow objects: ngrow = 2, agrow = 2. + Write object mask: mefmask[im1,append,type=mask] + ACE: + Image: mef[im2] - Example artificial galaxy field + Set sky and sigma: + Determine sky and sigma by surface fits: + start line = 1, end line = 512, step = 51.1 + xorder = 2, yorder = 2, xterms = half + hclip = 2., lclip = 3. + Determine sky and sigma by block statistics: + Number of blocks: 5 5 + Number of pixels per block: 100 100 + Number of subblocks: 10 10 + Number of pixels per subblock: 50 50 + Detect objects: + Convolution: + 1. 1. 1. + 1. 1. 1. + 1. 1. 1. + 410 objects detected + Grow objects: ngrow = 2, agrow = 2. + Write object mask: mefmask[im2,append,type=mask] + np> display mef[im1] 1 over=mefmask[im1] + z1=371.5644 z2=455.8792 + np> display mef[im2] 2 over=mefmask[im2] + z1=371.5666 z2=455.7844 +.fi + +4. This example shows outputing the sky information. + +.nf + np> objmasks galfield gfmask2 sky=gfsky2 + ACE: + Image: galfield - Example artificial galaxy field + Set sky and sigma: + Determine sky and sigma by surface fits: + start line = 1, end line = 512, step = 51.1 + xorder = 2, yorder = 2, xterms = half + hclip = 2., lclip = 3. + Determine sky and sigma by block statistics: + Number of blocks: 5 5 + Number of pixels per block: 100 100 + Number of subblocks: 10 10 + Number of pixels per subblock: 50 50 + Write sky map: gfsky2 + Detect objects: + Convolution: + 1. 1. 1. + 1. 1. 1. + 1. 1. 1. + 422 objects detected + Update sky map: gfsky2 + Grow objects: ngrow = 2, agrow = 2. + Write object mask: gfmask2[pl,append,type=mask] + np> imstat gfsky2 + # IMAGE NPIX MEAN STDDEV MIN MAX + gfsky2 25 401.1 0.4397 400.3 401.9 +.fi + +5. This examples shows specifying the sky information as constant values. +In this case we already know that the artificial image has a +constant background of 400 and a sigma of 10. + +.nf + np> objmasks galfield gfmask3 sky=400 sigma=10 + ACE: + Image: galfield - Example artificial galaxy field + Set sky and sigma: + Use constant input sky: 400. + Use constant input sigma: 10. + Detect objects: + Convolution: + 1. 1. 1. + 1. 1. 1. + 1. 1. 1. + 432 objects detected + Grow objects: ngrow = 2, agrow = 2. + Write object mask: gfmask3[pl,append,type=mask] +.fi + +.ih +REVISIONS +.le +.ih +SEE ALSO +.endhelp +266c266 +< fit to produce a function for <S>. +--- +> fit to produce a constant function for <S>. +273c273,274 +< weights are used to fit a 2D plane for both <I> and <S>. +--- +> weights are used to fit a 2D plane for both <I> and <S>. The <S> surface +> is a constant in order to avoid potential negative sigma values. + diff --git a/noao/nproto/ace/edgewts.xNEW b/noao/nproto/ace/edgewts.xNEW new file mode 100644 index 00000000..fdd8d8dd --- /dev/null +++ b/noao/nproto/ace/edgewts.xNEW @@ -0,0 +1,56 @@ +task test + +procedure test () + +double dx, dy, r[11], w[11], clgetd() +int i, nr + +begin + dx = clgetd ("dx") + dy = clgetd ("dy") + nr = 11 + + call edgewts (dx, dy, r, w, nr) + do i = 1, nr { + call eprintf ("%.2f %.4g\n") + call pargd (r[i]) + call pargd (w[i]) + } +end + +procedure edgewts (dx, dy, r, w, nr) + +double dx #I Distance from aperture center to pixel center +double dy #I Distance from aperture center to pixel center +double r[nr] #O Aperture radii +double w[nr] #O Weights +int nr #O Number of aperture radius points + +int i, j, k, n +double r2, rmin, rmax, dr, a, d, rap2, y2 + +begin + rmin = sqrt ((max(0.,dx-0.6))**2+(max(0.,dy-0.6))**2) + rmax = sqrt ((dx+0.6)**2+(dy+0.6)**2) + dr = (rmax - rmin) / nr + rmin = rmin + dr / 2 + + n = 100 + d = 1.0D0 / (2 * n + 1) + a = d * d + + do k = 1, nr { + rap2 = (rmin + (k - 1) * dr) ** 2 + r[k] = sqrt (rap2) + w[k] = 0.0D0 + do j = -n, n { + y2 = (dy + j * d) ** 2 + do i = -n, n { + r2 = y2 + (dx + i * d) ** 2 + if (r2 > rap2) + break + w[k] = w[k] + a + } + } + } +end diff --git a/noao/nproto/ace/evaluate.h b/noao/nproto/ace/evaluate.h new file mode 100644 index 00000000..e2ccf001 --- /dev/null +++ b/noao/nproto/ace/evaluate.h @@ -0,0 +1,6 @@ +# EVALUATE definitions + +define EVL_STRLEN 99 # Length of strings +define EVL_LEN 50 # Parameters structure length + +define EVL_MAGZERO Memc[P2C($1+$2-1)] # Magnitude zero point diff --git a/noao/nproto/ace/evaluate.par b/noao/nproto/ace/evaluate.par new file mode 100644 index 00000000..0fda4d32 --- /dev/null +++ b/noao/nproto/ace/evaluate.par @@ -0,0 +1,32 @@ +# ACEEVALUATE + +images,f,a,,,,"List of images" +incatalogs,s,a,"",,,"List of input catalogs" +outcatalogs,s,a,"",,,"List of output catalogs" +objmasks,s,h,"",,,"List of object masks" +catdefs,s,h,"",,,"List of catalog definitions" +skys,s,h,"",,,"List of sky maps" +sigmas,s,h,"",,,"List of sigma maps" +exps,s,h,"",,,"List of exposure maps" +gains,s,h,"",,,"List of gain maps" +logfiles,s,h,"STDOUT",,,"List of log files + +# Sky" +skytype,s,h,"block","fit|block",,"Type of sky estimation + +# Sky Fitting" +fitstep,i,h,100,1,,"Line step for sky sampling" +fitblk1d,i,h,10,,,"Block average for line fitting" +fithclip,r,h,2.,,,"High sky clipping during 1D sky estimation" +fitlclip,r,h,3.,,,"Low sky clippling during 1D sky estimation" +fitxorder,i,h,1,1,,"Sky fitting x order" +fityorder,i,h,1,1,,"Sky fitting y order" +fitxterms,s,h,"half","none|full|half",,"Sky fitting cross terms + +# Sky Blocks" +blkstep,i,h,10,1,,"Line step for sky sampling" +blksize,i,h,2,,,"Block size (+=pixels, -=blocks)" +blknsubblks,i,h,3,1,,"Number of subblocks per axis + +# Evaluate" +magzero,s,h,"INDEF",,,"Magnitude zero point" diff --git a/noao/nproto/ace/evaluate.x b/noao/nproto/ace/evaluate.x new file mode 100644 index 00000000..c3b5b608 --- /dev/null +++ b/noao/nproto/ace/evaluate.x @@ -0,0 +1,641 @@ +include <error.h> +include <imhdr.h> +include <pmset.h> +include "ace.h" +include "cat.h" +include "objs.h" +include "evaluate.h" + + +# EVALUATE -- Evaluate object parameters. + +procedure evaluate (evl, cat, im, om, skymap, sigmap, gainmap, expmap, logfd) + +pointer evl #I Parameters +pointer cat #I Catalog structure +pointer im #I Image pointer +pointer om #I Object mask pointer +pointer skymap #I Sky map +pointer sigmap #I Sigma map +pointer gainmap #I Gain map +pointer expmap #I Exposure map +int logfd #I Logfile + +int i, n, c, l, nc, nl, c1, c2, nummax, num, nobjsap +real x, x2, y, y2, s, s2, f, f2, val, sky, ssig, s2x, s2y +pointer objs, obj, rlptr +pointer data, skydata, ssigdata, gaindata, expdata, sigdata +pointer sp, v, rl, sum_s2x, sum_s2y + +int andi(), ori(), ctor() +real imgetr() +bool pm_linenotempty() +errchk salloc, calloc, malloc, evgdata + +begin + call smark (sp) + call salloc (v, PM_MAXDIM, TY_LONG) + call salloc (rl, 3+3*IM_LEN(im,1), TY_INT) + + if (logfd != NULL) + call fprintf (logfd, " Evaluate objects:\n") + + objs = CAT_OBJS(cat) + nummax = CAT_NUMMAX(cat) + + nc = IM_LEN(im,1) + nl = IM_LEN(im,2) + + # Allocate work arrays. + call salloc (sigdata, nc, TY_REAL) + call salloc (sum_s2x, nummax, TY_REAL) + call salloc (sum_s2y, nummax, TY_REAL) + call aclrr (Memr[sum_s2x], nummax) + call aclrr (Memr[sum_s2y], nummax) + + # Initialize isophotal quantities. + do i = NUMSTART-1, nummax-1 { + obj = Memi[objs+i] + if (obj == NULL) + next + OBJ_NPIX(obj) = 0 + OBJ_SKY(obj) = 0. + OBJ_PEAK(obj) = 0. + OBJ_FLUX(obj) = 0. + OBJ_X1(obj) = 0. + OBJ_Y1(obj) = 0. + OBJ_X2(obj) = 0. + OBJ_Y2(obj) = 0. + OBJ_XY(obj) = 0. + OBJ_SIG(obj) = 0. + OBJ_ISIGAVG(obj) = 0. + OBJ_ISIGAVG2(obj) = INDEFR + OBJ_FLUXVAR(obj) = 0. + OBJ_XVAR(obj) = 0. + OBJ_YVAR(obj) = 0. + OBJ_XYCOV(obj) = 0. + } + + # Initialize aperture photometry. + call evapinit (cat, nobjsap) + + # Get magnitude zero. + if (EVL_MAGZERO(evl,1) == '!') { + iferr (CAT_MAGZERO(cat) = imgetr (im, EVL_MAGZERO(evl,2))) { + call erract (EA_WARN) + CAT_MAGZERO(cat) = INDEFR + } + } else { + i = 1 + if (ctor (EVL_MAGZERO(evl,1), i, CAT_MAGZERO(cat)) == 0) + CAT_MAGZERO(cat) = INDEFR + } + call catputr (cat, "magzero", CAT_MAGZERO(cat)) + + # Go through the lines of the image accumulating the image data + # into the parameters. The data is read the first time it is + # required. + Memi[v] = 1 + do l = 1, nl { + Memi[v+1] = l + data = NULL + + # Do circular aperture photometry. Check nobjsap to avoid + # subroutine call. + if (nobjsap > 0) + call evapeval (l, im, skymap, sigmap, gainmap, expmap, + data, skydata, ssigdata, gaindata, expdata, sigdata) + + # Accumulate object region quantities if there are object + # regions in the current line. + if (!pm_linenotempty (om, Memi[v])) + next + call pmglri (om, Memi[v], Memi[rl], 0, nc, 0) + + # Go through each object region. + rlptr = rl + do i = 2, Memi[rl] { + rlptr = rlptr + 3 + c1 = Memi[rlptr] + c2 = c1 + Memi[rlptr+1] - 1 + num = MNUM(Memi[rlptr+2]) + + # Do all unevaluated objects and their parents. + while (num >= NUMSTART) { + if (data == NULL) + call evgdata (l, im, skymap, sigmap, gainmap, expmap, + data, skydata, ssigdata, gaindata, expdata, sigdata) + + obj = Memi[objs+num-1] + if (obj == NULL) + break + + if (OBJ_NPIX(obj) == 0) { + val = Memr[data+c1-1] + sky = Memr[skydata+c1-1] + ssig = Memr[ssigdata+c1-1] + + OBJ_XMIN(obj) = c1 + OBJ_XMAX(obj) = c1 + OBJ_YMIN(obj) = l + OBJ_YMAX(obj) = l + OBJ_ISIGMAX(obj) = (val - sky) / ssig + } + + s2x = Memr[sum_s2x+num-1] + s2y = Memr[sum_s2y+num-1] + do c = c1, c2 { + val = Memr[data+c-1] + sky = Memr[skydata+c-1] + ssig = Memr[ssigdata+c-1] + s = Memr[sigdata+c-1] + + x = c - OBJ_XMIN(obj) + y = l - OBJ_YMIN(obj) + x2 = x * x + y2 = y * y + s2 = s * s + + OBJ_NPIX(obj) = OBJ_NPIX(obj) + 1 + OBJ_SKY(obj) = OBJ_SKY(obj) + sky + OBJ_SIG(obj) = OBJ_SIG(obj) + ssig + val = val - sky + if (val > OBJ_PEAK(obj)) + OBJ_PEAK(obj) = val + OBJ_FLUX(obj) = OBJ_FLUX(obj) + val + OBJ_FLUXVAR(obj) = OBJ_FLUXVAR(obj) + s2 + + OBJ_XMIN(obj) = min (OBJ_XMIN(obj), c) + OBJ_XMAX(obj) = max (OBJ_XMAX(obj), c) + OBJ_X1(obj) = OBJ_X1(obj) + x * val + OBJ_X2(obj) = OBJ_X2(obj) + x2 * val + OBJ_XVAR(obj) = OBJ_XVAR(obj) + x2 * s2 + s2x = s2x + x * s2 + + OBJ_YMIN(obj) = min (OBJ_YMIN(obj), l) + OBJ_YMAX(obj) = max (OBJ_YMAX(obj), l) + OBJ_Y1(obj) = OBJ_Y1(obj) + y * val + OBJ_Y2(obj) = OBJ_Y2(obj) + y2 * val + OBJ_YVAR(obj) = OBJ_YVAR(obj) + y2 * s2 + s2y = s2y + y * s2 + + OBJ_XY(obj) = OBJ_XY(obj) + x * y * val + OBJ_XYCOV(obj) = OBJ_XYCOV(obj) + x * y * s2 + + val = val / ssig + OBJ_ISIGAVG(obj) = OBJ_ISIGAVG(obj) + val + OBJ_ISIGMAX(obj) = max (OBJ_ISIGMAX(obj), val) + + } + Memr[sum_s2x+num-1] = s2x + Memr[sum_s2y+num-1] = s2y + + num = OBJ_PNUM(obj) + } + } + } + + # Finish up the evaluations. + do i = NUMSTART-1, nummax-1 { + obj = Memi[objs+i] + if (obj == NULL) + next + n = OBJ_NPIX(obj) + if (n > 0) { + OBJ_SKY(obj) = OBJ_SKY(obj) / n + f = OBJ_FLUX(obj) + if (f > 0.) { + f2 = f * f + x = OBJ_X1(obj) / f + s2x = Memr[sum_s2x+i] + s2y = Memr[sum_s2y+i] + + OBJ_X1(obj) = x + OBJ_XMIN(obj) + OBJ_X2(obj) = OBJ_X2(obj) / f - x * x + OBJ_XVAR(obj) = (OBJ_XVAR(obj) - 2 * x * s2x + + x * x * OBJ_FLUXVAR(obj)) / f2 + + y = OBJ_Y1(obj) / f + OBJ_Y1(obj) = y + OBJ_YMIN(obj) + OBJ_Y2(obj) = OBJ_Y2(obj) / f - y * y + OBJ_YVAR(obj) = (OBJ_YVAR(obj) - 2 * y * s2y + + y * y * OBJ_FLUXVAR(obj)) / f2 + + OBJ_XY(obj) = OBJ_XY(obj) / f - x * y + OBJ_XYCOV(obj) = (OBJ_XYCOV(obj) - x * s2x - + y * s2y + x * y * OBJ_FLUXVAR(obj)) / f2 + + if (IS_INDEFR(OBJ_XAP(obj))) + OBJ_XAP(obj) = OBJ_X1(obj) + if (IS_INDEFR(OBJ_YAP(obj))) + OBJ_YAP(obj) = OBJ_Y1(obj) + } else { + OBJ_X1(obj) = INDEFR + OBJ_Y1(obj) = INDEFR + OBJ_X2(obj) = INDEFR + OBJ_Y2(obj) = INDEFR + OBJ_XY(obj) = INDEFR + OBJ_XVAR(obj) = INDEFR + OBJ_YVAR(obj) = INDEFR + OBJ_XYCOV(obj) = INDEFR + OBJ_FLUXVAR(obj) = INDEFR + } + if (OBJ_PEAK(obj) == 0.) + OBJ_PEAK(obj) = INDEFR + OBJ_SIG(obj) = OBJ_SIG(obj) / n + OBJ_ISIGAVG(obj) = OBJ_ISIGAVG(obj) / sqrt(real(n)) + } + SETFLAG (obj, OBJ_EVAL) + } + + # Do aperture photometry if we had to wait for the aperture centers + # to be defined. + if (nobjsap == 0) { + call evapinit (cat, nobjsap) + if (nobjsap > 0) { + Memi[v] = 1 + do l = 1, nl { + Memi[v+1] = l + data = NULL + call evapeval (l, im, skymap, sigmap, gainmap, expmap, + data, skydata, ssigdata, gaindata, expdata, sigdata) + } + } + } + call evapfree () + + # Set apportioned fluxes. + call evapportion (cat, Memr[sum_s2x]) + + # Set WCS coordinates. + call evalwcs (cat, im) + + call sfree (sp) +end + + +# EVAPINIT -- Initialize aperture photometry. nobjsap will signal whether +# there are any objects to evaluate. + +procedure evapinit (cat, nobjsap) + +pointer cat #I Catalog +int nobjsap #O Number of objects for aperture evaluation + +int i, nummax +pointer tbl, stp, sym, apflux, obj, sthead(), stnext() + +int ycompare() +extern ycompare +errchk calloc, malloc + +int nobjs # Number of objects to evaluate +int naps # Number of apertures per object +real rmax # Maximum aperture radius +pointer r2aps # Array of aperture radii squared (ptr) +pointer ysort # Array of Y sorted object number indices (ptr) +int ystart # Index of first object to consider +pointer objs # Array of object structure (ptr) +common /evapcom/ nobjs, naps, rmax, r2aps, ysort, ystart, objs + +begin + nobjsap = 0 + nobjs = 0 + naps = 0 + r2aps = NULL + ysort = NULL + + tbl = CAT_OUTTBL(cat) + if (tbl == NULL) + return + stp = TBL_STP(tbl) + + # Determine number of apertures. + naps = 0 + for (sym=sthead(stp); sym!=NULL; sym=stnext(stp,sym)) { + if (ENTRY_ID(sym) != ID_APFLUX) + next + } + if (naps == 0) + return + + objs = CAT_OBJS(cat) + nummax = CAT_NUMMAX(cat) + + # Allocate memory. + call calloc (CAT_APFLUX(cat), nummax*naps, TY_REAL) + call malloc (r2aps, naps, TY_REAL) + call malloc (ysort, nummax, TY_INT) + + # Get the maximum radius since that will define the line + # limits needed for each object. Compute array of radius squared + # for the apertures. Pixels are checked for being in the aperture + # in r^2 to avoid square roots. + rmax = 0. + naps = 0 + for (sym=sthead(stp); sym!=NULL; sym=stnext(stp,sym)) { + if (ENTRY_ID(sym) != ID_APFLUX) + next + rmax = max (ENTRY_RAP(sym), rmax) + Memr[r2aps+naps] = ENTRY_RAP(sym) ** 2 + naps = naps + 1 + } + + # Allocate regions of the apflux array to objects with + # defined aperture centers. For the objects create a sorted + # index array by YAP so that we can quickly find objects + # which include a particular line in their apertures. + + apflux = CAT_APFLUX(cat) + do i = NUMSTART-1, nummax-1 { + obj = Memi[objs+i] + if (obj == NULL) + next + if (IS_INDEFR(OBJ_XAP(obj)) || IS_INDEFR(OBJ_YAP(obj))) + next + OBJ_APFLUX(obj) = apflux + apflux = apflux + naps + Memi[ysort+nobjsap] = i + nobjsap = nobjsap + 1 + } + + if (nobjsap > 1) + call gqsort (Memi[ysort], nobjsap, ycompare, objs) + + if (nobjsap == 0) { + call mfree (CAT_APFLUX(cat), TY_REAL) + call evapfree () + } +end + + +# EVAPFREE -- Free aperture photometry memory. + +procedure evapfree () + +int nobjs # Number of objects to evaluate +int naps # Number of apertures per object +real rmax # Maximum aperture radius +pointer r2aps # Array of aperture radii squared (ptr) +pointer ysort # Array of Y sorted object number indices (ptr) +int ystart # Index of first object to consider +pointer objs # Array of object structure (ptr) +common /evapcom/ nobjs, naps, rmax, r2aps, ysort, ystart, objs + +begin + call mfree (r2aps, TY_REAL) + call mfree (ysort, TY_INT) +end + + +# EVAPEVAL -- Do circular aperture photometry. Maintain i1 as the +# first entry in the sorted index array to be considered. All +# earlier entries will have all aperture lines less than the +# current line. Break on the first object whose minimum aperture +# line is greater than the current line. + +procedure evapeval (l, im, skymap, sigmap, gainmap, expmap, data, skydata, + ssigdata, gaindata, expdata, sigdata) + +int l #I Line +pointer im #I Image +pointer skymap #I Sky map +pointer sigmap #I Sigma map +pointer gainmap #I Gain map +pointer expmap #I Exposure map +pointer data #O Image data +pointer skydata #O Sky data +pointer ssigdata #O Sky sigma data +pointer gaindata #O Gain data +pointer expdata #O Exposure data +pointer sigdata #O Total sigma data + +int i, j, nc, c +real x, y, l2, r2, val, sky +pointer obj, apflux + +int nobjs # Number of objects to evaluate +int naps # Number of apertures per object +real rmax # Maximum aperture radius +pointer r2aps # Array of aperture radii squared (ptr) +pointer ysort # Array of Y sorted object number indices (ptr) +int ystart # Index of first object to consider +pointer objs # Array of object structure (ptr) +common /evapcom/ nobjs, naps, rmax, r2aps, ysort, ystart, objs + +begin + nc = IM_LEN(im,1) + do i = ystart, nobjs { + obj = Memi[objs+Memi[ysort+i-1]] + y = OBJ_YAP(obj) + if (y - rmax > l) + break + if (y + rmax < l) { + ystart = ystart + 1 + next + } + x = OBJ_XAP(obj) + apflux = OBJ_APFLUX(obj) + if (data == NULL) + call evgdata (l, im, skymap, sigmap, gainmap, expmap, + data, skydata, ssigdata, gaindata, expdata, sigdata) + + # Accumulate data within in the apertures using the r^2 + # values. Currently partial pixels are not considered and + # errors are not evaluated. + # Note that bad pixels or object overlaps are not excluded + # in the apertures. + l2 = (l - y) ** 2 + do c = max (0, int(x-rmax)), min (nc, int(x+rmax+1)) { + r2 = (c - x) ** 2 + l2 + do j = 0, naps-1 { + if (r2 < Memr[r2aps+j]) { + val = Memr[data+c-1] + sky = Memr[skydata+c-1] + Memr[apflux+j] = Memr[apflux+j] + (val - sky) + } + } + } + } +end + + +# EVAPPORTION -- Compute apportioned fluxes after the object isophotoal +# fluxes have been computed. + +procedure evapportion (cat, sum_flux) + +pointer cat #I Catalog +real sum_flux[ARB] #I Work array of size NUMMAX + +int nummax, num, pnum, nindef +pointer objs, obj, pobj + +begin + objs = CAT_OBJS(cat) + nummax = CAT_NUMMAX(cat) + + call aclrr (sum_flux, nummax) + do num = NUMSTART, nummax { + obj = Memi[objs+num-1] + if (obj == NULL) + next + pnum = OBJ_PNUM(obj) + if (pnum == 0) { + OBJ_FRAC(obj) = 1. + OBJ_FRACFLUX(obj) = OBJ_FLUX(obj) + next + } + + sum_flux[pnum] = sum_flux[pnum] + max (0., OBJ_FLUX(obj)) + OBJ_FRACFLUX(obj) = INDEFR + } + + nindef = 0 + do num = NUMSTART, nummax { + obj = Memi[objs+num-1] + if (obj == NULL) + next + pnum = OBJ_PNUM(obj) + if (pnum == 0) + next + pobj = Memi[objs+pnum-1] + + if (sum_flux[pnum] > 0.) { + OBJ_FRAC(obj) = max (0., OBJ_FLUX(obj)) / sum_flux[pnum] + if (IS_INDEFR(OBJ_FRACFLUX(pobj))) + nindef = nindef + 1 + else + OBJ_FRACFLUX(obj) = OBJ_FRACFLUX(pobj) * OBJ_FRAC(obj) + } else { + OBJ_FRAC(obj) = INDEFR + OBJ_FRACFLUX(obj) = OBJ_FLUX(obj) + } + } + + while (nindef > 0) { + nindef = 0 + do num = NUMSTART, nummax { + obj = Memi[objs+num-1] + if (obj == NULL) + next + pnum = OBJ_PNUM(obj) + if (pnum == 0) + next + + pobj = Memi[objs+pnum-1] + if (IS_INDEFR(OBJ_FRACFLUX(pobj))) + nindef = nindef + 1 + else { + if (IS_INDEFR(OBJ_FRAC(obj))) + OBJ_FRACFLUX(obj) = OBJ_FLUX(obj) + else + OBJ_FRACFLUX(obj) = OBJ_FRACFLUX(pobj) * OBJ_FRAC(obj) + } + } + } +end + + +# EVALWCS -- Set WCS coordinates. + +procedure evalwcs (cat, im) + +pointer cat #I Catalog structure +pointer im #I IMIO pointer + +int i +pointer mw, ct, objs, obj, mw_openim(), mw_sctran() +errchk mw_openim + +begin + mw = mw_openim (im) + ct = mw_sctran (mw, "logical", "world", 03B) + + objs = CAT_OBJS(cat) + do i = NUMSTART-1, CAT_NUMMAX(cat)-1 { + obj = Memi[objs+i] + if (obj == NULL) + next + if (IS_INDEFR(OBJ_XAP(obj)) || IS_INDEFR(OBJ_YAP(obj))) { + OBJ_WX(obj) = INDEFD + OBJ_WY(obj) = INDEFD + } else + call mw_c2trand (ct, double(OBJ_XAP(obj)), + double(OBJ_YAP(obj)), OBJ_WX(obj), OBJ_WY(obj)) + } + + call mw_ctfree (ct) + call mw_close (mw) +end + + +# YCOMPARE -- Compare Y values of two objects for sorting. + +int procedure ycompare (objs, i1, i2) + +pointer objs #I Pointer to array of objects +int i1 #I Index of first object to compare +int i2 #I Index of second object to compare + +real y1, y2 + +begin + y1 = OBJ_YAP(Memi[objs+i1]) + y2 = OBJ_YAP(Memi[objs+i2]) + if (y1 < y2) + return (-1) + else if (y1 > y2) + return (1) + else + return (0) +end + + +# EVGDATA -- Get evaluation data for an image line. + +procedure evgdata (l, im, skymap, sigmap, gainmap, expmap, data, skydata, + ssigdata, gaindata, expdata, sigdata) + +int l #I Line +pointer im #I Image +pointer skymap #I Sky map +pointer sigmap #I Sigma map +pointer gainmap #I Gain map +pointer expmap #I Exposure map +pointer data #O Image data +pointer skydata #O Sky data +pointer ssigdata #O Sky sigma data +pointer gaindata #O Gain data +pointer expdata #O Exposure data +pointer sigdata #O Total sigma data + +int nc +pointer imgl2r(), map_glr() +errchk imgl2r, map_glr, noisemodel + +begin + nc = IM_LEN(im,1) + data = imgl2r (im, l) + skydata = map_glr (skymap, l, READ_ONLY) + ssigdata = map_glr (sigmap, l, READ_ONLY) + if (gainmap == NULL && expmap == NULL) + sigdata = ssigdata + else if (expmap == NULL) { + gaindata = map_glr (gainmap, l, READ_ONLY) + call noisemodel (Memr[data], Memr[skydata], + Memr[ssigdata], Memr[gaindata], INDEFR, + Memr[sigdata], nc) + } else if (gainmap == NULL) { + expdata = map_glr (expmap, l, READ_WRITE) + call noisemodel (Memr[data], Memr[skydata], + Memr[ssigdata], INDEFR, Memr[expdata], + Memr[sigdata], nc) + } else { + gaindata = map_glr (gainmap, l, READ_ONLY) + expdata = map_glr (expmap, l, READ_WRITE) + call noisemodel (Memr[data], Memr[skydata], + Memr[ssigdata], Memr[gaindata], + Memr[expdata], Memr[sigdata], nc) + } +end diff --git a/noao/nproto/ace/filter.h b/noao/nproto/ace/filter.h new file mode 100644 index 00000000..c61382b2 --- /dev/null +++ b/noao/nproto/ace/filter.h @@ -0,0 +1,14 @@ +# Filter operand names. +define FILT_NAMES "|id|number|x|y|wx|wy|npix|flux|peak|" +define FILT_OBJID 1 +define FILT_NUM 2 +define FILT_X 3 +define FILT_Y 4 +define FILT_WX 5 +define FILT_WY 6 +define FILT_NPIX 7 +define FILT_FLUX 8 +define FILT_PEAK 9 + +# Filter functions. +define FILT_FUNCS "|dummy|" diff --git a/noao/nproto/ace/filter.x b/noao/nproto/ace/filter.x new file mode 100644 index 00000000..b43e3de0 --- /dev/null +++ b/noao/nproto/ace/filter.x @@ -0,0 +1,134 @@ +include <evvexpr.h> +include "ace.h" +include "objs.h" +include "filter.h" + + +procedure t_filter () + +pointer catalog #I Catalog name +pointer filt #I Filter + +pointer sp, cat, obj, cathead(), catnext() +errchk catopen + +begin + call smark (sp) + call salloc (catalog, SZ_FNAME, TY_CHAR) + call salloc (filt, SZ_LINE, TY_CHAR) + + call clgstr ("catalog", Memc[catalog], SZ_FNAME) + call clgstr ("filter", Memc[filt], SZ_FNAME) + + call catopen (cat, Memc[catalog], Memc[catalog], "") + + for (obj=cathead(cat); obj!=NULL; obj=catnext(cat,obj)) { + call printf ("%d\n") + call pargi (OBJ_ROW(obj)) + } + + call catclose (cat) + + call sfree (sp) +end + + +bool procedure filter (obj, filt) + +pointer obj #I Object structure +char filt[ARB] #I Filter string +bool match #O Filter return value + +int type, locpr() +pointer o, evvexpr() +extern filt_op(), filt_func() +errchk evvexpr + +begin + if (obj == NULL) + return (false) + if (filt[1] == EOS) + return (true) + + # Evaluate filter. + o = evvexpr (filt, locpr (filt_op), obj, locpr (filt_func), obj, 0) + if (o == NULL) + return (false) + + type = O_TYPE(o) + if (O_TYPE(o) == TY_BOOL) + match = (O_VALI(o) == YES) + + call mfree (o, TY_STRUCT) + if (type != TY_BOOL) + call error (1, "Filter expression is not boolean") + + return (match) +end + + +procedure filt_op (obj, name, o) + +pointer obj #I Object structure +char name[ARB] #I Operand name +pointer o #O Pointer to output operand + +char lname[SZ_FNAME] +int i, strdic() + +begin + call strcpy (name, lname, SZ_FNAME) + call strlwr (lname) + i = strdic (lname, lname, SZ_FNAME, FILT_NAMES) + switch (i) { + case FILT_NUM: + call xvv_initop (o, 0, TY_INT) + O_VALI(o) = OBJ_NUM(obj) + case FILT_X: + call xvv_initop (o, 0, TY_DOUBLE) + O_VALD(o) = OBJ_XAP(obj) + case FILT_Y: + call xvv_initop (o, 0, TY_DOUBLE) + O_VALD(o) = OBJ_YAP(obj) + case FILT_WX: + call xvv_initop (o, 0, TY_DOUBLE) + O_VALD(o) = OBJ_WX(obj) + case FILT_WY: + call xvv_initop (o, 0, TY_DOUBLE) + O_VALD(o) = OBJ_WY(obj) + case FILT_NPIX: + call xvv_initop (o, 0, TY_INT) + O_VALI(o) = OBJ_NPIX(obj) + case FILT_FLUX: + call xvv_initop (o, 0, TY_DOUBLE) + O_VALD(o) = OBJ_FLUX(obj) + case FILT_PEAK: + call xvv_initop (o, 0, TY_DOUBLE) + O_VALD(o) = OBJ_PEAK(obj) + default: + call xvv_error1 ("quantity `%s' not found", name) + } +end + + + +procedure filt_func (obj, func, args, nargs, o) + +pointer obj #I Object structure +char func[ARB] #I Function +pointer args[ARB] #I Arguments +int nargs #I Number of arguments +pointer o #O Function value operand + +int ifunc, strdic() +pointer sp, buf +bool strne() + +begin + call smark (sp) + call salloc (buf, SZ_LINE, TY_CHAR) + + ifunc = strdic (func, Memc[buf], SZ_LINE, FILT_FUNCS) + if (ifunc == 0 || strne (func, Memc[buf])) + call xvv_error1 ("unknown function `%s'", func) +end diff --git a/noao/nproto/ace/grow.h b/noao/nproto/ace/grow.h new file mode 100644 index 00000000..ff91542e --- /dev/null +++ b/noao/nproto/ace/grow.h @@ -0,0 +1,6 @@ +# Grow parameter structure + +define GRW_LEN 2 # Length of parameter structure + +define GRW_NGROW Memi[$1] # Number of grow passes +define GRW_AGROW Memr[P2R($1+1)] # Grow area factor diff --git a/noao/nproto/ace/grow.x b/noao/nproto/ace/grow.x new file mode 100644 index 00000000..a9c84cd2 --- /dev/null +++ b/noao/nproto/ace/grow.x @@ -0,0 +1,959 @@ +include <pmset.h> +include "ace.h" +include "cat.h" +include "objs.h" +include "grow.h" + + +procedure grow (grw, cat, objmask, logfd) + +pointer grw #I Grow parameter structure +pointer cat #I Catalog of objects +pointer objmask #I Object mask +int logfd #I Logfile + +int ngrow #I Number of pixels to grow +real agrow #I Area factor grow + +int i, j, nc, nl, m, n +pointer sp, v, bufs, obuf +pointer buf1, buf2, buf3, obj + +int grow1(), grow2(), grow3(), andi(), ori(), noti() +pointer cathead(), catnext() + +begin + call grw_pars ("open", "", grw) + ngrow = GRW_NGROW(grw) + agrow = GRW_AGROW(grw) + + if (ngrow < 1 && agrow <= 1.) + return + + if (logfd != NULL) { + call fprintf (logfd, " Grow objects: ngrow = %d, agrow = %g\n") + call pargi (ngrow) + call pargr (agrow) + } + + call smark (sp) + call salloc (v, PM_MAXDIM, TY_LONG) + + call pm_gsize (objmask, i, Meml[v], n) + nc = Meml[v]; nl = Meml[v+1] + Meml[v] = 1 + + call salloc (bufs, 3, TY_POINTER) + do i = 1, 3 + call salloc (Memi[bufs+i-1], nc, TY_INT) + call salloc (obuf, nc, TY_INT) + + for (obj=cathead(cat); obj!=NULL; obj=catnext(cat,obj)) { + if (GROWN(obj)) + next + UNSETFLAG (obj, OBJ_EVAL) + OBJ_NDETECT(obj) = OBJ_NPIX(obj) + } + + do j = 1, ngrow { + m = 0 + buf2 = NULL; buf3 = NULL + do i = 1, nl { + buf1 = buf2 + buf2 = buf3 + buf3 = NULL + + if (i != 1 && buf1 == NULL) { + Meml[v+1] = i - 1 + buf1 = Memi[bufs+mod(Meml[v+1],3)] + call pmglpi (objmask, Meml[v], Memi[buf1], 0, nc, 0) + } + if (buf2 == NULL) { + Meml[v+1] = i + buf2 = Memi[bufs+mod(Meml[v+1],3)] + call pmglpi (objmask, Meml[v], Memi[buf2], 0, nc, 0) + } + if (i != nl && buf3 == NULL) { + Meml[v+1] = i+1 + buf3 = Memi[bufs+mod(Meml[v+1],3)] + call pmglpi (objmask, Meml[v], Memi[buf3], 0, nc, 0) + } + + if (i == 1) + n = grow1 (cat, i, Memi[buf2], Memi[buf3], + Memi[obuf], nc, nl) + else if (i == nl) + n = grow3 (cat, i, Memi[buf1], Memi[buf2], + Memi[obuf], nc, nl) + else + n = grow2 (cat, i, Memi[buf1], Memi[buf2], Memi[buf3], + Memi[obuf], nc, nl) + + if (n > 0) { + Meml[v+1] = i + call pmplpi (objmask, Meml[v], Memi[obuf], 0, nc, PIX_SRC) + m = m + n + } + } + + n = 0 + for (obj=cathead(cat); obj!=NULL; obj=catnext(cat,obj)) { + if (GROWN(obj)) + next + if (real (OBJ_NPIX(obj)) / OBJ_NDETECT(obj) >= agrow) + SETFLAG (obj, OBJ_GROW) + else + n = n + 1 + } + + if (n == 0 || m == 0) + break + } + + if (n != 0) { + for (obj=cathead(cat); obj!=NULL; obj=catnext(cat,obj)) { + if (GROWN(obj)) + next + SETFLAG (obj, OBJ_GROW) + } + } + + call sfree (sp) +end + + +int procedure grow1 (cat, line, in2, in3, out, nc, nl) + +pointer cat #I Catalog +int line #I Line +int in2[nc] #I Current line +int in3[nc] #I Next line +int out[nc] #I Output line +int nc, nl #I Dimension of image + +int i, j, n, id, id0, id1, num1, andi() +bool grow +pointer objs, obj, obj1 + +begin + objs = CAT_OBJS(cat) - 1 + obj1 = NULL + n = 0 + do i = 1, nc { + id0 = in2[i] + if (id0 != 0 && MNOTSPLIT(id0)) { + out[i] = id0 + next + } + + id = 0 + j = i - 1 + if (i > 1) { + id1 = in2[j] + num1 = MNUM(id1) + if (num1 >= NUMSTART) { + if (MNOTSPLIT(id1)) { + if (obj1 == NULL) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } else if (OBJ_NUM(obj1) != num1) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } + if (grow) { + if (id == 0) { + id = id1 + obj = obj1 + } else if (id != id1) { + if (OBJ_FLUX(obj) < OBJ_FLUX(obj1)) { + id = id1 + obj = obj1 + } + } + } + } + } + id1 = in3[j] + num1 = MNUM(id1) + if (num1 >= NUMSTART) { + if (MNOTSPLIT(id1)) { + if (obj1 == NULL) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } else if (OBJ_NUM(obj1) != num1) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } + if (grow) { + if (id == 0) { + id = id1 + obj = obj1 + } else if (id != id1) { + if (OBJ_FLUX(obj) < OBJ_FLUX(obj1)) { + id = id1 + obj = obj1 + } + } + } + } + } + } + id1 = in3[i] + num1 = MNUM(id1) + if (num1 >= NUMSTART) { + if (MNOTSPLIT(id1)) { + if (obj1 == NULL) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } else if (OBJ_NUM(obj1) != num1) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } + if (grow) { + if (id == 0) { + id = id1 + obj = obj1 + } else if (id != id1) { + if (OBJ_FLUX(obj) < OBJ_FLUX(obj1)) { + id = id1 + obj = obj1 + } + } + } + } + } + j = i + 1 + if (i < nc) { + id1 = in2[j] + num1 = MNUM(id1) + if (num1 >= NUMSTART) { + if (MNOTSPLIT(id1)) { + if (obj1 == NULL) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } else if (OBJ_NUM(obj1) != num1) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } + if (grow) { + if (id == 0) { + id = id1 + obj = obj1 + } else if (id != id1) { + if (OBJ_FLUX(obj) < OBJ_FLUX(obj1)) { + id = id1 + obj = obj1 + } + } + } + } + } + id1 = in3[j] + num1 = MNUM(id1) + if (num1 >= NUMSTART) { + if (MNOTSPLIT(id1)) { + if (obj1 == NULL) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } else if (OBJ_NUM(obj1) != num1) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } + if (grow) { + if (id == 0) { + id = id1 + obj = obj1 + } else if (id != id1) { + if (OBJ_FLUX(obj) < OBJ_FLUX(obj1)) { + id = id1 + obj = obj1 + } + } + } + } + } + } + + if (id == 0) + out[i] = in2[i] + else { + out[i] = id + OBJ_NPIX(obj) = OBJ_NPIX(obj) + 1 + n = n + 1 + } + } + + return (n) +end + + +int procedure grow2 (cat, line, in1, in2, in3, out, nc, nl) + +pointer cat #I Catalog +int line #I Line +int in1[nc] #I Previous line +int in2[nc] #I Current line +int in3[nc] #I Next line +int out[nc] #I Output line +int nc, nl #I Dimension of image + +int i, j, n, id, id0, id1, num1, andi() +bool grow +pointer objs, obj, obj1 + +begin + objs = CAT_OBJS(cat) - 1 + obj1 = NULL + n = 0 + do i = 2, nc-1 { + id0 = in2[i] + if (id0 != 0 && MNOTSPLIT(id0)) { + out[i] = id0 + next + } + + id = 0 + j = i - 1 + id1 = in1[j] + num1 = MNUM(id1) + if (num1 >= NUMSTART) { + if (MNOTSPLIT(id1)) { + if (obj1 == NULL) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } else if (OBJ_NUM(obj1) != num1) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } + if (grow) { + if (id == 0) { + id = id1 + obj = obj1 + } else if (id != id1) { + if (OBJ_FLUX(obj) < OBJ_FLUX(obj1)) { + id = id1 + obj = obj1 + } + } + } + } + } + id1 = in2[j] + num1 = MNUM(id1) + if (num1 >= NUMSTART) { + if (MNOTSPLIT(id1)) { + if (obj1 == NULL) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } else if (OBJ_NUM(obj1) != num1) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } + if (grow) { + if (id == 0) { + id = id1 + obj = obj1 + } else if (id != id1) { + if (OBJ_FLUX(obj) < OBJ_FLUX(obj1)) { + id = id1 + obj = obj1 + } + } + } + } + } + id1 = in3[j] + num1 = MNUM(id1) + if (num1 >= NUMSTART) { + if (MNOTSPLIT(id1)) { + if (obj1 == NULL) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } else if (OBJ_NUM(obj1) != num1) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } + if (grow) { + if (id == 0) { + id = id1 + obj = obj1 + } else if (id != id1) { + if (OBJ_FLUX(obj) < OBJ_FLUX(obj1)) { + id = id1 + obj = obj1 + } + } + } + } + } + id1 = in1[i] + num1 = MNUM(id1) + if (num1 >= NUMSTART) { + if (MNOTSPLIT(id1)) { + if (obj1 == NULL) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } else if (OBJ_NUM(obj1) != num1) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } + if (grow) { + if (id == 0) { + id = id1 + obj = obj1 + } else if (id != id1) { + if (OBJ_FLUX(obj) < OBJ_FLUX(obj1)) { + id = id1 + obj = obj1 + } + } + } + } + } + id1 = in3[i] + num1 = MNUM(id1) + if (num1 >= NUMSTART) { + if (MNOTSPLIT(id1)) { + if (obj1 == NULL) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } else if (OBJ_NUM(obj1) != num1) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } + if (grow) { + if (id == 0) { + id = id1 + obj = obj1 + } else if (id != id1) { + if (OBJ_FLUX(obj) < OBJ_FLUX(obj1)) { + id = id1 + obj = obj1 + } + } + } + } + } + j = i + 1 + id1 = in1[j] + num1 = MNUM(id1) + if (num1 >= NUMSTART) { + if (MNOTSPLIT(id1)) { + if (obj1 == NULL) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } else if (OBJ_NUM(obj1) != num1) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } + if (grow) { + if (id == 0) { + id = id1 + obj = obj1 + } else if (id != id1) { + if (OBJ_FLUX(obj) < OBJ_FLUX(obj1)) { + id = id1 + obj = obj1 + } + } + } + } + } + id1 = in2[j] + num1 = MNUM(id1) + if (num1 >= NUMSTART) { + if (MNOTSPLIT(id1)) { + if (obj1 == NULL) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } else if (OBJ_NUM(obj1) != num1) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } + if (grow) { + if (id == 0) { + id = id1 + obj = obj1 + } else if (id != id1) { + if (OBJ_FLUX(obj) < OBJ_FLUX(obj1)) { + id = id1 + obj = obj1 + } + } + } + } + } + id1 = in3[j] + num1 = MNUM(id1) + if (num1 >= NUMSTART) { + if (MNOTSPLIT(id1)) { + if (obj1 == NULL) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } else if (OBJ_NUM(obj1) != num1) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } + if (grow) { + if (id == 0) { + id = id1 + obj = obj1 + } else if (id != id1) { + if (OBJ_FLUX(obj) < OBJ_FLUX(obj1)) { + id = id1 + obj = obj1 + } + } + } + } + } + + if (id == 0) + out[i] = in2[i] + else { + out[i] = id + OBJ_NPIX(obj) = OBJ_NPIX(obj) + 1 + n = n + 1 + } + } + + # First pixel + id0 = in2[1] + if (id0 != 0 && MNOTSPLIT(id0)) + out[1] = id0 + else { + id = 0 + id1 = in1[1] + num1 = MNUM(id1) + if (num1 >= NUMSTART) { + if (MNOTSPLIT(id1)) { + if (obj1 == NULL) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } else if (OBJ_NUM(obj1) != num1) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } + if (grow) { + if (id == 0) { + id = id1 + obj = obj1 + } else if (id != id1) { + if (OBJ_FLUX(obj) < OBJ_FLUX(obj1)) { + id = id1 + obj = obj1 + } + } + } + } + } + id1 = in3[1] + num1 = MNUM(id1) + if (num1 >= NUMSTART) { + if (MNOTSPLIT(id1)) { + if (obj1 == NULL) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } else if (OBJ_NUM(obj1) != num1) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } + if (grow) { + if (id == 0) { + id = id1 + obj = obj1 + } else if (id != id1) { + if (OBJ_FLUX(obj) < OBJ_FLUX(obj1)) { + id = id1 + obj = obj1 + } + } + } + } + } + id1 = in1[2] + num1 = MNUM(id1) + if (num1 >= NUMSTART) { + if (MNOTSPLIT(id1)) { + if (obj1 == NULL) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } else if (OBJ_NUM(obj1) != num1) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } + if (grow) { + if (id == 0) { + id = id1 + obj = obj1 + } else if (id != id1) { + if (OBJ_FLUX(obj) < OBJ_FLUX(obj1)) { + id = id1 + obj = obj1 + } + } + } + } + } + id1 = in2[2] + num1 = MNUM(id1) + if (num1 >= NUMSTART) { + if (MNOTSPLIT(id1)) { + if (obj1 == NULL) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } else if (OBJ_NUM(obj1) != num1) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } + if (grow) { + if (id == 0) { + id = id1 + obj = obj1 + } else if (id != id1) { + if (OBJ_FLUX(obj) < OBJ_FLUX(obj1)) { + id = id1 + obj = obj1 + } + } + } + } + } + id1 = in3[2] + num1 = MNUM(id1) + if (num1 >= NUMSTART) { + if (MNOTSPLIT(id1)) { + if (obj1 == NULL) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } else if (OBJ_NUM(obj1) != num1) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } + if (grow) { + if (id == 0) { + id = id1 + obj = obj1 + } else if (id != id1) { + if (OBJ_FLUX(obj) < OBJ_FLUX(obj1)) { + id = id1 + obj = obj1 + } + } + } + } + } + + if (id == 0) + out[1] = in2[1] + else { + out[1] = id + OBJ_NPIX(obj) = OBJ_NPIX(obj) + 1 + n = n + 1 + } + } + + # Last pixel + id0 = in2[nc] + if (id0 != 0 && MNOTSPLIT(id0)) + out[nc] = id0 + else { + id = 0 + j = nc - 1 + id1 = in1[j] + num1 = MNUM(id1) + if (num1 >= NUMSTART) { + if (MNOTSPLIT(id1)) { + if (obj1 == NULL) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } else if (OBJ_NUM(obj1) != num1) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } + if (grow) { + if (id == 0) { + id = id1 + obj = obj1 + } else if (id != id1) { + if (OBJ_FLUX(obj) < OBJ_FLUX(obj1)) { + id = id1 + obj = obj1 + } + } + } + } + } + id1 = in2[j] + num1 = MNUM(id1) + if (num1 >= NUMSTART) { + if (MNOTSPLIT(id1)) { + if (obj1 == NULL) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } else if (OBJ_NUM(obj1) != num1) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } + if (grow) { + if (id == 0) { + id = id1 + obj = obj1 + } else if (id != id1) { + if (OBJ_FLUX(obj) < OBJ_FLUX(obj1)) { + id = id1 + obj = obj1 + } + } + } + } + } + id1 = in3[j] + num1 = MNUM(id1) + if (num1 >= NUMSTART) { + if (MNOTSPLIT(id1)) { + if (obj1 == NULL) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } else if (OBJ_NUM(obj1) != num1) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } + if (grow) { + if (id == 0) { + id = id1 + obj = obj1 + } else if (id != id1) { + if (OBJ_FLUX(obj) < OBJ_FLUX(obj1)) { + id = id1 + obj = obj1 + } + } + } + } + } + id1 = in1[nc] + num1 = MNUM(id1) + if (num1 >= NUMSTART) { + if (MNOTSPLIT(id1)) { + if (obj1 == NULL) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } else if (OBJ_NUM(obj1) != num1) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } + if (grow) { + if (id == 0) { + id = id1 + obj = obj1 + } else if (id != id1) { + if (OBJ_FLUX(obj) < OBJ_FLUX(obj1)) { + id = id1 + obj = obj1 + } + } + } + } + } + id1 = in3[nc] + num1 = MNUM(id1) + if (num1 >= NUMSTART) { + if (MNOTSPLIT(id1)) { + if (obj1 == NULL) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } else if (OBJ_NUM(obj1) != num1) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } + if (grow) { + if (id == 0) { + id = id1 + obj = obj1 + } else if (id != id1) { + if (OBJ_FLUX(obj) < OBJ_FLUX(obj1)) { + id = id1 + obj = obj1 + } + } + } + } + } + + if (id == 0) + out[nc] = in2[nc] + else { + out[nc] = id + OBJ_NPIX(obj) = OBJ_NPIX(obj) + 1 + n = n + 1 + } + } + + return (n) +end + + +int procedure grow3 (cat, line, in1, in2, out, nc, nl) + +pointer cat #I Catalog +int line #I Line +int in1[nc] #I Previous line +int in2[nc] #I Current line +int out[nc] #I Output line +int nc, nl #I Dimension of image + +int i, j, n, id, id0, id1, num1, andi() +bool grow +pointer objs, obj, obj1 + +begin + objs = CAT_OBJS(cat) - 1 + obj1 = NULL + n = 0 + do i = 1, nc { + id0 = in2[i] + if (id0 != 0 && MNOTSPLIT(id0)) { + out[i] = id0 + next + } + + id = 0 + j = i - 1 + if (i > 1) { + id1 = in1[j] + num1 = MNUM(id1) + if (num1 >= NUMSTART) { + if (MNOTSPLIT(id1)) { + if (obj1 == NULL) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } else if (OBJ_NUM(obj1) != num1) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } + if (grow) { + if (id == 0) { + id = id1 + obj = obj1 + } else if (id != id1) { + if (OBJ_FLUX(obj) < OBJ_FLUX(obj1)) { + id = id1 + obj = obj1 + } + } + } + } + } + id1 = in2[j] + num1 = MNUM(id1) + if (num1 >= NUMSTART) { + if (MNOTSPLIT(id1)) { + if (obj1 == NULL) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } else if (OBJ_NUM(obj1) != num1) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } + if (grow) { + if (id == 0) { + id = id1 + obj = obj1 + } else if (id != id1) { + if (OBJ_FLUX(obj) < OBJ_FLUX(obj1)) { + id = id1 + obj = obj1 + } + } + } + } + } + } + id1 = in1[i] + num1 = MNUM(id1) + if (num1 >= NUMSTART) { + if (MNOTSPLIT(id1)) { + if (obj1 == NULL) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } else if (OBJ_NUM(obj1) != num1) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } + if (grow) { + if (id == 0) { + id = id1 + obj = obj1 + } else if (id != id1) { + if (OBJ_FLUX(obj) < OBJ_FLUX(obj1)) { + id = id1 + obj = obj1 + } + } + } + } + } + j = i + 1 + if (i < nc) { + id1 = in1[j] + num1 = MNUM(id1) + if (num1 >= NUMSTART) { + if (MNOTSPLIT(id1)) { + if (obj1 == NULL) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } else if (OBJ_NUM(obj1) != num1) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } + if (grow) { + if (id == 0) { + id = id1 + obj = obj1 + } else if (id != id1) { + if (OBJ_FLUX(obj) < OBJ_FLUX(obj1)) { + id = id1 + obj = obj1 + } + } + } + } + } + id1 = in2[j] + num1 = MNUM(id1) + if (num1 >= NUMSTART) { + if (MNOTSPLIT(id1)) { + if (obj1 == NULL) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } else if (OBJ_NUM(obj1) != num1) { + obj1 = Memi[objs+num1] + grow = NOTGROWN(obj1) + } + if (grow) { + if (id == 0) { + id = id1 + obj = obj1 + } else if (id != id1) { + if (OBJ_FLUX(obj) < OBJ_FLUX(obj1)) { + id = id1 + obj = obj1 + } + } + } + } + } + } + + if (id == 0) + out[i] = in2[i] + else { + out[i] = id + OBJ_NPIX(obj) = OBJ_NPIX(obj) + 1 + n = n + 1 + } + } + + return (n) +end diff --git a/noao/nproto/ace/gwindow.h b/noao/nproto/ace/gwindow.h new file mode 100644 index 00000000..ae91e2ea --- /dev/null +++ b/noao/nproto/ace/gwindow.h @@ -0,0 +1,49 @@ +# Window descriptor structure. + +define LEN_WDES (210+(W_MAXWC+1)*LEN_WC) +define LEN_WC 10 # 4=[XbXeYbYe]+2=tr_type[xy] +define W_MAXWC 5 # max world coord systems +define W_SZSTRING 99 # size of strings +define W_SZIMSECT W_SZSTRING # image section string + +define W_DEVICE Memi[$1] +define W_FRAME Memi[$1+1] # device frame number +define W_XRES Memi[$1+2] # device resolution, x +define W_YRES Memi[$1+3] # device resolution, y +define W_BPDISP Memi[$1+4] # bad pixel display option +define W_BPCOLORS Memi[$1+5] # overlay colors +define W_OCOLORS Memi[$1+6] # badpixel colors +define W_IMSECT Memc[P2C($1+10)] # image section +define W_OVRLY Memc[P2C($1+60)] # overlay mask +define W_BPM Memc[P2C($1+110)] # bad pixel mask +define W_ZPM Memc[P2C($1+160)] # Z scaling pixel mask +define W_WC ($1+$2*LEN_WC+210) # ptr to coord descriptor + +# Fields of the WC coordinate descriptor, a substructure of the window +# descriptor. "W_XB(W_WC(w,0))" is the XB field of wc 0 of window W. + +define W_XS Memr[P2R($1)] # starting X value +define W_XE Memr[P2R($1+1)] # ending X value +define W_XT Memi[$1+2] # X transformation type +define W_YS Memr[P2R($1+3)] # starting Y value +define W_YE Memr[P2R($1+4)] # ending Y value +define W_YT Memi[$1+5] # Y transformation type +define W_ZS Memr[P2R($1+6)] # starting Z value (greyscale) +define W_ZE Memr[P2R($1+7)] # ending Z value +define W_ZT Memi[$1+8] # Z transformation type +define W_UPTR Memi[$1+9] # LUT when ZT=USER + +# WC types. + +define W_NWIN 0 # Display window in NDC coordinates +define W_DWIN 1 # Display window in image pixel coordinates +define W_WWIN 2 # Display window in image world coordinates +define W_IPIX 3 # Image pixel coordinates (in pixels) +define W_DPIX 4 # Display pixel coordinates (in pixels) + +# Types of coordinate and greyscale transformations. + +define W_UNITARY 0 # values map without change +define W_LINEAR 1 # linear mapping +define W_LOG 2 # logarithmic mapping +define W_USER 3 # user specifies transformation diff --git a/noao/nproto/ace/mapio.x b/noao/nproto/ace/mapio.x new file mode 100644 index 00000000..d8f9f9de --- /dev/null +++ b/noao/nproto/ace/mapio.x @@ -0,0 +1,406 @@ +include <error.h> +include <imhdr.h> + +define MAP_LENSTR 99 # Length of strings + +# Map data structure. +define MAP_LEN 64 # Length of map structure +define MAP_NAME Memc[P2C($1)] # Name of map +define MAP_TYPE Memi[$1+51] # Type of map +define MAP_MAP Memi[$1+52] # Structure pointer +define MAP_COPY Memi[$1+53] # Data buffer for copy +define MAP_NC Memi[$1+54] # Number of columns +define MAP_NL Memi[$1+55] # Number of columns +define MAP_SAMPLE Memi[$1+56] # Sample size for lines +define MAP_BUF Memi[$1+57] # Data buffer for constant or sampling +define MAP_BUF1 Memi[$1+58] # Data buffer for sampling +define MAP_BUF2 Memi[$1+59] # Data buffer for sampling +define MAP_LINE1 Memi[$1+60] # Sampling line number +define MAP_LINE2 Memi[$1+61] # Sampling line number +define MAP_LASTLINE Memi[$1+62] # Last line +define MAP_LASTBUF Memi[$1+63] # Data buffer last returned + +# Types of maps allowed. +define MAP_CONST 1 # Constant +define MAP_IMAGE 2 # Image +define MAP_GSURFIT 3 # GSURFIT + + +# MAP_GLR -- Get a line of map data. + +pointer procedure map_glr (map, line, mode) + +pointer map #I Map pointer +int line #I Line +int mode #I Access mode (READ_ONLY, READ_WRITE) + +int i, nc, nl, sample, line1, line2 +real a, b +pointer buf, buf1, buf2, mim_glr(), mgs_glr() +errchk malloc, mim_glr, mgs_glr + +begin + # Check for repeated request. + if (line == MAP_LASTLINE(map)) { + buf = MAP_LASTBUF(map) + if (mode == READ_WRITE) { + nc = MAP_NC(map) + if (MAP_COPY(map) == NULL) + call malloc (MAP_COPY(map), nc, TY_REAL) + call amovr (Memr[buf], Memr[MAP_COPY(map)], nc) + buf = MAP_COPY(map) + } + return (buf) + } + + nc = MAP_NC(map) + nl = MAP_NL(map) + sample = MAP_SAMPLE(map) + + # Check for subsampling. A constant map will never be sampled. + if (sample > 1) { + if (MAP_BUF1(map) == NULL) { + call malloc (MAP_BUF(map), nc, TY_REAL) + call malloc (MAP_BUF1(map), nc, TY_REAL) + call malloc (MAP_BUF2(map), nc, TY_REAL) + } + line1 = (line-1) / sample * sample + 1 + line2 = min (nl, line1 + sample) + buf1 = MAP_BUF1(map) + buf2 = MAP_BUF2(map) + if (line1 == MAP_LINE2(map)) { + MAP_BUF2(map) = buf1 + MAP_BUF1(map) = buf2 + MAP_LINE2(map) = MAP_LINE1(map) + MAP_LINE1(map) = line1 + buf1 = MAP_BUF1(map) + buf2 = MAP_BUF2(map) + } else if (line2 == MAP_LINE1(map)) { + MAP_BUF1(map) = buf2 + MAP_BUF2(map) = buf1 + MAP_LINE1(map) = MAP_LINE2(map) + MAP_LINE2(map) = line2 + buf1 = MAP_BUF1(map) + buf2 = MAP_BUF2(map) + } + if (line1 != MAP_LINE1(map)) { + switch (MAP_TYPE(map)) { + case MAP_IMAGE: + buf = mim_glr (MAP_MAP(map), line1) + case MAP_GSURFIT: + buf = mgs_glr (MAP_MAP(map), line1) + } + call amovr (Memr[buf], Memr[buf1], nc) + MAP_LINE1(map) = line1 + } + if (line2 != MAP_LINE2(map)) { + switch (MAP_TYPE(map)) { + case MAP_IMAGE: + buf = mim_glr (MAP_MAP(map), line2) + case MAP_GSURFIT: + buf = mgs_glr (MAP_MAP(map), line2) + } + call amovr (Memr[buf], Memr[buf2], nc) + MAP_LINE2(map) = line2 + } + if (line == line1) + buf = buf1 + else if (line == line2) + buf = buf2 + else { + buf = MAP_BUF(map) + b = real (line - line1) / sample + a = 1 - b + do i = 0, nc-1 + Memr[buf+i] = a * Memr[buf1+i] + b * Memr[buf2+i] + } + } else { + switch (MAP_TYPE(map)) { + case MAP_IMAGE: + buf = mim_glr (MAP_MAP(map), line) + case MAP_GSURFIT: + buf = mgs_glr (MAP_MAP(map), line) + case MAP_CONST: + buf = MAP_BUF(map) + } + } + MAP_LASTLINE(map) = line + MAP_LASTBUF(map) = buf + + # Make a copy which might be modified by the caller. + if (mode == READ_WRITE) { + nc = MAP_NC(map) + if (MAP_COPY(map) == NULL) + call malloc (MAP_COPY(map), nc, TY_REAL) + call amovr (Memr[buf], Memr[MAP_COPY(map)], nc) + buf = MAP_COPY(map) + } + + return (buf) +end + + +# MAP_OPEN -- Open map. Return NULL if no map is found. + +pointer procedure map_open (name, refim) + +char name[ARB] #I Name +pointer refim #I Reference image +pointer map #O Map pointer returned + +int i, nc, nl, nowhite(), ctor() +real const +pointer sp, mapstr, im, gs, immap(), mim_open(), mgs_open() +errchk calloc, malloc, imgstr, mim_open, mgs_open + +begin + call smark (sp) + call salloc (mapstr, SZ_FNAME, TY_CHAR) + + i = 1 + nc = IM_LEN(refim,1) + nl = IM_LEN(refim,2) + + call calloc (map, MAP_LEN, TY_STRUCT) + MAP_NC(map) = nc + MAP_NL(map) = nl + + iferr { + # Check for missing map name, and keyword redirection. + if (nowhite (name, Memc[mapstr], SZ_FNAME) == 0) + call error (1, "No map specified") + if (Memc[mapstr] == '!') + call imgstr (refim, Memc[mapstr+1], Memc[mapstr], SZ_FNAME) + call strcpy (Memc[mapstr], MAP_NAME(map), MAP_LENSTR) + + ifnoerr (im = immap (MAP_NAME(map), READ_ONLY, 0)) { + call imunmap (im) + MAP_TYPE(map) = MAP_IMAGE + MAP_MAP(map) = mim_open (MAP_NAME(map), refim) + } else ifnoerr (call mgs_ggs (refim, MAP_NAME(map), gs)) { + MAP_TYPE(map) = MAP_GSURFIT + MAP_MAP(map) = mgs_open (MAP_NAME(map), refim, gs) + } else if (ctor (MAP_NAME(map), i, const) > 0) { + MAP_TYPE(map) = MAP_CONST + call malloc (MAP_BUF(map), nc, TY_REAL) + call amovkr (const, Memr[MAP_BUF(map)], nc) + } else { + call mfree (map, TY_STRUCT) + call sprintf (Memc[mapstr], SZ_FNAME, "Can't open map (%s)") + call pargstr (name) + call error (2, Memc[mapstr]) + } + } then { + call map_close (map) + call erract (EA_ERROR) + } + + call sfree (sp) + return (map) +end + + +# MAP_OPENGS -- Open GSURFIT map given the GSURFIT pointer. + +pointer procedure map_opengs (gs, refim) + +pointer gs #I GSURFIT pointer +pointer refim #I Reference image +pointer map #O Map pointer returned + +pointer mgs_open() +errchk calloc, mgs_open + +begin + iferr { + call calloc (map, MAP_LEN, TY_STRUCT) + MAP_NC(map) = IM_LEN(refim,1) + MAP_NL(map) = IM_LEN(refim,2) + MAP_TYPE(map) = MAP_GSURFIT + MAP_MAP(map) = mgs_open (MAP_NAME(map), refim, gs) + } then { + call map_close (map) + call erract (EA_ERROR) + } + + return (map) +end + + +# MAP_CLOSE -- Unmap map structure. + +procedure map_close (map) + +pointer map #I Map pointer + +begin + if (map == NULL) + return + + switch (MAP_TYPE(map)) { + case MAP_IMAGE: + call mim_close (MAP_MAP(map)) + case MAP_GSURFIT: + call mgs_close (MAP_MAP(map)) + } + + call mfree (MAP_COPY(map), TY_REAL) + call mfree (MAP_BUF(map), TY_REAL) + call mfree (MAP_BUF1(map), TY_REAL) + call mfree (MAP_BUF2(map), TY_REAL) + call mfree (map, TY_STRUCT) +end + + +# MAP_GETS -- Get string parameter. + +procedure map_gets (map, param, val, maxchar) + +pointer map #I Map pointer +char param[ARB] #I Parameter +char val[ARB] #O Parameter string value +int maxchar #I Maximum number of characters to return + +bool streq() +errchk mim_gets(), mgs_gets() + +begin + if (streq (param, "mapname")) + call strcpy (MAP_NAME(map), val, maxchar) + else { + switch (MAP_TYPE(map)) { + case MAP_IMAGE: + call mim_gets (MAP_MAP(map), param, val, maxchar) + case MAP_GSURFIT: + call mgs_gets (MAP_MAP(map), param, val, maxchar) + default: + call error (1, "map_gets: unknown parameter") + } + } +end + + +# MAP_GETI -- Get integer parameter. + +procedure map_geti (map, param, val) + +pointer map #I Map pointer +char param[ARB] #I Parameter +int val #O Value + +errchk mim_geti(), mgs_geti() + +begin + switch (MAP_TYPE(map)) { + case MAP_IMAGE: + call mim_geti (MAP_MAP(map), param, val) + case MAP_GSURFIT: + call mgs_geti (MAP_MAP(map), param, val) + default: + call error (1, "map_geti: unknown parameter") + } +end + + +# MAP_GETR -- Get real parameter. + +procedure map_getr (map, param, val) + +pointer map #I Map pointer +char param[ARB] #I Parameter +real val #O Value + +bool streq() +errchk mim_getr(), mgs_getr() + +begin + if (streq (param, "constant")) { + if (MAP_TYPE(map) == MAP_CONST) { + val = Memr[MAP_BUF(map)] + return + } else + call error (1, "map_getr: map is not constant") + } + + switch (MAP_TYPE(map)) { + case MAP_IMAGE: + call mim_getr (MAP_MAP(map), param, val) + case MAP_GSURFIT: + call mgs_getr (MAP_MAP(map), param, val) + default: + call error (1, "map_getr: unknown parameter") + } +end + + +# MAP_SETI -- Set integer parameter. + +procedure map_seti (map, param, val) + +pointer map #I Map pointer +char param[ARB] #I Parameter +int val #I Value + +bool streq() +errchk mim_seti(), mgs_seti + +begin + switch (MAP_TYPE(map)) { + case MAP_CONST: + ; + case MAP_IMAGE: + if (streq (param, "sample")) + MAP_SAMPLE(map) = max (1, val) + else + call mim_seti (MAP_MAP(map), param, val) + case MAP_GSURFIT: + if (streq (param, "sample")) + MAP_SAMPLE(map) = max (1, val) + else + call mgs_seti (MAP_MAP(map), param, val) + } +end + + +# MAP_SETR -- Set real parameter. + +procedure map_setr (map, param, val) + +pointer map #I Map pointer +char param[ARB] #I Parameter +real val #I Value + +errchk mim_setr(), mgs_setr + +begin + switch (MAP_TYPE(map)) { + case MAP_IMAGE: + call mim_setr (MAP_MAP(map), param, val) + case MAP_GSURFIT: + call mgs_setr (MAP_MAP(map), param, val) + default: + call error (1, "map_setr: unknown parameter") + } +end + + +# MAP_SETS -- Set string parameter. + +procedure map_sets (map, param, val) + +pointer map #I Map pointer +char param[ARB] #I Parameter +char val[ARB] #I Value + +errchk mim_sets(), mgs_sets + +begin + switch (MAP_TYPE(map)) { + case MAP_IMAGE: + call mim_sets (MAP_MAP(map), param, val) + case MAP_GSURFIT: + call mgs_sets (MAP_MAP(map), param, val) + default: + call error (1, "map_sets: unknown parameter") + } +end diff --git a/noao/nproto/ace/maskcolor.x b/noao/nproto/ace/maskcolor.x new file mode 100644 index 00000000..29e25e55 --- /dev/null +++ b/noao/nproto/ace/maskcolor.x @@ -0,0 +1,54 @@ +# MASKCOLOR -- A color for a mask value. + +procedure mcolors (colors, maskval, dataval) + +pointer colors #I Mask colormap object +int maskval #I Mask value +short dataval #U Data value to be set + +int i, j, offset, color + +begin + color = Memi[colors+2] + offset = Memi[colors+3] + do i = 2, Memi[colors] { + j = 4 * i - 4 + if (maskval >= Memi[colors+j] && maskval <= Memi[colors+j+1]) { + color = Memi[colors+j+2] + offset = Memi[colors+j+3] + break + } + } + + if (offset == YES) + color = maskval + color + if (color >= 0) + dataval = color +end + + +procedure mcolorr (colors, maskval, dataval) + +pointer colors #I Mask colormap object +int maskval #I Mask value +real dataval #U Data value to be set + +int i, j, offset, color + +begin + color = Memi[colors+2] + offset = Memi[colors+3] + do i = 2, Memi[colors] { + j = 4 * i - 4 + if (maskval >= Memi[colors+j] && maskval <= Memi[colors+j+1]) { + color = Memi[colors+j+2] + offset = Memi[colors+j+3] + break + } + } + + if (offset == YES) + color = maskval + color + if (color >= 0) + dataval = color +end diff --git a/noao/nproto/ace/mgs.x b/noao/nproto/ace/mgs.x new file mode 100644 index 00000000..2e11cab7 --- /dev/null +++ b/noao/nproto/ace/mgs.x @@ -0,0 +1,321 @@ +include <error.h> +include <imhdr.h> +include <imio.h> +include <math/gsurfit.h> + +# Data structure. +define MGS_SZNAME 99 # Length of mgs name string +define MGS_LEN 56 # Length of structure +define MGS_GS Memi[$1] # GSURFIT pointer +define MGS_X Memi[$1+1] # Pointer to line of x values +define MGS_Y Memi[$1+2] # Pointer to line of y values +define MGS_Z Memi[$1+3] # Pointer to line of z values +define MGS_NC Memi[$1+4] # Number of columns +define MGS_REFIM Memi[$1+5] # Reference image pointer +define MGS_NAME Memc[P2C($1+6)] # Map name + + +# MGS_GLR -- Get a line of data. + +pointer procedure mgs_glr (mgs, line) + +pointer mgs #I Map pointer +int line #I Line + +int nc +pointer x, y, z, gs + +begin + if (mgs == NULL) + call error (1, "Map is undefined") + + gs = MGS_GS(mgs) + x = MGS_X(mgs) + y = MGS_Y(mgs) + z = MGS_Z(mgs) + nc = MGS_NC(mgs) + + call amovkr (real(line), Memr[y], nc) + call gsvector (gs, Memr[x], Memr[y], Memr[z], nc) + + return (z) +end + + +# MGS_OPEN -- Open mgs. + +pointer procedure mgs_open (name, refim, gsin) + +char name[ARB] #I Name +pointer refim #I Reference image +pointer gsin #I GSURFIT pointer +pointer mgs #O Map pointer returned + +int i, nc, nl +real gsgetr() +pointer gs +errchk mgs_ggs + +begin + nc = IM_LEN(refim,1) + nl = IM_LEN(refim,2) + + call calloc (mgs, MGS_LEN, TY_STRUCT) + MGS_REFIM(mgs) = refim + call strcpy (name, MGS_NAME(mgs), MGS_SZNAME) + MGS_NC(mgs) = nc + + iferr { + gs = gsin + if (gs == NULL) { + call mgs_ggs (refim, name, gs) + MGS_GS(mgs) = gs + } + + if (1 < gsgetr (gs, GSXMIN) || nc > gsgetr (gs, GSXMAX) || + 1 < gsgetr (gs, GSYMIN) || nl > gsgetr (gs, GSYMAX)) + call error (2, "Map and data images have different sizes") + + MGS_GS(mgs) = gs + call malloc (MGS_X(mgs), nc, TY_REAL) + call malloc (MGS_Y(mgs), nc, TY_REAL) + call malloc (MGS_Z(mgs), nc, TY_REAL) + do i = 1, nc + Memr[MGS_X(mgs)+i-1] = i + } then { + call mgs_close (mgs) + call erract (EA_ERROR) + } + + return (mgs) +end + + +# MGS_CLOSE -- Close mgs. + +procedure mgs_close (mgs) + +pointer mgs #I Map pointer + +begin + if (mgs == NULL) + return + + if (MGS_GS(mgs) != NULL) + call gsfree (MGS_GS(mgs)) + call mfree (MGS_X(mgs), TY_REAL) + call mfree (MGS_Y(mgs), TY_REAL) + call mfree (MGS_Z(mgs), TY_REAL) + call mfree (mgs, TY_STRUCT) +end + + +# MGS_GETS -- Get string parameter. + +procedure mgs_gets (mgs, param, val, maxchar) + +pointer mgs #I Map pointer +char param[ARB] #I Parameter +char val[ARB] #O Parameter string value +int maxchar #I Maximum number of characters to return + +begin + call error (1, "mgs_gets: unknown parameter") +end + + +# MGS_SETS -- Set string parameter. + +procedure mgs_sets (mgs, param, val) + +pointer mgs #I Map pointer +char param[ARB] #I Parameter +char val[ARB] #O Parameter string value + +begin + call error (1, "mgs_sets: unknown parameter") +end + + +# MGS_GETI -- Get integer parameter. + +procedure mgs_geti (mgs, param, val) + +pointer mgs #I Map pointer +char param[ARB] #I Parameter +int val #O Value + +bool streq() + +begin + if (streq (param, "gsurfit")) + val = MGS_GS(mgs) + else + call error (1, "mgs_geti: unknown parameter") +end + + +# MGS_SETI -- Set integer parameter. + +procedure mgs_seti (mgs, param, val) + +pointer mgs #I Map pointer +char param[ARB] #I Parameter +int val #I Value + +bool streq() + +begin + if (streq (param, "gsurfit")) { + call mgs_pgs (MGS_REFIM(mgs), MGS_NAME(mgs), val) + call gsfree (MGS_GS(mgs)) + MGS_GS(mgs) = val + } else + call error (1, "mgs_seti: unknown parameter") +end + + +# MGS_GETR -- Get real parameter. + +procedure mgs_getr (mgs, param, val) + +pointer mgs #I Map pointer +char param[ARB] #I Parameter +real val #O Value + +begin + call error (1, "mgs_getr: unknown parameter") +end + + +# MGS_SETR -- Set real parameter. + +procedure mgs_setr (mgs, param, val) + +pointer mgs #I Map pointer +char param[ARB] #I Parameter +real val #I Value + +begin + call error (1, "mgs_setr: unknown parameter") +end + + +# MAP_PGS -- Put mgs surface fit. + +procedure mgs_pgs (im, key, gs) + +pointer im #I Image pointer +char key[ARB] #I Keyword root +pointer gs #I Surface fit pointer + +int i, nc, fd, gsgeti(), stropen() +pointer sp, kw, card, coeffs, strbuf, cp, cp1, cp2 + +begin + if (IM_SECTUSED(im) == YES) + return + + call smark (sp) + call salloc (kw, 80, TY_CHAR) + call salloc (card, 68, TY_CHAR) + + nc = gsgeti (gs, GSNSAVE) + call salloc (coeffs, nc, TY_REAL) + call gssave (gs, Memr[coeffs]) + + # Convert coeffs to a string. Last character will be space. + call salloc (strbuf, 20*nc, TY_CHAR) + call aclrc (Memc[strbuf], 20*nc) + fd = stropen (Memc[strbuf], 20*nc, WRITE_ONLY) + do i = 1, nc { + call fprintf (fd, "%g ") + call pargr (Memr[coeffs+i-1]) + } + call close (fd) + + i = 1 + cp1 = strbuf + for (cp=cp1; Memc[cp] != EOS; cp=cp+1) { + if (Memc[cp] == ' ') + cp2 = cp + if (cp - cp1 + 1 == 68) { + call sprintf (Memc[kw], 8, "%.6s%02d") + call pargstr (key) + call pargi (i) + i = i + 1 + Memc[cp2] = EOS + call imastr (im, Memc[kw], Memc[cp1]) + cp1 = cp2 + 1 + cp = cp1 + } + } + if (cp - cp1 + 1 > 0) { + call sprintf (Memc[kw], 8, "%.6s%02d") + call pargstr (key) + call pargi (i) + i = i + 1 + Memc[cp2] = EOS + call imastr (im, Memc[kw], Memc[cp1]) + } + repeat { + call sprintf (Memc[kw], 8, "%.6s%02d") + call pargstr (key) + call pargi (i) + i = i + 1 + iferr (call imdelf (im, Memc[kw])) + break + } + + call sfree (sp) +end + + +# MAP_GGS -- Get mgs surface fit. + +procedure mgs_ggs (im, key, gs) + +pointer im #I Image pointer +char key[ARB] #I Keyword root +pointer gs #O Surface fit pointer + +int i, j, nc, ctor() +pointer sp, kw, card, coeffs + +begin + if (IM_SECTUSED(im) == YES) + call error (1, "No surface fit with an image section") + + call smark (sp) + call salloc (kw, 8, TY_CHAR) + call salloc (card, 68, TY_CHAR) + + call malloc (coeffs, 100, TY_REAL) + iferr { + nc = 0 + do i = 1, ARB { + call sprintf (Memc[kw], 8, "%.6s%02d") + call pargstr (key) + call pargi (i) + iferr (call imgstr (im, Memc[kw], Memc[card], 68)) + break + j = 1 + while (ctor (Memc[card], j, Memr[coeffs+nc]) != 0) { + nc = nc + 1 + if (mod (nc, 100) == 0) + call realloc (coeffs, nc+100, TY_REAL) + } + } + + if (nc == 0) + call error (1, "Surface fit not found") + + call gsrestore (gs, Memr[coeffs]) + call mfree (coeffs, TY_REAL) + } then { + call mfree (coeffs, TY_REAL) + call erract (EA_ERROR) + } + + call sfree (sp) +end diff --git a/noao/nproto/ace/mim.x b/noao/nproto/ace/mim.x new file mode 100644 index 00000000..9a621e40 --- /dev/null +++ b/noao/nproto/ace/mim.x @@ -0,0 +1,544 @@ +# MIM (Match IMage) -- Match a 2D image to a 2D reference image. +# +# These routines provide an I/O interface to get data from a 2D image which +# matches a line of a 2D reference image. The two common uses are to get a +# subraster of the image which matches the reference image and to interpolate +# an image which is blocked to a lower resolution than the reference image. +# The matching is done in physical pixel coordinates. It is completely +# general in allowing any linear transformation between the physical +# coordinates. But in most cases the reference image and the input image +# will be related either by an image section or some kind of blocking factor +# without rotation. Any relative rotation of the two in physical pixels is +# likely to be slow for large images (either the reference image or the mim +# image). Interpolation (if any is required) is done with the MSI library. +# Extrapolation outside of the input image uses the nearest edge value. +# +# mim = mim_open (input, refim) +# buf = mim_glr (mim, refline) +# mim_close (mim) +# +# Parameters may be queried and set by the following routines. +# +# mim_geti (mim, param, val) +# mim_getr (mim, param, val) +# mim_gets (mim, param, str, maxchar) +# mim_seti (mim, param, val) +# mim_setr (mim, param, val) +# mim_sets (mim, param, str) +# +# The parameters are specified by strings as given below. The default values +# are in parentheses. Currently there are only integer parameters. +# +# msitype - interpolation type defined by the MSI library +# (II_BISPLINE3) +# msiedge - number of additional lines at each edge to include +# in interpolation (3) +# msimax - maximum number of pixels to allow in MSIFIT calls (500000) + + +include <error.h> +include <imhdr.h> +include <imset.h> +include <math/iminterp.h> + +# Data structure. +define MIM_LEN 18 +define MIM_INTERP Memi[$1] # Use interpolation? +define MIM_ROTATE Memi[$1+1] # Is there any rotation? +define MIM_IM Memi[$1+2] # IMIO mim pointer +define MIM_MSI Memi[$1+3] # MSI interpolation pointer +define MIM_NCREF Memi[$1+4] # Number of columns in ref image +define MIM_NC Memi[$1+5] # Number of columns in input image +define MIM_NL Memi[$1+6] # Number of lines in input image +define MIM_LINE1 Memi[$1+7] # First line in msi fit +define MIM_LINE2 Memi[$1+8] # Last line in msi fit +define MIM_X Memi[$1+9] # Pointer to line of x values +define MIM_Y Memi[$1+10] # Pointer to line of y values +define MIM_Z Memi[$1+11] # Pointer to line of z values +define MIM_MW Memi[$1+12] # MWCS pointer +define MIM_CT Memi[$1+13] # CT from ref logical to input logical +define MIM_MSITYPE Memi[$1+14] # MSI interpolation type +define MIM_MSIEDGE Memi[$1+15] # Number of edge pixels to reserve +define MIM_MSIMAX Memi[$1+16] # Maximum number of pixels in msi fit +define MIM_DELETE Memi[$1+17] # Delete image after closing? + +# Defaults +define MIM_MSITYPEDEF II_BISPLINE3 +define MIM_MSIEDGEDEF 3 +define MIM_MSIMAXDEF 500000 + + +# MIM_GL -- Get a line of data matching a line of the reference image. +# A pointer to the data is returned. The data buffer is assumed to be +# read-only and not to be modified by the calling routine. + +pointer procedure mim_glr (mim, line) + +pointer mim #I Map pointer +int line #I Reference image line + +int i, j, nc, nl, ncref, line1, line2, nlines +pointer msi, ct, x, y, z, imname, ptr +real rnl, val + +real mw_c1tranr() +pointer imgl2r(), imgs2r() + +errchk imgl2r, msiinit, msifit, imdelete + +begin + if (mim == NULL) + call error (1, "Map is undefined") + + # If interpolation is not needed return the IMIO buffer. + if (MIM_INTERP(mim) == NO) { + ptr = imgl2r (MIM_IM(mim), line) + return (ptr) + } + + nc = MIM_NC(mim) + nl = MIM_NL(mim) + ncref = MIM_NCREF(mim) + rnl = nl + msi = MIM_MSI(mim) + ct = MIM_CT(mim) + x = MIM_X(mim) + y = MIM_Y(mim) + z = MIM_Z(mim) + + # Set the interpolation coordinates in the input image logical pixels. + # This is limited to be within the input image. Therefore, requests + # outside the input image will use the nearest edge value. + # Also set the minimum range of input lines required. + + if (MIM_ROTATE(mim) == NO) { + val = mw_c1tranr (ct, real(line)) + val = max (1., min (rnl, val)) + call amovkr (val, Memr[y], ncref) + line1 = max (1., val - 1) + line2 = min (rnl, val + 1) + } else { + call amovkr (real(line), Memr[y], ncref) + call mw_v2tranr (ct, Memr[x], Memr[y], Memr[z], Memr[y], ncref) + x = z + + # Limit the x range to within the input image. + ptr = x + val = nc + do i = 1, ncref { + Memr[ptr] = max (1., min (val, Memr[ptr])) + ptr = ptr + 1 + } + + # Limit the y range to within the input image and find the range + # of lines required. + j = nint (Memr[y]) + line1 = max (1, min (nl, j)) + line2 = line1 + ptr = y + rnl = nl + do i = 1, ncref { + val = max (1., min (rnl, Memr[ptr])) + j = nint (val) + line1 = min (j, line1) + line2 = max (j, line2) + Memr[ptr] = val + ptr = ptr + 1 + } + line1 = max (1, line1 - 1) + line2 = min (nl, line2 + 1) + } + + # Set or reset image interpolator. For small input interpolation + # images read the entire image, fit the interpolator, and free the + # image. For larger input images determine the range of lines + # required including edge space and fit the interpolator to those + # lines. Providing the reference lines are requested sequentially + # this is about as efficient as we can make it. + + if (line1 < MIM_LINE1(mim) || line2 > MIM_LINE2(mim)) { + if (msi != NULL) + call msifree (MIM_MSI(mim)) + if (min (nc, nl) > 3) + call msiinit (MIM_MSI(mim), MIM_MSITYPE(mim)) + else if (min (nc, nl) > 1) + call msiinit (MIM_MSI(mim), II_BILINEAR) + else + call msiinit (MIM_MSI(mim), II_BINEAREST) + msi = MIM_MSI(mim) + if (nc * nl <= MIM_MSIMAX(mim)) { + nlines = nl + line1 = 1 + line2 = nlines + ptr = imgs2r (MIM_IM(mim), 1, nc, line1, line2) + call msifit (msi, Memr[ptr], nc, nlines, nc) + if (MIM_DELETE(mim) == YES) { + call malloc (imname, SZ_FNAME, TY_CHAR) + call imstats (MIM_IM(mim), IM_IMAGENAME, Memc[imname], + SZ_FNAME) + call imgimage (Memc[imname], Memc[imname], SZ_FNAME) + call imunmap (MIM_IM(mim)) + call imdelete (Memc[imname]) + call mfree (imname, TY_CHAR) + } else + call imunmap (MIM_IM(mim)) + } else { + nlines = max (2*MIM_MSIEDGE(mim)+(line2-line1+1), + MIM_MSIMAX(mim) / nc) + line1 = max (1, min (nl, line1 - MIM_MSIEDGE(mim))) + line2 = max (1, min (nl, line1 + nlines - 1)) + line1 = max (1, min (nl, line2 - nlines + 1)) + nlines = line2 - line1 + 1 + ptr = imgs2r (MIM_IM(mim), 1, nc, line1, line2) + call msifit (msi, Memr[ptr], nc, nlines, nc) + } + MIM_LINE1(mim) = line1 + MIM_LINE2(mim) = line2 + } + + # Interpolate input image to a line in the reference image. + call msivector (msi, Memr[x], Memr[y], Memr[z], ncref) + + return (z) +end + + +# MIM_OPEN -- Open an image matched to a reference image. +# +# Fitting of any interpolator is later. This allows calls to reset +# the interpolation type, edge buffer, and maximum size to fit. + +pointer procedure mim_open (input, refim) + +char input[ARB] #I Input image name +pointer refim #I Reference image +pointer mim #O Map pointer returned + +bool interp, rotate +int i, nc, nl, ncref, nlref, ilt[6] +double lt[6], ltref[6], ltin[6] +pointer sp, section, im, mw, ct, x, ptr + +int strlen(), btoi() +pointer immap(), mw_openim(), mw_sctran() +errchk calloc, malloc +errchk immap +errchk mw_openim, mw_invertd, mw_sctran + +begin + call smark (sp) + call salloc (section, SZ_FNAME, TY_CHAR) + + iferr { + mim = NULL; im = NULL; mw = NULL + + call calloc (mim, MIM_LEN, TY_STRUCT) + MIM_DELETE(mim) = NO + + call imgimage (input, Memc[section], SZ_FNAME) + ptr = immap (Memc[section], READ_ONLY, 0); im = ptr + nc = IM_LEN(im,1) + nl = IM_LEN(im,2) + ncref = IM_LEN(refim,1) + nlref = IM_LEN(refim,2) + + # Check relationship between reference and input images in physical + # coordinates. + + ptr = mw_openim (refim); mw = ptr + call mw_gltermd (mw, lt, lt[5], 2) + call mw_close (mw) + + mw = mw_openim (im) + call mw_gltermd (mw, ltin, ltin[5], 2) + + # Combine lterms. + call mw_invertd (lt, ltref, 2) + call mw_mmuld (ltref, ltin, lt, 2) + call mw_vmuld (lt, lt[5], lt[5], 2) + lt[5] = ltin[5] - lt[5] + lt[6] = ltin[6] - lt[6] + do i = 1, 6 + lt[i] = nint (1D6 * lt[i]) / 1D6 + + # Check if interpolation is required. + interp = false + do i = 1, 6 { + ilt[i] = nint (lt[i]) + if (lt[i] - ilt[i] > 1D-3) { + interp = true + break + } + } + if (lt[2] != 0. || lt[3] != 0.) + rotate = true + else + rotate = false + if (!interp && rotate) + interp = true + + if (interp) { + # Use IMIO to extract a smaller section if possible to + # minimize the requirements for the interpolation. + # This could be more general if we deal with a section + # of a rotated image. + + if (!rotate) { + ilt[1] = lt[1] + lt[5] + ilt[2] = lt[1] * ncref + lt[5] + 0.999 + ilt[3] = lt[3] + lt[4] + lt[6] + ilt[4] = lt[4] * nlref + lt[6] + 0.999 + ilt[1] = max (1, min (nc, ilt[1])) + ilt[2] = max (1, min (nc, ilt[2])) + ilt[3] = max (1, min (nl, ilt[3])) + ilt[4] = max (1, min (nl, ilt[4])) + if (ilt[1]!=1 || ilt[2]!=nc ||ilt[1]!=1 || ilt[2]!=nl) { + i = strlen(Memc[section]) + 1 + call sprintf (Memc[section+i-1], SZ_FNAME-i, + "[%d:%d,%d:%d]") + call pargi (ilt[1]) + call pargi (ilt[2]) + call pargi (ilt[3]) + call pargi (ilt[4]) + call imunmap (im) + im = immap (Memc[section], READ_ONLY, 0) + nc = IM_LEN(im,1) + nl = IM_LEN(im,2) + lt[5] = lt[5] - ilt[1] + 1 + lt[6] = lt[6] - ilt[3] + 1 + } + } + + # Set reference logical to input logical transformation. + # The reference logical coordinates are the physical + # coordinates of the transformation. + + call mw_sltermd (mw, lt, lt[5], 2) + + # If there are cross terms set the x array to the reference + # logical coordinates (physical transformation coordinates). + # Otherwise we only need to evalute x array once in the + # input logical coordinates to be interpolated. + + call malloc (x, ncref, TY_REAL) + do i = 1, ncref + Memr[x+i-1] = i + if (rotate) + ct = mw_sctran (mw, "physical", "logical", 3B) + else { + ct = mw_sctran (mw, "physical", "logical", 1B) + call mw_v1tranr (ct, Memr[x], Memr[x], ncref) + ptr = x + do i = 1, ncref { + Memr[ptr] = max (1., min (real(nc), Memr[ptr])) + ptr = ptr + 1 + } + call mw_ctfree (ct) + ct = mw_sctran (mw, "physical", "logical", 2B) + } + + MIM_X(mim) = x + call malloc (MIM_Y(mim), ncref, TY_REAL) + call malloc (MIM_Z(mim), ncref, TY_REAL) + MIM_MW(mim) = mw + MIM_CT(mim) = ct + MIM_MSITYPE(mim) = MIM_MSITYPEDEF + MIM_MSIEDGE(mim) = MIM_MSIEDGEDEF + MIM_MSIMAX(mim) = MIM_MSIMAXDEF + + } else { + # If ref is a subraster of the input use IMIO section to match. + if (ilt[1]!=1 || ilt[4]!=1 || ilt[5]!=0 || ilt[6]!=0) { + i = strlen(Memc[section]) + 1 + call sprintf (Memc[section+i-1], SZ_FNAME-i, + "[%d:%d:%d,%d:%d:%d]") + call pargi (ilt[1]+ilt[5]) + call pargi (ilt[1]*ncref+ilt[5]) + call pargi (ilt[1]) + call pargi (ilt[4]+ilt[6]) + call pargi (ilt[4]*nlref+ilt[6]) + call pargi (ilt[4]) + call imunmap (im) + im = immap (Memc[section], READ_ONLY, 0) + nc = IM_LEN(im,1) + nl = IM_LEN(im,2) + } + call mw_close (mw) + } + + MIM_IM(mim) = im + MIM_INTERP(mim) = btoi (interp) + MIM_ROTATE(mim) = btoi (rotate) + MIM_NC(mim) = nc + MIM_NL(mim) = nl + MIM_NCREF(mim) = ncref + } then { + if (mw != NULL) + call mw_close (mw) + if (im != NULL) + call imunmap (im) + call mim_close (mim) + call sfree (sp) + call erract (EA_ERROR) + } + + call sfree (sp) + return (mim) +end + + +# MIM_CLOSE -- Close mim structure. + +procedure mim_close (mim) + +pointer mim #I MIM pointer + +pointer imname +errchk imdelete + +begin + if (mim == NULL) + return + + if (MIM_IM(mim) != NULL) { + if (MIM_DELETE(mim) == YES) { + call malloc (imname, SZ_FNAME, TY_CHAR) + call imstats (MIM_IM(mim), IM_IMAGENAME, Memc[imname], SZ_FNAME) + call imgimage (Memc[imname], Memc[imname], SZ_FNAME) + call imunmap (MIM_IM(mim)) + call imdelete (Memc[imname]) + call mfree (imname, TY_CHAR) + } else + call imunmap (MIM_IM(mim)) + } + if (MIM_MSI(mim) != NULL) + call msifree (MIM_MSI(mim)) + if (MIM_MW(mim) != NULL) + call mw_close (MIM_MW(mim)) + call mfree (MIM_X(mim), TY_REAL) + call mfree (MIM_Y(mim), TY_REAL) + call mfree (MIM_Z(mim), TY_REAL) + call mfree (mim, TY_STRUCT) +end + + +# MIM_GETS -- Get string parameter. + +procedure mim_gets (mim, param, val, maxchar) + +pointer mim #I MIM pointer +char param[ARB] #I Parameter +char val[ARB] #O Parameter string value +int maxchar #I Maximum number of characters to return + +begin + call error (1, "mim_gets: unknown parameter") +end + + +# MIM_GETI -- Get integer parameter. + +procedure mim_geti (mim, param, val) + +pointer mim #I MIM pointer +char param[ARB] #I Parameter +int val #O Value + +bool streq() + +begin + if (streq (param, "msitype")) + val = MIM_MSITYPE(mim) + else if (streq (param, "msiedge")) + val = MIM_MSIEDGE(mim) + else if (streq (param, "msimax")) + val = MIM_MSIMAX(mim) + else if (streq (param, "delete")) + val = MIM_DELETE(mim) + else + call error (1, "mim_geti: unknown parameter") +end + + +# MIM_GETR -- Get real parameter. + +procedure mim_getr (mim, param, val) + +pointer mim #I MIM pointer +char param[ARB] #I Parameter +real val #O Value + +begin + call error (1, "mim_getr: unknown parameter") +end + + +# MIM_SETS -- Set string parameter. + +procedure mim_sets (mim, param, val) + +pointer mim #I MIM pointer +char param[ARB] #I Parameter +char val[ARB] #I Value + +begin + call error (1, "mim_sets: unknown parameter") +end + + +# MIM_SETI -- Set integer parameter. + +procedure mim_seti (mim, param, val) + +pointer mim #I MIM pointer +char param[ARB] #I Parameter +int val #I Value + +bool streq() + +begin + if (streq (param, "msitype")) { + if (val != MIM_MSITYPE(mim)) { + MIM_MSITYPE(mim) = val + if (MIM_MSI(mim) != NULL) { + call msifree (MIM_MSI(mim)) + MIM_LINE1(mim) = 0 + MIM_LINE2(mim) = 0 + } + } + } else if (streq (param, "msiedge")) { + if (val != max (3, MIM_MSIEDGE(mim))) { + MIM_MSIEDGE(mim) = val + if (MIM_MSI(mim) != NULL) { + call msifree (MIM_MSI(mim)) + MIM_LINE1(mim) = 0 + MIM_LINE2(mim) = 0 + } + } + } else if (streq (param, "msimax")) { + if (val != max (64000, MIM_MSIMAX(mim))) { + MIM_MSIMAX(mim) = val + if (MIM_MSI(mim) != NULL) { + call msifree (MIM_MSI(mim)) + MIM_LINE1(mim) = 0 + MIM_LINE2(mim) = 0 + } + } + } else if (streq (param, "delete")) + MIM_DELETE(mim) = val + else + call error (1, "mim_setr: unknown parameter") +end + + +# MIM_SETR -- Set real parameter. + +procedure mim_setr (mim, param, val) + +pointer mim #I MIM pointer +char param[ARB] #I Parameter +real val #I Value + +begin + call error (1, "mim_setr: unknown parameter") +end diff --git a/noao/nproto/ace/mkpkg b/noao/nproto/ace/mkpkg new file mode 100644 index 00000000..d385a296 --- /dev/null +++ b/noao/nproto/ace/mkpkg @@ -0,0 +1,60 @@ +# Make ACE. + +$call relink +$exit + +update: + $call relink + $call install + ; + +relink: + $update libpkg.a + $omake x_ace.x + $link x_ace.o libpkg.a -lds -lgsurfit -lcurfit -lxtools -liminterp\ + -ltbtables -o xx_ace.e + ; + +install: + $move xx_ace.e acebin$x_ace.e + ; + +libpkg.a: + aceoverlay.x ace.h <error.h> <imhdr.h> <imset.h> <pmset.h> + bndry.x ace.h <pmset.h> + catdefine.x ace.h cat.h objs.h + catio.x ace.h cat.h <imset.h> <math.h> objs.h + convolve.x <ctype.h> <imhdr.h> + detect.x ace.h cat.h detect.h <imhdr.h> <mach.h> objs.h\ + <pmset.h> skyblock.h split.h + evaluate.x ace.h cat.h <error.h> evaluate.h <imhdr.h> objs.h\ + <pmset.h> + filter.x ace.h <evvexpr.h> filter.h objs.h + grow.x ace.h cat.h grow.h objs.h <pmset.h> + mapio.x <error.h> <imhdr.h> + maskcolor.x + mgs.x <error.h> <imhdr.h> <imio.h> <math/gsurfit.h> + mim.x <error.h> <imhdr.h> <imset.h> <math/iminterp.h> + noisemodel.x + omwrite.x <imhdr.h> <pmset.h> ace.h + pars.x <ctype.h> detect.h evaluate.h grow.h <math/curfit.h>\ + <math/gsurfit.h> skyblock.h skyfit.h sky.h split.h + skyblock.x <ctype.h> <error.h> <imhdr.h> <imset.h> <mach.h>\ + skyblock.h + skyfit.x <imhdr.h> <math/curfit.h> <math/gsurfit.h> skyfit.h + skyimages.x <error.h> <imhdr.h> + sky.x <error.h> sky.h + split.x ace.h cat.h <mach.h> objs.h <pmset.h> split.h + tables.x + t_acedetect.x ace.h acedetect.h cat.h <error.h> <fset.h> <imhdr.h>\ + <imset.h> <pmset.h> + t_acedisplay.x <ctype.h> display.h <error.h> gwindow.h <imhdr.h>\ + <imhdr.h> <imset.h> <imset.h> <mach.h> <mach.h>\ + <pmset.h> + t_imext.x <ctype.h> <error.h> <imhdr.h> <imset.h> <mach.h> + t_mscext.x <error.h> <imhdr.h> <imset.h> + x_ace.x + xtmaskname.x + xtpmmap.x <ctype.h> <error.h> <imhdr.h> <imset.h> <mach.h>\ + <mwset.h> <pmset.h> + ; diff --git a/noao/nproto/ace/noisemodel.x b/noao/nproto/ace/noisemodel.x new file mode 100644 index 00000000..0503c4a1 --- /dev/null +++ b/noao/nproto/ace/noisemodel.x @@ -0,0 +1,102 @@ +# NOISEMODEL -- Compute noise model. +# +# var = (var(sky) + (image-sky)/gain) / sqrt (exposure) +# +# What is actually returned is the square root of the variance. +# The variance of the sky and the effective gain are for a unit +# exposure in the exposure map. + +procedure noisemodel (image, sky, sig, gain, exp, sigma, npix) + +real image[npix] #I Image +real sky[npix] #I Sky +real sig[npix] #I Sky sigma +real gain[npix] #I Gain +real exp[npix] #I Exposure +real sigma[npix] #O Sigma +int npix #I Number of pixels + +int i +real e, elast, sqrte + +begin + if (IS_INDEFR(exp[1])) { + if (IS_INDEFR(gain[1])) + call amovr (sig, sigma, npix) + else { + do i = 1, npix + sigma[i] = sqrt (sig[i] * sig[1] + + (image[i] - sky[i]) / gain[i]) + } + } else if (IS_INDEFR(gain[1])) { + elast = INDEFR + do i = 1, npix { + e = exp[i] + if (e == 0.) { + sigma[i] = sig[i] + next + } + if (e != elast) { + sqrte = sqrt (e) + elast = e + } + sigma[i] = sig[i] / sqrte + } + } else { + do i = 1, npix { + e = exp[i] + if (e == 0.) { + sigma[i] = sqrt (sig[i] * sig[i] + + (image[i] - sky[i]) / gain[i]) + next + } + sigma[i] = sqrt ((sig[i] * sig[i] + + (image[i] - sky[i]) / gain[i]) / e) + } + } +end + + +# EXPSIGMA -- Apply exposure map to correct sky sigma. +# Assume the exposure map has region of contiguous constant values so +# that the number of square roots can be minimized. An exposure map +# value of zero leaves the sigma unchanged. + +procedure expsigma (sigma, expmap, npix, mode) + +real sigma[npix] #U Sigma values +real expmap[npix] #I Exposure map values +int npix #I Number of pixels +int mode #I 0=divide, 1=multiply + +int i +real exp, lastexp, scale + +begin + switch (mode) { + case 0: + lastexp = INDEFR + do i = 1, npix { + exp = expmap[i] + if (exp == 0.) + next + if (exp != lastexp) { + scale = sqrt (exp) + lastexp = exp + } + sigma[i] = sigma[i] / scale + } + case 1: + lastexp = INDEFR + do i = 1, npix { + exp = expmap[i] + if (exp == 0.) + next + if (exp != lastexp) { + scale = sqrt (exp) + lastexp = exp + } + sigma[i] = sigma[i] * scale + } + } +end diff --git a/noao/nproto/ace/objmasks.cl b/noao/nproto/ace/objmasks.cl new file mode 100644 index 00000000..2ff5e201 --- /dev/null +++ b/noao/nproto/ace/objmasks.cl @@ -0,0 +1,28 @@ +# OBJMASK -- Make object masks from image data. + +procedure objmasks () + +begin + detect (images, objmasks=objmasks, masks=masks, omtype=omtype, + skys=skys, sigmas=sigmas, + extnames=extnames, logfiles=logfiles, blkstep=blkstep, + blksize=blksize, convolve=convolve, hsigma=hsigma, + lsigma=lsigma, hdetect=hdetect, ldetect=ldetect, + neighbors=neighbors, minpix=minpix, ngrow=ngrow, agrow=agrow, + exps=objmasks1.exps, gains=objmasks1.gains, + catalogs=objmasks1.catalogs, catdefs=objmasks1.catdefs, + dodetect=objmasks1.dodetect, dosplit=objmasks1.dosplit, + dogrow=objmasks1.dogrow, doevaluate=objmasks1.doevaluate, + skytype=objmasks1.skytype, fitstep=objmasks1.fitstep, + fitblk1d=objmasks1.fitblk1d, fithclip=objmasks1.fithclip, + fitlclip=objmasks1.fitlclip, fitxorder=objmasks1.fitxorder, + fityorder=objmasks1.fityorder, fitxterms=objmasks1.fitxterms, + blknsubblks=objmasks1.blknsubblks, + updatesky=objmasks1.updatesky, sigavg=objmasks1.sigavg, + sigmax=objmasks1.sigmax, bpval=objmasks1.bpval, + splitmax=objmasks1.splitmax, splitstep=objmasks1.splitstep, + splitthresh=objmasks1.splitthresh, sminpix=objmasks1.sminpix, + ssigavg=objmasks1.ssigavg, ssigmax=objmasks1.ssigmax, + magzero=objmasks1.magzero) + +end diff --git a/noao/nproto/ace/objmasks.par b/noao/nproto/ace/objmasks.par new file mode 100644 index 00000000..d77ceffe --- /dev/null +++ b/noao/nproto/ace/objmasks.par @@ -0,0 +1,22 @@ +# OBJMASKS + +images,f,a,,,,"List of images or MEF files" +objmasks,s,a,"",,,"List of output object masks" +omtype,s,h,"numbers","boolean|numbers|colors|all",,"Object mask type" +skys,s,h,"",,,"List of input/output sky maps" +sigmas,s,h,"",,,"List of input/output sigma maps" +masks,s,h,"!BPM",,,"List of input bad pixel masks" +extnames,s,h,"",,,"Extension names" +logfiles,s,h,"STDOUT",,,"List of log files +" +blkstep,i,h,1,1,,"Line step for sky sampling" +blksize,i,h,-10,,,"Sky block size (+=pixels, -=blocks)" +convolve,s,h,"block 3 3",,,"Convolution kernel" +hsigma,r,h,3.,.1,,"Sigma threshold above sky" +lsigma,r,h,10.,.1,,"Sigma threshold below sky" +hdetect,b,h,yes,,,"Detect objects above sky?" +ldetect,b,h,no,,,"Detect objects below sky?" +neighbors,s,h,"8","4|8",,Neighbor type" +minpix,i,h,6,1,,"Minimum number of pixels in detected objects" +ngrow,i,h,2,0,,"Number of grow rings" +agrow,r,h,2.,0,,"Area grow factor" diff --git a/noao/nproto/ace/objmasks1.par b/noao/nproto/ace/objmasks1.par new file mode 100644 index 00000000..9d822a88 --- /dev/null +++ b/noao/nproto/ace/objmasks1.par @@ -0,0 +1,30 @@ +# OBJMASKS1 + +exps,s,h,"",,,"List of exposure maps" +gains,s,h,"",,,"List of gain maps" +catalogs,s,h,"",,,"List of catalogs" +catdefs,s,h,"",,,"List of catalog definitions" +dodetect,b,h,yes,,,"Detect objects?" +dosplit,b,h,no,,,"Split merged objects?" +dogrow,b,h,yes,,,"Grow object regions?" +doevaluate,b,h,no,,,"Evaluate objects?" +skytype,s,h,"block","fit|block",,"Type of sky estimation" +fitstep,i,h,100,1,,"Line step for sky sampling" +fitblk1d,i,h,10,,,"Block average for line fitting" +fithclip,r,h,2.,,,"High sky clipping during 1D sky estimation" +fitlclip,r,h,3.,,,"Low sky clippling during 1D sky estimation" +fitxorder,i,h,2,1,,"Sky fitting x order" +fityorder,i,h,2,1,,"Sky fitting y order" +fitxterms,s,h,"half","none|full|half",,"Sky fitting cross terms" +blknsubblks,i,h,2,1,,"Number of subblocks per axis" +updatesky,b,h,yes,,,"Update sky during detection?" +sigavg,r,h,4.,0.,,"Sigma of mean flux cutoff" +sigmax,r,h,4.,0.,,"Sigma of maximum pixel" +bpval,i,h,INDEF,,,"Output bad pixel value" +splitmax,r,h,INDEF,,,"Maximum sigma above sky for splitting" +splitstep,r,h,0.4,,,"Splitting steps in convolved sigma" +splitthresh,r,h,5.,,,"Splitting threshold in sigma" +sminpix,i,h,8,1,,"Minimum number of pixels in split objects" +ssigavg,r,h,10.,0.,,"Sigma of mean flux cutoff" +ssigmax,r,h,5.,0.,,"Sigma of maximum pixel" +magzero,s,h,"INDEF",,,"Magnitude zero point" diff --git a/noao/nproto/ace/objs.h b/noao/nproto/ace/objs.h new file mode 100644 index 00000000..20dff95a --- /dev/null +++ b/noao/nproto/ace/objs.h @@ -0,0 +1,139 @@ +# This file defines the object parameters. + +# The following are the parameter ids which are the offsets into the object +# data structure. Note that the first group of parameters are those +# determined during detection for potential objects. The second group +# are parameters added after an object has been accepted. + +define ID_ROW 0 # i "" "" "Catalog row" +define ID_NUM 1 # i "" "" "Object number" +define ID_PNUM 2 # i "" "" "Parent number" +define ID_XAP 3 # r pixels %.2f "X aperture coordinate" +define ID_YAP 4 # r pixels %.2f "Y aperture coordinate" +define ID_FLUX 5 # r counts "" "Isophotal flux (I - sky)" +define ID_NPIX 6 # i pixels "" "Number of pixels" +define ID_NDETECT 7 # i pixels "" "Number of detected pixels" +define ID_ISIGAVG 8 # r sigma "" "Average (I - sky) / sig" +define ID_ISIGMAX 9 # r sigma "" "Maximum (I - sky) / sig" +define ID_ISIGAVG2 10 # r sigma "" "*Ref average (I - sky) / sig" +define ID_FLAGS 11 # 8 "" "" "Flags" + +define ID_SKY 12 # r counts "" "Mean sky" +define ID_SIG 13 # r counts "" "Sky sigma" +define ID_PEAK 14 # r counts "" "Peak pixel value above sky" +define ID_APFLUX 15 # r counts "" "Aperture fluxes" +define ID_FRACFLUX 16 # r counts "" "Apportioned flux" +define ID_FRAC 17 # r "" "" "Apportioned fraction" +define ID_XMIN 18 # i pixels "" "Minimum X" +define ID_XMAX 19 # i pixels "" "Maxium X" +define ID_YMIN 20 # i pixels "" "Minimum Y" +define ID_YMAX 21 # i pixels "" "Maxium Y" +define ID_WX 22 # d pixels %.2f "X world coordinate" +define ID_WY 24 # d pixels %.2f "Y world coordinate" +define ID_X1 26 # r pixels %.2f "X centroid" +define ID_Y1 27 # r pixels %.2f "Y centroid" +define ID_X2 28 # r pixels "" "X 2nd moment" +define ID_Y2 29 # r pixels "" "Y 2nd moment" +define ID_XY 30 # r pixels "" "X 2nd cross moment" + +define ID_FLUXVAR 31 # r counts "" "*Variance in the flux" +define ID_XVAR 32 # r pixels "" "*Variance in X centroid" +define ID_YVAR 33 # r pixels "" "*Variance in Y centroid" +define ID_XYCOV 34 # r pixels "" "*Covariance of X and Y" + +# The following are derived quantities which have ids above 1000. + +define ID_A 1001 # r pixels "" "Semimajor axis" +define ID_B 1002 # r pixels "" "Semiminor axis" +define ID_THETA 1003 # r degrees "" "Position angle" +define ID_ELONG 1004 # r "" "" "Elongation = A/B" +define ID_ELLIP 1005 # r "" "" "Ellipticity = 1 - B/A" +define ID_R 1006 # r pixels "" "Second moment radius" +define ID_CXX 1007 # r pixels "" "Second moment ellipse" +define ID_CYY 1008 # r pixels "" "Second moment ellipse" +define ID_CXY 1009 # r pixels "" "Second moment ellipse" + +define ID_FLUXERR 1011 # r counts "" "Error in flux" +define ID_XERR 1012 # r pixels "" "Error in X centroid" +define ID_YERR 1013 # r pixels "" "Error in Y centroid" +define ID_AERR 1014 # r "" "" "Error in A" +define ID_BERR 1015 # r "" "" "Error in B" +define ID_THETAERR 1016 # r degrees "" "Error in THETA" +define ID_CXXERR 1017 # r pixels "" "Error in CXX" +define ID_CYYERR 1018 # r pixels "" "Error in CYY" +define ID_CXYERR 1019 # r pixels "" "Error in CXY" + + +# Reference to elements of the object data structure may be made with +# the generic OBJ[IRDC] macros or with the individual structure macros. + +define OBJI Memi[$1+$2] # Reference integer parameter +define OBJR Memr[P2R($1+$2)] # Reference real parameter +define OBJD Memd[P2D($1+$2)] # Reference double parameter +define OBJC Memc[P2C($1+$2)] # Reference char parameter + +define OBJ_DETLEN 12 # Length for candidate objects +define OBJ_LEN 35 # Length for accepted objects + +# Detection pass parameters. +define OBJ_ROW OBJI($1,ID_ROW) # Catalog row +define OBJ_NUM OBJI($1,ID_NUM) # Object number +define OBJ_PNUM OBJI($1,ID_PNUM) # Parent object number +define OBJ_XAP OBJR($1,ID_XAP) # X aperture coordinate +define OBJ_YAP OBJR($1,ID_YAP) # Y aperture coordinate +define OBJ_NPIX OBJI($1,ID_NPIX) # Number of pixels +define OBJ_NDETECT OBJI($1,ID_NDETECT) # Number of detected pixels +define OBJ_ISIGAVG OBJR($1,ID_ISIGAVG) # Average (I - sky) / sig +define OBJ_ISIGMAX OBJR($1,ID_ISIGMAX) # Maximum (I - sky) / sig +define OBJ_ISIGAVG2 OBJR($1,ID_ISIGAVG2) # Ref average (I - sky) / sig +define OBJ_FLAGS OBJI($1,ID_FLAGS) # Flags + +define OBJ_SKY OBJR($1,ID_SKY) # Mean sky +define OBJ_SIG OBJR($1,ID_SIG) # Sky sigma +define OBJ_PEAK OBJR($1,ID_PEAK) # Peak pixel value above sky +define OBJ_FLUX OBJR($1,ID_FLUX) # Isophotal flux (I - sky) +define OBJ_APFLUX OBJI($1,ID_APFLUX) # Array of aperture fluxes (ptr) +define OBJ_FRACFLUX OBJR($1,ID_FRACFLUX) # Apportioned flux +define OBJ_FRAC OBJR($1,ID_FRAC) # Approtioned fraction +define OBJ_XMIN OBJI($1,ID_XMIN) # Minimum X +define OBJ_XMAX OBJI($1,ID_XMAX) # Maxium X +define OBJ_YMIN OBJI($1,ID_YMIN) # Minimum Y +define OBJ_YMAX OBJI($1,ID_YMAX) # Maxium Y +define OBJ_WX OBJD($1,ID_WX) # X world coordinate +define OBJ_WY OBJD($1,ID_WY) # Y world coordinate +define OBJ_X1 OBJR($1,ID_X1) # X centroid +define OBJ_Y1 OBJR($1,ID_Y1) # Y centroid +define OBJ_X2 OBJR($1,ID_X2) # X centroid +define OBJ_Y2 OBJR($1,ID_Y2) # Y centroid +define OBJ_XY OBJR($1,ID_XY) # X centroid + +define OBJ_FLUXVAR OBJR($1,ID_FLUXVAR) # Variance in flux +define OBJ_XVAR OBJR($1,ID_XVAR) # Variance in X centroid +define OBJ_YVAR OBJR($1,ID_YVAR) # Variance in Y centroid +define OBJ_XYCOV OBJR($1,ID_XYCOV) # Covariance of X and Y centroid + + + + +# Object flags. +define OBJ_EVAL 001B # Object was evaluated +define OBJ_GROW 002B # Object was grown +define OBJ_SPLIT 004B # Object was split +define OBJ_SINGLE 010B # Object was not split +define OBJ_DARK 020B # Object was below sky + +define FLAGSET (andi(OBJ_FLAGS($1),$2)!=0) +define FLAGNOTSET (andi(OBJ_FLAGS($1),$2)==0) +define SETFLAG OBJ_FLAGS($1)=ori(OBJ_FLAGS($1),$2) +define UNSETFLAG OBJ_FLAGS($1)=andi(OBJ_FLAGS($1),noti($2)) + +define DARK (andi(OBJ_FLAGS($1),OBJ_DARK)!=0) +define EVAL (andi(OBJ_FLAGS($1),OBJ_EVAL)!=0) +define SPLIT (andi(OBJ_FLAGS($1),OBJ_SPLIT)!=0) +define NOTSPLIT (andi(OBJ_FLAGS($1),OBJ_SPLIT)==0) +define SINGLE (andi(OBJ_FLAGS($1),OBJ_SINGLE)!=0) +define NOTSINGLE (andi(OBJ_FLAGS($1),OBJ_SINGLE)==0) +define GROWN (andi(OBJ_FLAGS($1),OBJ_GROW)!=0) +define NOTGROWN (andi(OBJ_FLAGS($1),OBJ_GROW)==0) + +define SZ_FLAGS 5 # Size of flag string diff --git a/noao/nproto/ace/omwrite.x b/noao/nproto/ace/omwrite.x new file mode 100644 index 00000000..83b96d2f --- /dev/null +++ b/noao/nproto/ace/omwrite.x @@ -0,0 +1,98 @@ +include <imhdr.h> +include <pmset.h> +include "ace.h" + + +procedure omwrite (pm, fname, omtype, refim, cat, catalog, objid, logfd) + +pointer pm #I Pixel mask pointer to save +char fname[ARB] #I Filename +int omtype #I Type of mask values +pointer refim #I Reference image pointer +pointer cat #I Catalog pointer +char catalog[ARB] #I Catalog filename +char objid[ARB] #I Object ID string +int logfd #I Logfile + +int i, j, k, nc, nl, stridxs(), andi() +long v[2] +pointer sp, str, im, buf, immap(), impl2i() + +errchk immap + +begin + call smark (sp) + call salloc (str, SZ_LINE, TY_CHAR) + + # Remove output only fields. + call strcpy (fname, Memc[str], SZ_LINE) + i = stridxs (",", fname) + if (i > 0) { + Memc[str+i-1] = ']' + Memc[str+i] = EOS + } + + if (logfd != NULL) { + call fprintf (logfd, " Write object mask: %s\n") + call pargstr (Memc[str]) + } + + im = immap (fname, NEW_COPY, refim) + IM_PIXTYPE(im) = TY_INT + + nc = IM_LEN(refim,1) + nl = IM_LEN(refim,2) + + v[1] = 1 + switch (omtype) { + case OM_BOOL: + do i = 1, nl { + v[2] = i + buf = impl2i (im, i) + call pmglpi (pm, v, Memi[buf], 0, nc, PIX_SRC) + call aminki (Memi[buf], 1, Memi[buf], nc) + } + case OM_ONUM: + do i = 1, nl { + v[2] = i + buf = impl2i (im, i) + call pmglpi (pm, v, Memi[buf], 0, nc, PIX_SRC) + do j = buf, buf+nc-1 + Memi[j] = MNUM(Memi[j]) + } + case OM_COLORS: + do i = 1, nl { + v[2] = i + buf = impl2i (im, i) + call pmglpi (pm, v, Memi[buf], 0, nc, PIX_SRC) + do j = buf, buf+nc-1 { + k = MNUM(Memi[j]) + if (k > 0) { + if (k < NUMSTART) + k = 1 + else + k = mod (k, 8) + 2 + } + Memi[j] = k + } + } + default: + do i = 1, nl { + v[2] = i + call pmglpi (pm, v, Memi[impl2i(im,i)], 0, nc, PIX_SRC) + } + } + + iferr (call imdelf (im, "DATASEC")) + ; + iferr (call imdelf (im, "TRIMSEC")) + ; + if (catalog[1] != EOS) + call imastr (im, "CATALOG", catalog) + if (objid[1] != EOS) + call imastr (im, "OBJID", objid) + + call imastr (refim, "OBJMASK", Memc[str]) + + call imunmap (im) +end diff --git a/noao/nproto/ace/overlay.par b/noao/nproto/ace/overlay.par new file mode 100644 index 00000000..a5fad3f5 --- /dev/null +++ b/noao/nproto/ace/overlay.par @@ -0,0 +1,30 @@ +# Parameter file for DISPLAY + +image,f,a,,,,image to be displayed +frame,i,a,1,1,4,frame to be written into +bpmask,f,h,"",,,bad pixel mask +bpdisplay,s,h,"none","none|overlay|interpolate",,bad pixel display (none|overlay|interpolate) +bpcolors,s,h,"red",,,bad pixel colors +overlay,f,h,"!objmask",,,overlay mask +ocolors,s,h,"1=red,green",,,overlay colors +erase,b,h,yes,,,erase frame +border_erase,b,h,no,,,erase unfilled area of window +select_frame,b,h,yes,,,display frame being loaded +repeat,b,h,no,,,repeat previous display parameters +fill,b,h,no,,,scale image to fit display window +zscale,b,h,yes,,,display range of greylevels near median +contrast,r,h,0.25,,,contrast adjustment for zscale algorithm +zrange,b,h,yes,,,display full image intensity range +zmask,f,h,"",,,sample mask +nsample,i,h,1000,100,,maximum number of sample pixels to use +xcenter,r,h,0.5,0,1,display window horizontal center +ycenter,r,h,0.5,0,1,display window vertical center +xsize,r,h,1,0,1,display window horizontal size +ysize,r,h,1,0,1,display window vertical size +xmag,r,h,1.,,,display window horizontal magnification +ymag,r,h,1.,,,display window vertical magnification +order,i,h,0,0,1,"spatial interpolator order (0=replicate, 1=linear)" +z1,r,h,,,,minimum greylevel to be displayed +z2,r,h,,,,maximum greylevel to be displayed +ztrans,s,h,linear,,,greylevel transformation (linear|log|none|user) +lutfile,f,h,"",,,file containing user defined look up table diff --git a/noao/nproto/ace/pars.x b/noao/nproto/ace/pars.x new file mode 100644 index 00000000..516a8b7d --- /dev/null +++ b/noao/nproto/ace/pars.x @@ -0,0 +1,375 @@ +include <ctype.h> +include <math/curfit.h> +include <math/gsurfit.h> +include "sky.h" +include "skyfit.h" +include "skyblock.h" +include "detect.h" +include "split.h" +include "grow.h" +include "evaluate.h" + + + +# SKY_PARS -- Sky parameters. + +procedure sky_pars (option, pset, pars) + +char option[ARB] #I Option +char pset[ARB] #I Pset +pointer pars #U Parameter structure + +pointer pp + +int strdic() +pointer clopset() + +errchk calloc + +begin + switch (option[1]) { + case 'o': + if (pars != NULL) + return + call calloc (pars, SKY_LEN, TY_STRUCT) + + pp = clopset (pset) + call clgpseta (pp, "skytype", SKY_STR(pars), SKY_STRLEN) + SKY_TYPE(pars) = strdic (SKY_STR(pars), SKY_STR(pars), SKY_STRLEN, + SKY_TYPES) + call clcpset (pp) + case 'c': + if (pars != NULL) { + call skf_pars ("close", "", SKY_SKF(pars)) + call skb_pars ("close", "", SKY_SKB(pars)) + } + call mfree (pars, TY_STRUCT) + } +end + + +# SKF_PARS -- Sky fit parameters. + +procedure skf_pars (option, pset, pars) + +char option[ARB] #I Option +char pset[ARB] #I Pset +pointer pars #U Parameter structure + +pointer pp + +int clgpseti(), strdic() +real clgpsetr() +pointer clopset() + +errchk calloc + +begin + switch (option[1]) { + case 'o': + if (pars != NULL) + return + call calloc (pars, SKF_LEN, TY_STRUCT) + + pp = clopset (pset) + + SKF_STEP(pars) = clgpsetr (pp, "fitstep") + SKF_BLK1D(pars) = clgpseti (pp, "fitblk1d") + SKF_HCLIP(pars) = clgpsetr (pp, "fithclip") + SKF_LCLIP(pars) = clgpsetr (pp, "fitlclip") + SKF_XORDER(pars) = clgpseti (pp, "fitxorder") + SKF_YORDER(pars) = clgpseti (pp, "fityorder") + + SKF_LMIN(pars) = SKFLMIN + SKF_FUNC1D(pars) = strdic (SKFFUNC1D, SKF_STR(pars), + SKF_STRLEN, CV_FUNCTIONS) + SKF_FUNC2D(pars) = strdic (SKFFUNC2D, SKF_STR(pars), + SKF_STRLEN, GS_FUNCTIONS) + SKF_XTERMS(pars) = strdic (SKFXTERMS, SKF_STR(pars), + SKF_STRLEN, GS_XTYPES) - 1 + SKF_NITER(pars) = SKFNITER + + call clcpset (pp) + case 'c': + call mfree (pars, TY_STRUCT) + } +end + + +# SKB_PARS -- Sky block parameters. + +procedure skb_pars (option, pset, pars) + +char option[ARB] #I Option +char pset[ARB] #I Pset +pointer pars #U Parameter structure + +pointer pp, cp +double x, y, sum1, sum2 + +int clgpseti() +pointer clopset() + +errchk calloc + +begin + switch (option[1]) { + case 'o': + if (pars != NULL) + return + + call calloc (pars, SKB_LEN, TY_STRUCT) + + pp = clopset (pset) + SKB_BLKSTEP(pars) = clgpseti (pp, "blkstep") + SKB_BLKSIZE(pars) = clgpseti (pp, "blksize") + SKB_NSUBBLKS(pars) = max (1, clgpseti (pp, "blknsubblks")) + + call strcpy (SKBCNV, Memc[SKB_CNV(pars)], SKB_STRLEN) + SKB_SKYMIN(pars) = SKBSKYMIN + SKB_FRAC(pars) = SKBFRAC + SKB_GROW(pars) = SKBGROW + SKB_SIGBIN(pars) = SKBSIGBIN + SKB_NMINPIX(pars) = SKBNMINPIX + SKB_NMINBINS(pars) = SKBNMINBINS + SKB_HISTWT(pars) = SKBHISTWT + #SKB_HISTWT(pars) = 1 + SKB_A(pars) = 1. / SKBA + #SKB_A(pars) = 1. / .05 + SKB_NBINS(pars) = nint (2 * SKB_SIGBIN(pars) * SKB_A(pars)) + SKB_NBINS(pars) = SKB_NBINS(pars) + mod (SKB_NBINS(pars)+1, 2) + SKB_B(pars) = SKB_NBINS(pars) / 2. + 1 + + for (cp=SKB_CNV(pars); IS_WHITE(Memc[cp]); cp=cp+1) + ; + call strcpy (Memc[cp], Memc[SKB_CNV(pars)], SKB_STRLEN) + + # Compute sigma correction factor from mean absolute deviation. + sum1 = 0. + sum2 = 0. + for (x=-SKB_SIGBIN(pars); x<=SKB_SIGBIN(pars); x=x+0.01) { + y = exp (-x*x/2.) + sum1 = sum1 + abs(x)*y + sum2 = sum2 + y + } + SKB_SIGFAC(pars) = sum2 / sum1 + + call clcpset (pp) + case 'c': + call mfree (pars, TY_STRUCT) + } +end + + +# DET_PARS -- Detect parameters. + +procedure det_pars (option, pset, pars) + +char option[ARB] #I Option +char pset[ARB] #I Pset +pointer pars #U Parameter structure + +pointer pp + +int i, j +pointer cp, ptr +bool clgpsetb() +int clgpseti(), btoi() +real clgpsetr() +pointer clopset() + +errchk calloc + +begin + switch (option[1]) { + case 'o': + if (pars != NULL) + return + call calloc (pars, DET_LEN, TY_STRUCT) + + pp = clopset (pset) + + call clgpseta (pp, "convolve", Memc[DET_CNV(pars)], DET_STRLEN) + DET_HSIG(pars) = clgpsetr (pp, "hsigma") + DET_LSIG(pars) = clgpsetr (pp, "lsigma") + DET_HDETECT(pars) = btoi (clgpsetb (pp, "hdetect")) + DET_LDETECT(pars) = btoi (clgpsetb (pp, "ldetect")) + DET_NEIGHBORS(pars) = clgpseti (pp, "neighbors") + DET_MINPIX(pars) = clgpseti (pp, "minpix") + DET_SIGAVG(pars) = clgpsetr (pp, "sigavg") + DET_SIGPEAK(pars) = clgpsetr (pp, "sigmax") + DET_BPVAL(pars) = clgpseti (pp, "bpval") + if (clgpsetb (pp, "updatesky")) + call skb_pars ("open", pset, DET_SKB(pars)) + + # Check convolution kernel. + for (cp=DET_CNV(pars); IS_WHITE(Memc[cp]); cp=cp+1) + ; + call strcpy (Memc[cp], Memc[DET_CNV(pars)], DET_STRLEN) + if (Memc[DET_CNV(pars)] != EOS) { + call cnvparse (Memc[DET_CNV(pars)], ptr, i, j, NULL) + call mfree (ptr, TY_REAL) + if (i == 1 && j == 1) + Memc[DET_CNV(pars)] = EOS + } + + call clcpset (pp) + case 'd': + if (pars != NULL) + return + call calloc (pars, DET_LEN, TY_STRUCT) + + pp = clopset (pset) + + call clgpseta (pp, "convolve", Memc[DET_CNV(pars)], DET_STRLEN) + DET_HSIG(pars) = clgpsetr (pp, "hsigma") + DET_LSIG(pars) = clgpsetr (pp, "lsigma") + DET_HDETECT(pars) = btoi (clgpsetb (pp, "hdetect")) + DET_LDETECT(pars) = btoi (clgpsetb (pp, "ldetect")) + DET_NEIGHBORS(pars) = clgpseti (pp, "neighbors") + DET_MINPIX(pars) = clgpseti (pp, "minpix") + DET_SIGAVG(pars) = clgpsetr (pp, "sigavg") + DET_SIGPEAK(pars) = clgpsetr (pp, "sigmax") + DET_BPVAL(pars) = clgpseti (pp, "bpval") + if (clgpsetb (pp, "updatesky")) + call skb_pars ("open", pset, DET_SKB(pars)) + + # Check convolution kernel. + for (cp=DET_CNV(pars); IS_WHITE(Memc[cp]); cp=cp+1) + ; + call strcpy (Memc[cp], Memc[DET_CNV(pars)], DET_STRLEN) + if (Memc[DET_CNV(pars)] != EOS) { + call cnvparse (Memc[DET_CNV(pars)], ptr, i, j, NULL) + call mfree (ptr, TY_REAL) + if (i == 1 && j == 1) + Memc[DET_CNV(pars)] = EOS + } + + # The following are unique to diffdetect. + DET_FRAC2(pars) = clgpsetr (pp, "rfrac") + + call clcpset (pp) + case 'c': + if (pars != NULL) + call skb_pars ("close", "", DET_SKB(pars)) + call mfree (pars, TY_STRUCT) + } + +end + + +# SPT_PARS -- Split parameters. + +procedure spt_pars (option, pset, pars) + +char option[ARB] #I Option +char pset[ARB] #I Pset +pointer pars #U Parameter structure + +pointer pp + +int clgpseti() +real clgpsetr() +pointer clopset() + +errchk calloc + +begin + switch (option[1]) { + case 'o': + if (pars != NULL) + return + call calloc (pars, SPT_LEN, TY_STRUCT) + + pp = clopset (pset) + + SPT_NEIGHBORS(pars) = clgpseti (pp, "neighbors") + SPT_SPLITMAX(pars) = clgpsetr (pp, "splitmax") + SPT_SPLITSTEP(pars) = clgpsetr (pp, "splitstep") + SPT_SPLITTHRESH(pars) = clgpsetr (pp, "splitthresh") + SPT_MINPIX(pars) = clgpseti (pp, "minpix") + SPT_SIGAVG(pars) = clgpsetr (pp, "sigavg") + SPT_SIGPEAK(pars) = clgpsetr (pp, "sigmax") + SPT_SMINPIX(pars) = clgpseti (pp, "sminpix") + SPT_SSIGAVG(pars) = clgpsetr (pp, "ssigavg") + SPT_SSIGPEAK(pars) = clgpsetr (pp, "ssigmax") + + call clcpset (pp) + case 'c': + call mfree (pars, TY_STRUCT) + } + +end + + +# GRW_PARS -- Grow parameters. + +procedure grw_pars (option, pset, pars) + +char option[ARB] #I Option +char pset[ARB] #I Pset +pointer pars #U Parameter structure + +pointer pp + +int clgpseti() +real clgpsetr() +pointer clopset() + +errchk calloc + +begin + switch (option[1]) { + case 'o': + if (pars != NULL) + return + call calloc (pars, GRW_LEN, TY_STRUCT) + + pp = clopset (pset) + GRW_NGROW(pars) = clgpseti (pp, "ngrow") + GRW_AGROW(pars) = clgpsetr (pp, "agrow") + call clcpset (pp) + case 'c': + call mfree (pars, TY_STRUCT) + } + +end + + +# EVL_PARS -- Evaluate parameters. + +procedure evl_pars (option, pset, pars) + +char option[ARB] #I Option +char pset[ARB] #I Pset +pointer pars #U Parameter structure + +int i, nowhite(), ctor() +real magzero +pointer pp + +pointer clopset() + +errchk calloc + +begin + switch (option[1]) { + case 'o': + if (pars != NULL) + return + call calloc (pars, EVL_LEN, TY_STRUCT) + + pp = clopset (pset) + call clgpseta (pp, "magzero", EVL_MAGZERO(pars,1), EVL_STRLEN) + if (nowhite(EVL_MAGZERO(pars,1),EVL_MAGZERO(pars,1),EVL_STRLEN)==0) + call strcpy ("INDEF", EVL_MAGZERO(pars,1), EVL_STRLEN) + if (EVL_MAGZERO(pars,1) != '!') { + i = 1 + if (ctor (EVL_MAGZERO(pars,1), i, magzero) == 0) + call error (1, "Magnitude zero point parameter syntax") + } + call clcpset (pp) + case 'c': + call mfree (pars, TY_STRUCT) + } +end diff --git a/noao/nproto/ace/reviewproto.cl b/noao/nproto/ace/reviewproto.cl new file mode 100644 index 00000000..2af722de --- /dev/null +++ b/noao/nproto/ace/reviewproto.cl @@ -0,0 +1,215 @@ +# REVIEWPROTO + +procedure reviewproto (catalog) + +string catalog {prompt="Catalog"} +bool nooverlay = yes {prompt="Display image without overlays"} +bool overlay = yes {prompt="Display image with overlays"} +bool comparison = yes {prompt="Display comparison image"} +file compimage = "" {prompt="Comparison image"} +int box = 200 {prompt="Box size (pixels)"} +string ocolors = "green" {prompt="Object mask color"} +string lcolor = "red" {prompt="Label color"} + +struct *fd + +begin + file cat, im, mask, coords, compim, temp + int naxis1, naxis2, icolor, frame, nframe, x1, x2, y1, y2 + real r, d, x, y, xt, yt + bool pause + string key, imsec + struct title + + coords = mktemp ("tmp$iraf") + temp = mktemp ("tmp$iraf") + + # Get query parameters. + cat = catalog + + # Get header and coordinates. + tdump (cat, cdfile="", pfile=temp, datafile=coords, + columns="ra,dec", rows="", pwidth=80) + match ("IMAGE", temp, stop-) | scan (im, im, im) + match ("MASK", temp, stop-) | scan (mask, mask, mask) + delete (temp, verify-) + + # Set image size. + sections (im, option="root") | scan (im) + hselect (im, "naxis1,naxis2", yes) | scan (naxis1, naxis2) + + # Set comparison. + sections (compimage, option="root") | scan (compim) + + # Translate color specification. + match (lcolor, "ace$colors.dat", stop-) | scan (lcolor, icolor) + if (nscan() != 2) + icolor = 200 + + # Number of frames. + nframe = 0 + if (nooverlay) + nframe = nframe + 1 + if (overlay) + nframe = nframe + 1 + if (comparison && compim != "") + nframe = nframe + 1 + + # Loop through the list of catalog coordinates. + pause = NO + fd = coords + while (fscan (fd, r, d) != EOF) { + if (nscan() < 2) + next + if (r == INDEF ||d == INDEF) + next + + # Pause with cursor read if there is more than one coordinate. + if (pause) { + printf ("q to quit any other key to continue...\n") + if (fscan (imcur, x, y, i, key) == EOF) + break + if (key == 'q') + break + pause = NO + } + + # Display. + frame = nframe + + if (comparison && compim != "") { + # Convert world coordinate to image section. + print (r, d) | wcsctran ("STDIN", "STDOUT", compim, "world", + "logical", columns="1 2", units="native native", + formats="", min_sigdigit=9, verbose=no) | scan (x, y) + x = nint (x); y = nint (y) + x1 = max (1, nint (x-box/2.)) + x2 = min (naxis1, nint (x+box/2.)) + y1 = max (1, nint (y-box/2.)) + y2 = min (naxis2, nint (y+box/2.)) + if (x2 > x1 && y2 > y1) { + # Display section. + printf ("%s[%d:%d,%d:%d]\n", compim, x1, x2, y1, y2) | + scan (imsec) + acedisplay (imsec, frame, bpmask="", bpdisplay="none", + bpcolors="red", overlay="", ocolors=ocolors, + erase=yes, border_erase=no, select_frame=yes, + repeat=no, fill=no, zscale=yes, contrast=0.25, + zrange=yes, zmask="", nsample=1000, xcenter=0.5, + ycenter=0.5, xsize=1., ysize=1., xmag=2., ymag=2., + order=0, z1=0., z2=0., ztrans="linear", lutfile="", + >> "dev$null") + + # Mark. + printf ("%g %g\n", x, y, >> temp) + tvmark (frame, temp, logfile="", autolog=no, + outimage="", deletions="", commands="", + mark="circle", radii="10", lengths="0", + font="raster", color=icolor, label=no, + number=no, nxoffset=0, nyoffset=0, pointsize=1, + txsize=1, tolerance=1.5, interactive=no) + delete (temp, verify-) + + # Label. + xt = x1 + 10 + yt = y2 + 10 + printf ("%g %g '%.2H %.1h'\n", xt, yt, r, d, >> temp) + tvmark (frame, temp, logfile="", autolog=no, + outimage="", deletions="", commands="", + mark="none", radii="0", lengths="0", + font="raster", color=icolor, label=yes, + number=no, nxoffset=0, nyoffset=0, pointsize=1, + txsize=2, tolerance=1.5, interactive=no) + delete (temp, verify-) + } + frame = frame - 1 + } + + # Convert world coordinate to image section. + print (r, d) | wcsctran ("STDIN", "STDOUT", im, "world", + "logical", columns="1 2", units="native native", + formats="", min_sigdigit=9, verbose=no) | scan (x, y) + x = nint (x); y = nint (y) + x1 = max (1, nint (x-box/2.)) + x2 = min (naxis1, nint (x+box/2.)) + y1 = max (1, nint (y-box/2.)) + y2 = min (naxis2, nint (y+box/2.)) + if (x2 <= x1 || y2 <= y1) + next + + # Display. + if (overlay) { + printf ("%s[%d:%d,%d:%d]\n", im, x1, x2, y1, y2) | scan (imsec) + acedisplay (imsec, frame, bpmask="", bpdisplay="none", + bpcolors="red", overlay=mask, ocolors=ocolors, + erase=yes, border_erase=no, select_frame=yes, + repeat=no, fill=no, zscale=yes, contrast=0.25, + zrange=yes, zmask="", nsample=1000, xcenter=0.5, + ycenter=0.5, xsize=1., ysize=1., xmag=2., ymag=2., + order=0, z1=0., z2=0., ztrans="linear", lutfile="", + >> "dev$null") + + # Mark + printf ("%g %g\n", x, y, >> temp) + tvmark (frame, temp, logfile="", autolog=no, + outimage="", deletions="", commands="", + mark="circle", radii="10", lengths="0", + font="raster", color=icolor, label=no, + number=no, nxoffset=0, nyoffset=0, pointsize=1, + txsize=1, tolerance=1.5, interactive=no) + delete (temp, verify-) + + xt = x1 + 10 + yt = y2 + 10 + printf ("%g %g '%.2H %.1h'\n", xt, yt, r, d, >> temp) + tvmark (frame, temp, logfile="", autolog=no, + outimage="", deletions="", commands="", + mark="none", radii="0", lengths="0", + font="raster", color=icolor, label=yes, + number=no, nxoffset=0, nyoffset=0, pointsize=1, + txsize=2, tolerance=1.5, interactive=no) + delete (temp, verify-) + + frame = frame - 1 + } + + # Display. + if (nooverlay) { + printf ("%s[%d:%d,%d:%d]\n", im, x1, x2, y1, y2) | scan (imsec) + acedisplay (imsec, frame, bpmask="", bpdisplay="none", + bpcolors="red", overlay="", ocolors=ocolors, + erase=yes, border_erase=no, select_frame=yes, + repeat=no, fill=no, zscale=yes, contrast=0.25, + zrange=yes, zmask="", nsample=1000, xcenter=0.5, + ycenter=0.5, xsize=1., ysize=1., xmag=2., ymag=2., + order=0, z1=0., z2=0., ztrans="linear", lutfile="", + >> "dev$null") + + # Mark + printf ("%g %g\n", x, y, >> temp) + tvmark (frame, temp, logfile="", autolog=no, + outimage="", deletions="", commands="", + mark="circle", radii="10", lengths="0", + font="raster", color=icolor, label=no, + number=no, nxoffset=0, nyoffset=0, pointsize=1, + txsize=1, tolerance=1.5, interactive=no) + delete (temp, verify-) + + xt = x1 + 10 + yt = y2 + 10 + printf ("%g %g '%.2H %.1h'\n", xt, yt, r, d, >> temp) + tvmark (frame, temp, logfile="", autolog=no, + outimage="", deletions="", commands="", + mark="none", radii="0", lengths="0", + font="raster", color=icolor, label=yes, + number=no, nxoffset=0, nyoffset=0, pointsize=1, + txsize=2, tolerance=1.5, interactive=no) + delete (temp, verify-) + + frame = frame - 1 + } + + pause = YES + } + fd = ""; delete (coords, verify-) +end diff --git a/noao/nproto/ace/sky.h b/noao/nproto/ace/sky.h new file mode 100644 index 00000000..4aca7214 --- /dev/null +++ b/noao/nproto/ace/sky.h @@ -0,0 +1,14 @@ +# Grow parameter structure + +define SKY_LEN 8 # Length of parameter structure +define SKY_STRLEN 9 # Length of string + +define SKY_TYPE Memi[$1] # Type of sky +define SKY_SKF Memi[$1+1] # Sky fit parameters +define SKY_SKB Memi[$1+2] # Sky block parameters +define SKY_STR Memc[P2C($1+3)] # String + + +define SKY_TYPES "|fit|block|" +define SKY_FIT 1 # Sky fitting algorithm +define SKY_BLOCK 2 # Sky block algorithm diff --git a/noao/nproto/ace/sky.x b/noao/nproto/ace/sky.x new file mode 100644 index 00000000..c713a437 --- /dev/null +++ b/noao/nproto/ace/sky.x @@ -0,0 +1,118 @@ +include <error.h> +include "sky.h" + + +# SKY -- Determine sky and sky sigma in an image. +# +# Get the sky and sigma map pointers. This is layered on the MAPIO routines +# and lower level sky algorithms. The sky parameter structure will be +# allocated if needed and must be freed by the calling program. +# +# If they are not defined compute an initial +# sky and/or sky sigma surface fit using a subset of the input lines. +# Whether the sky and/or the sigma are fit is determined by whether the input +# sky and sky sigma pointers are NULL. The initial data for the surface fit +# is measured at a subset of lines with any masked pixels excluded. Objects +# are removed by fitting a 1D curve to each line, rejection points with large +# residuals and iterating until only sky is left. The sky points are then +# accumulated for a 2D surface fit and the residuals are added to a +# histogram. The absolute deviations, scaled by 0.7979 to convert to an +# gausian sigma, are accumulated for a sky sigma surface fit. After all the +# sample lines are accumulated the surface fits are computed. The histogram +# of residuals is then fit by a gaussian to estimate an offset from the sky +# fit to the sky mode caused by unrejected object light. The offset is +# applied to the sky surface. + +procedure sky (par, im, bpm, expmap, skyname, signame, skymap, sigmap, + dosky, dosig, logfd) + +pointer par #I Parameters +pointer im #I Input image +pointer bpm #I Input mask +pointer expmap #I Exposure map +char skyname[ARB] #I Sky map name +char signame[ARB] #I Sigma map name +pointer skymap #O Sky map +pointer sigmap #O Sigma map +bool dosky #O Sky computed? +bool dosig #O Sigma computed? +int logfd #I Verbose? + +real rval +pointer sp, namesky, namesig + +int errcode() +pointer map_open() +errchk map_open, sky_fit, sky_block + +begin + call smark (sp) + call salloc (namesky, SZ_FNAME, TY_CHAR) + call salloc (namesig, SZ_FNAME, TY_CHAR) + + if (logfd != NULL) + call fprintf (logfd, " Set sky and sigma:\n") + + # Check whether to compute a sky. + skymap = NULL + if (skyname[1] != EOS) { + iferr (skymap = map_open (skyname, im)) { + skymap = NULL + if (errcode() != 2) + call erract (EA_ERROR) + } + if (logfd != NULL && skymap != NULL) { + ifnoerr (call map_getr (skymap, "constant", rval)) { + call fprintf (logfd, " Use constant input sky: %g\n") + call pargr (rval) + } else { + call fprintf (logfd, " Use input sky: %s\n") + call pargstr (skyname) + } + } + } + dosky = (skymap == NULL) + + # Check whether to compute a sky sigma. + sigmap = NULL + if (signame[1] != EOS) { + iferr (sigmap = map_open (signame, im)) { + sigmap = NULL + if (errcode() != 2) + call erract (EA_ERROR) + } + if (logfd != NULL && sigmap != NULL) { + ifnoerr (call map_getr (sigmap, "constant", rval)) { + call fprintf (logfd, " Use constant input sigma: %g\n") + call pargr (rval) + } else { + call fprintf (logfd, " Use input sigma: %s\n") + call pargstr (signame) + } + } + } + dosig = (sigmap == NULL) + + # Compute the sky. + if (dosky || dosig) { + # Set parameters. + call sky_pars ("open", "", par) + + switch (SKY_TYPE(par)) { + case SKY_FIT: + call sky_fit (SKY_SKF(par), dosky, dosig, im, bpm, expmap, + skyname, signame, skymap, sigmap, logfd) + case SKY_BLOCK: + call sky_fit (SKY_SKF(par), dosky, dosig, im, bpm, expmap, + "", "", skymap, sigmap, logfd) + call map_seti (skymap, "sample", 5) + call map_seti (sigmap, "sample", 5) + call sky_block (SKY_SKB(par), dosky, dosig, im, bpm, expmap, + skyname, signame, skymap, sigmap, logfd) + default: + call error (1, "Unknown sky type") + } + } + + call sfree (sp) +end diff --git a/noao/nproto/ace/skyblock.h b/noao/nproto/ace/skyblock.h new file mode 100644 index 00000000..40f5758d --- /dev/null +++ b/noao/nproto/ace/skyblock.h @@ -0,0 +1,50 @@ +# Definitions for SKYBLOCK algorithm. + +define SKBSKYMIN 10000 # Minimum number of sky pixels in subblock +define SKBFRAC 0.66 # Frac of sky pix in subblock for sky estimate +define SKBGROW 1.5 # Grow for rejected subblocks +define SKBSIGBIN 2.5 # Sigma width of histogram +define SKBA 0.01 # Histogram resolution +define SKBNMINPIX 50 # Minimum number of pixels/subblock/side +define SKBNMINBINS 500 # Minimum average bin population +define SKBHISTWT 2 # Default histogram weighting power +define SKBCNV "" # Convolution + +define SKB_STRLEN 99 # String length in parameters +define SKB_LEN 82 # Sky block structure length + +# The following apply to all images. +define SKB_BLKSTEP Memi[$1] # Step size +define SKB_BLKSIZE Memi[$1+1] # Number of pixels or blocks +define SKB_NSUBBLKS Memi[$1+2] # Number of subblocks per block +define SKB_SKYMIN Memi[$1+3] # Minimum number of sky pixels +define SKB_NMINPIX Memi[$1+4] # Min pixels/subblock/side +define SKB_SIGBIN Memr[P2R($1+5)] # Histogram sigma limit +define SKB_A Memr[P2R($1+6)] # Histogram resolution +define SKB_B Memr[P2R($1+7)] # Bin start +define SKB_NBINS Memi[$1+8] # Number of bins +define SKB_NMINBINS Memi[$1+9] # Min avg bin population +define SKB_HISTWT Memi[$1+10] # Histogram weighting power +define SKB_SIGFAC Memr[P2R($1+11)] # Sigma correction factor +define SKB_FRAC Memr[P2R($1+12)] # Frac of sky pix in subblock +define SKB_GROW Memr[P2R($1+13)] # Grow for rejected subblocks +define SKB_CNV P2C($1+14) # Pointer to convolution string (99) + +# The following are set for each image. +define SKB_NCBLK Memi[$1+65] # Number of blocks across image +define SKB_NLBLK Memi[$1+66] # Number of blocks across image +define SKB_NCPIX Memi[$1+67] # Number of pixels in blocks +define SKB_NLPIX Memi[$1+68] # Number of pixels in blocks +define SKB_NCSBLK Memi[$1+69] # Number of subblocks across image +define SKB_NLSBLK Memi[$1+70] # Number of subblocks across image +define SKB_NCSPIX Memi[$1+71] # Number of pixels in subblocks +define SKB_NLSPIX Memi[$1+72] # Number of pixels in subblocks +define SKB_NSKYMIN Memi[$1+73] # Minimum pixels to evaluate histogram +define SKB_BINS Memi[$1+74] # Pointer to bins +define SKB_NAV Memi[$1+75] # Number of bins to average for weights +define SKB_NSKY Memi[$1+76] # Pointer to num sky pix +define SKB_EXP Memi[$1+77] # Pointer to exposure values +define SKB_SKYS Memi[$1+78] # Pointer to sky block values +define SKB_SIGS Memi[$1+79] # Pointer to sigma block values +define SKB_SKY Memi[$1+80] # Pointer to current sky block line +define SKB_SIG Memi[$1+81] # Pointer to current sigma block line diff --git a/noao/nproto/ace/skyblock.x b/noao/nproto/ace/skyblock.x new file mode 100644 index 00000000..5e3eb5f9 --- /dev/null +++ b/noao/nproto/ace/skyblock.x @@ -0,0 +1,1039 @@ +include <error.h> +include <ctype.h> +include <imhdr.h> +include <imset.h> +include <mach.h> +include "skyblock.h" + + +# SKY_BLOCK - Determine sky and sky sigma in blocks. +# +# This is layered on MAPIO and CONVOLVE. + +procedure sky_block (skb, dosky, dosig, in, bpm, expmap, skyname, signame, + skymap, sigmap, logfd) + +pointer skb #U Sky block structure +bool dosky #I Compute sky +bool dosig #I Compute sigma +pointer in #I Input image pointer +pointer bpm #I Input mask +pointer expmap #I Exposure map +char skyname[ARB] #I Sky map name (if none then no output) +char signame[ARB] #I Sigma map name (if none then no output) +pointer skymap #U Sky map +pointer sigmap #U Sigma map +int logfd #I Verbose? + +int l, blkstep, nc, nl +real cnvwt +pointer sp, cnv, cnvdata, bp +pointer im[2], indata, skydata, sigdata, expdata +errchk skb_pars, skb_iminit, convolve, skb_accum, skb_update + +begin + if (!(dosky||dosig)) + return + + call smark (sp) + + # Log operation. + if (logfd != NULL) { + if (dosky && dosig) + call fprintf (logfd, + " Determine sky and sigma by block statistics:\n") + else if (dosky) + call fprintf (logfd, " Determine sky by block statistics:\n") + else + call fprintf (logfd, + " Determine sigma by block statistics:\n") + } + + # Set parameters if not set in a previous call or set externally. + if (skb == NULL) + call skb_pars ("open", "", skb) + + # Set parameters for the image. + blkstep = SKB_BLKSTEP(skb) + call skb_iminit (skb, in, expmap, blkstep, logfd) + + # Set maximum number of image columns and lines to use. + nc = SKB_NCSBLK(skb) * SKB_NCSPIX(skb) + nl = SKB_NLSBLK(skb) * SKB_NLSPIX(skb) + + # Set up convolution. Note we can't use convolution with a blkstep. + cnv = SKB_CNV(skb) + if (Memc[cnv] != EOS) { + if (blkstep > 1) { + call salloc (cnv, 1, TY_CHAR) + Memc[cnv] = EOS + } else + call salloc (cnvdata, nc, TY_REAL) + } + + # Setup bad pixel mask. + if (bpm == NULL) { + call salloc (bp, nc, TY_INT) + call aclri (Memi[bp], nc) + } + + # Go through image creating low resolution sky blocks. + im[1] = in; im[2] = NULL + do l = 1, nl, blkstep { + call convolve (im, bpm, skymap, sigmap, expmap, 0, + 1., l, Memc[cnv], indata, bp, cnvdata, skydata, + sigdata, expdata, cnvwt, logfd) + call skb_accum (skb, l, blkstep, Memr[cnvdata], Memr[skydata], + Memr[sigdata], Memr[expdata], Memi[bp], nc, cnvwt) + } + + # Free convolution memory. + call convolve (im, bpm, skymap, sigmap, expmap, 0, + 1., 0, Memc[cnv], indata, bp, cnvdata, skydata, + sigdata, expdata, cnvwt, logfd) + + # Turn the sky blocks into sky maps. + call skb_update (skb, dosky, dosig, in, skyname, signame, + skymap, sigmap, logfd) + + # Free memory. + call skb_imfree (skb) + call sfree (sp) +end + + +# SKB_IMINIT -- Initialize parameters and allocate memory for an image. + +procedure skb_iminit (skb, im, expmap, blkstep, logfd) + +pointer skb #U Sky block structure +pointer im #I Image pointer +pointer expmap #I Exposure map pointer +int blkstep #U Line step for speed +int logfd #I Log file descriptor + +int nc, nl + +begin + # Number of pixels per subblock. + nc = IM_LEN(im,1) + nl = IM_LEN(im,2) + if (SKB_BLKSIZE(skb) < 0) { + if (nc < nl) { + SKB_NCSPIX(skb) = max (SKB_NMINPIX(skb), + nc / (SKB_NSUBBLKS(skb) * max(1,-SKB_BLKSIZE(skb)))) + SKB_NLSPIX(skb) = SKB_NCSPIX(skb) + } else { + SKB_NLSPIX(skb) = max (SKB_NMINPIX(skb), + nl / (SKB_NSUBBLKS(skb) * max(1,-SKB_BLKSIZE(skb)))) + SKB_NCSPIX(skb) = SKB_NLSPIX(skb) + } + } else { + SKB_NCSPIX(skb) = max (SKB_NMINPIX(skb), + min (nc, SKB_BLKSIZE(skb)) / SKB_NSUBBLKS(skb)) + SKB_NLSPIX(skb) = max (SKB_NMINPIX(skb), + min (nl, SKB_BLKSIZE(skb)) / SKB_NSUBBLKS(skb)) + } + + # Number of subblocks, blocks, and number of pixels per block. + SKB_NCSBLK(skb) = max (1, nc / SKB_NCSPIX(skb)) + SKB_NLSBLK(skb) = max (1, nl / SKB_NLSPIX(skb)) + SKB_NCBLK(skb) = (SKB_NCSBLK(skb)+SKB_NSUBBLKS(skb)-1)/SKB_NSUBBLKS(skb) + SKB_NLBLK(skb) = (SKB_NLSBLK(skb)+SKB_NSUBBLKS(skb)-1)/SKB_NSUBBLKS(skb) + SKB_NCPIX(skb) = SKB_NCSPIX(skb) * SKB_NSUBBLKS(skb) + SKB_NLPIX(skb) = SKB_NLSPIX(skb) * SKB_NSUBBLKS(skb) + + # Each subblock must have at least SKYMIN or FRAC sky pixels. + SKB_NSKYMIN(skb) = min (SKB_SKYMIN(skb), + nint (SKB_FRAC(skb) * SKB_NCSPIX(skb) * SKB_NLSPIX(skb))) + + # Histogram parameters. + SKB_NAV(skb) = nint (real(SKB_NBINS(skb)) / (min (SKB_NBINS(skb), + SKB_NCSPIX(skb) * SKB_NLSPIX(skb) / SKB_NMINBINS(skb)))) + SKB_NAV(skb) = SKB_NAV(skb) + mod (SKB_NAV(skb)+1, 2) + #SKB_NAV(skb) = 1 + + # Set line subsampling for speed. + if (blkstep > 1) { + blkstep = min (1 + SKB_NLSPIX(skb) / 30, blkstep) + SKB_NSKYMIN(skb) = SKB_NSKYMIN(skb) / blkstep + } + + # Allocate and initialize memory. + call calloc (SKB_BINS(skb), SKB_NBINS(skb)*(SKB_NCSBLK(skb)+1), TY_INT) + call calloc (SKB_NSKY(skb), SKB_NCSBLK(skb), TY_INT) + call calloc (SKB_SKYS(skb), SKB_NCSBLK(skb)*SKB_NLSBLK(skb), TY_REAL) + call calloc (SKB_SIGS(skb), SKB_NCSBLK(skb)*SKB_NLSBLK(skb), TY_REAL) + if (expmap == NULL) { + call malloc (SKB_EXP(skb), 1, TY_REAL) + Memr[SKB_EXP(skb)] = INDEFR + } else + call calloc (SKB_EXP(skb), SKB_NCSBLK(skb), TY_REAL) + + # Set pointers to first line of blocks. + SKB_SKY(skb) = SKB_SKYS(skb) + SKB_SIG(skb) = SKB_SIGS(skb) + + if (logfd != NULL) { + call fprintf (logfd, " Number of blocks: %d %d\n") + call pargi (SKB_NCBLK(skb)) + call pargi (SKB_NLBLK(skb)) + call fprintf (logfd, " Number of pixels per block: %d %d\n") + call pargi (SKB_NCPIX(skb)) + call pargi (SKB_NLPIX(skb)) + call fprintf (logfd, " Number of subblocks: %d %d\n") + call pargi (SKB_NCSBLK(skb)) + call pargi (SKB_NLSBLK(skb)) + call fprintf (logfd, " Number of pixels per subblock: %d %d\n") + call pargi (SKB_NCSPIX(skb)) + call pargi (SKB_NLSPIX(skb)) + if (blkstep > 1) { + call fprintf (logfd, " Line sampling step: %d\n") + call pargi (blkstep) + } + } +end + + +# SKB_IMFREE -- Free memory for an image. + +procedure skb_imfree (skb) + +pointer skb #I Sky block structure + +begin + call mfree (SKB_BINS(skb), TY_INT) + call mfree (SKB_NSKY(skb), TY_INT) + call mfree (SKB_SKYS(skb), TY_REAL) + call mfree (SKB_SIGS(skb), TY_REAL) + call mfree (SKB_EXP(skb), TY_REAL) +end + + +# SKB_ACCUM -- Accumulate sky pixels in block histograms. +# Evaluate histograms when a block is complete. + +procedure skb_accum (skb, line, blkstep, cnv, sky, sig, exp, bp, nc, cnvwt) + +pointer skb #I Sky block structure +int line #I Line +int blkstep #I Line step +real cnv[nc] #I Convolved image data +real sky[nc] #I Sky data +real sig[nc] #I Sky sigma data +real exp[nc] #I Exposure data +int bp[nc] #I Bad pixel values +int nc #I Number of columns +real cnvwt #I Sigma weight + +real a, b, s, t, rcnv, tcnv +int c, n, ncmax, nbins, bin, csky +pointer bins, skys, sigs, exps, nsky + +begin + if (line > SKB_NLSBLK(skb) * SKB_NLSPIX(skb)) + return + ncmax = min (nc, SKB_NCSBLK(skb) * SKB_NCSPIX(skb)) + + a = SKB_A(skb) + b = SKB_B(skb) + n = SKB_NCSPIX(skb) + nbins = SKB_NBINS(skb) + bins = SKB_BINS(skb) + skys = SKB_SKY(skb) + sigs = SKB_SIG(skb) + exps = SKB_EXP(skb) + nsky = SKB_NSKY(skb) + + if (IS_INDEFR(Memr[exps])) { + do c = 1, ncmax { + if (bp[c] != 0) + next + + s = sky[c] + t = sig[c] + rcnv = cnv[c] - s + tcnv = t / cnvwt + bin = a * rcnv / tcnv + b + if (bin < 1 || bin > nbins) + next + + csky = (c-1) / n + bin = bins + csky * nbins + bin - 1 + Memi[bin] = Memi[bin] + 1 + Memr[skys+csky] = Memr[skys+csky] + s + Memr[sigs+csky] = Memr[sigs+csky] + t + Memi[nsky+csky] = Memi[nsky+csky] + 1 + } + } else { + do c = 1, ncmax { + if (bp[c] != 0) + next + + s = sky[c] + t = sig[c] + rcnv = cnv[c] - s + tcnv = t / cnvwt + bin = a * rcnv / tcnv + b + if (bin < 1 || bin > nbins) + next + + csky = (c-1) / n + bin = bins + csky * nbins + bin - 1 + Memi[bin] = Memi[bin] + 1 + Memr[skys+csky] = Memr[skys+csky] + s + Memr[sigs+csky] = Memr[sigs+csky] + t + Memr[exps+csky] = Memr[exps+csky] + exp[c] + Memi[nsky+csky] = Memi[nsky+csky] + 1 + } + } + + # Evaluate histogram sky values if all lines have been accumulated. + n = mod (line, SKB_NLSPIX(skb)) + if (n == 0 || n + blkstep > SKB_NLSPIX(skb)) { + n = SKB_NCSBLK(skb) + call skb_blkeval (Memi[bins], nbins, a, b, Memr[skys], Memr[sigs], + Memr[exps], Memi[nsky], n, SKB_NSKYMIN(skb), SKB_NAV(skb), + SKB_HISTWT(skb), SKB_SIGFAC(skb)) + + # Initialize for accumulation of next line of blocks. + SKB_SKY(skb) = skys + n + SKB_SIG(skb) = sigs + n + if (!IS_INDEFR(Memr[exps])) + call aclrr (Memr[exps], n) + call aclri (Memi[nsky], n) + call aclri (Memi[bins], n*nbins) + } +end + + +# SKB_BLKEVAL -- Evaluate sky and sigma for each histogram in line of blocks. +# Set to INDEF if there are not enough pixels in the histogram. + +procedure skb_blkeval (bins, nbins, a, b, skys, sigs, exps, nsky, ncsblk, + nskymin, nav, histwt, sigfac) + +int bins[nbins,ncsblk] #I Sky subblock bins +int nbins #I Number of bins +real a, b #I Binning coefficients +real skys[ncsblk] #U Sky sum in, sky estimate out +real sigs[ncsblk] #U Sigma sum in, sigma estimate out +real exps[ncsblk] #I Exposure sum +int nsky[ncsblk] #I Number of values in bin +int ncsblk #I Number of sky pixels per subblock +int nskymin #I Minimum number of sky pixels for good sky +int nav #I Number of bins to average +int histwt #I Histogram weighting power +real sigfac #I Sigma conversion factor from mean abs dev. + +int i, j, k, l, m, n +double sky, sig, exp, x, wt, skymean, skymed, skybin, sigbin +double sum1, sum2, sum3 + +begin +# do i = 1, ncsblk { +# do j = 1, nbins { +# call printf ("%d\n") +# call pargi (bins[j,i]) +# } +# } + m = nav / 2 + do i = 1, ncsblk { + n = nsky[i] + if (n < nskymin) { + skys[i] = INDEFR + sigs[i] = INDEFR + next + } + + sky = skys[i] / n + sig = sigs[i] / n + if (!IS_INDEFR(exps[1])) { + exp = exps[i] / n + exps[i] = exp + } else + exp = 1 + + # Compute mean and median using a power weighting of the histogram. + sum1 = 0. + sum2 = 0. + sum3 = 0. + k = ncsblk + 1 + call aclri (bins[1,k], nbins) + do j = 1, nbins { + n = bins[j,i] + do l = max(1,j-m), min (nbins,j+m) + bins[l,k] = bins[l,k] + n + } + n = nsky[i] + switch (histwt) { + case 1: + do j = 1, nbins { + wt = real (bins[j,k]) / n + x = j + sum1 = sum1 + wt * x + sum2 = sum2 + wt + } + sum2 = sum2 + x = 0 + do j = 1, nbins { + wt = real (bins[j,k]) / n + sum3 = sum3 + wt + x + if (sum3 >= sum2) + break + x = wt + } + case 2: + do j = 1, nbins { + wt = real (bins[j,k]) / n + wt = wt * wt + x = j + sum1 = sum1 + wt * x + sum2 = sum2 + wt + } + sum2 = sum2 + x = 0 + do j = 1, nbins { + wt = real (bins[j,k]) / n + wt = wt * wt + sum3 = sum3 + wt + x + if (sum3 >= sum2) + break + x = wt + } + case 3: + do j = 1, nbins { + wt = real (bins[j,k]) / n + wt = wt * wt * wt + x = j + sum1 = sum1 + wt * x + sum2 = sum2 + wt + } + sum2 = sum2 + x = 0 + do j = 1, nbins { + wt = real (bins[j,k]) / n + wt = wt * wt * wt + sum3 = sum3 + wt + x + if (sum3 >= sum2) + break + x = wt + } + case 4: + do j = 1, nbins { + wt = real (bins[j,k]) / n + wt = wt * wt + wt = wt * wt + x = j + sum1 = sum1 + wt * x + sum2 = sum2 + wt + } + sum2 = sum2 + x = 0 + do j = 1, nbins { + wt = real (bins[j,k]) / n + wt = wt * wt + wt = wt * wt + sum3 = sum3 + wt + x + if (sum3 >= sum2) + break + x = wt + } + default: + do j = 1, nbins { + wt = real (bins[j,k]) / n + wt = wt ** histwt + x = j + sum1 = sum1 + wt * x + sum2 = sum2 + wt + } + sum2 = sum2 + x = 0 + do j = 1, nbins { + wt = real (bins[j,k]) / n + wt = wt ** histwt + sum3 = sum3 + wt + x + if (sum3 >= sum2) + break + x = wt + } + } + skymean = sum1 / sum2 + skymed = j - (sum3 - sum2) / (wt + x) + #skybin = skymean - max (0D0, 3 * (skymean - skymed)) + skybin = skymean - 3 * (skymean - skymed) + #skybin = skymean + skys[i] = ((skybin + 0.5 - b) / a) * sig + sky + + sum1 = 0. + sum2 = 0. + do j = 1, nbins { + wt = bins[j,k] + x = abs (j - skybin) + sum1 = sum1 + wt * x + sum2 = sum2 + wt + } + sigbin = sum1 / sum2 + sigs[i] = sigbin / a * sig * sqrt (exp) * sigfac + } +end + + +# SKB_UPDATE -- Update the sky and sigma maps using the block values. + +procedure skb_update (skb, dosky, dosig, im, skyname, signame, + skymap, sigmap, logfd) + +pointer skb #I Sky block structure +bool dosky #I Compute sky +bool dosig #I Compute sigma +pointer im #I Image pointer +char skyname[ARB] #I Output sky map name +char signame[ARB] #I Output sigma map name +pointer skymap #U Sky map pointer +pointer sigmap #U Sigma map pointer +int logfd #I Log file descriptor + +bool skydebug, sigdebug +pointer sp, fname, tmp, map_open() +errchk skb_wmap, skb_grow, skb_merge, skb_wmap, map_close, map_open + +begin + call smark (sp) + call salloc (fname, SZ_FNAME, TY_CHAR) + + + if (dosky) { + skydebug = false + if (skydebug) + call skb_wmap ("skydebug.fits", im, SKB_SKYS(skb), + SKB_NCSBLK(skb), SKB_NLSBLK(skb), SKB_NCSPIX(skb), + SKB_NLSPIX(skb), 0., NULL) + + # Grow subblocks contaminated by large objects. + call skb_grow (SKB_SKYS(skb), SKB_NCSBLK(skb), SKB_NLSBLK(skb), + SKB_GROW(skb)) + + if (skydebug) + call skb_wmap ("skydebug.fits", im, SKB_SKYS(skb), + SKB_NCSBLK(skb), SKB_NLSBLK(skb), SKB_NCSPIX(skb), + SKB_NLSPIX(skb), 0., NULL) + + # Merge sky from subblocks and interpolate missing regions. + call skb_merge (Memr[SKB_SKYS(skb)], SKB_NCSBLK(skb), + SKB_NLSBLK(skb), Memr[SKB_SKYS(skb)], SKB_NCBLK(skb), + SKB_NLBLK(skb)) + + # Write block maps and map them with the MAPIO interface. + # If no name is given then use a temporary image. + if (skyname[1] == EOS) { + call mktemp ("tmpsky", Memc[fname], SZ_FNAME) + call skb_wmap (Memc[fname], im, SKB_SKYS(skb), + SKB_NCBLK(skb), SKB_NLBLK(skb), SKB_NCPIX(skb), + SKB_NLPIX(skb), INDEFR, NULL) + } else { + call strcpy (skyname, Memc[fname], SZ_FNAME) + call skb_wmap (Memc[fname], im, SKB_SKYS(skb), + SKB_NCBLK(skb), SKB_NLBLK(skb), SKB_NCPIX(skb), + SKB_NLPIX(skb), INDEFR, logfd) + } + tmp = skymap + iferr (skymap = map_open (Memc[fname], im)) + skymap = NULL + if (skymap == NULL) { + skymap = tmp + call error (1, "Could not update sky") + } + call map_close (tmp) + if (skyname[1] == EOS) + call map_seti (skymap, "delete", YES) + } + + if (dosig) { + sigdebug = false + if (sigdebug) + call skb_wmap ("sigdebug.fits", im, SKB_SIGS(skb), + SKB_NCSBLK(skb), SKB_NLSBLK(skb), SKB_NCSPIX(skb), + SKB_NLSPIX(skb), 0., NULL) + + # Grow subblocks contaminated by large objects. + call skb_grow (SKB_SIGS(skb), SKB_NCSBLK(skb), SKB_NLSBLK(skb), + SKB_GROW(skb)) + + if (sigdebug) + call skb_wmap ("sigdebug.fits", im, SKB_SIGS(skb), + SKB_NCSBLK(skb), SKB_NLSBLK(skb), SKB_NCSPIX(skb), + SKB_NLSPIX(skb), 0., NULL) + + # Merge sky sigma from subblocks and interpolate missing regions. + call skb_merge (Memr[SKB_SIGS(skb)], SKB_NCSBLK(skb), + SKB_NLSBLK(skb), Memr[SKB_SIGS(skb)], SKB_NCBLK(skb), + SKB_NLBLK(skb)) + + # Write block maps and map them with the MAPIO interface. + # If no name is given then use a temporary image. + if (signame[1] == EOS) { + call mktemp ("tmpsig", Memc[fname], SZ_FNAME) + call skb_wmap (Memc[fname], im, SKB_SIGS(skb), + SKB_NCBLK(skb), SKB_NLBLK(skb), SKB_NCPIX(skb), + SKB_NLPIX(skb), INDEFR, NULL) + } else { + call strcpy (signame, Memc[fname], SZ_FNAME) + call skb_wmap (Memc[fname], im, SKB_SIGS(skb), + SKB_NCBLK(skb), SKB_NLBLK(skb), SKB_NCPIX(skb), + SKB_NLPIX(skb), INDEFR, logfd) + } + tmp = sigmap + iferr (sigmap = map_open (Memc[fname], im)) + sigmap = NULL + if (sigmap == NULL) { + sigmap = tmp + call error (1, "Could not update sky sigma") + } + call map_close (tmp) + if (signame[1] == EOS) + call map_seti (sigmap, "delete", YES) + } + + call sfree (sp) +end + + +# SKB_GROW -- Grow around subblocks with insufficient data. + +procedure skb_grow (sky, nc, nl, grow) + +pointer sky # Pointer to real sky array to be grown +int nc, nl # Size of sky array +real grow # Grow radius + +int i, j, k, l1, l2, ngrow, nbufs +real grow2, val1, val2, y2 +pointer buf, buf1, buf2, ptr +errchk calloc + +begin + # Initialize. + ngrow = int (grow) + grow2 = grow * grow + nbufs = min (1 + 2 * ngrow, nl) + call calloc (buf, nc*nbufs, TY_REAL) + + l1 = 1; l2 = 1 + while (l1 <= nl) { + buf1 = sky + (l1 - 1) * nc + buf2 = buf + mod (l1, nbufs) * nc + do i = 1, nc { + val1 = Memr[buf1] + val2 = Memr[buf2] + if (IS_INDEFR(val1)) { + do j = max(1,l1-ngrow), min (nl,l1+ngrow) { + ptr = buf + mod (j, nbufs) * nc - 1 + y2 = (j - l1) ** 2 + do k = max(1,i-ngrow), min (nc,i+ngrow) { + if ((k-i)**2 + y2 > grow2) + next + Memr[ptr+k] = INDEFR + } + } + } else if (!IS_INDEFR(val2)) + Memr[buf2] = val1 + buf1 = buf1 + 1 + buf2 = buf2 + 1 + } + + if (l1 > ngrow) { + while (l2 <= nl) { + buf1 = sky + (l2 - 1) * nc + buf2 = buf + mod (l2, nbufs) * nc + do i = 1, nc { + Memr[buf1] = Memr[buf2] + Memr[buf2] = 0 + buf1 = buf1 + 1 + buf2 = buf2 + 1 + } + l2 = l2 + 1 + if (l1 != nl) + break + } + } + l1 = l1 + 1 + } + + call mfree (buf, TY_REAL) +end + + +# SKB_MERGE -- Merge subblock into blocks. +# Use average of subblocks with minimum and maximum excluded. + +procedure skb_merge (in, ncin, nlin, out, ncout, nlout) + +real in[ncin,nlin] +int ncin, nlin +real out[ncout,nlout] +int ncout, nlout + +int ncs, nls +int i, i1, i2, iout, j, j1, j2, jout, n, nindef +real val, sum, minval, maxval +pointer work + +begin + # Number of input subblocks per output block. + ncs = nint (real (ncin) / ncout) + nls = nint (real (nlin) / nlout) + + nindef = 0 + j2 = 0; jout = 0 + do j1 = 1, nlin, nls { + jout = jout + 1 + j2 = min (nlin, j2 + nls) + i2 = 0; iout = 0 + do i1 = 1, ncin, ncs { + iout = iout + 1 + i2 = min (ncin, i2 + ncs) + + n = 0 + sum = 0. + minval = MAX_REAL + maxval = -MAX_REAL + do j = j1, j2 { + do i = i1, i2 { + if (IS_INDEFR(in[i,j])) + next + val = in[i,j] + sum = sum + val + minval = min (val, minval) + maxval = max (val, maxval) + n = n + 1 + } + } + if (n > 2) + out[iout,jout] = (sum - minval - maxval) / (n - 2) + else if (n >= min (ncs, nls)) + out[iout,jout] = sum / n + else { + out[iout,jout] = INDEFR + nindef = nindef + 1 + } + } + } + + # Interpolate to fill in blocks with no sky data. + if (nindef > 0) { + call malloc (work, ncout*nlout, TY_REAL) + call interp2 (out, Memr[work], ncout, nlout) + call amovr (Memr[work], out, ncout*nlout) + call mfree (work, TY_REAL) + } +end + + +## SKB_ESTIMATE -- Estimate of sky in block from subblocks. +## Use order selection. +# +#procedure skb_merge (in, ncin, nlin, out, ncout, nlout, select) +# +#real in[ncin,nlin] +#int ncin, nlin +#real out[ncout,nlout] +#int ncout, nlout +#real select # Selection fraction +# +#int ncs, nls +#int i, i1, i2, iout, j, j1, j2, jout, n, nindef, nselect +#pointer sp, work, ptr +#real asokr() +# +#begin +# # Number of input subblocks per output block. +# ncs = nint (real (ncin) / ncout) +# nls = nint (real (nlin) / nlout) +# +# call smark (sp) +# call salloc (work, ncs*nls, TY_REAL) +# +# nindef = 0 +# j2 = 0; jout = 0 +# do j1 = 1, nlin, nls { +# jout = jout + 1 +# j2 = min (nlin, j2 + nls) +# i2 = 0; iout = 0 +# do i1 = 1, ncin, ncs { +# iout = iout + 1 +# i2 = min (ncin, i2 + ncs) +# ptr = work +# do j = j1, j2 { +# do i = i1, i2 { +# if (IS_INDEFR(in[i,j])) +# next +# Memr[ptr] = in[i,j] +# ptr = ptr + 1 +# } +# } +# n = ptr - work +# if (n >= min (ncs, nls)) { +# nselect = nint (select * (n - 1)) + 1 +# out[iout,jout] = asokr (Memr[work], n, nselect) +# } else { +# out[iout,jout] = INDEFR +# nindef = nindef + 1 +# } +# } +# } +# +# # Interpolate to fill in blocks with no sky data. +# if (nindef > 0) { +# call salloc (work, ncout*nlout, TY_REAL) +# call interp2 (out, Memr[work], ncout, nlout) +# call amovr (Memr[work], out, ncout*nlout) +# } +# +# call sfree (sp) +#end + + +# SKB_WMAP -- Write map from block data. + +procedure skb_wmap (name, imref, data, ncblk, nlblk, ncpix, nlpix, blank, logfd) + +char name[ARB] #I Output name +pointer imref #I Reference image pointer +pointer data #I Block image data +int ncblk, nlblk #I Block image dimensions +int ncpix, nlpix #I Number of reference image pixels per block +real blank #I Blank value +int logfd #I Log file descriptor + +bool strne() +int i, j, imaccess(), strlen(), stridxs() +real a[2] +pointer sp, title, str +pointer im, mw, buf, immap(), impl2r(), mw_openim() +errchk immap, imrename + +begin + call smark (sp) + call salloc (title, SZ_IMTITLE, TY_CHAR) + call salloc (str, SZ_FNAME, TY_CHAR) + + # Create title for new image or to check for updating. + call sprintf (Memc[title], SZ_IMTITLE, "Sky for ") + i = strlen (Memc[title]) + call imstats (imref, IM_IMAGENAME, Memc[title+i], SZ_IMTITLE-i) + + iferr { + im = NULL; mw = NULL + +# # Check for existing image and rename. +# if (imaccess (name, 0) == YES) { +# j = strlen (name) +# call malloc (fname, j+SZ_FNAME, TY_CHAR) +# i = strldxs (".", name) - 1 +# if (i < 0) +# i = j +# do j = 1, ARB { +# call strcpy (name, Memc[fname], i) +# call sprintf (Memc[fname+i], SZ_FNAME, "%d%s") +# call pargi (j) +# call pargstr (name[i+1]) +# if (imaccess (Memc[fname], 0) == YES) +# next +# call imrename (name, Memc[fname]) +# break +# } +# call mfree (fname, TY_CHAR) +# } + + if (imaccess (name, 0) == NO) { + if (logfd != NULL) { + call strcpy (name, Memc[str], SZ_FNAME) + i = stridxs (",", Memc[str]) + if (i > 0) { + Memc[str+i-1] = ']' + Memc[str+i] = EOS + } + call fprintf (logfd, " Write sky map: %s\n") + call pargstr (Memc[str]) + } + buf = immap (name, NEW_COPY, imref); im = buf + IM_PIXTYPE(im) = TY_REAL + IM_LEN(im,1) = ncblk + IM_LEN(im,2) = nlblk + call strcpy (Memc[title], IM_TITLE(im), SZ_IMTITLE) + iferr (call imdelf (im, "BPM")) + ; + iferr (call imdelf (im, "DATASEC")) + ; + iferr (call imdelf (im, "TRIMSEC")) + ; + + do i = 1, nlblk { + buf = impl2r(im,i) + call amovr (Memr[data+(i-1)*ncblk], Memr[buf], ncblk) + if (!IS_INDEFR(blank)) { + do j = 1, ncblk + if (IS_INDEFR(Memr[buf+j-1])) + Memr[buf+j-1] = blank + } + } + + # Update the WCS. + mw = mw_openim (imref) + a[1] = 1. / ncpix + a[2] = 1. / nlpix + call mw_scale (mw, a, 3) + a[1] = 0.5 + a[2] = 0.5 + call mw_shift (mw, a, 3) + call mw_saveim (mw, im) + } else { + if (logfd != NULL) { + call strcpy (name, Memc[str], SZ_FNAME) + i = stridxs (",", Memc[str]) + if (i > 0) { + Memc[str+i-1] = ']' + Memc[str+i] = EOS + } + call fprintf (logfd, " Update sky map: %s\n") + call pargstr (Memc[str]) + } + buf = immap (name, READ_WRITE, 0); im = buf + if (strne (IM_TITLE(im), Memc[title]) || + IM_LEN(im,1) != ncblk || IM_LEN(im,2) != nlblk) + call error (1, "Cannot update sky map") + + do i = 1, nlblk { + buf = impl2r(im,i) + call amovr (Memr[data+(i-1)*ncblk], Memr[buf], ncblk) + if (!IS_INDEFR(blank)) { + do j = 1, ncblk + if (IS_INDEFR(Memr[buf+j-1])) + Memr[buf+j-1] = blank + } + } + } + } then + call erract (EA_WARN) + + if (mw != NULL) + call mw_close (mw) + if (im != NULL) + call imunmap (im) + call sfree (sp) +end + + +# INTERP2 -- Interpolate 2D array by averaging 1D interpolations along lines +# and columns. It is an error if there is no data to interpolate. + +procedure interp2 (in, out, nc, nl) + +real in[nc,nl] # Input data +real out[nc,nl] # Output data (not the same as input) +int nc, nl # Size of data + +int i, j, k1, k2, nerr +pointer sp, flags, buf + +begin + call smark (sp) + call salloc (flags, nl, TY_INT) + call salloc (buf, nl, TY_REAL) + + call amovki (OK, Memi[flags], nl) + + # Interpolate along lines. Flag lines with no data. + nerr = 0 + do i = 1, nl + iferr (call interp1 (in[1,i], out[1,i], nc)) { + Memi[flags+i-1] = ERR + nerr = nerr + 1 + } + + if (nerr == nl) + call error (1, "No data to interpolate") + + # Interpolate along columns. Check for columns and lines with no data. + do j = 1, nc { + do i = 1, nl + Memr[buf+i-1] = in[j,i] + + ifnoerr (call interp1 (Memr[buf], Memr[buf], nl)) { + do i = 1, nl { + if (Memi[flags+i-1] == OK) + out[j,i] = (out[j,i] + Memr[buf+i-1]) / 2. + else + out[j,i] = Memr[buf+i-1] + } + } else { + do i = 1, nl { + if (Memi[flags+i-1] == ERR) { + # Find nearest line with good data. + do k1 = i-1, 1, -1 + if (Memi[flags+k1-1] == OK) + break + do k2 = i+1, nl + if (Memi[flags+k2-1] == OK) + break + if (k1 >= 1 & k2 <= nl) { + if (i - k1 < k2 - i) + out[j,i] = out[j,k1] + else + out[j,i] = out[j,k2] + } else if (k1 >= 1) + out[j,i] = out[j,k1] + else if (k2 <= nl) + out[j,i] = out[j,k2] + } + } + } + } + call sfree (sp) +end + + +# INTERP1 -- Interpolate 1D vectors. +# An error is generated if there is no data to interpolate. + +procedure interp1 (in, out, npts) + +real in[npts] # Input line +real out[npts] # Output line (may be the same as input) +int npts # Number of points in line + +int i, i1, i2, j +real v, v1, dv + +begin + i1 = 0 + i2 = 1 + do i = 1, npts { + v = in[i] + if (IS_INDEFR(v)) + next + if (i > i2) { + if (i1 > 0) { + dv = (v - v1) / (i - i1) + do j = i2, i-1 + out[j] = v + dv * (j - i) + } else { + do j = i2, i-1 + out[j] = v + } + } + out[i] = v + v1 = v + i1 = i + i2 = i1+1 + } + + if (i1 == 0) + call error (1, "No data to interpolate") + else if (i2 <= npts) { + do j = i2, npts + out[j] = v1 + } + +end diff --git a/noao/nproto/ace/skyfit.h b/noao/nproto/ace/skyfit.h new file mode 100644 index 00000000..585d1c95 --- /dev/null +++ b/noao/nproto/ace/skyfit.h @@ -0,0 +1,24 @@ +# Sky surface algorithm definitions. + +define SKF_LEN 16 # Length of parameter structure +define SKF_STRLEN 9 # Length of string + +define SKF_STEP Memr[P2R($1)] # Number of sky lines to sample +define SKF_LMIN Memr[P2R($1+1)] # Minimum number of lines to fit +define SKF_FUNC1D Memi[$1+2] # 1D Fitting function +define SKF_FUNC2D Memi[$1+3] # 2D Fitting function +define SKF_XORDER Memi[$1+4] # Sky fitting x order +define SKF_YORDER Memi[$1+5] # Sky fitting y order +define SKF_XTERMS Memi[$1+6] # Sky fitting cross terms +define SKF_BLK1D Memi[$1+7] # Sky block size for 1D averages +define SKF_HCLIP Memr[P2R($1+8)] # Sky fitting high sigma clip +define SKF_LCLIP Memr[P2R($1+9)] # Sky fitting low sigma clip +define SKF_NITER Memi[$1+10] # Number of iterations +define SKF_STR Memc[P2C($1+11)] # String + + +define SKFLMIN 10 # Minimum number of lines to fit +define SKFFUNC1D "chebyshev" # 1D fitting function +define SKFFUNC2D "chebyshev" # 2D fitting function +define SKFXTERMS "half" # Cross terms +define SKFNITER 5 # Number of iterations diff --git a/noao/nproto/ace/skyfit.x b/noao/nproto/ace/skyfit.x new file mode 100644 index 00000000..0b295e8e --- /dev/null +++ b/noao/nproto/ace/skyfit.x @@ -0,0 +1,393 @@ +include <imhdr.h> +include <math/curfit.h> +include <math/gsurfit.h> +include "skyfit.h" + + +# SKY_FIT -- Fit sky surface. +# +# Compute a sky and/or sky sigma surface fit using a subset of the input +# lines. the input sky and sky sigma pointers are NULL. The initial data +# for the surface fit is measured at a subset of lines with any masked +# pixels excluded. Objects are removed by fitting a 1D curve to each line, +# rejection points with large residuals and iterating until only sky is left. +# The sky points are then accumulated for a 2D surface fit and the residuals +# are added to a histogram. The absolute deviations, scaled by 0.7979 to +# convert to an gausian sigma, are accumulated for a sky sigma surface fit. +# After all the sample lines are accumulated the surface fits are computed. +# The histogram of residuals is then fit by a gaussian to estimate an +# offset from the sky fit to the sky mode caused by unrejected object light. +# The offset is applied to the sky surface. + +procedure sky_fit (par, dosky, dosig, im, bpm, expmap, skyname, signame, + skymap, sigmap, logfd) + +pointer par #U Sky parameters +bool dosky #I Compute sky +bool dosig #I Compute sigma +pointer im #I Input image +pointer bpm #I Input mask +pointer expmap #I Exposure map +char skyname[ARB] #I Sky map name +char signame[ARB] #I Sigma map name +pointer skymap #U Sky map +pointer sigmap #U Sigma map +int logfd #I Verbose? + +# Parameters +real step # Line sample step +int lmin # Minimum number of lines to fit +int func1d # 1D fitting function +int func2d # 2D fitting function +int xorder # Sky fitting x order +int yorder # Sky fitting y order +int xterms # Sky fitting cross terms +int blk1d # Block average +real hclip # Sky fitting high sigma clip +real lclip # Sky fitting low sigma clip +int niter # Number of clipping iterations + +int l1, l2 +int i, j, c, l, n, nc, nl, nskyblk, ier +real res, sigma +pointer sp, x, y, z, r, a, x1, w1, w2, skydata, sigdata, expdata, w, ptr +pointer cvsky, cvsig, gssky, gssig + +pointer imgl2r(), imgl2i(), map_opengs(), map_glr() +bool im_pmlne2() +real amedr() +errchk map_opengs, map_glr + +begin + if (!(dosky||dosig)) + return + + # Set parameters. + if (par == NULL) + call skf_pars ("open", "", par) + step = SKF_STEP(par) + lmin = SKF_LMIN(par) + xorder = SKF_XORDER(par) + yorder = SKF_YORDER(par) + xterms = SKF_XTERMS(par) + blk1d = SKF_BLK1D(par) + hclip = SKF_HCLIP(par) + lclip = SKF_LCLIP(par) + func1d = SKF_FUNC1D(par) + func2d = SKF_FUNC2D(par) + niter = SKF_NITER(par) + + nc = IM_LEN(im,1) + nl = IM_LEN(im,2) + l1 = 1 + step / 2 + l2 = nl - step / 2 + step = real (l2-l1) / max (nint((l2-l1)/step),xorder+2,lmin) + + if (logfd != NULL) { + if (dosky && dosig) + call fprintf (logfd, + " Determine sky and sigma by surface fits:\n") + else if (dosky) + call fprintf (logfd, " Determine sky by surface fit:\n") + else + call fprintf (logfd, " Determine sigma by surface fit:\n") + call fprintf (logfd, + " start line = %d, end line = %d, step = %.1f\n") + call pargi (l1) + call pargi (l2) + call pargr (step) + call fprintf (logfd, + " xorder = %d, yorder = %d, xterms = %s\n") + call pargi (xorder) + call pargi (yorder) + switch (xterms) { + case GS_XNONE: + call pargstr ("none") + case GS_XFULL: + call pargstr ("full") + case GS_XHALF: + call pargstr ("half") + } + call fprintf (logfd, " hclip = %g, lclip = %g\n") + call pargr (hclip) + call pargr (lclip) + } + + # Allocate memory and initialize. + call smark (sp) + call salloc (x1, nc, TY_REAL) + call salloc (w1, nc, TY_REAL) + call salloc (w2, nc, TY_REAL) + + nskyblk = nc / blk1d + call salloc (x, nskyblk, TY_REAL) + call salloc (y, nskyblk, TY_REAL) + call salloc (z, nskyblk, TY_REAL) + call salloc (r, nskyblk, TY_REAL) + call salloc (a, nskyblk, TY_REAL) + call salloc (skydata, nskyblk, TY_REAL) + call salloc (sigdata, nskyblk, TY_REAL) + if (expmap != NULL) + call salloc (expdata, nskyblk, TY_REAL) + + do c = 1, nc + Memr[x1+c-1] = c + call amovkr (1., Memr[w1], nc) + + # Initialize the 1D and 2D fitting pointers as needed. + if (dosky) { + call cvinit (cvsky, func1d, xorder, Memr[x1], + Memr[x1+nc-1]) + call gsinit (gssky, func2d, xorder, yorder, + xterms, 1., real(nc), 1., real(nl)) + } + if (dosig) { + call cvinit (cvsig, CHEBYSHEV, 1, Memr[x1], Memr[x1+nc-1]) + call gsinit (gssig, GS_CHEBYSHEV, 1, 1, xterms, + 1., real(nc), 1., real(nl)) + } + + # For each sample line find sky points by 1D fitting and sigma + # rejection and then accumulate 2D surface fitting points. + do j = 0, ARB { + l = nint (l1 + j * step) + if (l > l2) + break + + # Get input data and block average. + if (bpm == NULL) + w = w1 + else if (!im_pmlne2 (bpm, l)) + w = w1 + else { + w = imgl2i (bpm, l) + n = nc + do c = 0, nc-1 { + if (Memi[w+c] != 0) { + Memr[w2+c] = 0 + n = n - 1 + } else + Memr[w2+c] = Memr[w1+c] + } + w = w2 + if (n < 10) + next + } + + # Block average. + if (skymap != NULL) { + ptr = map_glr (skymap, l, READ_ONLY) + call blkavg1 (Memr[ptr], Memr[w], nc, Memr[skydata], + nskyblk, blk1d) + } + if (expmap != NULL) { + ptr = map_glr (expmap, l, READ_ONLY) + call blkavg1 (Memr[ptr], Memr[w], nc, Memr[expdata], + nskyblk, blk1d) + } + if (sigmap != NULL) { + ptr = map_glr (sigmap, l, READ_ONLY) + call blkavg1 (Memr[ptr], Memr[w], nc, Memr[sigdata], + nskyblk, blk1d) + call adivkr (Memr[sigdata], sqrt(real(blk1d)), Memr[sigdata], + nskyblk) + if (expmap != NULL) + call expsigma (Memr[sigdata], Memr[expdata], nskyblk, 0) + } + call blkavg (Memr[x1], Memr[imgl2r(im,l)], Memr[w], nc, + Memr[x], Memr[z], Memr[w2], nskyblk, blk1d) + w = w2 + + # Iterate using line fitting. + do i = 1, niter { + + # Fit sky. + if (dosky) { + call cvfit (cvsky, Memr[x], Memr[z], Memr[w], nskyblk, + WTS_USER, ier) + if (ier == NO_DEG_FREEDOM) + call error (1, "Fitting error") + call cvvector (cvsky, Memr[x], Memr[skydata], nskyblk) + } + + # Compute residuals. + call asubr (Memr[z], Memr[skydata], Memr[r], nskyblk) + + # Fit sky sigma. + if (dosig) { + do c = 0, nskyblk-1 + Memr[a+c] = abs(Memr[r+c]) / 0.7979 + if (expmap != NULL) + call expsigma (Memr[a], Memr[expdata], nskyblk, 1) + if (i == 1) + call amovkr (amedr(Memr[a],nskyblk), Memr[sigdata], + nskyblk) + else { + call cvfit (cvsig, Memr[x], Memr[a], Memr[w], nskyblk, + WTS_USER, ier) + if (ier == NO_DEG_FREEDOM) + call error (1, "Fitting error") + call cvvector (cvsig, Memr[x], Memr[sigdata], nskyblk) + } + if (expmap != NULL) + call expsigma (Memr[sigdata], Memr[expdata], nskyblk, 0) + } + + # Reject deviant points. + n = 0 + do c = 0, nskyblk-1 { + if (Memr[w+c] == 0.) + next + res = Memr[r+c] + sigma = Memr[sigdata+c] + if (res > hclip * sigma || res < -lclip * sigma) { + Memr[w+c] = 0. + n = n + 1 + } + } + if (n == 0) { + if (i == 1 && dosig) { + call cvfit (cvsig, Memr[x], Memr[a], Memr[w], nskyblk, + WTS_USER, ier) + if (ier == NO_DEG_FREEDOM) + call error (1, "Fitting error") + } + break + } + } + + # Accumulate the sky data for the line. + call amovkr (real(l), Memr[y], nskyblk) + if (dosky && dosig) { + call amulkr (Memr[a], sqrt(real(blk1d)), Memr[a], nskyblk) + call gsacpts (gssky, Memr[x], Memr[y], Memr[z], Memr[w], + nskyblk, WTS_USER) + call gsacpts (gssig, Memr[x], Memr[y], Memr[a], Memr[w], + nskyblk, WTS_USER) + } else if (dosky) { + call gsacpts (gssky, Memr[x], Memr[y], Memr[z], Memr[w], + nskyblk, WTS_USER) + } else { + call amulkr (Memr[a], sqrt(real(blk1d)), Memr[a], nskyblk) + call gsacpts (gssig, Memr[x], Memr[y], Memr[a], + Memr[w], nskyblk, WTS_USER) + } + } + + # Compute the surface fits, store in header, and set output pointers. + if (dosky) { + if (skymap != NULL) + call map_close (skymap) + call cvfree (cvsky) + call gssolve (gssky, ier) + if (ier == NO_DEG_FREEDOM) + call error (1, "Fitting error") + if (skyname[1] != EOS) + call mgs_pgs (im, skyname, gssky) + skydata = map_opengs (gssky, im); skymap = skydata + } + if (dosig) { + if (sigmap != NULL) + call map_close (sigmap) + call cvfree (cvsig) + call gssolve (gssig, ier) + if (ier == NO_DEG_FREEDOM) + call error (1, "Fitting error") + if (signame[1] != EOS) + call mgs_pgs (im, signame, gssig) + sigdata = map_opengs (gssig, im); sigmap = sigdata + } + + call sfree (sp) +end + + +procedure blkavg (xin, yin, win, nin, xout, yout, wout, nout, blksize) + +real xin[nin] #I Input values +real yin[nin] #I Input values +real win[nin] #I Input weights +int nin #I Number of input values +real xout[nout] #O Output values +real yout[nout] #O Output values +real wout[nout] #O Output weights +int nout #O Number of output values +int blksize #I Block size + +int i, j, n, imax +real xavg, yavg, wsum, w + +begin + if (blksize == 1) { + nout = nin + call amovr (xin, xout, nout) + call amovr (yin, yout, nout) + call amovr (win, wout, nout) + return + } + + n = blksize + imax = nin - 2 * blksize + 1 + nout = 0 + for (i=1; i<=nin; ) { + if (i > imax) + n = nin - i + 1 + xavg = 0. + yavg = 0. + wsum = 0. + do j = 1, n { + w = win[i] + xavg = xavg + w * xin[i] + yavg = yavg + w * yin[i] + wsum = wsum + w + i = i + 1 + } + if (wsum > 0.) { + nout = nout + 1 + xout[nout] = xavg / wsum + yout[nout] = yavg / wsum + wout[nout] = wsum + } + } +end + + +procedure blkavg1 (in, win, nin, out, nout, blksize) + +real in[nin] #I Input values +real win[nin] #I Input weights +int nin #I Number of input values +real out[nout] #O Output values +int nout #O Number of output values +int blksize #I Block size + +int i, j, n, imax +real avg, wsum, w + +begin + if (blksize == 1) { + nout = nin + call amovr (in, out, nout) + return + } + + n = blksize + imax = nin - 2 * blksize + 1 + nout = 0 + for (i=1; i<=nin; ) { + if (i > imax) + n = nin - i + 1 + avg = 0. + wsum = 0. + do j = 1, n { + w = win[i] + avg = avg + w * in[i] + wsum = wsum + w + i = i + 1 + } + if (wsum > 0.) { + nout = nout + 1 + out[nout] = avg / wsum + } + } +end diff --git a/noao/nproto/ace/skygrow.xNEW b/noao/nproto/ace/skygrow.xNEW new file mode 100644 index 00000000..8c78a4bc --- /dev/null +++ b/noao/nproto/ace/skygrow.xNEW @@ -0,0 +1,89 @@ +include <imhdr.h> + +task skygrow = t_skygrow + +procedure t_skygrow () + +int nc, nl +pointer im, sky, immap(), imps2r(), imgs2r() + +begin + im = immap ("skyblk", READ_WRITE, 0) + nc = IM_LEN(im,1) + nl = IM_LEN(im,2) + sky = imps2r (im, 1, nc, 1, nl) + call amovr (Memr[imgs2r(im,1,nc,1,nl)], Memr[sky], nc*nl) + call skygrow (sky, nc, nl, 1.5, 0.) + call imunmap (im) +end + + +procedure skygrow (sky, nc, nl, grow, growval) + +pointer sky # Pointer tor eal sky array to be grown +int nc, nl # Size of sky array +real grow # Grow radius +real growval # Value to be grown + +int i, j, k, l1, l2, ngrow, nbufs +real grow2, growval1, val1, val2, y2 +pointer buf, buf1, buf2, ptr +errchk calloc + +begin + # Initialize. + ngrow = int (grow) + grow2 = grow * grow + nbufs = min (1 + 2 * ngrow, nl) + if (growval == 0.) { + growval1 = 1. + call malloc (buf, nc*nbufs, TY_REAL) + call amovkr (growval1, Memr[buf], nc*nbufs) + } else { + growval1 = 0. + call calloc (buf, nc*nbufs, TY_REAL) + } + + l1 = 1; l2 = 1 + while (l1 <= nl) { + buf1 = sky + (l1 - 1) * nc + buf2 = buf + mod (l1, nbufs) * nc + do i = 1, nc { + val1 = Memr[buf1] + val2 = Memr[buf2] + if (val1 == growval) { + do j = max(1,l1-ngrow), min (nl,l1+ngrow) { + ptr = buf + mod (j, nbufs) * nc - 1 + y2 = (j - l1) ** 2 + do k = max(1,i-ngrow), min (nc,i+ngrow) { + if ((k-i)**2 + y2 > grow2) + next + Memr[ptr+k] = growval + } + } + } else if (val2 != growval) + Memr[buf2] = val1 + buf1 = buf1 + 1 + buf2 = buf2 + 1 + } + + if (l1 > ngrow) { + while (l2 <= nl) { + buf1 = sky + (l2 - 1) * nc + buf2 = buf + mod (l2, nbufs) * nc + do i = 1, nc { + Memr[buf1] = Memr[buf2] + Memr[buf2] = growval1 + buf1 = buf1 + 1 + buf2 = buf2 + 1 + } + l2 = l2 + 1 + if (l1 != nl) + break + } + } + l1 = l1 + 1 + } + + call mfree (buf, TY_REAL) +end diff --git a/noao/nproto/ace/skyimages.par b/noao/nproto/ace/skyimages.par new file mode 100644 index 00000000..a1458d39 --- /dev/null +++ b/noao/nproto/ace/skyimages.par @@ -0,0 +1,10 @@ +# SKYIMAGES + +images,f,a,,,,"List of images" +skyimages,f,a,,,,"List of output sky images" +sigmaimages,f,a,,,,"List of output sigma images" +skys,s,h,"",,,"List of sky maps" +sigmas,s,h,"",,,"List of sigma maps" +exps,s,h,"",,,"List of exposure maps" +gains,s,h,"",,,"List of gain maps" +logfiles,s,h,"STDOUT",,,"List of log files" diff --git a/noao/nproto/ace/skyimages.x b/noao/nproto/ace/skyimages.x new file mode 100644 index 00000000..899fc5da --- /dev/null +++ b/noao/nproto/ace/skyimages.x @@ -0,0 +1,120 @@ +include <error.h> +include <imhdr.h> + + +# SKYIMAGES -- Write out sky images. + +procedure skyimages (outsky, outsig, im, skymap, sigmap, gainmap, expmap, logfd) + +char outsky[ARB] #I Output sky image name +char outsig[ARB] #I Output sigma image name +pointer im #I Image pointer +pointer skymap #I Sky map +pointer sigmap #I Sigma map +pointer gainmap #I Gain map +pointer expmap #I Exposure map +int logfd #I Logfile + +int l, nc, nl +pointer skyim, sigim, data, skydata, ssigdata, gaindata, expdata, sigdata, ptr + +pointer immap(), imgl2r(), impl2r(), map_glr() +errchk immap, map_glr + +begin + # Return no output is needed. + if (outsky[1] == EOS && outsig[1] == EOS) + return + + # Write log information. + if (logfd != NULL) { + call fprintf (logfd, " Output sky images:") + if (outsky[1] != EOS) { + call fprintf (logfd, " sky = %s") + call pargstr (outsky) + } + if (outsig[1] != EOS) { + call fprintf (logfd, " sigma = %s") + call pargstr (outsig) + } + call fprintf (logfd, "\n") + } + + iferr { + skyim = NULL; sigim = NULL + + # Map output image(s) + if (outsky[1] != EOS) { + ptr = immap (outsky, NEW_COPY, im) + skyim = ptr + } + if (outsig[1] != EOS) { + ptr = immap (outsig, NEW_COPY, im) + sigim = ptr + } + + # Output the sky image data. + nc = IM_LEN(im,1) + nl = IM_LEN(im,2) + do l = 1, nl { + data = NULL + skydata = NULL + if (skyim != NULL) { + skydata = map_glr (skymap, l, READ_ONLY) + call amovr (Memr[skydata], Memr[impl2r(skyim,l)], nc) + } + if (sigim != NULL) { + ssigdata = map_glr (sigmap, l, READ_ONLY) + if (gainmap == NULL && expmap == NULL) + sigdata = ssigdata + else if (expmap == NULL) { + if (data == NULL) + data = imgl2r (im, l) + if (skydata == NULL) + skydata = map_glr (skymap, l, READ_ONLY) + gaindata = map_glr (gainmap, l, READ_ONLY) + call noisemodel (Memr[data], Memr[skydata], + Memr[ssigdata], Memr[gaindata], INDEFR, + Memr[sigdata], nc) + } else if (gainmap == NULL) { + expdata = map_glr (expmap, l, READ_WRITE) + call noisemodel (Memr[expdata], Memr[expdata], + Memr[ssigdata], INDEFR, Memr[expdata], + Memr[sigdata], nc) + } else { + if (data == NULL) + data = imgl2r (im, l) + if (skydata == NULL) + skydata = map_glr (skymap, l, READ_ONLY) + gaindata = map_glr (gainmap, l, READ_ONLY) + expdata = map_glr (expmap, l, READ_WRITE) + call noisemodel (Memr[data], Memr[skydata], + Memr[ssigdata], Memr[gaindata], + Memr[expdata], Memr[sigdata], nc) + } + if (skyim != NULL) + call amovr (Memr[sigdata], Memr[impl2r(sigim,l)], nc) + } + } + + # Finish up. + if (skyim != NULL) + call imunmap (skyim) + if (sigim != NULL) + call imunmap (sigim) + } then { + call erract (EA_WARN) + + # Close and delete output images on an errror. + if (skyim != NULL) { + call imunmap (skyim) + iferr (call imdelete (outsky)) + ; + } + if (sigim != NULL) { + call imunmap (sigim) + iferr (call imdelete (outsig)) + ; + } + } +end diff --git a/noao/nproto/ace/split.h b/noao/nproto/ace/split.h new file mode 100644 index 00000000..db9589a1 --- /dev/null +++ b/noao/nproto/ace/split.h @@ -0,0 +1,13 @@ +# Detection parameter structure. +define SPT_LEN 10 # Length of parameter structure + +define SPT_NEIGHBORS Memi[$1] # Neighbor type +define SPT_SPLITMAX Memr[P2R($1+1)] # Maximum convolved sigma for splitting +define SPT_SPLITSTEP Memr[P2R($1+2)] # Minimum split step in convolved sigma +define SPT_SPLITTHRESH Memr[P2R($1+3)] # Transition convolved sigma +define SPT_MINPIX Memi[$1+4] # Minimum number of pixels +define SPT_SIGAVG Memr[P2R($1+5)] # Minimum average above sky in sigma +define SPT_SIGPEAK Memr[P2R($1+6)] # Minimum peak above sky in sigma +define SPT_SMINPIX Memi[$1+7] # Minimum number of split pixels +define SPT_SSIGAVG Memr[P2R($1+8)] # Minimum split avg above sky in sigma +define SPT_SSIGPEAK Memr[P2R($1+9)] # Minimum split peak above sky in sigma diff --git a/noao/nproto/ace/split.x b/noao/nproto/ace/split.x new file mode 100644 index 00000000..a0d564e4 --- /dev/null +++ b/noao/nproto/ace/split.x @@ -0,0 +1,625 @@ +include <pmset.h> +include <mach.h> +include "ace.h" +include "cat.h" +include "objs.h" +include "split.h" + + +# SPLIT - Split detected objects. +# +# Note that the sigma level map is modified and will be empty when done. + +procedure split (spt, cat, objmask, siglevel, siglevels, logfd) + +pointer spt #I Split parameters +pointer cat #U Catalog structure +pointer objmask #I Input and modified object mask +pointer siglevel #I Sigma level mask. +real siglevels[ARB] #I Sigma levels +int logfd #I Logfile + +int neighbors # Neighbor type +int dminpix # Minimum number of pixels for split object +int sminpix # Minimum number of split pixels +real sigavg # Minimum average above sky in sigma +real sigmax # Minimum peak above sky in sigma +real ssigavg # Minimum split average above sky in sigma +real ssigmax # Minimum split peak above sky in sigma +real splitmax # Maximum convolved sigma for splitting +real splitstep # Minimum split step in convolved sigma +real splitthresh # Transition convolved sigma + +int i, c, c1, c2, cs, clast, l, nc, nc1, nl +int level, nsobjs, navail, nalloc, nummax, val, num, pnum, oval, sval +long v[PM_MAXDIM] +real threshold +pointer sp, pnums, buf1, buf2, irl, orl, srl, outbuf, lastbuf +pointer objs, obj, splitmask, irlptr, orlptr, srlptr +pointer flags, ids, sobjs, links + +int andi(), ori() +bool pm_linenotempty() +pointer pm_create() + +begin + # Check for splitting map. + if (siglevel == NULL) + return + + # Set parameters. + call spt_pars ("open", "", spt) + + neighbors = SPT_NEIGHBORS(spt) + dminpix = SPT_MINPIX(spt) + sminpix = SPT_SMINPIX(spt) + sigavg = SPT_SIGAVG(spt) + sigmax = SPT_SIGPEAK(spt) + ssigavg = SPT_SSIGAVG(spt) + ssigmax = SPT_SSIGPEAK(spt) + splitmax = SPT_SPLITMAX(spt) + splitstep = SPT_SPLITSTEP(spt) + splitthresh = SPT_SPLITTHRESH(spt) + + if (logfd != NULL) { + call fprintf (logfd, " Split objects: sminpix = %d\n") + call pargi (sminpix) + } + + if (IS_INDEFR(splitmax)) + splitmax = MAX_REAL + + call pm_gsize (objmask, c, v, l) + splitmask = pm_create (c, v, l) + nc = v[1] + nl = v[2] + + call smark (sp) + call salloc (pnums, nc, TY_INT) + call salloc (buf1, nc+2, TY_INT) + call salloc (buf2, nc+2, TY_INT) + call salloc (irl, 3+3*nc, TY_INT) + call salloc (orl, 3+3*nc, TY_INT) + call salloc (srl, 3+3*nc, TY_INT) + + navail = 2 * CAT_NUMMAX(cat) + call calloc (ids, navail, TY_INT) + call calloc (links, navail, TY_INT) + call calloc (sobjs, navail, TY_POINTER) + nalloc = 0 + + # Go through sigma levels. + do level = 1, ARB { + + # Check if sigma value is in splitting range. + threshold = siglevels[level] + if (threshold == 0.) + next + if (threshold > splitmax) + break + + # Initialize flags. + nummax = CAT_NUMMAX(cat) + objs = CAT_OBJS(cat) + call calloc (flags, nummax+1, TY_SHORT) + do l = NUMSTART, nummax { + obj = Memi[objs+l-1] + if (obj == NULL) + next + if (SPLIT(obj) || SINGLE(obj)) + next + if (OBJ_NPIX(obj) < 2 * sminpix) { + SETFLAG (obj, OBJ_SINGLE) + next + } + Mems[flags+l] = 1 + } + + # Clear the mask. + call pm_clear (splitmask) + + outbuf = NULL + nsobjs = NUMSTART - 1 + do l = 1, nl { + v[1] = 1 + v[2] = l + if (!pm_linenotempty (siglevel, v)) { + outbuf = NULL + next + } + + lastbuf = outbuf + if (lastbuf == buf1) + outbuf = buf2 + else + outbuf = buf1 + + # Get sigma level mask. + call pmglri (siglevel, v, Memi[irl], 0, nc, 0) + + # Get parent object mask. Skip end regions not in siglev mask. + i = Memi[irl] - 1 + cs = Memi[irl+3] + nc1 = Memi[irl+3*i] + Memi[irl+3*i+1] - cs + v[1] = cs + call pmglpi (objmask, v, Memi[pnums], 0, nc1, 0) + v[1] = 1 + + # Initialize output range lists. + orlptr = orl; Memi[orlptr] = 0 + srlptr = srl + 3; sval = 0 + clast = 0 + + call aclri (Memi[outbuf], nc+2) + irlptr = irl + do i = 2, Memi[irl] { + irlptr = irlptr + 3 + val = Memi[irlptr+2] + if (val < level) + next + c1 = Memi[irlptr] + c2 = c1 + Memi[irlptr+1] - 1 + do c = c1, c2 { + pnum = Memi[pnums+c-cs] + if (MSPLIT(pnum)) + next + pnum = MNUM (pnum) + if (Mems[flags+pnum] == 0) + next + + if (lastbuf == NULL) + call sadd (c+1, l, Memi[outbuf], INDEFI, nc+2, + Memi[ids], Memi[links], Memi[sobjs], + nsobjs, nalloc, pnum, siglevels[val], + threshold, neighbors, num) + else + call sadd (c+1, l, Memi[outbuf], Memi[lastbuf], + nc+2, Memi[ids], Memi[links], Memi[sobjs], + nsobjs, nalloc, pnum, siglevels[val], + threshold, neighbors, num) + + if (nalloc == navail) { + navail = max (100*nalloc*(nl+1)/l/100, nalloc+10000) + call realloc (ids, navail, TY_INT) + call realloc (links, navail, TY_INT) + call realloc (sobjs, navail, TY_POINTER) + } + + # Update split object mask. + if (num != oval || c != clast) { + Memi[orlptr+1] = clast - Memi[orlptr] + orlptr = orlptr + 3 + + oval = num + Memi[orlptr] = c + Memi[orlptr+2] = oval + } + + # Update sigma level mask. + if (val != sval || c != clast) { + if (sval > level) { + Memi[srlptr+1] = clast - Memi[srlptr] + srlptr = srlptr + 3 + } + + sval = val + if (sval > level) { + Memi[srlptr] = c + Memi[srlptr+2] = sval + } + } + + clast = c + 1 + } + } + + # Update masks. + i = 1 + (orlptr - orl) / 3 + if (i > 1) { + Memi[orlptr+1] = clast - Memi[orlptr] + Memi[orl] = i + Memi[orl+1] = nc + call pmplri (splitmask, v, Memi[orl], 0, nc, PIX_SRC) + } + + if (sval > level) { + Memi[srlptr+1] = clast - Memi[srlptr] + Memi[srl] = 1 + (srlptr - srl) / 3 + } else + Memi[srl] = (srlptr - srl) / 3 + Memi[srl+1] = nc + call pmplri (siglevel, v, Memi[srl], 0, nc, PIX_SRC) + } + if (nsobjs < NUMSTART) + break + + if (threshold <= splitthresh) + call srenum (cat, objmask, splitmask, Memi[ids], Memi[sobjs], + nsobjs, dminpix, sigavg, sigmax) + else + call srenum (cat, objmask, splitmask, Memi[ids], Memi[sobjs], + nsobjs, sminpix, ssigavg, ssigmax) + + # Reuse object structures. + nsobjs = nalloc + nalloc = NUMSTART-1 + do i = NUMSTART-1, nsobjs-1 { + obj = Memi[sobjs+i] + if (obj != NULL) { + Memi[sobjs+nalloc] = Memi[sobjs+i] + nalloc = nalloc + 1 + } + } + + call mfree (flags, TY_SHORT) + } + + do i = 0, nalloc-1 + call mfree (Memi[sobjs+i], TY_POINTER) + call mfree (ids, TY_INT) + call mfree (links, TY_INT) + call mfree (sobjs, TY_POINTER) + + call pm_close (splitmask) + + call sfree (sp) +end + + +# SPLITADD -- Add a pixel to the object list and set the mask value. + +procedure sadd (c, l, z, zlast, nc, ids, links, objs, nobjs, nalloc, + pnum, data, threshold, neighbors, num) + +int c, l #I Pixel coordinate +int z[nc] #I Pixel values for current line +int zlast[nc] #I Pixel values for last line +int nc #I Number of pixels in a line +int ids[ARB] #I Mask ids +int links[ARB] #I Link to other mask ids with same number +int objs[ARB] #I Object numbers +int nobjs #U Number of objects +int nalloc #U Number of allocated objects +int pnum #I Parent number +real data #I Approximate (I(convolved) - sky) / sigma(convolved) +real threshold #I Threshold above sky in sigma units +int neighbors #I Neighbor type +int num #O Assigned mask value. + +int i, num1, c1, c2 +real val +bool merge +pointer obj, obj1 + +begin + # Inherit number of a neighboring pixel. + num = INDEFI + merge = false + if (neighbors == 4) { + c1 = c - 1 + c2 = c + if (IS_INDEFI(zlast[1])) { + if (z[c1] >= NUMSTART) + num = z[c1] + } else { + if (z[c1] >= NUMSTART) { + num = z[c1] + merge = true + } else if (zlast[c] >= NUMSTART) + num = ids[zlast[c]] + } + } else { + c1 = c - 1 + c2 = c + 1 + if (IS_INDEFI(zlast[1])) { + if (z[c1] >= NUMSTART) + num = z[c1] + } else { + if (z[c1] >= NUMSTART) { + num = z[c1] + merge = true + } else if (zlast[c1] >= NUMSTART) + num = ids[zlast[c1]] + else if (zlast[c] >= NUMSTART) + num = ids[zlast[c]] + else if (zlast[c2] >= NUMSTART) + num = ids[zlast[c2]] + } + } + + # If no number assign a new number. + if (num == INDEFI) { + nobjs = nobjs + 1 + num = nobjs + ids[num] = num + links[num] = 0 + if (nalloc < nobjs) { + call malloc (objs[num], OBJ_DETLEN, TY_STRUCT) + nalloc = nobjs + OBJ_FLAGS(objs[num]) = 0 + } + obj = objs[num] + OBJ_PNUM(obj) = pnum + OBJ_XAP(obj) = 0. + OBJ_YAP(obj) = 0. + OBJ_FLUX(obj) = 0. + OBJ_NPIX(obj) = 0 + OBJ_ISIGAVG(obj) = 0. + OBJ_ISIGMAX(obj) = 0. + } + obj = objs[num] + + # Merge overlapping objects from previous line. + if (merge) { + i = zlast[c2] + if (i >= NUMSTART && num != ids[i]) { + num1 = ids[i] + + obj1 = objs[num1] + OBJ_XAP(obj) = OBJ_XAP(obj) + OBJ_XAP(obj1) + OBJ_YAP(obj) = OBJ_YAP(obj) + OBJ_YAP(obj1) + OBJ_FLUX(obj) = OBJ_FLUX(obj) + OBJ_FLUX(obj1) + OBJ_NPIX(obj) = OBJ_NPIX(obj) + OBJ_NPIX(obj1) + OBJ_ISIGAVG(obj) = OBJ_ISIGAVG(obj) + OBJ_ISIGAVG(obj1) + OBJ_ISIGMAX(obj) = max (OBJ_ISIGMAX(obj), OBJ_ISIGMAX(obj1)) + + i = num + while (links[i] != 0) + i = links[i] + links[i] = num1 + repeat { + i = links[i] + ids[i] = num + } until (links[i] == 0) + + nalloc = nalloc + 1 + objs[nalloc] = obj1 + objs[num1] = NULL + } + } + + z[c] = num + OBJ_NPIX(obj) = OBJ_NPIX(obj) + 1 + val = data - threshold + OBJ_XAP(obj) = OBJ_XAP(obj) + val * c1 + OBJ_YAP(obj) = OBJ_YAP(obj) + val * l + OBJ_FLUX(obj) = OBJ_FLUX(obj) + val + OBJ_ISIGAVG(obj) = OBJ_ISIGAVG(obj) + val + OBJ_ISIGMAX(obj) = max (OBJ_ISIGMAX(obj), val) +end + + +# SRENUM -- Find detected pieces with a common parent and add to the +# catalog and the object mask. + +procedure srenum (cat, om, sm, ids, sobjs, nsobjs, minpix, + sigavg, sigmax) + +pointer cat #I Catalog structure +pointer om #I Object mask +pointer sm #I Split mask +int ids[nsobjs] #I Mask IDs +pointer sobjs[nsobjs] #U Input and output object list +int nsobjs #U Number of objects +int minpix #I Minimum number of pixels +real sigavg #I Cutoff of SIGAVG +real sigmax #I Cutoff of SIGMAX + +int i, j, n, nummax, nc, nl +real rval +pointer sp, nsplit, v, irl, srl, orl +pointer objs, obj, pobj +int ori() + +begin + nummax = CAT_NUMMAX(cat) + objs = CAT_OBJS(cat) + + call smark (sp) + call salloc (nsplit, nummax, TY_INT) + call aclri (Memi[nsplit], nummax) + + # Eliminate objects, by setting ids to zero, which don't satisfy + # the selection criteria (size, peak value, etc). Find objects + # that have split by counting, in the nsplit array, how many pieces + # belong to each parent. + + do i = NUMSTART, nsobjs { + obj = sobjs[i] + if (obj == NULL) + next + + n = OBJ_NPIX(obj) + rval = sqrt (real(n)) + OBJ_ISIGAVG(obj) = OBJ_ISIGAVG(obj) / rval + if (n < minpix || + (OBJ_ISIGMAX(obj) < sigmax && OBJ_ISIGAVG(obj) < sigavg)) { + ids[i] = 0 + next + } + + rval = OBJ_FLUX(obj) + if (rval > 0.) { + OBJ_XAP(obj) = OBJ_XAP(obj) / rval + OBJ_YAP(obj) = OBJ_YAP(obj) / rval + } else { + OBJ_XAP(obj) = INDEFR + OBJ_YAP(obj) = INDEFR + } + + n = OBJ_PNUM(obj) + Memi[nsplit+n-1] = Memi[nsplit+n-1] + 1 + } + + # Count objects that have a common parent (nsplit > 1) and assign + # new object numbers. Those not split are eliminated by setting + # ids to zero. Mark those unsplit objects whose parent objects + # are too small at the current size threshold as single to eliminate + # them from future attempts to split. + + j = nummax + do i = NUMSTART, nsobjs { + obj = sobjs[i] + if (obj == NULL || ids[i] == 0) + next + + n = OBJ_PNUM(obj) + if (Memi[nsplit+n-1] < 2) { + pobj = Memi[objs+n-1] + if (pobj != NULL) { + if (OBJ_NPIX(obj) < 2 * minpix) + SETFLAG (pobj, OBJ_SINGLE) + } + ids[i] = 0 + } else { + j = j + 1 + OBJ_NUM(obj) = j + nummax = nummax + 1 + } + } + + # If there are no split objects return. + if (nummax == CAT_NUMMAX(cat)) { + call sfree (sp) + return + } + + # Update the object mask for the split objects. + call salloc (v, PM_MAXDIM, TY_LONG) + call pm_gsize (om, i, Meml[v], j) + nc = Meml[v]; nl = Meml[v+1] + call salloc (irl, 3+3*nc, TY_INT) + call salloc (srl, 3+3*nc, TY_INT) + call salloc (orl, 3+3*nc, TY_INT) + + call srenum1 (om, sm, nc, nl, ids, sobjs, Memi[nsplit], + Meml[v], Memi[irl], Memi[srl], Memi[orl]) + + # Add split objects to catalog. Expand object structure. + call realloc (objs, nummax, TY_POINTER) + j = CAT_NUMMAX(cat) + do i = NUMSTART, nsobjs { + obj = sobjs[i] + if (obj == NULL || ids[i] == 0) + next + + call newobj (obj) + + sobjs[i] = NULL + Memi[objs+j] = obj + j = j + 1 + } + + # Set split flags for the split parent objects. + do i = NUMSTART, CAT_NUMMAX(cat)-1 { + obj = Memi[objs+i-1] + if (obj == NULL) + next + if (Memi[nsplit+i-1] > 1) + SETFLAG (obj, OBJ_SPLIT) + } + + # Update catalog info. + CAT_NOBJS(cat) = nummax + CAT_NUMMAX(cat) = nummax + CAT_OBJS(cat) = objs + + call sfree (sp) +end + + +procedure srenum1 (om, sm, nc, nl, ids, objs, nsplit, v, irl, srl, orl) + +pointer om #I Object mask pointer +pointer sm #I Split mask pointer +int nc, nl #I Dimensions +int ids[ARB] #I Mask IDs +pointer objs[ARB] #I Split objects +int nsplit[ARB] #I Number of split pieces +long v[PM_MAXDIM] #I Work array for line index +int irl[3,nc] #I Work array for input range list +int srl[3,nc] #I Work array for split range list +int orl[3,nc] #I Work array for output range list + +int i, j, k, l, n, c1, c2, sc1, id, sid, andi(), ori() + +begin + v[1] = 1 + do l = 1, nl { + v[2] = l + call pmglri (om, v, irl, 0, nc, 0) + call pmglri (sm, v, srl, 0, nc, 0) + + srl[1,srl[1,1]+1] = nc + 1 + sc1 = srl[1,2] + + j = 1 + k = 2 + do i = 2, irl[1,1] { + sid = irl[3,i] + id = MNUM(sid) + + # Unsplit object. + if (id < NUMSTART || nsplit[id] < 2) { + j = j + 1 + orl[1,j] = irl[1,i] + orl[2,j] = irl[2,i] + orl[3,j] = sid + next + } + + c1 = irl[1,i] + c2 = c1 + irl[2,i] - 1 + id = MSETFLAG (id, MASK_SPLIT) + + while (sc1 < c1) { + k = k + 1 + sc1 = srl[1,k] + } + + while (sc1 <= c2) { + sid = ids[srl[3,k]] + + # Check for split piece that was eliminated. + if (sid == 0) { + k = k + 1 + sc1 = srl[1,k] + next + } + sid = ids[sid] + if (sid == 0) { + k = k + 1 + sc1 = srl[1,k] + next + } + + # Add split piece to output. + if (sc1 > c1) { + j = j + 1 + orl[1,j] = c1 + orl[2,j] = sc1 - c1 + orl[3,j] = id + } + n = srl[2,k] + j = j + 1 + orl[1,j] = sc1 + orl[2,j] = n + orl[3,j] = OBJ_NUM(objs[sid]) + c1 = sc1 + n + + k = k + 1 + sc1 = srl[1,k] + } + + if (c1 <= c2) { + j = j + 1 + orl[1,j] = c1 + orl[2,j] = c2 - c1 + 1 + orl[3,j] = id + } + } + orl[1,1] = j + orl[2,1] = nc + call pmplri (om, v, orl, 0, nc, PIX_SRC) + } +end diff --git a/noao/nproto/ace/t_acedetect.x b/noao/nproto/ace/t_acedetect.x new file mode 100644 index 00000000..8c211cef --- /dev/null +++ b/noao/nproto/ace/t_acedetect.x @@ -0,0 +1,1195 @@ +include <error.h> +include <fset.h> +include <imset.h> +include <pmset.h> +include <imhdr.h> +include "ace.h" +include "acedetect.h" +include "cat.h" + + +# T_ACEDETECT -- Detect objects in images. +# This entry procedure simply sets up the parameters. + +procedure t_acedetect () + +pointer par # Parameters + +pointer sp, str + +bool clgetb() +int clgwrd(), imtopenp(), imtopen(), clpopnu(), fntopnb() + +begin + call smark (sp) + call salloc (par, PAR_LEN, TY_STRUCT) + call salloc (str, SZ_LINE, TY_CHAR) + call aclri (Memi[par], PAR_LEN) + + # Get list parameters. + PAR_IMLIST(par,1) = imtopenp ("images") + PAR_BPMLIST(par,1) = imtopenp ("masks") + PAR_SKYLIST(par,1) = imtopenp ("skys") + PAR_SIGLIST(par,1) = imtopenp ("sigmas") + PAR_EXPLIST(par,1) = imtopenp ("exps") + PAR_GAINLIST(par,1) = imtopenp ("gains") + PAR_SCALELIST(par,1) = fntopnb ("", NO) + + PAR_IMLIST(par,2) = imtopen ("") + PAR_BPMLIST(par,2) = imtopen ("") + PAR_SKYLIST(par,2) = imtopen ("") + PAR_SIGLIST(par,2) = imtopen ("") + PAR_EXPLIST(par,2) = imtopen ("") + PAR_GAINLIST(par,2) = imtopen ("") + PAR_SCALELIST(par,2) = fntopnb ("", NO) + + PAR_OMLIST(par) = imtopenp ("objmasks") + PAR_OMTYPE(par) = clgwrd ("omtype", Memc[str], SZ_LINE, OM_TYPES) + PAR_INCATLIST(par) = imtopen ("") + PAR_OUTCATLIST(par) = imtopenp ("catalogs") + PAR_CATDEFLIST(par) = clpopnu ("catdefs") + PAR_LOGLIST(par) = clpopnu ("logfiles") + + PAR_OUTSKYLIST(par) = imtopen ("") + PAR_OUTSIGLIST(par) = imtopen ("") + + call clgstr ("extnames", PAR_EXTNAMES(par), PAR_SZSTR) + + # Get other parameters. + # The parameter structures flag whether an operation is requested. + #if (clgetb ("dosky")) + call sky_pars ("open", "", PAR_SKY(par)) + if (clgetb ("dodetect")) + call det_pars ("open", "", PAR_DET(par)) + if (clgetb ("dosplit")) + call spt_pars ("open", "", PAR_SPT(par)) + if (clgetb ("dogrow")) + call grw_pars ("open", "", PAR_GRW(par)) + if (clgetb ("doevaluate")) + call evl_pars ("open", "", PAR_EVL(par)) + + # Do the detection. + call aceall (par) + + # Finish up. + call sky_pars ("close", "", PAR_SKY(par)) + call det_pars ("close", "", PAR_DET(par)) + call spt_pars ("close", "", PAR_SPT(par)) + call grw_pars ("close", "", PAR_GRW(par)) + call evl_pars ("close", "", PAR_EVL(par)) + + call imtclose (PAR_OUTSIGLIST(par)) + call imtclose (PAR_OUTSKYLIST(par)) + + call clpcls (PAR_LOGLIST(par)) + call imtclose (PAR_OMLIST(par)) + call clpcls (PAR_CATDEFLIST(par)) + call imtclose (PAR_OUTCATLIST(par)) + call imtclose (PAR_INCATLIST(par)) + + call clpcls (PAR_SCALELIST(par,2)) + call imtclose (PAR_GAINLIST(par,2)) + call imtclose (PAR_EXPLIST(par,2)) + call imtclose (PAR_SIGLIST(par,2)) + call imtclose (PAR_SKYLIST(par,2)) + call imtclose (PAR_BPMLIST(par,2)) + call imtclose (PAR_IMLIST(par,2)) + + call clpcls (PAR_SCALELIST(par,1)) + call imtclose (PAR_GAINLIST(par,1)) + call imtclose (PAR_EXPLIST(par,1)) + call imtclose (PAR_SIGLIST(par,1)) + call imtclose (PAR_SKYLIST(par,1)) + call imtclose (PAR_BPMLIST(par,1)) + call imtclose (PAR_IMLIST(par,1)) + + call sfree (sp) +end + + +# T_ACEEVALUATE -- Evaluate objects. +# This entry procedure simply sets up the parameters. + +procedure t_aceevaluate () + +pointer par # Parameters + +pointer sp, str + +int imtopenp(), imtopen(), clpopnu(), fntopnb() + +begin + call smark (sp) + call salloc (par, PAR_LEN, TY_STRUCT) + call salloc (str, SZ_LINE, TY_CHAR) + call aclri (Memi[par], PAR_LEN) + + # Get list parameters. + PAR_IMLIST(par,1) = imtopenp ("images") + PAR_BPMLIST(par,1) = imtopen ("") + PAR_SKYLIST(par,1) = imtopenp ("skys") + PAR_SIGLIST(par,1) = imtopenp ("sigmas") + PAR_EXPLIST(par,1) = imtopenp ("exps") + PAR_GAINLIST(par,1) = imtopenp ("gains") + PAR_SCALELIST(par,1) = fntopnb ("", NO) + + PAR_IMLIST(par,2) = imtopen ("") + PAR_BPMLIST(par,2) = imtopen ("") + PAR_SKYLIST(par,2) = imtopen ("") + PAR_SIGLIST(par,2) = imtopen ("") + PAR_EXPLIST(par,2) = imtopen ("") + PAR_GAINLIST(par,2) = imtopen ("") + PAR_SCALELIST(par,2) = fntopnb ("", NO) + + PAR_OMLIST(par) = imtopenp ("objmasks") + PAR_OMTYPE(par) = OM_ALL + PAR_INCATLIST(par) = imtopenp ("incatalogs") + PAR_OUTCATLIST(par) = imtopenp ("outcatalogs") + PAR_CATDEFLIST(par) = clpopnu ("catdefs") + PAR_LOGLIST(par) = clpopnu ("logfiles") + + PAR_OUTSKYLIST(par) = imtopen ("") + PAR_OUTSIGLIST(par) = imtopen ("") + + # Get other parameters. + # The parameter structures flag whether an operation is requested. + call sky_pars ("open", "", PAR_SKY(par)) + call evl_pars ("open", "", PAR_EVL(par)) + + # Do the detection. + call aceall (par) + + # Finish up. + call sky_pars ("close", "", PAR_SKY(par)) + call det_pars ("close", "", PAR_DET(par)) + call spt_pars ("close", "", PAR_SPT(par)) + call grw_pars ("close", "", PAR_GRW(par)) + call evl_pars ("close", "", PAR_EVL(par)) + + call imtclose (PAR_OUTSIGLIST(par)) + call imtclose (PAR_OUTSKYLIST(par)) + + call clpcls (PAR_LOGLIST(par)) + call imtclose (PAR_OMLIST(par)) + call clpcls (PAR_CATDEFLIST(par)) + call imtclose (PAR_INCATLIST(par)) + call imtclose (PAR_OUTCATLIST(par)) + + call clpcls (PAR_SCALELIST(par,2)) + call imtclose (PAR_GAINLIST(par,2)) + call imtclose (PAR_EXPLIST(par,2)) + call imtclose (PAR_SIGLIST(par,2)) + call imtclose (PAR_SKYLIST(par,2)) + call imtclose (PAR_BPMLIST(par,2)) + call imtclose (PAR_IMLIST(par,2)) + + call clpcls (PAR_SCALELIST(par,1)) + call imtclose (PAR_GAINLIST(par,1)) + call imtclose (PAR_EXPLIST(par,1)) + call imtclose (PAR_SIGLIST(par,1)) + call imtclose (PAR_SKYLIST(par,1)) + call imtclose (PAR_BPMLIST(par,1)) + call imtclose (PAR_IMLIST(par,1)) + + call sfree (sp) +end + + +# T_ACESKY -- Output sky images. +# This entry procedure simply sets up the parameters. + +procedure t_acesky () + +pointer par # Parameters + +pointer sp, str + +int imtopenp(), imtopen(), clpopnu(), fntopnb() + +begin + call smark (sp) + call salloc (par, PAR_LEN, TY_STRUCT) + call salloc (str, SZ_LINE, TY_CHAR) + call aclri (Memi[par], PAR_LEN) + + # Get list parameters. + PAR_IMLIST(par,1) = imtopenp ("images") + PAR_OUTSKYLIST(par) = imtopenp ("skyimages") + PAR_OUTSIGLIST(par) = imtopenp ("sigmaimages") + PAR_BPMLIST(par,1) = imtopen ("") + PAR_SKYLIST(par,1) = imtopenp ("skys") + PAR_SIGLIST(par,1) = imtopenp ("sigmas") + PAR_EXPLIST(par,1) = imtopenp ("exps") + PAR_GAINLIST(par,1) = imtopenp ("gains") + PAR_SCALELIST(par,1) = fntopnb ("", NO) + + PAR_IMLIST(par,2) = imtopen ("") + PAR_BPMLIST(par,2) = imtopen ("") + PAR_SKYLIST(par,2) = imtopen ("") + PAR_SIGLIST(par,2) = imtopen ("") + PAR_EXPLIST(par,2) = imtopen ("") + PAR_GAINLIST(par,2) = imtopen ("") + PAR_SCALELIST(par,2) = fntopnb ("", NO) + + PAR_OMLIST(par) = imtopen ("") + PAR_OMTYPE(par) = OM_ALL + PAR_INCATLIST(par) = imtopen ("") + PAR_OUTCATLIST(par) = imtopen ("") + PAR_CATDEFLIST(par) = fntopnb ("", NO) + PAR_LOGLIST(par) = clpopnu ("logfiles") + + # Do the detection. + call aceall (par) + + # Finish up. + call sky_pars ("close", "", PAR_SKY(par)) + call det_pars ("close", "", PAR_DET(par)) + call spt_pars ("close", "", PAR_SPT(par)) + call grw_pars ("close", "", PAR_GRW(par)) + call evl_pars ("close", "", PAR_EVL(par)) + + call imtclose (PAR_OUTSIGLIST(par)) + call imtclose (PAR_OUTSKYLIST(par)) + + call clpcls (PAR_LOGLIST(par)) + call imtclose (PAR_OMLIST(par)) + call clpcls (PAR_CATDEFLIST(par)) + call imtclose (PAR_INCATLIST(par)) + call imtclose (PAR_OUTCATLIST(par)) + + call clpcls (PAR_SCALELIST(par,2)) + call imtclose (PAR_GAINLIST(par,2)) + call imtclose (PAR_EXPLIST(par,2)) + call imtclose (PAR_SIGLIST(par,2)) + call imtclose (PAR_SKYLIST(par,2)) + call imtclose (PAR_BPMLIST(par,2)) + call imtclose (PAR_IMLIST(par,2)) + + call clpcls (PAR_SCALELIST(par,1)) + call imtclose (PAR_GAINLIST(par,1)) + call imtclose (PAR_EXPLIST(par,1)) + call imtclose (PAR_SIGLIST(par,1)) + call imtclose (PAR_SKYLIST(par,1)) + call imtclose (PAR_BPMLIST(par,1)) + call imtclose (PAR_IMLIST(par,1)) + + call sfree (sp) +end + + +# T_DIFFDETECT -- Detect objects in the difference of images. + +procedure t_diffdetect () + +pointer par # Parameters + +pointer sp, str + +int imtopenp(), imtopen(), clpopnu() + +begin + call smark (sp) + call salloc (par, PAR_LEN, TY_STRUCT) + call salloc (str, SZ_LINE, TY_CHAR) + call aclri (Memi[par], PAR_LEN) + + # Get list parameters. + PAR_IMLIST(par,1) = imtopenp ("images") + PAR_BPMLIST(par,1) = imtopenp ("masks") + PAR_SKYLIST(par,1) = imtopenp ("skys") + PAR_SIGLIST(par,1) = imtopenp ("sigmas") + PAR_EXPLIST(par,1) = imtopenp ("exps") + PAR_GAINLIST(par,1) = imtopenp ("gains") + PAR_SCALELIST(par,1) = clpopnu ("scales") + + PAR_IMLIST(par,2) = imtopenp ("rimages") + PAR_BPMLIST(par,2) = imtopenp ("rmasks") + PAR_SKYLIST(par,2) = imtopenp ("rskys") + PAR_SIGLIST(par,2) = imtopenp ("rsigmas") + PAR_EXPLIST(par,2) = imtopenp ("rexps") + PAR_GAINLIST(par,2) = imtopen ("") + PAR_SCALELIST(par,2) = clpopnu ("rscales") + + PAR_OMLIST(par) = imtopenp ("objmasks") + PAR_OMTYPE(par) = OM_ALL + PAR_INCATLIST(par) = imtopen ("") + PAR_OUTCATLIST(par) = imtopenp ("catalogs") + PAR_CATDEFLIST(par) = clpopnu ("catdefs") + PAR_LOGLIST(par) = clpopnu ("logfiles") + + PAR_OUTSKYLIST(par) = imtopen ("") + PAR_OUTSIGLIST(par) = imtopen ("") + + # Get other parameters. + call sky_pars ("open", "", PAR_SKY(par)) + call det_pars ("diff", "", PAR_DET(par)) + call grw_pars ("open", "", PAR_GRW(par)) + call evl_pars ("open", "", PAR_EVL(par)) + + # Do the detection. + call aceall (par) + + # Finish up. + call sky_pars ("close", "", PAR_SKY(par)) + call det_pars ("close", "", PAR_DET(par)) + call spt_pars ("close", "", PAR_SPT(par)) + call grw_pars ("close", "", PAR_GRW(par)) + call evl_pars ("close", "", PAR_EVL(par)) + + call imtclose (PAR_OUTSIGLIST(par)) + call imtclose (PAR_OUTSKYLIST(par)) + + call clpcls (PAR_LOGLIST(par)) + call imtclose (PAR_OMLIST(par)) + call clpcls (PAR_CATDEFLIST(par)) + call imtclose (PAR_INCATLIST(par)) + call imtclose (PAR_OUTCATLIST(par)) + + call clpcls (PAR_SCALELIST(par,2)) + call imtclose (PAR_GAINLIST(par,2)) + call imtclose (PAR_EXPLIST(par,2)) + call imtclose (PAR_SIGLIST(par,2)) + call imtclose (PAR_SKYLIST(par,2)) + call imtclose (PAR_BPMLIST(par,2)) + call imtclose (PAR_IMLIST(par,2)) + + call clpcls (PAR_SCALELIST(par,1)) + call imtclose (PAR_GAINLIST(par,1)) + call imtclose (PAR_EXPLIST(par,1)) + call imtclose (PAR_SIGLIST(par,1)) + call imtclose (PAR_SKYLIST(par,1)) + call imtclose (PAR_BPMLIST(par,1)) + call imtclose (PAR_IMLIST(par,1)) + + call sfree (sp) +end + + + +# ACEALL -- Expand input list and set filenames. +# This calls ACE for each image to be analyzed. + +procedure aceall (par) + +pointer par #I Parameters + +int i, j, k, list, imext +pointer sp, str +pointer image[4], bpmask[4], skyname[4], signame[4], expname[4], gainname[4] +pointer incat[2], outcat[2], objmask[2], outsky[2], outsig[2], scalestr[2] +pointer catdef, logfile +pointer im, ptr + +int nowhite(), mscextensions(), strldxs(), strlen() +int imtlen(), imtgetim(), clplen(), clgfil() +pointer immap() +errchk immap + +begin + call smark (sp) + + # Allocate memory for all the file names. The first half of each + # array of names is for image names including extensions and the + # second half is for cluster names. The names are initialized + # to EOS and are only filled in if specified. + + do j = 1, 4 { + call salloc (image[j], SZ_FNAME, TY_CHAR) + call salloc (bpmask[j], SZ_FNAME, TY_CHAR) + call salloc (skyname[j], SZ_FNAME, TY_CHAR) + call salloc (signame[j], SZ_FNAME, TY_CHAR) + call salloc (expname[j], SZ_FNAME, TY_CHAR) + call salloc (gainname[j], SZ_FNAME, TY_CHAR) + Memc[image[j]] = EOS + Memc[bpmask[j]] = EOS + Memc[skyname[j]] = EOS + Memc[signame[j]] = EOS + Memc[expname[j]] = EOS + Memc[gainname[j]] = EOS + } + do j = 1, 2 { + call salloc (objmask[j], SZ_FNAME, TY_CHAR) + call salloc (incat[j], SZ_FNAME, TY_CHAR) + call salloc (outcat[j], SZ_FNAME, TY_CHAR) + call salloc (outsky[j], SZ_FNAME, TY_CHAR) + call salloc (outsig[j], SZ_FNAME, TY_CHAR) + call salloc (scalestr[j], SZ_FNAME, TY_CHAR) + Memc[objmask[j]] = EOS + Memc[incat[j]] = EOS + Memc[outcat[j]] = EOS + Memc[outsky[j]] = EOS + Memc[outsig[j]] = EOS + Memc[scalestr[j]] = EOS + } + call salloc (catdef, SZ_FNAME, TY_CHAR) + call salloc (logfile, SZ_FNAME, TY_CHAR) + Memc[catdef] = EOS + Memc[logfile] = EOS + + call salloc (str, SZ_LINE, TY_CHAR) + + # Check lists match. + j = imtlen (PAR_IMLIST(par,1)) + i = imtlen (PAR_BPMLIST(par,1)) + if (i > 1 && i != j) + call error (1, + "Image and bad pixel mask lists do not match") + i = imtlen (PAR_SKYLIST(par,1)) + if (i > 1 && i != j) + call error (1, + "Image and sky lists do not match") + i = imtlen (PAR_SIGLIST(par,1)) + if (i > 1 && i != j) + call error (1, + "Image and sky sigma lists do not match") + i = imtlen (PAR_EXPLIST(par,1)) + if (i > 1 && i != j) + call error (1, + "Image and exposure map lists do not match") + i = imtlen (PAR_GAINLIST(par,1)) + if (i > 1 && i != j) + call error (1, + "Image and measurement gain lists do not match") + i = clplen (PAR_SCALELIST(par,1)) + if (i > 1 && i != j) + call error (1, + "Image and scale lists do not match") + + k = imtlen (PAR_IMLIST(par,2)) + if (k > 1 && i != j) + call error (1, + "Image and reference lists do not match") + i = imtlen (PAR_BPMLIST(par,2)) + if (i > 1 && i != k) + call error (1, + "Reference image bad pixel mask lists do not match") + i = imtlen (PAR_SKYLIST(par,2)) + if (i > 1 && i != k) + call error (1, + "Reference image and sky lists do not match") + i = imtlen (PAR_SIGLIST(par,2)) + if (i > 1 && i != k) + call error (1, + "Reference image and sky sigma lists do not match") + i = imtlen (PAR_EXPLIST(par,2)) + if (i > 1 && i != k) + call error (1, + "Reference image and exposure map lists do not match") + i = imtlen (PAR_GAINLIST(par,2)) + if (i > 1 && i != j) + call error (1, + "Reference image and measurement gain lists do not match") + i = clplen (PAR_SCALELIST(par,2)) + if (i > 1 && i != k) + call error (1, + "Reference image and scale lists do not match") + + i = clplen (PAR_INCATLIST(par)) + if (i > 0 && i != j) + call error (1, + "Input image and input catalog lists do not match") + i = clplen (PAR_OUTCATLIST(par)) + if (i > 0 && i != j) + call error (1, + "Input image and output catalog lists do not match") + i = clplen (PAR_CATDEFLIST(par)) + if (i > 1 && i != j) + call error (1, + "Input image and catalog definition lists do not match") + i = imtlen (PAR_OMLIST(par)) + if (i > 0 && i != j) + call error (1, + "Input image and object mask lists do not match") + i = clplen (PAR_LOGLIST(par)) + if (i > 1 && i != j) + call error (1, + "Input image and logfile lists do not match") + i = imtlen (PAR_OUTSKYLIST(par)) + if (i > 0 && i != j) + call error (1, + "Input image and output sky lists do not match") + i = imtlen (PAR_OUTSIGLIST(par)) + if (i > 0 && i != j) + call error (1, + "Input image and output sigma lists do not match") + + # Do each input image cluster. + while (imtgetim (PAR_IMLIST(par,1), Memc[image[1]], SZ_FNAME) != EOF) { + if (imtgetim (PAR_IMLIST(par,2), Memc[str], SZ_LINE) != EOF) + call strcpy (Memc[str], Memc[image[2]], SZ_FNAME) + + # Get associated cluster names. + # Initialize image names to the cluster names. + # Strip whitespace to check for no name. + do j = 1, 2 { + if (imtgetim (PAR_BPMLIST(par,j), Memc[str], SZ_LINE) != EOF) + call strcpy (Memc[str], Memc[bpmask[j]], SZ_FNAME) + if (imtgetim (PAR_SKYLIST(par,j), Memc[str], SZ_LINE) != EOF) + call strcpy (Memc[str], Memc[skyname[j]], SZ_FNAME) + if (imtgetim (PAR_SIGLIST(par,j), Memc[str], SZ_LINE) != EOF) + call strcpy (Memc[str], Memc[signame[j]], SZ_FNAME) + if (imtgetim (PAR_EXPLIST(par,j), Memc[str], SZ_LINE) != EOF) + call strcpy (Memc[str], Memc[expname[j]], SZ_FNAME) + if (imtgetim (PAR_GAINLIST(par,j), Memc[str], SZ_LINE) != EOF) + call strcpy (Memc[str], Memc[gainname[j]], SZ_FNAME) + if (clgfil (PAR_SCALELIST(par,j), Memc[str], SZ_LINE) != EOF) + call strcpy (Memc[str], Memc[scalestr[j]], SZ_FNAME) + + i = nowhite (Memc[bpmask[j]], Memc[bpmask[j]], SZ_FNAME) + i = nowhite (Memc[skyname[j]], Memc[skyname[j]], SZ_FNAME) + i = nowhite (Memc[signame[j]], Memc[signame[j]], SZ_FNAME) + i = nowhite (Memc[expname[j]], Memc[expname[j]], SZ_FNAME) + i = nowhite (Memc[gainname[j]], Memc[gainname[j]], SZ_FNAME) + i = nowhite (Memc[scalestr[j]], Memc[scalestr[j]], SZ_FNAME) + } + + if (clgfil (PAR_INCATLIST(par), Memc[str], SZ_LINE) != EOF) + call strcpy (Memc[str], Memc[incat[1]], SZ_FNAME) + if (clgfil (PAR_OUTCATLIST(par), Memc[str], SZ_LINE) != EOF) + call strcpy (Memc[str], Memc[outcat[1]], SZ_FNAME) + if (imtgetim (PAR_OMLIST(par), Memc[str], SZ_LINE) != EOF) + call strcpy (Memc[str], Memc[objmask[1]], SZ_FNAME) + if (imtgetim (PAR_OUTSKYLIST(par), Memc[str], SZ_LINE) != EOF) + call strcpy (Memc[str], Memc[outsky[1]], SZ_FNAME) + if (imtgetim (PAR_OUTSIGLIST(par), Memc[str], SZ_LINE) != EOF) + call strcpy (Memc[str], Memc[outsig[1]], SZ_FNAME) + if (clgfil (PAR_CATDEFLIST(par), Memc[str], SZ_LINE) != EOF) + call strcpy (Memc[str], Memc[catdef], SZ_FNAME) + if (clgfil (PAR_LOGLIST(par), Memc[str], SZ_LINE) != EOF) + call strcpy (Memc[str], Memc[logfile], SZ_FNAME) + + i = nowhite (Memc[incat[1]], Memc[incat[1]], SZ_FNAME) + i = nowhite (Memc[outcat[1]], Memc[outcat[1]], SZ_FNAME) + i = nowhite (Memc[objmask[1]], Memc[objmask[1]], SZ_FNAME) + i = nowhite (Memc[outsky[1]], Memc[outsky[1]], SZ_FNAME) + i = nowhite (Memc[outsig[1]], Memc[outsig[1]], SZ_FNAME) + i = nowhite (Memc[catdef], Memc[catdef], SZ_FNAME) + i = nowhite (Memc[logfile], Memc[logfile], SZ_FNAME) + + # Expand clusters to images. As a special case, if the input is + # an explicit extension image then don't treat the filenames as MEF. + list = mscextensions (Memc[image[1]], "0-", PAR_EXTNAMES(par), + "", NO, YES, NO, "", NO, imext) + if (strldxs ("[", Memc[image[1]]) != 0) + imext = NO + while (imtgetim (list, Memc[image[3]], SZ_FNAME) != EOF) { + call strcpy (Memc[image[2]], Memc[image[4]], SZ_FNAME) + do j = 1, 2 { + call strcpy (Memc[bpmask[j]], Memc[bpmask[j+2]], SZ_FNAME) + call strcpy (Memc[skyname[j]], Memc[skyname[j+2]], SZ_FNAME) + call strcpy (Memc[signame[j]], Memc[signame[j+2]], SZ_FNAME) + call strcpy (Memc[expname[j]], Memc[expname[j+2]], SZ_FNAME) + call strcpy (Memc[gainname[j]],Memc[gainname[j+2]],SZ_FNAME) + } + call strcpy (Memc[incat[1]], Memc[incat[2]], SZ_FNAME) + call strcpy (Memc[outcat[1]], Memc[outcat[2]], SZ_FNAME) + call strcpy (Memc[objmask[1]], Memc[objmask[2]], SZ_FNAME) + call strcpy (Memc[outsky[1]], Memc[outsky[2]], SZ_FNAME) + call strcpy (Memc[outsig[1]], Memc[outsig[2]], SZ_FNAME) + + # Add extensions if needed. + i = strldxs ("[", Memc[image[3]]) + if (imext == YES && i > 0) { + i = image[3]+i-1 + call strcpy (Memc[i], Memc[str], SZ_LINE) + Memc[str+strldxs ("]", Memc[str])-1] = EOS + call strcat (",append]", Memc[str], SZ_LINE) + + if (Memc[image[2]]!=EOS && + strldxs ("[", Memc[image[2]]) == 0) + call strcat (Memc[i], Memc[image[4]], SZ_FNAME) + do j = 1, 2 { + if (Memc[bpmask[j]]!=EOS && Memc[bpmask[j]]!='!' && + strldxs ("[", Memc[bpmask[j]]) == 0) + call strcat (Memc[i], Memc[bpmask[j+2]], SZ_FNAME) + if (Memc[skyname[j]]!=EOS && Memc[skyname[j]]!='!' && + strldxs ("[", Memc[skyname[j]]) == 0) + call strcat (Memc[str], Memc[skyname[j+2]], + SZ_FNAME) + if (Memc[signame[j]]!=EOS && Memc[signame[j]]!='!' && + strldxs ("[", Memc[signame[j]]) == 0) + call strcat (Memc[str], Memc[signame[j+2]], + SZ_FNAME) + if (Memc[expname[j]]!=EOS && Memc[expname[j]]!='!' && + strldxs ("[", Memc[expname[j]]) == 0) + call strcat (Memc[i], Memc[expname[j+2]], SZ_FNAME) + if (Memc[gainname[j]]!=EOS && Memc[gainname[j]]!='!' && + strldxs ("[", Memc[gainname[j]]) == 0) + call strcat (Memc[i], Memc[gainname[j+2]], SZ_FNAME) + } + if (Memc[incat[1]]!=EOS && Memc[incat[1]]!='!' && + strldxs ("[", Memc[incat[1]]) == 0) + call strcat (Memc[i], Memc[incat[2]], SZ_FNAME) + if (Memc[outcat[1]]!=EOS && Memc[outcat[1]]!='!' && + strldxs ("[", Memc[outcat[1]]) == 0) + call strcat (Memc[i], Memc[outcat[2]], SZ_FNAME) + if (Memc[outsky[1]]!=EOS && Memc[outsky[1]]!='!' && + strldxs ("[", Memc[outsky[1]]) == 0) + call strcat (Memc[str], Memc[outsky[2]], SZ_FNAME) + if (Memc[outsig[1]]!=EOS && Memc[outsig[1]]!='!' && + strldxs ("[", Memc[outsig[1]]) == 0) + call strcat (Memc[str], Memc[outsig[2]], SZ_FNAME) + if (Memc[objmask[1]]!=EOS && Memc[objmask[1]]!='!' && + strldxs ("[", Memc[objmask[1]]) == 0) + call strcat (Memc[str], Memc[objmask[2]], SZ_FNAME) + } + + # Append DATASEC. + do i = 3, 4 { + if (Memc[image[i]] == EOS) + next + iferr { + im = NULL + ptr = immap (Memc[image[i]], READ_ONLY, 0); im = ptr + j = strlen (Memc[image[i]]) + call imgstr (im, "DATASEC", Memc[image[i]+j], + SZ_FNAME-j) + } then + ; + if (im != NULL) + call imunmap (im) + } + + # Process the image. + call ace (par, image[3], bpmask[3], skyname[3], signame[3], + expname[3], gainname[3], scalestr, Memc[incat[2]], + Memc[outcat[2]], Memc[objmask[2]], Memc[outsky[2]], + Memc[outsig[2]], Memc[catdef], Memc[logfile]) + + } + call imtclose (list) + } + + call sfree (sp) +end + + +# ACE -- Do all the primary steps for a single input image/catalog. + +procedure ace (par, image, bpmask, skyname, signame, expname, gainname, + scalestr, incat, outcat, objmask, outsky, outsig, catdef, logfile) + +pointer par #I Parameters +pointer image[2], bpmask[2], skyname[2], signame[2], expname[2] +pointer gainname[2], scalestr[2] +char incat[ARB], outcat[ARB], objmask[ARB], outsky[ARB], outsig[ARB] +char catdef[ARB], logfile[ARB] + +bool dosky[2], dosig[2] +int i, j, logfd, offset[2,2] +real scale[2] +pointer sp, bpname[2], str +pointer im[2], bpm[2], skymap[2], sigmap[2], expmap[2], gainmap[2] +pointer ptr, cat, om, omim, siglevmap, siglevels + +bool strne() +real imgetr() +int ctor(), strdic(), fnextn(), imstati() +int open(), access(), imaccess() +pointer immap(), xt_pmmap(), pm_open(), map_open() + +errchk open, immap, xt_pmmap, pm_newmask +errchk cnvparse, sky, detect, split, grow, evaluate, map_open +errchk catdefine, catopen, catgets + +#pointer bpm1, im_pmmapo() + +begin + call smark (sp) + call salloc (bpname[1], SZ_FNAME, TY_CHAR) + call salloc (bpname[2], SZ_FNAME, TY_CHAR) + call salloc (str, SZ_LINE, TY_CHAR) + + # Deal with image types if needed. + if (Memc[bpmask[1]] != EOS && Memc[bpmask[1]] != '!') + call xt_maskname (Memc[bpmask[1]], "pl", READ_ONLY, Memc[bpmask[1]], + SZ_FNAME) + if (Memc[bpmask[2]] != EOS && Memc[bpmask[2]] != '!') + call xt_maskname (Memc[bpmask[2]], "pl", READ_ONLY, Memc[bpmask[2]], + SZ_FNAME) + if (objmask[1] != EOS && objmask[1] != '!') + call xt_maskname (objmask, "pl", NEW_IMAGE, objmask, SZ_FNAME) + if (incat[1] != EOS) { + i = fnextn (incat, Memc[str], SZ_LINE) + if (i > 0) + i = strdic (Memc[str], Memc[str], SZ_LINE, CATEXTNS) + #if (i == 0) + # call strcat (".fits", incat, SZ_FNAME) + } + if (outcat[1] != EOS) { + i = fnextn (outcat, Memc[str], SZ_LINE) + if (i > 0) + i = strdic (Memc[str], Memc[str], SZ_LINE, CATEXTNS) + #if (i == 0) + # call strcat (".fits", outcat, SZ_FNAME) + } + + iferr { + # Initialize for error recovery. + do j = 1, 2 { + im[j] = NULL; bpm[j] = NULL; skymap[j] = NULL + sigmap[j] = NULL; expmap[j] = NULL; gainmap[j] = NULL + } + cat = NULL; logfd = NULL + + # Log file. + if (logfile[1] != EOS) { + ptr = open (logfile, APPEND, TEXT_FILE) + logfd = ptr + call fseti (logfd, F_FLUSHNL, YES) + } + + # Open images. + if (PAR_DET(par) == NULL && PAR_EVL(par) == NULL) + ptr = immap (Memc[image[1]], READ_ONLY, 0) + else { + iferr (ptr = immap (Memc[image[1]], READ_WRITE, 0)) + ptr = immap (Memc[image[1]], READ_ONLY, 0) + } + im[1] = ptr + + # Open input catalog and object mask. + if (PAR_DET(par) == NULL && PAR_EVL(par) == NULL) + ; + else if (PAR_DET(par) == NULL) { + if (incat[1] == EOS) { + call sprintf (Memc[str], SZ_LINE, + "No input catalog for image (%s)") + call pargstr (Memc[image[1]]) + call error (1, Memc[str]) + } else { + if (access (incat, 0, 0) != YES) { + call sprintf (Memc[str], SZ_LINE, + "Catalog does not exist (%s)") + call pargstr (incat) + call error (1, Memc[str]) + } + } + if (outcat[1]!=EOS && strne(incat,outcat)) { + if (access (outcat, 0, 0) == YES) { + call sprintf (Memc[str], SZ_LINE, + "Catalog already exists (%s)") + call pargstr (outcat) + call error (1, Memc[str]) + } + } + call catopen (cat, incat, outcat, catdef) + call catrobjs (cat, "") + if (objmask[1] == EOS) + call catgets (cat, "mask", objmask, SZ_FNAME) + omim = xt_pmmap (objmask, im[1], objmask, SZ_FNAME) + om = imstati (omim, IM_PMDES) + } else { + # Check for existing catalog. Check catalog definitions. + if (outcat[1] != EOS) { + if (access (outcat, 0, 0) == YES) { + call sprintf (Memc[str], SZ_LINE, + "Catalog already exists (%s)") + call pargstr (outcat) + call error (1, Memc[str]) + } + call catdefine (NULL, NULL, catdef) + } + call catopen (cat, "", "", "") + + # Check for existing mask and initialize. + if (objmask[1] != EOS) { + if (imaccess (objmask, 0) == YES) { + call sprintf (Memc[str], SZ_LINE, + "Object mask already exists (%s)") + call pargstr (objmask) + call error (1, Memc[str]) + } + } + } + + # Open bad pixel mask. + ptr = xt_pmmap (Memc[bpmask[1]], im[1], Memc[bpname[1]], + SZ_FNAME) + bpm[1] = ptr + + # Do reference image. + if (Memc[image[2]] != EOS) { +# if (Memc[bpmask[2]] == EOS) +# call imgimage (Memc[image[2]], Memc[image[2]], SZ_FNAME) + + iferr (ptr = immap (Memc[image[2]], READ_WRITE, 0)) + ptr = immap (Memc[image[2]], READ_ONLY, 0) + im[2] = ptr + + # Set offsets. + call get_offsets (im, 2, "world", offset) + offset[1,2] = offset[1,2] - offset[1,1] + offset[2,2] = offset[2,2] - offset[2,1] + +# # Attempt to make an overlapping image section if +# # there is no bad pixel mask. This is a kludge. +# if (Memc[bpmask[2]] == EOS) { +# c1 = max (1, 1-offset[1,2]) +# c2 = min (IM_LEN(im[2],1), IM_LEN(im[1],1)-offset[1,2]) +# l1 = max (1, 1-offset[2,2]) +# l2 = min (IM_LEN(im[2],2), IM_LEN(im[1],2)-offset[2,2]) +# if (c1!=1 || c2!=IM_LEN(im[2],1) || +# l1!=1 || l2!=IM_LEN(im[2],2)) { +# call sprintf (Memc[str], SZ_LINE, "%s[%d:%d,%d:%d]") +# call pargstr (Memc[image[2]]) +# call pargi (c1) +# call pargi (c2) +# call pargi (l1) +# call pargi (l2) +# call strcpy (Memc[str], Memc[image[2]], SZ_FNAME) +# call imunmap (im[2]) +# iferr (ptr = immap (Memc[image[2]], READ_WRITE, 0)) +# ptr = immap (Memc[image[2]], READ_ONLY, 0) +# im[2] = ptr +# +# call get_offsets (im, 2, "world", offset) +# offset[1,2] = offset[1,2] - offset[1,1] +# offset[2,2] = offset[2,2] - offset[2,1] +# PAR_OFFSET(par,1) = offset[1,2] +# PAR_OFFSET(par,2) = offset[2,2] +# } +# } + + ptr = xt_pmmap (Memc[bpmask[2]], im[2], Memc[bpname[2]], + SZ_FNAME) + bpm[2] = ptr + + i = 1 + if (Memc[scalestr[1]] == EOS) + scale[1] = 1. + else if (Memc[scalestr[1]] == '!') { + iferr (scale[1] = imgetr (im[1], Memc[scalestr[1]+1])) + call error (1, "Bad scale for input image") + } else if (ctor (Memc[scalestr[1]], i, scale[1]) == 0) + call error (1, "Bad scale for image") + + i = 1 + if (Memc[scalestr[2]] == EOS) + scale[2] = 1. + else if (Memc[scalestr[2]] == '!') { + iferr (scale[2] = imgetr (im[2], Memc[scalestr[2]+1])) + call error (1, "Bad scale for reference image") + } else if (ctor (Memc[scalestr[2]], i, scale[2]) == 0) + call error (1, "Bad scale for reference image") + } + + if (logfd != NULL) { + call sysid (Memc[str], SZ_LINE) + call fprintf (logfd, "ACE: %s\n") + call pargstr (Memc[str]) + call fprintf (logfd, " Image: %s - %s\n") + call pargstr (Memc[image[1]]) + call pargstr (IM_TITLE(im[1])) + if (bpm[1] != NULL) { + call fprintf (logfd, " Bad pixel mask: %s\n") + call pargstr (Memc[bpname[1]]) + } + if (im[2] != EOS) { + call fprintf (logfd, " Reference image: %s - %s\n") + call pargstr (Memc[image[2]]) + call pargstr (IM_TITLE(im[2])) + if (bpm[2] != NULL) { + call fprintf (logfd, + " Reference bad pixel mask: %s\n") + call pargstr (Memc[bpname[2]]) + } + } + } + + # Open optional maps. + do j = 1, 2 { + if (im[j] == NULL) + next + if (Memc[expname[j]] != EOS) + expmap[j] = map_open (Memc[expname[j]], im[j]) + } + do j = 1, 2 { + if (im[j] == NULL) + next + if (Memc[gainname[j]] != EOS) + gainmap[j] = map_open (Memc[gainname[j]], im[j]) + } + + # Get sky and sky sigma. + do j = 1, 2 { + dosky[j] = false + dosig[j] = false + if (im[j] == NULL) + next + if (PAR_SKY(par) == NULL) { + if (Memc[skyname[j]] != EOS) + skymap[j] = map_open (Memc[skyname[j]], im[j]) + if (Memc[signame[j]] != EOS) + sigmap[j] = map_open (Memc[signame[j]], im[j]) + } else { + if (j == 1 && om != NULL) + call sky (PAR_SKY(par), im[j], omim, expmap[j], + Memc[skyname[j]], Memc[signame[j]], + skymap[j], sigmap[j], dosky[j], dosig[j], logfd) + else + call sky (PAR_SKY(par), im[j], bpm[j], expmap[j], + Memc[skyname[j]], Memc[signame[j]], + skymap[j], sigmap[j], dosky[j], dosig[j], logfd) + } + if (skymap[j] != NULL) + call map_seti (skymap[j], "sample", 5) + if (sigmap[j] != NULL) + call map_seti (sigmap[j], "sample", 5) + } + + # Detect objects. + if (PAR_DET(par) != NULL) { + # Open object mask. + om = pm_open (NULL) + call pm_ssize (om, IM_NDIM(im[1]), IM_LEN(im[1],1), 27) + + # Initialize splitting map if needed. + if (PAR_SPT(par) != NULL) { + siglevmap = pm_open (NULL) + call pm_ssize (siglevmap, IM_NDIM(im[1]), + IM_LEN(im[1],1), 27) + } else + siglevmap = NULL + + # Detect objects. + call detect (PAR_DET(par), PAR_SPT(par), dosky, dosig, + Memc[skyname[1]], Memc[signame[1]], im, bpm, skymap, + sigmap, expmap, scale, offset[1,2], om, siglevmap, + siglevels, logfd, cat) + + # Split objects. + if (PAR_SPT(par) != NULL) + call split (PAR_SPT(par), cat, om, siglevmap, + Memr[siglevels], logfd) + + # Grow objects. + if (PAR_GRW(par) != NULL) + call grow (PAR_GRW(par), cat, om, logfd) + + # Set boundary flags and write out the object mask. + if (objmask[1] != EOS) { + if (PAR_OMTYPE(par) == OM_ALL) + call bndry (om, NULL) + call omwrite (om, objmask, PAR_OMTYPE(par), im[1], cat, + outcat, outcat, logfd) + } + } + + # Evaluate and write out the catalog. + if (PAR_EVL(par) != NULL && outcat[1] != EOS) { + if (incat[1] == EOS) + call catopen (cat, "", outcat, catdef) + call catputs (cat, "image", Memc[image[1]]) + if (objmask[1] != EOS) + call catputs (cat, "mask", objmask) + call catputs (cat, "catalog", outcat) + call catputs (cat, "objid", outcat) + + # Evaluate objects. + call evaluate (PAR_EVL(par), cat, im[1], om, skymap[1], + sigmap[1], gainmap[1], expmap[1], logfd) + + if (logfd != NULL) { + call fprintf (logfd, + " Write catalog: catalog = %s\n") + call pargstr (outcat) + } + + call catcreate (cat) + call catwcs (cat, im) + call catwhdr (cat, im) + call catwobjs (cat) + + call imastr (im[1], "CATALOG", outcat) + } + + # Output sky images. + call skyimages (outsky, outsig, im[1], skymap[1], + sigmap[1], gainmap[1], expmap[1], logfd) + + } then + call erract (EA_WARN) + + if (logfd != NULL) + call close (logfd) + if (cat != NULL) + call catclose (cat) + if (siglevmap != NULL) { + call pm_close (siglevmap) + call mfree (siglevels, TY_REAL) + } + if (omim != NULL) { + call imunmap (omim) + om = NULL + } else if (om != NULL) + call pm_close (om) + + do j = 1, 2 { + if (gainmap[j] != NULL) + call map_close (gainmap[j]) + if (expmap[j] != NULL) + call map_close (expmap[j]) + if (sigmap[j] != NULL) + call map_close (sigmap[j]) + if (skymap[j] != NULL) + call map_close (skymap[j]) + if (bpm[j] != NULL) + call imunmap (bpm[j]) + if (im[j] != NULL) + call imunmap (im[j]) + } + + call sfree (sp) +end + + +define OFFTYPES "|none|wcs|world|physical|" +define FILE 0 +define NONE 1 +define WCS 2 +define WORLD 3 +define PHYSICAL 4 + +# GET_OFFSETS -- Get offsets. + +procedure get_offsets (in, nimages, param, offsets) + +pointer in[nimages] #I Input image pointers +int nimages #I Number of images +char param[ARB] #I Offset parameter string +int offsets[2,nimages] #O Offsets + +int i, j, fd, offtype, off +real val +bool flip, streq(), fp_equald() +pointer sp, str, fname +pointer pref, lref, wref, cd, ltm, coord, section +pointer mw, ct, mw_openim(), mw_sctran(), immap() +int open(), fscan(), nscan(), strlen(), strdic() +errchk mw_openim, mw_gwtermd, mw_gltermd, mw_gaxmap +errchk mw_sctran, mw_ctrand, open, immap + +begin + call smark (sp) + call salloc (str, SZ_LINE, TY_CHAR) + call salloc (fname, SZ_LINE, TY_CHAR) + call salloc (lref, 2, TY_DOUBLE) + call salloc (wref, 2, TY_DOUBLE) + call salloc (cd, 2*2, TY_DOUBLE) + call salloc (coord, 2, TY_DOUBLE) + + call aclri (offsets, 2*nimages) + + # Parse the user offset string. If "none" then there are no offsets. + # If "world" or "wcs" then set the offsets based on the world WCS. + # If "physical" then set the offsets based on the physical WCS. + # If a file scan the offsets. + + call sscan (param) + call gargwrd (Memc[str], SZ_LINE) + if (nscan() == 0) + offtype = NONE + else { + offtype = strdic (Memc[str], Memc[fname], SZ_LINE, OFFTYPES) + if (offtype > 0 && !streq (Memc[str], Memc[fname])) + offtype = 0 + } + if (offtype == 0) + offtype = FILE + + switch (offtype) { + case NONE: + ; + case WORLD, WCS: + mw = mw_openim (in[1]) + call mw_gwtermd (mw, Memd[lref], Memd[wref], Memd[cd], 2) + ct = mw_sctran (mw, "world", "logical", 0) + call mw_ctrand (ct, Memd[wref], Memd[lref], 2) + call mw_close (mw) + + do i = 2, nimages { + mw = mw_openim (in[i]) + ct = mw_sctran (mw, "world", "logical", 0) + call mw_ctrand (ct, Memd[wref], Memd[coord], 2) + do j = 1, 2 + offsets[j,i] = nint (Memd[lref+j-1] - Memd[coord+j-1]) + call mw_close (mw) + } + case PHYSICAL: + call salloc (pref, 2, TY_DOUBLE) + call salloc (ltm, 4, TY_DOUBLE) + call salloc (section, SZ_FNAME, TY_CHAR) + + mw = mw_openim (in[1]) + call mw_gltermd (mw, Memd[ltm], Memd[coord], 2) + call mw_close (mw) + do i = 2, nimages { + mw = mw_openim (in[i]) + call mw_gltermd (mw, Memd[cd], Memd[coord], 2) + call strcpy ("[", Memc[section], SZ_FNAME) + flip = false + do j = 0, 3, 3 { + if (Memd[ltm+j] * Memd[cd+j] >= 0.) + call strcat ("*,", Memc[section], SZ_FNAME) + else { + call strcat ("-*,", Memc[section], SZ_FNAME) + flip = true + } + } + Memc[section+strlen(Memc[section])-1] = ']' + if (flip) { + call imstats (in[i], IM_IMAGENAME, Memc[fname], SZ_LINE) + call strcat (Memc[section], Memc[fname], SZ_LINE) + call imunmap (in[i]) + in[i] = immap (Memc[fname], READ_ONLY, TY_CHAR) + call mw_close (mw) + mw = mw_openim (in[i]) + call mw_gltermd (mw, Memd[cd], Memd[coord], 2) + do j = 0, 3 + if (!fp_equald (Memd[ltm+j], Memd[cd+j])) + call error (1, + "Cannot match physical coordinates") + } + call mw_close (mw) + } + + mw = mw_openim (in[1]) + ct = mw_sctran (mw, "logical", "physical", 0) + call mw_ctrand (ct, Memd[lref], Memd[pref], 2) + call mw_close (mw) + do i = 2, nimages { + mw = mw_openim (in[i]) + ct = mw_sctran (mw, "physical", "logical", 0) + call mw_ctrand (ct, Memd[pref], Memd[coord], 2) + do j = 1, 2 + offsets[j,i] = nint (Memd[lref+j-1] - Memd[coord+j-1]) + call mw_close (mw) + } + case FILE: + fd = open (Memc[str], READ_ONLY, TEXT_FILE) + i = 1 + while (fscan (fd) != EOF) { + do j = 1, 2 { + call gargr (val) + offsets[j,i] = nint (val) + } + if (nscan() == 2) + i = i + 1 + } + call close (fd) + if (i <= nimages) + call error (1, "offset file incomplete") + } + + # Adjust offsets to be positive. + do j = 1, 2 { + off = offsets[j,1] + do i = 2, nimages + off = min (off, offsets[j,i]) + do i = 1, nimages + offsets[j,i] = offsets[j,i] - off + } + + call sfree (sp) +end diff --git a/noao/nproto/ace/t_acedisplay.x b/noao/nproto/ace/t_acedisplay.x new file mode 100644 index 00000000..7b19851b --- /dev/null +++ b/noao/nproto/ace/t_acedisplay.x @@ -0,0 +1,639 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <mach.h> +include <imset.h> +include <imhdr.h> +include <error.h> +include <pmset.h> +include "display.h" +include "gwindow.h" + +# DISPLAY - Display an image. The specified image section is mapped into +# the specified section of an image display frame. The mapping involves +# a linear transformation in X and Y and a linear or logarithmic transformation +# in Z (greyscale). Images of all pixel datatypes are supported, and there +# no upper limit on the size of an image. The display device is interfaced +# to FIO as a file and is accessed herein via IMIO as just another imagefile. +# The physical characteristics of the display (i.e., X, Y, and Z resolution) +# are taken from the image header. The display frame buffer is the pixel +# storage "file". + +# This is a version of the standard display that allows the overlay mask +# to be manipuated in memory prior to displaying. + +procedure t_acedisplay() + +char image[SZ_FNAME] # Image to display +int frame # Display frame +int erase # Erase frame? + +int i +pointer sp, wdes, im, ds, ovrly + +bool clgetb() +int clgeti(), btoi() +pointer immap(), imd_mapframe1(), overlay() +errchk immap, imd_mapframe1 +errchk ds_getparams, ds_setwcs, ds_load_display, ds_erase_border + +begin + call smark (sp) + call salloc (wdes, LEN_WDES, TY_STRUCT) + call aclri (Memi[wdes], LEN_WDES) + + # Open input imagefile. + call clgstr ("image", image, SZ_FNAME) + im = immap (image, READ_ONLY, 0) + if (IM_NDIM(im) <= 0) + call error (1, "image has no pixels") + + # Open display device as an image. + frame = clgeti ("frame") + erase = btoi (clgetb ("erase")) + if (erase == YES) + ds = imd_mapframe1 (frame, WRITE_ONLY, + btoi (clgetb ("select_frame")), erase) + else + ds = imd_mapframe1 (frame, READ_WRITE, + btoi (clgetb ("select_frame")), erase) + + # Get display parameters and set up transformation. + call ds_getparams (im, ds, wdes) + + # Compute and output the screen to image pixel WCS. + call ds_setwcs (im, ds, wdes, image, frame) + + # Setup the overlay. + ovrly = overlay (W_OVRLY(wdes), im) + + # Display the image and zero the border if necessary. + call ods_load_display (im, ds, wdes, ovrly) + if (!clgetb ("erase") && clgetb ("border_erase")) + call ds_erase_border (im, ds, wdes) + + # Free storage. + call maskcolor_free (W_OCOLORS(wdes)) + call maskcolor_free (W_BPCOLORS(wdes)) + do i = 0, W_MAXWC + if (W_UPTR(W_WC(wdes,i)) != NULL) + call ds_ulutfree (W_UPTR(W_WC(wdes,i))) + if (ovrly != NULL) + call imunmap (ovrly) + call imunmap (ds) + call imunmap (im) + + call sfree (sp) +end + + +# DS_LOAD_DISPLAY -- Map an image into the display window. In general this +# involves independent linear transformations in the X, Y, and Z (greyscale) +# dimensions. If a spatial dimension is larger than the display window then +# the image is block averaged. If a spatial dimension or a block averaged +# dimension is smaller than the display window then linear interpolation is +# used to expand the image. Both the input image and the output device appear +# to us as images, accessed via IMIO. All spatial scaling is +# handled by the "scaled input" package, i.e., SIGM2[SR]. Our task is to +# get lines from the scaled input image, transform the greyscale if necessary, +# and write the lines to the output device. + +# This version passes the overlay mask pointer rather than mapping it. +# Otherwise this is unchanged from the standard version. + +procedure ods_load_display (im, ds, wdes, ovrly) + +pointer im # input image +pointer ds # output image +pointer wdes # graphics window descriptor +pointer ovrly # overlay pointer + +real z1, z2, dz1, dz2, px1, px2, py1, py2 +int i, order, zt, wx1, wx2, wy1, wy2, wy, nx, ny, xblk, yblk +pointer wdwin, wipix, wdpix, bpm, pm, uptr +pointer in, out, si, si_ovrly, si_bpovrly, ocolors, bpcolors, rtemp +bool unitary_greyscale_transformation +short lut1, lut2, dz1_s, dz2_s, z1_s, z2_s + +bool fp_equalr() +int imstati() +real if_elogr() +pointer ds_pmmap(), imps2s(), imps2r(), sigm2s(), sigm2r(), sigm2_setup() +errchk ds_pmmap, imps2s, imps2r, sigm2s, sigm2r, sigm2_setup + +extern if_elogr + +begin + wdwin = W_WC(wdes,W_DWIN) + wipix = W_WC(wdes,W_IPIX) + wdpix = W_WC(wdes,W_DPIX) + + # Set image and display pixels. + px1 = nint (W_XS(wipix)) + px2 = nint (W_XE(wipix)) + py1 = nint (W_YS(wipix)) + py2 = nint (W_YE(wipix)) + wx1 = nint (W_XS(wdpix)) + wx2 = nint (W_XE(wdpix)) + wy1 = nint (W_YS(wdpix)) + wy2 = nint (W_YE(wdpix)) + + z1 = W_ZS(wdwin) + z2 = W_ZE(wdwin) + zt = W_ZT(wdwin) + uptr = W_UPTR(wdwin) + order = max (W_XT(wdwin), W_YT(wdwin)) + + # Setup scaled input and masks. + si = NULL + si_ovrly = NULL + si_bpovrly = NULL + nx = wx2 - wx1 + 1 + ny = wy2 - wy1 + 1 + xblk = INDEFI + yblk = INDEFI + + ocolors = W_OCOLORS(wdes) +# iferr (ovrly = ds_pmmap (W_OVRLY(wdes), im)) { +# call erract (EA_WARN) +# ovrly = NULL +# } + if (ovrly != NULL) { + xblk = INDEFI + yblk = INDEFI + si_ovrly = sigm2_setup (ovrly, NULL, px1,px2,nx,xblk, + py1,py2,ny,yblk, -1) + } + + bpcolors = W_BPCOLORS(wdes) + switch (W_BPDISP(wdes)) { + case BPDNONE: + si = sigm2_setup (im, NULL, px1,px2,nx,xblk, py1,py2,ny,yblk, order) + case BPDOVRLY: + si = sigm2_setup (im, NULL, px1,px2,nx,xblk, py1,py2,ny,yblk, order) + iferr (bpm = ds_pmmap (W_BPM(wdes), im)) + bpm = NULL + if (bpm != NULL) + si_bpovrly = sigm2_setup (bpm, NULL, px1,px2,nx,xblk, + py1,py2,ny,yblk, -1) + case BPDINTERP: + iferr (bpm = ds_pmmap (W_BPM(wdes), im)) + bpm = NULL + if (bpm != NULL) + pm = imstati (bpm, IM_PMDES) + else + pm = NULL + si = sigm2_setup (im, pm, px1,px2,nx,xblk, py1,py2,ny,yblk, order) + } + + # The device IM_MIN and IM_MAX parameters define the acceptable range + # of greyscale values for the output device (e.g., 0-255 for most 8-bit + # display devices). Values Z1 and Z2 are mapped linearly or + # logarithmically into IM_MIN and IM_MAX. + + dz1 = IM_MIN(ds) + dz2 = IM_MAX(ds) + if (fp_equalr (z1, z2)) { + z1 = z1 - 1 + z2 = z2 + 1 + } + + # If the user specifies the transfer function, verify that the + # intensity and greyscale are in range. + + if (zt == W_USER) { + call alims (Mems[uptr], U_MAXPTS, lut1, lut2) + dz1_s = short (dz1) + dz2_s = short (dz2) + if (lut2 < dz1_s || lut1 > dz2_s) + call eprintf ("User specified greyscales out of range\n") + if (z2 < IM_MIN(im) || z1 > IM_MAX(im)) + call eprintf ("User specified intensities out of range\n") + } + + # Type short pixels are treated as a special case to minimize vector + # operations for such images (which are common). If the image pixels + # are either short or real then only the ALTR (greyscale transformation) + # vector operation is required. The ALTR operator linearly maps + # greylevels in the range Z1:Z2 to DZ1:DZ2, and does a floor ceiling + # of DZ1:DZ2 on all pixels outside the range. If unity mapping is + # employed the data is simply copied, i.e., floor ceiling constraints + # are not applied. This is very fast and will produce a contoured + # image on the display which will be adequate for some applications. + + if (zt == W_UNITARY) { + unitary_greyscale_transformation = true + } else if (zt == W_LINEAR) { + unitary_greyscale_transformation = + (fp_equalr(z1,dz1) && fp_equalr(z2,dz2)) + } else + unitary_greyscale_transformation = false + + if (IM_PIXTYPE(im) == TY_SHORT && zt != W_LOG) { + z1_s = z1; z2_s = z2 + if (z1_s == z2_s) { + z1_s = z1_s - 1 + z2_s = z2_s + 1 + } + + for (wy=wy1; wy <= wy2; wy=wy+1) { + in = sigm2s (si, wy - wy1 + 1) + out = imps2s (ds, wx1, wx2, wy, wy) + + if (unitary_greyscale_transformation) { + call amovs (Mems[in], Mems[out], nx) + } else if (zt == W_USER) { + dz1_s = U_Z1; dz2_s = U_Z2 + call amaps (Mems[in],Mems[out],nx, z1_s,z2_s, dz1_s,dz2_s) + call aluts (Mems[out], Mems[out], nx, Mems[uptr]) + } else { + dz1_s = dz1; dz2_s = dz2 + call amaps (Mems[in],Mems[out],nx, z1_s,z2_s, dz1_s,dz2_s) + } + + if (si_ovrly != NULL) { + in = sigm2s (si_ovrly, wy - wy1 + 1) + do i = 0, nx-1 { + if (Mems[in+i] != 0) + call mcolors (ocolors, int(Mems[in+i]), + Mems[out+i]) + } + } + if (si_bpovrly != NULL) { + in = sigm2s (si_bpovrly, wy - wy1 + 1) + do i = 0, nx-1 { + if (Mems[in+i] != 0) + call mcolors (bpcolors, int(Mems[in+i]), + Mems[out+i]) + } + } + } + + } else if (zt == W_USER) { + call salloc (rtemp, nx, TY_REAL) + + for (wy=wy1; wy <= wy2; wy=wy+1) { + in = sigm2r (si, wy - wy1 + 1) + out = imps2s (ds, wx1, wx2, wy, wy) + + call amapr (Memr[in], Memr[rtemp], nx, z1, z2, + real(U_Z1), real(U_Z2)) + call achtrs (Memr[rtemp], Mems[out], nx) + call aluts (Mems[out], Mems[out], nx, Mems[uptr]) + + if (si_ovrly != NULL) { + in = sigm2s (si_ovrly, wy - wy1 + 1) + do i = 0, nx-1 { + if (Mems[in+i] != 0) + call mcolors (ocolors, int(Mems[in+i]), + Mems[out+i]) + } + } + if (si_bpovrly != NULL) { + in = sigm2s (si_bpovrly, wy - wy1 + 1) + do i = 0, nx-1 { + if (Mems[in+i] != 0) + call mcolors (bpcolors, int(Mems[in+i]), + Mems[out+i]) + } + } + } + + } else { + for (wy=wy1; wy <= wy2; wy=wy+1) { + in = sigm2r (si, wy - wy1 + 1) + out = imps2r (ds, wx1, wx2, wy, wy) + + if (unitary_greyscale_transformation) { + call amovr (Memr[in], Memr[out], nx) + } else if (zt == W_LOG) { + call amapr (Memr[in], Memr[out], nx, + z1, z2, 1.0, 10.0 ** MAXLOG) + call alogr (Memr[out], Memr[out], nx, if_elogr) + call amapr (Memr[out], Memr[out], nx, + 0.0, real(MAXLOG), dz1, dz2) + } else + call amapr (Memr[in], Memr[out], nx, z1, z2, dz1, dz2) + + if (si_ovrly != NULL) { + in = sigm2s (si_ovrly, wy - wy1 + 1) + do i = 0, nx-1 { + if (Mems[in+i] != 0) + call mcolorr (ocolors, int(Mems[in+i]), + Memr[out+i]) + } + } + if (si_bpovrly != NULL) { + in = sigm2s (si_bpovrly, wy - wy1 + 1) + do i = 0, nx-1 { + if (Mems[in+i] != 0) + call mcolorr (bpcolors, int(Mems[in+i]), + Memr[out+i]) + } + } + } + } + + call sigm2_free (si) + if (si_ovrly != NULL) + call sigm2_free (si_ovrly) + if (si_bpovrly != NULL) + call sigm2_free (si_bpovrly) +# if (ovrly != NULL) +# call imunmap (ovrly) + if (bpm != NULL) + call imunmap (bpm) +end + + +# The ds_pmmap routines needed to be modified for 27 bit masks. + +include <mach.h> +include <ctype.h> +include <error.h> +include <imhdr.h> +include <imset.h> +include <pmset.h> +include <syserr.h> + + +# DS_PMMAP -- Open a pixel mask READ_ONLY. +# +# Open the pixel mask. If a regular image is specified convert it to +# a pixel mask. Match the mask to the reference image based on the +# physical coordinates. A null filename is allowed and returns NULL. + +pointer procedure ods_pmmap (pmname, refim) + +char pmname[ARB] #I Pixel mask name +pointer refim #I Reference image pointer + +pointer im +char fname[SZ_FNAME] +int nowhite(), errcode() +bool streq() +pointer im_pmmap(), ods_immap() +errchk ods_immap, ods_match + +begin + if (nowhite (pmname, fname, SZ_FNAME) == 0) + return (NULL) + if (streq (fname, "EMPTY")) + return (NULL) + if (streq (fname, "BPM")) { + iferr (call imgstr (refim, "BPM", fname, SZ_FNAME)) + return (NULL) + } + + iferr (im = im_pmmap (fname, READ_ONLY, NULL)) { + switch (errcode()) { + case SYS_FOPNNEXFIL, SYS_PLBADSAVEF: + im = ods_immap (fname, refim) + default: + call erract (EA_ERROR) + } + } + + iferr (call ods_match (im, refim)) + call erract (EA_WARN) + + return (im) +end + + +# DS_PMIMMAP -- Open a pixel mask from a non-pixel list image. +# Return error if the image cannot be opened. + +pointer procedure ods_immap (pmname, refim) + +char pmname[ARB] #I Image name +pointer refim #I Reference image pointer + +short val +int i, ndim, npix +pointer sp, v1, v2, im_in, im_out, pm, mw, data + +int imgnli() +pointer immap(), pm_newmask(), im_pmmapo(), imgl1i(), mw_openim() +errchk immap, mw_openim + +begin + call smark (sp) + call salloc (v1, IM_MAXDIM, TY_LONG) + call salloc (v2, IM_MAXDIM, TY_LONG) + + call amovkl (long(1), Meml[v1], IM_MAXDIM) + call amovkl (long(1), Meml[v2], IM_MAXDIM) + + im_in = immap (pmname, READ_ONLY, 0) + pm = pm_newmask (im_in, 16) + + ndim = IM_NDIM(im_in) + npix = IM_LEN(im_in,1) + + while (imgnli (im_in, data, Meml[v1]) != EOF) { + do i = 0, npix-1 { + val = Memi[data+i] + if (val < 0) + Memi[data+i] = 0 + } + call pmplpi (pm, Meml[v2], Memi[data], 0, npix, PIX_SRC) + call amovl (Meml[v1], Meml[v2], ndim) + } + + im_out = im_pmmapo (pm, im_in) + data = imgl1i (im_out) # Force I/O to set header + mw = mw_openim (im_in) # Set WCS + call mw_saveim (mw, im_out) + call mw_close (mw) + + call imunmap (im_in) + call sfree (sp) + return (im_out) +end + + +# DS_MATCH -- Set the pixel mask to match the reference image. +# This matches sizes and physical coordinates and allows the +# original mask to be smaller or larger than the reference image. +# Subsequent use of the pixel mask can then work in the logical +# coordinates of the reference image. A null input returns a null output. + +procedure ods_match (im, refim) + +pointer im #U Pixel mask image pointer +pointer refim #I Reference image pointer + +int i, j, k, nc, nl, ncpm, nlpm, c1, c2, l1, l2, nref, npm +int steptype, xoffset, xstep, yoffset, ystep +double x1, x2, y1, y2 +long vold[IM_MAXDIM], vnew[IM_MAXDIM] +pointer mwref, mwpm, ctref, ctpm, pm, pmnew, imnew, bufref, bufpm + +int imstati() +pointer pm_open(), mw_openim(), im_pmmapo(), imgl1i(), mw_sctran() +bool pm_empty(), pm_linenotempty() +errchk pm_open, mw_openim + +begin + if (im == NULL) + return + + # Set sizes. + pm = imstati (im, IM_PMDES) + nc = IM_LEN(refim,1) + nl = IM_LEN(refim,2) + ncpm = IM_LEN(im,1) + nlpm = IM_LEN(im,2) + + # Check if the two are the same logical size and the mask is empty. + if (nc == ncpm && nl == nlpm && pm_empty (pm)) + return + + # Check coordinate transformations. + mwref = mw_openim (refim) + mwpm = mw_openim (im) + + steptype = 1 + ctref = mw_sctran (mwref, "logical", "physical", 3) + ctpm = mw_sctran (mwpm, "physical", "logical", 3) + call mw_c2trand (ctref, 1D0, 1D0, x1, y1) + call mw_c2trand (ctpm, x1, y1, x1, y1) + call mw_c2trand (ctref, 2D0, 1D0, x2, y2) + call mw_c2trand (ctpm, x2, y2, x2, y2) + if (abs(x2-x1) < 1.) { + steptype = 2 + call mw_ctfree (ctref) + call mw_ctfree (ctpm) + ctref = mw_sctran (mwref, "physical", "logical", 3) + ctpm = mw_sctran (mwpm, "logical", "physical", 3) + call mw_c2trand (ctpm, 1D0, 1D0, x1, y1) + call mw_c2trand (ctref, x1, y1, x1, y1) + call mw_c2trand (ctpm, 2D0, 1D0, x2, y2) + call mw_c2trand (ctref, x2, y2, x2, y2) + } + x2 = x2 - x1 + if (abs(y1-y2) > 10*EPSILONR) + call error (0, "Image and mask have a relative rotation") + if (abs(x1-nint(x1)) > 10*EPSILONR && + abs(x1-nint(x1))-0.5 > 10*EPSILONR) + call error (0, "Image and mask have non-integer relative offsets") + if (abs(x2-nint(x2)) > 10*EPSILONR) + call error (0, "Image and mask have non-integer relative steps") + xoffset = nint (x1 - 1D0) + xstep = nint (x2) + + if (steptype == 1) { + call mw_c2trand (ctref, 1D0, 1D0, x1, y1) + call mw_c2trand (ctpm, x1, y1, x1, y1) + call mw_c2trand (ctref, 1D0, 2D0, x2, y2) + call mw_c2trand (ctpm, x2, y2, x2, y2) + } else { + call mw_c2trand (ctpm, 1D0, 1D0, x1, y1) + call mw_c2trand (ctref, x1, y1, x1, y1) + call mw_c2trand (ctpm, 1D0, 2D0, x2, y2) + call mw_c2trand (ctref, x2, y2, x2, y2) + } + y2 = y2 - y1 + if (abs(x1-x2) > 10*EPSILONR) + call error (0, "Image and mask have a relative rotation") + if (abs(y1-nint(y1)) > 10*EPSILONR && + abs(y1-nint(y1))-0.5 > 10*EPSILONR) + call error (0, "Image and mask have non-integer relative offsets") + if (abs(y2-nint(y2)) > 10*EPSILONR) + call error (0, "Image and mask have non-integer relative steps") + yoffset = nint (y1 - 1D0) + ystep = nint (y2) + + call mw_ctfree (ctref) + call mw_ctfree (ctpm) + call mw_close (mwref) + call mw_close (mwpm) + + # Check if the two have the same coordinate system. + if (nc==ncpm && nl==nlpm && xoffset==0 && yoffset==0 && xstep==ystep) + return + + # Create a new pixel mask of the required size and offset. + pmnew = pm_open (NULL) + call pm_ssize (pmnew, 2, IM_LEN(refim,1), 27) + imnew = im_pmmapo (pmnew, NULL) + bufref = imgl1i (imnew) + + if (steptype == 1) { + c1 = 1 + xoffset + max (0, (xstep - 1 - xoffset) / xstep) * xstep + c2 = 1 + xoffset + min (nc-1, (ncpm - 1 - xoffset) / xstep) * xstep + l1 = 1 + yoffset + max (0, (ystep - 1 - yoffset) / ystep) * ystep + l2 = 1 + yoffset + min (nl-1, (nlpm - 1 - yoffset) / ystep) * ystep + npm = c2 - c1 + 1 + nref = npm / xstep + if (nref > 0) { + call malloc (bufpm, npm, TY_INT) + call malloc (bufref, nref, TY_INT) + call amovkl (long(1), vold, IM_MAXDIM) + call amovkl (long(1), vnew, IM_MAXDIM) + vold[1] = c1 + vnew[1] = c1 - xoffset + do i = l1, l2, ystep { + vold[2] = i + if (!pm_linenotempty (pm, vold)) + next + call pmglpi (pm, vold, Memi[bufpm], 0, npm, 0) + vnew[2] = l1 - yoffset + (i - l1) / ystep + j = 0 + do k = 0, npm-1, xstep { + Memi[bufref+j] = Memi[bufpm+k] + j = j + 1 + } + call pmplpi (pmnew, vnew, Memi[bufref], 0, nref, PIX_SRC) + } + } + } else { + c1 = max (1, 1 - xoffset) + c2 = min (ncpm, nc / xstep - xoffset) + l1 = max (1, 1 - yoffset) + l2 = min (nlpm, nl / ystep - yoffset) + npm = c2 - c1 + 1 + nref = npm * xstep + if (nref > 0) { + call malloc (bufpm, npm, TY_INT) + call malloc (bufref, nref, TY_INT) + call amovkl (long(1), vold, IM_MAXDIM) + call amovkl (long(1), vnew, IM_MAXDIM) + vold[1] = c1 + vnew[1] = c1 + xoffset + do i = l1, l2 { + vold[2] = i + if (!pm_linenotempty (pm, vold)) + next + call pmglpi (pm, vold, Memi[bufpm], 0, npm, 0) + call aclri (Memi[bufref], nref) + do j = 0, npm-1 { + k = j * xstep + Memi[bufref+k] = Memi[bufpm+j] + } + vnew[2] = l1 + yoffset + (i - l1) * ystep + call pmplpi (pmnew, vnew, Memi[bufref], 0, nref, PIX_SRC) + } + } + call mfree (bufpm, TY_INT) + call mfree (bufref, TY_INT) + } + + # Update the IMIO descriptor. + call imunmap (im) + im = imnew + call imseti (im, IM_PMDES, pmnew) +end + + +# IF_ELOG -- The error function for log10. Note that MAX_EXPONENT is +# currently an integer so it is converted to the appropriate data type +# before being returned. + +real procedure if_elogr (x) + +real x # the input pixel value + +begin + return (real(-MAX_EXPONENT)) +end diff --git a/noao/nproto/ace/t_imext.x b/noao/nproto/ace/t_imext.x new file mode 100644 index 00000000..178f6937 --- /dev/null +++ b/noao/nproto/ace/t_imext.x @@ -0,0 +1,533 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <error.h> +include <syserr.h> +include <imhdr.h> +include <imset.h> + +define OUTPUTS "|none|list|file|" +define NONE 1 # No output +define LIST 2 # List output +define FILE 3 # File output + +define SZ_RANGE 100 # Size of range list +define SZ_LISTOUT 255 # Size of output list + + +# T_IMEXTENSIONS -- Expand a template of FITS files into a list of image +# extensions on the standard output and record the number image extensions +# in a parameter. + +procedure t_imextensions() + +pointer input # List of ME file names +int output # Output list (none|list|file) +pointer index # Range list of extension indexes +pointer extname # Patterns for extension names +pointer extver # Range list of extension versions +int lindex # List index number? +int lname # List extension name? +int lver # List extension version? +pointer ikparams # Image kernel parameters + +pointer sp, image, listout +int list, nimages, fd +int clgwrd(), btoi(), imextensions(), stropen() +int imtgetim(), imtlen() +bool clgetb() +errchk stropen, fprintf, strclose + +begin + call smark (sp) + call salloc (input, SZ_LINE, TY_CHAR) + call salloc (index, SZ_LINE, TY_CHAR) + call salloc (extname, SZ_LINE, TY_CHAR) + call salloc (extver, SZ_LINE, TY_CHAR) + call salloc (ikparams, SZ_LINE, TY_CHAR) + call salloc (image, SZ_FNAME, TY_CHAR) + + # Task parameters + call clgstr ("input", Memc[input], SZ_LINE) + output = clgwrd ("output", Memc[image], SZ_FNAME, OUTPUTS) + call clgstr ("index", Memc[index], SZ_LINE) + call clgstr ("extname", Memc[extname], SZ_LINE) + call clgstr ("extver", Memc[extver], SZ_LINE) + lindex = btoi (clgetb ("lindex")) + lname = btoi (clgetb ("lname")) + lver = btoi (clgetb ("lver")) + call clgstr ("ikparams", Memc[ikparams], SZ_LINE) + + # Get the list. + list = imextensions (Memc[input], Memc[index], Memc[extname], + Memc[extver], lindex, lname, lver, Memc[ikparams], YES) + + # Format the output and set the number of images. + switch (output) { + case LIST: + call salloc (listout, SZ_LISTOUT, TY_CHAR) + iferr { + fd = stropen (Memc[listout], SZ_LISTOUT, WRITE_ONLY) + nimages = 0 + while (imtgetim (list, Memc[image], SZ_FNAME) != EOF) { + nimages = nimages + 1 + if (nimages == 1) { + call fprintf (fd, "%s") + call pargstr (Memc[image]) + } else { + call fprintf (fd, ",%s") + call pargstr (Memc[image]) + } + } + call strclose (fd) + call printf ("%s\n") + call pargstr (Memc[listout]) + } then { + call imtclose (list) + call sfree (sp) + call error (1, "Output list format is too long") + } + case FILE: + while (imtgetim (list, Memc[image], SZ_FNAME) != EOF) { + call printf ("%s\n") + call pargstr (Memc[image]) + } + } + call clputi ("nimages", imtlen (list)) + + call imtclose (list) + call sfree (sp) +end + + +# IMEXTENSIONS -- Expand a template of ME files into a list of image extensions. + +int procedure imextensions (files, index, extname, extver, lindex, lname, lver, + ikparams, err) + +char files[ARB] #I List of ME files +char index[ARB] #I Range list of extension indexes +char extname[ARB] #I Patterns for extension names +char extver[ARB] #I Range list of extension versions +int lindex #I List index number? +int lname #I List extension name? +int lver #I List extension version? +char ikparams[ARB] #I Image kernel parameters +int err #I Print errors? +int list #O Image list + +int i, fd +pointer sp, temp, fname, imname, section, rindex, rextver, ikp, str +int imtopen(), imtgetim() +int ix_decode_ranges(), nowhite(), open() +errchk open, imextension, delete + +begin + call smark (sp) + call salloc (temp, SZ_FNAME, TY_CHAR) + call salloc (fname, SZ_FNAME, TY_CHAR) + call salloc (imname, SZ_FNAME, TY_CHAR) + call salloc (section, SZ_FNAME, TY_CHAR) + call salloc (ikp, SZ_LINE, TY_CHAR) + call salloc (str, SZ_LINE, TY_CHAR) + + # Expand parameters. + list = imtopen (files) + call salloc (rindex, 3*SZ_RANGE, TY_INT) + if (ix_decode_ranges (index, Memi[rindex], SZ_RANGE, i) == ERR) + call error (1, "Bad index range list") + + rextver = NULL + if (nowhite (extver, Memc[str], SZ_LINE) > 0) { + call salloc (rextver, 3*SZ_RANGE, TY_INT) + if (ix_decode_ranges (Memc[str], Memi[rextver], SZ_RANGE, i)==ERR) + call error (1, "Bad extension version range list") + } + i = nowhite (ikparams, Memc[ikp], SZ_LINE) + + # Expand ME files into list of image extensions in a temp file. + call mktemp ("@tmp$iraf", Memc[temp], SZ_FNAME) + fd = open (Memc[temp+1], NEW_FILE, TEXT_FILE) + while (imtgetim (list, Memc[fname], SZ_FNAME) != EOF) { + call imgimage (Memc[fname], Memc[imname], SZ_FNAME) + call imgsection (Memc[fname], Memc[section], SZ_FNAME) + call imextension (fd, Memc[imname], rindex, extname, rextver, + lindex, lname, lver, Memc[ikp], Memc[section], err) + } + call imtclose (list) + call close (fd) + + # Return list. + list = imtopen (Memc[temp]) + call delete (Memc[temp+1]) + call sfree (sp) + return (list) +end + + +# IMEXTENSION -- Expand a single ME file into a list of image extensions. +# The image extensions are written to the input file descriptor. + +procedure imextension (fd, fname, index, extname, extver, lindex, lname, lver, + ikparams, section, err) + +int fd #I File descriptor for list +char fname[SZ_FNAME] #I File image name (without kernel or image sec) +pointer index #I Range list of extension indexes +char extname[ARB] #I Pattern for extension names +pointer extver #I Range list of extension versions +int lindex #I List index number? +int lname #I List extension name? +int lver #I List extension version? +char ikparams[ARB] #I Image kernel parameters +char section[ARB] #I Image section +int err #I Print errors? + +bool extmatch() +int i, j, ver, ix_get_next_number(), errcode(), imgeti(), stridxs() +pointer sp, image, name, str, im, immap() +bool is_in_range() + +begin + call smark (sp) + call salloc (image, SZ_FNAME, TY_CHAR) + call salloc (name, SZ_LINE, TY_CHAR) + call salloc (str, SZ_LINE, TY_CHAR) + + i = -1 + while (ix_get_next_number (Memi[index], i) != EOF) { + j = stridxs ("[", fname) + if (j > 0) { + if (i > 0) + break + call strcpy (fname, Memc[image], SZ_FNAME) + } else { + call sprintf (Memc[image], SZ_FNAME, "%s[%d]") + call pargstr (fname) + call pargi (i) + } + iferr (im = immap (Memc[image], READ_ONLY, 0)) { + switch (errcode()) { + case SYS_FXFRFEOF: + break + case SYS_IKIEXTN: + next + case SYS_IKIOPEN: + switch (i) { + case 0: + next + case 1: + if (err == YES) + call erract (EA_WARN) + break + default: + break + } + default: + call erract (EA_ERROR) + } + } + + # Check the extension name. + if (extname[1] != EOS) { + iferr (call imgstr (im, "extname", Memc[name], SZ_LINE)) { + Memc[name] = EOS + #call imunmap (im) + #next + } + if (!extmatch (Memc[name], extname)) { + call imunmap (im) + next + } + } + + # Check the extension version. + if (extver != NULL) { + iferr (ver = imgeti (im, "extver")) { + call imunmap (im) + next + } + if (!is_in_range (Memi[extver], ver)) { + call imunmap (im) + next + } + } + + # Set the extension name and version. + if (lname == YES) { + iferr (call imgstr (im, "extname", Memc[name], SZ_LINE)) + Memc[name] = EOS + } else + Memc[name] = EOS + if (lver == YES) { + iferr (ver = imgeti (im, "extver")) + ver = INDEFI + } else + ver = INDEFI + + # Write the image name. + call fprintf (fd, fname) + if (j == 0) { + if (lindex == YES || (Memc[name] == EOS && IS_INDEFI(ver))) { + call fprintf (fd, "[%d]") + call pargi (i) + } + if (Memc[name] != EOS) { + call fprintf (fd, "[%s") + call pargstr (Memc[name]) + if (!IS_INDEFI(ver)) { + call fprintf (fd, ",%d") + call pargi (ver) + } + if (ikparams[1] != EOS) { + call fprintf (fd, ",%s") + call pargstr (ikparams) + } + call fprintf (fd, "]") + } else if (!IS_INDEFI(ver)) { + call fprintf (fd, "[extver=%d") + call pargi (ver) + if (ikparams[1] != EOS) { + call fprintf (fd, ",%s") + call pargstr (ikparams) + } + call fprintf (fd, "]") + } else if (ikparams[1] != EOS) { + call fprintf (fd, "[%s]") + call pargstr (ikparams) + } + } + call fprintf (fd, "%s") + call pargstr (section) + call fprintf (fd, "\n") + + call imunmap (im) + } + + call sfree (sp) +end + + +include <mach.h> +include <ctype.h> + +define FIRST 1 # Default starting range +define LAST MAX_INT # Default ending range +define STEP 1 # Default step +define EOLIST -1 # End of list + +# IX_DECODE_RANGES -- Parse a string containing a list of integer numbers or +# ranges, delimited by either spaces or commas. Return as output a list +# of ranges defining a list of numbers, and the count of list numbers. +# Range limits must be positive nonnegative integers. ERR is returned as +# the function value if a conversion error occurs. The list of ranges is +# delimited by EOLIST. + +int procedure ix_decode_ranges (range_string, ranges, max_ranges, nvalues) + +char range_string[ARB] # Range string to be decoded +int ranges[3, max_ranges] # Range array +int max_ranges # Maximum number of ranges +int nvalues # The number of values in the ranges + +int ip, nrange, first, last, step, ctoi() + +begin + ip = 1 + nvalues = 0 + + do nrange = 1, max_ranges - 1 { + # Defaults to all nonnegative integers + first = FIRST + last = LAST + step = STEP + + # Skip delimiters + while (IS_WHITE(range_string[ip]) || range_string[ip] == ',') + ip = ip + 1 + + # Get first limit. + # Must be a number, '-', 'x', or EOS. If not return ERR. + if (range_string[ip] == EOS) { # end of list + if (nrange == 1) { + # Null string defaults + ranges[1, 1] = first + ranges[2, 1] = last + ranges[3, 1] = step + ranges[1, 2] = EOLIST + nvalues = MAX_INT + return (OK) + } else { + ranges[1, nrange] = EOLIST + return (OK) + } + } else if (range_string[ip] == '-') + ; + else if (range_string[ip] == 'x') + ; + else if (IS_DIGIT(range_string[ip])) { # ,n.. + if (ctoi (range_string, ip, first) == 0) + return (ERR) + } else + return (ERR) + + # Skip delimiters + while (IS_WHITE(range_string[ip]) || range_string[ip] == ',') + ip = ip + 1 + + # Get last limit + # Must be '-', or 'x' otherwise last = first. + if (range_string[ip] == 'x') + ; + else if (range_string[ip] == '-') { + ip = ip + 1 + while (IS_WHITE(range_string[ip]) || range_string[ip] == ',') + ip = ip + 1 + if (range_string[ip] == EOS) + ; + else if (IS_DIGIT(range_string[ip])) { + if (ctoi (range_string, ip, last) == 0) + return (ERR) + } else if (range_string[ip] == 'x') + ; + else + return (ERR) + } else + last = first + + # Skip delimiters + while (IS_WHITE(range_string[ip]) || range_string[ip] == ',') + ip = ip + 1 + + # Get step. + # Must be 'x' or assume default step. + if (range_string[ip] == 'x') { + ip = ip + 1 + while (IS_WHITE(range_string[ip]) || range_string[ip] == ',') + ip = ip + 1 + if (range_string[ip] == EOS) + ; + else if (IS_DIGIT(range_string[ip])) { + if (ctoi (range_string, ip, step) == 0) + ; + if (step == 0) + return (ERR) + } else if (range_string[ip] == '-') + ; + else + return (ERR) + } + + # Output the range triple. + ranges[1, nrange] = first + ranges[2, nrange] = last + ranges[3, nrange] = step + nvalues = nvalues + abs (last-first) / step + 1 + } + + return (ERR) # ran out of space +end + + +# IX_GET_NEXT_NUMBER -- Given a list of ranges and the current file number, +# find and return the next file number. Selection is done in such a way +# that list numbers are always returned in monotonically increasing order, +# regardless of the order in which the ranges are given. Duplicate entries +# are ignored. EOF is returned at the end of the list. + +int procedure ix_get_next_number (ranges, number) + +int ranges[ARB] # Range array +int number # Both input and output parameter + +int ip, first, last, step, next_number, remainder + +begin + # If number+1 is anywhere in the list, that is the next number, + # otherwise the next number is the smallest number in the list which + # is greater than number+1. + + number = number + 1 + next_number = MAX_INT + + for (ip=1; ranges[ip] != EOLIST; ip=ip+3) { + first = min (ranges[ip], ranges[ip+1]) + last = max (ranges[ip], ranges[ip+1]) + step = ranges[ip+2] + if (step == 0) + call error (1, "Step size of zero in range list") + if (number >= first && number <= last) { + remainder = mod (number - first, step) + if (remainder == 0) + return (number) + if (number - remainder + step <= last) + next_number = number - remainder + step + } else if (first > number) + next_number = min (next_number, first) + } + + if (next_number == MAX_INT) + return (EOF) + else { + number = next_number + return (number) + } +end + + +# EXTMATCH -- Match extname against a comma-delimited list of patterns. + +bool procedure extmatch (extname, patterns) + +char extname[ARB] #I Extension name to match +char patterns[ARB] #I Comma-delimited list of patterns +bool stat #O Match? + +int i, j, k, sz_pat, strlen(), patmake(), patmatch(), nowhite() +pointer sp, patstr, patbuf + +begin + stat = false + + sz_pat = strlen (patterns) + if (sz_pat == 0) + return (stat) + sz_pat = sz_pat + SZ_LINE + + call smark (sp) + call salloc (patstr, sz_pat, TY_CHAR) + call salloc (patbuf, sz_pat, TY_CHAR) + + i = nowhite (patterns, Memc[patstr], sz_pat) + if (i == 0) + stat = true + else if (i == 1 && Memc[patstr] == '*') + stat = true + else { + i = 1 + for (j=i;; j=j+1) { + if (patterns[j] != ',' && patterns[j] != EOS) + next + if (j - i > 0) { + if (j-i == 1 && patterns[i] == '*') { + stat = true + break + } + call strcpy (patterns[i], Memc[patstr+1], j-i) + Memc[patstr] = '^' + Memc[patstr+j-i+1] = '$' + Memc[patstr+j-i+2] = EOS + k = patmake (Memc[patstr], Memc[patbuf], sz_pat) + if (patmatch (extname, Memc[patbuf]) > 0) { + stat = true + break + } + } + if (patterns[j] == EOS) + break + i = j + 1 + } + } + + call sfree (sp) + return (stat) +end diff --git a/noao/nproto/ace/t_mscext.x b/noao/nproto/ace/t_mscext.x new file mode 100644 index 00000000..b57ba5cf --- /dev/null +++ b/noao/nproto/ace/t_mscext.x @@ -0,0 +1,180 @@ +# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + +include <error.h> +include <syserr.h> +include <imhdr.h> +include <imset.h> + +define OUTPUTS "|none|list|file|" +define NONE 1 # No output +define LIST 2 # List output +define FILE 3 # File output + +define SZ_RANGE 100 # Size of range list +define SZ_LISTOUT 255 # Size of output list + + +# T_MSCEXTENSIONS -- Expand a template of FITS files into a list of image +# extensions on the standard output and record the number image extensions +# in a parameter. +# +# This differs from IMEXTENSIONS in that extension zero is not returned +# unless it is a simple image and, in that case, the extension is removed. +# Also a parameter is written indicating if the list contains image extensions. + +procedure t_mscextensions() + +pointer input # List of ME file names +int output # Output list (none|list|file) +pointer index # Range list of extension indexes +pointer extname # Patterns for extension names +pointer extver # Range list of extension versions +int lindex # List index number? +int lname # List extension name? +int lver # List extension version? +pointer ikparams # Image kernel parameters + +pointer sp, image, listout +int list, nimages, fd, imext +int clgwrd(), btoi(), mscextensions(), stropen() +int imtgetim(), imtlen() +bool clgetb() +errchk stropen, fprintf, strclose + +begin + call smark (sp) + call salloc (input, SZ_LINE, TY_CHAR) + call salloc (index, SZ_LINE, TY_CHAR) + call salloc (extname, SZ_LINE, TY_CHAR) + call salloc (extver, SZ_LINE, TY_CHAR) + call salloc (ikparams, SZ_LINE, TY_CHAR) + call salloc (image, SZ_FNAME, TY_CHAR) + + # Task parameters + call clgstr ("input", Memc[input], SZ_LINE) + output = clgwrd ("output", Memc[image], SZ_FNAME, OUTPUTS) + call clgstr ("index", Memc[index], SZ_LINE) + call clgstr ("extname", Memc[extname], SZ_LINE) + call clgstr ("extver", Memc[extver], SZ_LINE) + lindex = btoi (clgetb ("lindex")) + lname = btoi (clgetb ("lname")) + lver = btoi (clgetb ("lver")) + call clgstr ("ikparams", Memc[ikparams], SZ_LINE) + + # Get the list. + list = mscextensions (Memc[input], Memc[index], Memc[extname], + Memc[extver], lindex, lname, lver, Memc[ikparams], NO, imext) + + # Format the output and set the number of images. + switch (output) { + case LIST: + call salloc (listout, SZ_LISTOUT, TY_CHAR) + iferr { + fd = stropen (Memc[listout], SZ_LISTOUT, WRITE_ONLY) + nimages = 0 + while (imtgetim (list, Memc[image], SZ_FNAME) != EOF) { + nimages = nimages + 1 + if (nimages == 1) { + call fprintf (fd, "%s") + call pargstr (Memc[image]) + } else { + call fprintf (fd, ",%s") + call pargstr (Memc[image]) + } + } + call strclose (fd) + call printf ("%s\n") + call pargstr (Memc[listout]) + } then { + call imtclose (list) + call sfree (sp) + call error (1, "Output list format is too long") + } + case FILE: + while (imtgetim (list, Memc[image], SZ_FNAME) != EOF) { + call printf ("%s\n") + call pargstr (Memc[image]) + } + } + call clputi ("nimages", imtlen (list)) + call clputb ("imext", (imext==YES)) + + call imtclose (list) + call sfree (sp) +end + + +# MSCEXTENSIONS -- Expand template of files into a list of image extensions. +# +# This differs from IMEXTENSIONS in that extension zero is not returned +# unless it is a simple image and, in that case, the extension is removed. + +int procedure mscextensions (files, index, extname, extver, lindex, lname, lver, + ikparams, err, imext) + +char files[ARB] #I List of ME files +char index[ARB] #I Range list of extension indexes +char extname[ARB] #I Patterns for extension names +char extver[ARB] #I Range list of extension versions +int lindex #I List index number? +int lname #I List extension name? +int lver #I List extension version? +char ikparams[ARB] #I Image kernel parameters +int err #I Print errors? +int imext #O Image extensions? +int list #O Image list + +int i, j, nphu, nimages, fd +pointer sp, temp, image, im, immap() +int imextensions(), gstrmatch(), imtopen(), imtgetim(), open() +errchk imextensions, open, immap, delete + +begin + call smark (sp) + call salloc (temp, SZ_FNAME, TY_CHAR) + call salloc (image, SZ_FNAME, TY_CHAR) + + # Get the list. + list = imextensions (files, index, extname, extver, lindex, lname, + lver, ikparams, err) + + # Check and edit the list. + nphu = 0 + nimages = 0 + call mktemp ("@tmp$iraf", Memc[temp], SZ_FNAME) + fd = open (Memc[temp+1], NEW_FILE, TEXT_FILE) + while (imtgetim (list, Memc[image], SZ_FNAME) != EOF) { + if (gstrmatch (Memc[image], "\[0\]", i, j) > 0) { + call strcpy (Memc[image+j], Memc[image+i-1], SZ_FNAME) + ifnoerr (im = immap (Memc[image], READ_ONLY, 0)) { + call imunmap (im) + nphu = nphu + 1 + } else + next + } else if (gstrmatch (Memc[image], "\[1\]", i, j) > 0) { + Memc[image+i] = '0' + iferr { + im = immap (Memc[image], READ_ONLY, 0) + call imunmap (im) + Memc[image+i] = '1' + } then { + nphu = nphu + 1 + call strcpy (Memc[image+j], Memc[image+i-1], SZ_FNAME) + } + } + nimages = nimages + 1 + call fprintf (fd, "%s\n") + call pargstr (Memc[image]) + } + call close (fd) + + # Return new list and extension flag. + imext = YES + if (nphu == nimages) + imext = NO + call imtclose (list) + list = imtopen (Memc[temp]) + call delete (Memc[temp+1]) + call sfree (sp) + return (list) +end diff --git a/noao/nproto/ace/tables.x b/noao/nproto/ace/tables.x new file mode 100644 index 00000000..53a0d48b --- /dev/null +++ b/noao/nproto/ace/tables.x @@ -0,0 +1,197 @@ +procedure tbcfmt (tp, cdef, str) + +pointer tp +pointer cdef +char str[ARB] + +begin +end + +procedure tbcnam (tp, cdef, str) + +pointer tp +pointer cdef +char str[ARB] + +begin +end + +procedure tbcnit (tp, cdef, str) + +pointer tp +pointer cdef +char str[ARB] + +begin +end + +procedure tbegtd (tp, cdef, row, val) + +pointer tp +pointer cdef +int row +double val + +begin +end + +procedure tbegtr (tp, cdef, row, val) + +pointer tp +pointer cdef +int row +real val + +begin +end + +procedure tbegti (tp, cdef, row, val) + +pointer tp +pointer cdef +int row +int val + +begin +end + +procedure tbegtt (tp, cdef, row, val, len) + +pointer tp +pointer cdef +int row +char val[ARB] +int len + +begin +end + +procedure tbeptd (tp, cdef, row, val) + +pointer tp +pointer cdef +int row +double val + +begin +end + +procedure tbeptr (tp, cdef, row, val) + +pointer tp +pointer cdef +int row +real val + +begin +end + +procedure tbepti (tp, cdef, row, val) + +pointer tp +pointer cdef +int row +int val + +begin +end + +procedure tbeptt (tp, cdef, row, val) + +pointer tp +pointer cdef +int row +char val[ARB] + +begin +end + +procedure tbhgtr (tp, key, val) + +pointer tp +char key[ARB] +char val[ARB] + +begin +end + +procedure tbhgtt (tp, key, val, maxchar) + +pointer tp +char key[ARB] +char val[ARB] +int maxchar + +begin +end + +procedure tbhadr (tp, key, val) + +pointer tp +char key[ARB] +char val[ARB] + +begin +end + +procedure tbhadt (tp, key, val) + +pointer tp +char key[ARB] +char val[ARB] + +begin +end + +procedure tbpsta (tp, par) + +pointer tp +int par + +begin +end + +procedure tbtclo (tp) + +pointer tp + +begin +end + +procedure tbtcre (tp) + +pointer tp + +begin +end + +pointer procedure tbtopn (fname, mode, arg) + +char fname[ARB] +int mode +pointer arg + +begin +end + +procedure tbcdef1 (tp, cdef, label, units, format, type, n) + +pointer tp +pointer cdef +char label[ARB] +char units[ARB] +char format[ARB] +int type +int n + +begin +end + +procedure tbcfnd1 (tp, label, cdef) + +pointer tp +char label[ARB] +pointer cdef + +begin +end diff --git a/noao/nproto/ace/x_ace.x b/noao/nproto/ace/x_ace.x new file mode 100644 index 00000000..c7b257b7 --- /dev/null +++ b/noao/nproto/ace/x_ace.x @@ -0,0 +1,4 @@ +task detect = t_acedetect, + evaluate = t_aceevaluate, + overlay = t_acedisplay, + skyimages = t_acesky diff --git a/noao/nproto/ace/xtmaskname.x b/noao/nproto/ace/xtmaskname.x new file mode 100644 index 00000000..9a55fb29 --- /dev/null +++ b/noao/nproto/ace/xtmaskname.x @@ -0,0 +1,114 @@ +#task test +#procedure test() +#char fname[SZ_FNAME] +#begin +# call clgstr ("fname", fname, SZ_FNAME) +# #call xt_maskname (fname, "im1", READ_ONLY, fname, SZ_FNAME) +# call xt_maskname (fname, "im1", NEW_IMAGE, fname, SZ_FNAME) +# call printf ("mname = %s\n") +# call pargstr (fname) +#end + +# MASKNAME -- Make a mask name. This creates a FITS mask extension if +# possible, otherwise it creates a pixel list file. To create a FITS +# extension the filename must explicitly select the FITS kernel or the +# default image type must be a FITS file. The input and output strings +# may be the same. + +procedure xt_maskname (fname, extname, mode, mname, maxchar) + +char fname[ARB] #I File name +char extname[ARB] #I Default pixel mask extension name +int mode #I Mode +char mname[maxchar] #O Output mask name +int maxchar #I Maximum characters in mask name + +int i, fits +pointer sp, temp + +bool streq() +int strmatch(), stridxs(), strldxs(), strncmp() +int envfind(), access(), imaccess() + +begin + call smark (sp) + call salloc (temp, maxchar, TY_CHAR) + + # Determine whether to use FITS pixel mask extensions. One may set + # fits=NO to force use of pl even when FITS mask extensions are + # supported. + fits = access ("iraf$sys/imio/iki/fxf/fxfplwrite.x", 0, 0) + if (fits == YES && envfind ("masktype", Memc[temp], maxchar) > 0) { + if (streq (Memc[temp], "pl")) + fits = NO + } + i = strldxs ("]", fname) + + # Check for explicit .pl extension. + if (strmatch (fname, ".pl$") > 0) + call strcpy (fname, mname, maxchar) + + # Check for explicit mask extension. + else if (strmatch (fname, "type=mask") > 0) + call strcpy (fname, mname, maxchar) + else if (strmatch (fname, "type\\\=mask") > 0) + call strcpy (fname, mname, maxchar) + + # Check for kernel section and add mask type. + else if (i > 0) { + if (mode != READ_ONLY) { + call strcpy (fname[i], Memc[temp], maxchar) + call sprintf (mname[i], maxchar-i, ",type=mask%s") + call pargstr (Memc[temp]) + } + + # Create output from rootname name. + } else if (fits == YES) { + call strcpy (fname, Memc[temp], SZ_FNAME) + if (mode == READ_ONLY) { + call sprintf (mname, maxchar, "%s[%s]") + call pargstr (Memc[temp]) + call pargstr (extname) + } else { + call sprintf (mname, maxchar, "%s[%s,type=mask]") + call pargstr (Memc[temp]) + call pargstr (extname) + } + } else + call strcat (".pl", mname, maxchar) + + # Convert to pl form if required. + i = stridxs ("[", mname) + if (i > 0 && mode == READ_ONLY) + fits = imaccess (mname, mode) + if (fits == NO && i > 0) { + mname[i] = EOS + if (mode == NEW_IMAGE) { + if (access (mname, 0, 0) == NO) { + ifnoerr (call fmkdir (mname)) + mname[i] = '/' + else + mname[i] = '.' + } else + mname[i] = '/' + } else { + if (access (mname, 0, 0) == NO) + mname[i] = '.' + else + mname[i] = '/' + } + + if (strncmp (mname[i+1], "type", 4) == 0 || + strncmp (mname[i+1], "append", 6) == 0 || + strncmp (mname[i+1], "inherit", 7) == 0) { + mname[i+1] = EOS + call strcat (extname, mname, maxchar) + } else { + i = stridxs (",]", mname) + mname[i] = EOS + } + call strcat (".pl", mname, maxchar) + } + + call sfree (sp) +end diff --git a/noao/nproto/ace/xtpmmap.x b/noao/nproto/ace/xtpmmap.x new file mode 100644 index 00000000..17fcf934 --- /dev/null +++ b/noao/nproto/ace/xtpmmap.x @@ -0,0 +1,603 @@ +include <mach.h> +include <ctype.h> +include <error.h> +include <imhdr.h> +include <imset.h> +include <pmset.h> +include <mwset.h> +include <syserr.h> + + +# XT_PMMAP -- Open a pixel mask READ_ONLY. +# +# This routine maps multiple types of mask files and designations. +# It matches the mask coordinates to the reference image based on the +# physical coordinate system so the mask may be of a different size. +# The mask name is returned so that the task has the name pointed to by "BPM". +# A null filename is allowed and returns NULL. + +pointer procedure yt_pmmap (pmname, refim, mname, sz_mname) + +char pmname[ARB] #I Pixel mask name +pointer refim #I Reference image pointer +char mname[ARB] #O Expanded mask name +int sz_mname #O Size of expanded mask name + +int i, flag, nowhite() +pointer sp, fname, im, ref, yt_pmmap1() +bool streq() +errchk yt_pmmap1 + +begin + call smark (sp) + call salloc (fname, SZ_FNAME, TY_CHAR) + + im = NULL + i = nowhite (pmname, Memc[fname], SZ_FNAME) + if (Memc[fname] == '!') { + iferr (call imgstr (refim, Memc[fname+1], Memc[fname], SZ_FNAME)) + Memc[fname] = EOS + } else if (streq (Memc[fname], "BPM")) { + iferr (call imgstr (refim, "BPM", Memc[fname], SZ_FNAME)) + Memc[fname] = EOS + } else if (streq (Memc[fname], "^BPM")) { + flag = INVERT_MASK + iferr (call imgstr (refim, "BPM", Memc[fname+1], SZ_FNAME)) + Memc[fname] = EOS + } + + if (Memc[fname] == '^') { + flag = INVERT_MASK + call strcpy (Memc[fname+1], Memc[fname], SZ_FNAME) + } else + flag = NO + + if (streq (Memc[fname], "EMPTY")) + ref = refim + else + ref = NULL + + if (Memc[fname] != EOS) + im = yt_pmmap1 (Memc[fname], ref, refim, flag) + call strcpy (Memc[fname], mname, sz_mname) + + call sfree (sp) + return (im) +end + + +# XT_PMUNMAP -- Unmap a mask image. +# Note that the imio pointer may be purely an internal pointer opened +# with im_pmmapo so we need to free the pl pointer explicitly. + +procedure yt_pmunmap (im) + +pointer im #I IMIO pointer for mask + +pointer pm +int imstati() + +begin + pm = imstati (im, IM_PMDES) + call pm_close (pm) + call imseti (im, IM_PMDES, NULL) + call imunmap (im) +end + + +# XT_PMMAP1 -- Open a pixel mask READ_ONLY. The input mask may be +# a pixel list image, a non-pixel list image, or a text file. +# Return error if the pixel mask cannot be opened. For pixel masks +# or image masks match the WCS. + +pointer procedure yt_pmmap1 (pmname, ref, refim, flag) + +char pmname[ARB] #I Pixel mask name +pointer ref #I Reference image for pixel mask +pointer refim #I Reference image for image or text +int flag #I Mask flag + +int imstati(), errcode() +pointer im, pm +pointer im_pmmap(), yt_pmimmap(), yt_pmtext(), yt_pmsection() +bool streq() +errchk yt_match + +begin + im = NULL + + if (streq (pmname, "STDIN")) + im = yt_pmtext (pmname, refim, flag) + + else if (pmname[1] == '[') + im = yt_pmsection (pmname, refim, flag) + + else { + ifnoerr (im = im_pmmap (pmname, READ_ONLY, ref)) { + call yt_match (im, refim) + if (flag == INVERT_MASK) { + pm = imstati (im, IM_PMDES) + call yt_pminvert (pm) + call imseti (im, IM_PMDES, pm) + } + } else { + switch (errcode()) { + case SYS_IKIOPEN, SYS_FOPNNEXFIL, SYS_PLBADSAVEF, SYS_FOPEN: + ifnoerr (im = yt_pmimmap (pmname, refim, flag)) + call yt_match (im, refim) + else { + switch (errcode()) { + case SYS_IKIOPEN: + im = yt_pmtext (pmname, refim, flag) + default: + call erract (EA_ERROR) + } + } + default: + call erract (EA_ERROR) + } + } + } + + return (im) +end + + +# XT_PMIMMAP -- Open a pixel mask from a non-pixel list image. +# Return error if the image cannot be opened. + +pointer procedure yt_pmimmap (pmname, refim, flag) + +char pmname[ARB] #I Image name +pointer refim #I Reference image pointer +int flag #I Mask flag + +int i, ndim, npix, rop, val +pointer sp, v1, v2, im_in, im_out, pm, mw, data + +int imstati(), imgnli() +pointer immap(), pm_newmask(), im_pmmapo(), imgl1i(), mw_openim() +errchk immap, mw_openim + +begin + call smark (sp) + call salloc (v1, IM_MAXDIM, TY_LONG) + call salloc (v2, IM_MAXDIM, TY_LONG) + + call amovkl (long(1), Meml[v1], IM_MAXDIM) + call amovkl (long(1), Meml[v2], IM_MAXDIM) + + im_in = immap (pmname, READ_ONLY, 0) + pm = imstati (im_in, IM_PMDES) + if (pm != NULL) + return (im_in) + + pm = pm_newmask (im_in, 16) + + ndim = IM_NDIM(im_in) + npix = IM_LEN(im_in,1) + + if (flag == INVERT_MASK) + rop = PIX_NOT(PIX_SRC) + else + rop = PIX_SRC + + while (imgnli (im_in, data, Meml[v1]) != EOF) { + if (flag == INVERT_MASK) { + do i = 0, npix-1 { + val = Memi[data+i] + if (val <= 0) + Memi[data+i] = 1 + else + Memi[data+i] = 0 + } + } else { + do i = 0, npix-1 { + val = Memi[data+i] + if (val < 0) + Memi[data+i] = 0 + } + } + call pmplpi (pm, Meml[v2], Memi[data], 0, npix, rop) + call amovl (Meml[v1], Meml[v2], ndim) + } + + im_out = im_pmmapo (pm, im_in) + data = imgl1i (im_out) # Force I/O to set header + mw = mw_openim (im_in) # Set WCS + call mw_saveim (mw, im_out) + call mw_close (mw) + + #call imunmap (im_in) + call yt_pmunmap (im_in) + call sfree (sp) + return (im_out) +end + + +# XT_PMTEXT -- Create a pixel mask from a text file of rectangles. +# Return error if the file cannot be opened. +# This routine only applies to the first 2D plane. + +pointer procedure yt_pmtext (pmname, refim, flag) + +char pmname[ARB] #I Image name +pointer refim #I Reference image pointer +int flag #I Mask flag + +int fd, nc, nl, c1, c2, l1, l2, nc1, nl1, rop +pointer pm, im, mw, dummy + +int open(), fscan(), nscan() +pointer pm_newmask(), im_pmmapo(), imgl1i(), mw_openim() +errchk open + +begin + fd = open (pmname, READ_ONLY, TEXT_FILE) + pm = pm_newmask (refim, 16) + + nc = IM_LEN(refim,1) + nl = IM_LEN(refim,2) + + if (flag == INVERT_MASK) + call pl_box (pm, 1, 1, nc, nl, PIX_SET+PIX_VALUE(1)) + + while (fscan (fd) != EOF) { + call gargi (c1) + call gargi (c2) + call gargi (l1) + call gargi (l2) + if (nscan() != 4) { + if (nscan() == 2) { + l1 = c2 + c2 = c1 + l2 = l1 + } else + next + } + + c1 = max (1, c1) + c2 = min (nc, c2) + l1 = max (1, l1) + l2 = min (nl, l2) + nc1 = c2 - c1 + 1 + nl1 = l2 - l1 + 1 + if (nc1 < 1 || nl1 < 1) + next + + # Select mask value based on shape of rectangle. + if (flag == INVERT_MASK) + rop = PIX_CLR + else if (nc1 <= nl1) + rop = PIX_SET+PIX_VALUE(2) + else + rop = PIX_SET+PIX_VALUE(3) + + # Set mask rectangle. + call pm_box (pm, c1, l1, c2, l2, rop) + } + + call close (fd) + im = im_pmmapo (pm, refim) + dummy = imgl1i (im) # Force I/O to set header + mw = mw_openim (refim) # Set WCS + call mw_saveim (mw, im) + call mw_close (mw) + + return (im) +end + + +# XT_PMSECTION -- Create a pixel mask from an image section. +# This only applies the mask to the first plane of the image. + +pointer procedure yt_pmsection (section, refim, flag) + +char section[ARB] #I Image section +pointer refim #I Reference image pointer +int flag #I Mask flag + +int i, j, ip, temp, a[2], b[2], c[2], rop, ctoi() +pointer pm, im, mw, dummy, pm_newmask(), im_pmmapo(), imgl1i(), mw_openim() +define error_ 99 + +begin + # This is currently only for 1D and 2D images. + if (IM_NDIM(refim) > 2) + call error (1, "Image sections only allowed for 1D and 2D images") + + # Decode the section string. + call amovki (1, a, 2) + call amovki (1, b, 2) + call amovki (1, c, 2) + do i = 1, IM_NDIM(refim) + b[i] = IM_LEN(refim,i) + + ip = 1 + while (IS_WHITE(section[ip])) + ip = ip + 1 + if (section[ip] == '[') { + ip = ip + 1 + + do i = 1, IM_NDIM(refim) { + while (IS_WHITE(section[ip])) + ip = ip + 1 + + # Get a:b:c. Allow notation such as "-*:c" + # (or even "-:c") where the step is obviously negative. + + if (ctoi (section, ip, temp) > 0) { # a + a[i] = temp + if (section[ip] == ':') { + ip = ip + 1 + if (ctoi (section, ip, b[i]) == 0) # a:b + goto error_ + } else + b[i] = a[i] + } else if (section[ip] == '-') { # -* + temp = a[i] + a[i] = b[i] + b[i] = temp + ip = ip + 1 + if (section[ip] == '*') + ip = ip + 1 + } else if (section[ip] == '*') # * + ip = ip + 1 + if (section[ip] == ':') { # ..:step + ip = ip + 1 + if (ctoi (section, ip, c[i]) == 0) + goto error_ + else if (c[i] == 0) + goto error_ + } + if (a[i] > b[i] && c[i] > 0) + c[i] = -c[i] + + while (IS_WHITE(section[ip])) + ip = ip + 1 + if (i < IM_NDIM(refim)) { + if (section[ip] != ',') + goto error_ + } else { + if (section[ip] != ']') + goto error_ + } + ip = ip + 1 + } + } + + # In this case make the values be increasing only. + do i = 1, IM_NDIM(refim) + if (c[i] < 0) { + temp = a[i] + a[i] = b[i] + b[i] = temp + c[i] = -c[i] + } + + # Make the mask. + pm = pm_newmask (refim, 16) + + if (flag == INVERT_MASK) { + rop = PIX_SET+PIX_VALUE(1) + call pm_box (pm, 1, 1, IM_LEN(refim,1), IM_LEN(refim,2), rop) + rop = PIX_CLR + } else + rop = PIX_SET+PIX_VALUE(1) + + if (c[1] == 1 && c[2] == 1) + call pm_box (pm, a[1], a[2], b[1], b[2], rop) + + else if (c[1] == 1) + for (i=a[2]; i<=b[2]; i=i+c[2]) + call pm_box (pm, a[1], i, b[1], i, rop) + + else + for (i=a[2]; i<=b[2]; i=i+c[2]) + for (j=a[1]; j<=b[1]; j=j+c[1]) + call pm_point (pm, j, i, rop) + + im = im_pmmapo (pm, refim) + dummy = imgl1i (im) # Force I/O to set header + mw = mw_openim (refim) # Set WCS + call mw_saveim (mw, im) + call mw_close (mw) + + return (im) + +error_ + call error (1, "Error in image section specification") +end + + +# XT_PMINVERT -- Invert a pixel mask by changing 0 to 1 and non-zero to zero. + +procedure yt_pminvert (pm) + +pointer pm #I Pixel mask to be inverted + +int i, naxes, axlen[IM_MAXDIM], depth, npix, val +pointer sp, v, buf, one +bool pm_linenotempty() + +begin + call pm_gsize (pm, naxes, axlen, depth) + + call smark (sp) + call salloc (v, IM_MAXDIM, TY_LONG) + call salloc (buf, axlen[1], TY_INT) + call salloc (one, 6, TY_INT) + + npix = axlen[1] + RLI_LEN(one) = 2 + RLI_AXLEN(one) = npix + Memi[one+3] = 1 + Memi[one+4] = npix + Memi[one+5] = 1 + + call amovkl (long(1), Meml[v], IM_MAXDIM) + repeat { + if (pm_linenotempty (pm, Meml[v])) { + call pmglpi (pm, Meml[v], Memi[buf], 0, npix, 0) + do i = 0, npix-1 { + val = Memi[buf+i] + if (val == 0) + Memi[buf+i] = 1 + else + Memi[buf+i] = 0 + } + call pmplpi (pm, Meml[v], Memi[buf], 0, npix, PIX_SRC) + } else + call pmplri (pm, Meml[v], Memi[one], 0, npix, PIX_SRC) + + do i = 2, naxes { + Meml[v+i-1] = Meml[v+i-1] + 1 + if (Meml[v+i-1] <= axlen[i]) + break + else if (i < naxes) + Meml[v+i-1] = 1 + } + } until (Meml[v+naxes-1] > axlen[naxes]) + + call sfree (sp) +end + + +# XT_MATCH -- Set the pixel mask to match the reference image. +# This matches sizes and physical coordinates and allows the +# original mask to be smaller or larger than the reference image. +# Subsequent use of the pixel mask can then work in the logical +# coordinates of the reference image. The mask values are the maximum +# of the mask values which overlap each reference image pixel. +# A null input returns a null output. + +procedure yt_match (im, refim) + +pointer im #U Pixel mask image pointer +pointer refim #I Reference image pointer + +int i, j, k, l, i1, i2, j1, j2, nc, nl, ncpm, nlpm, nx, val +double x1, x2, y1, y2, lt[6], lt1[6], lt2[6] +long vold[IM_MAXDIM], vnew[IM_MAXDIM] +pointer pm, pmnew, imnew, mw, ctx, cty, bufref, bufpm + +int imstati() +double mw_c1trand() +pointer pm_open(), mw_openim(), im_pmmapo(), imgl1i(), mw_sctran() +bool pm_empty(), pm_linenotempty() +errchk pm_open, mw_openim + +begin + if (im == NULL) + return + + # Set sizes. + nc = IM_LEN(refim,1) + nl = IM_LEN(refim,2) + ncpm = IM_LEN(im,1) + nlpm = IM_LEN(im,2) + + # If the mask is empty and the sizes are the same then it does not + # matter if the two are actually matched in physical coordinates. + pm = imstati (im, IM_PMDES) + if (pm_empty(pm) && nc == ncpm && nl == nlpm) + return + + # Compute transformation between reference (logical) coordinates + # and mask (physical) coordinates. + + mw = mw_openim (im) + call mw_gltermd (mw, lt, lt[5], 2) + call mw_close (mw) + + mw = mw_openim (refim) + call mw_gltermd (mw, lt2, lt2[5], 2) + call mw_close (mw) + + # Combine lterms. + call mw_invertd (lt, lt1, 2) + call mw_mmuld (lt1, lt2, lt, 2) + call mw_vmuld (lt, lt[5], lt[5], 2) + lt[5] = lt2[5] - lt[5] + lt[6] = lt2[6] - lt[6] + do i = 1, 6 + lt[i] = nint (1D6 * (lt[i]-int(lt[i]))) / 1D6 + int(lt[i]) + + # Check for a rotation. For now don't allow any rotation. + if (lt[2] != 0. || lt[3] != 0.) + call error (1, "Image and mask have a relative rotation") + + # Check for an exact match. + if (lt[1] == 1D0 && lt[4] == 1D0 && lt[5] == 0D0 && lt[6] == 0D0) + return + + # Set reference to mask coordinates. + mw = mw_openim (im) + call mw_sltermd (mw, lt, lt[5], 2) + ctx = mw_sctran (mw, "logical", "physical", 1) + cty = mw_sctran (mw, "logical", "physical", 2) + + # Create a new pixel mask of the required size and offset. + # Do dummy image I/O to set the header. + pmnew = pm_open (NULL) + call pm_ssize (pmnew, 2, IM_LEN(refim,1), 27) + imnew = im_pmmapo (pmnew, NULL) + bufref = imgl1i (imnew) + + # Compute region of mask overlapping the reference image. + x1 = mw_c1trand (ctx, 1-0.5D0) + x2 = mw_c1trand (ctx, nc+0.5D0) + i1 = max (1, nint(min(x1,x2)+1D-5)) + i2 = min (ncpm, nint(max(x1,x2)-1D-5)) + y1 = mw_c1trand (cty, 1-0.5D0) + y2 = mw_c1trand (cty, nl+0.5D0) + j1 = max (1, nint(min(y1,y2)+1D-5)) + j2 = min (nlpm, nint(max(y1,y2)-1D-5)) + + # Set the new mask values to the maximum of all mask values falling + # within each reference pixel in the overlap region. + if (i1 >= i2 && j1 >= j2) { + nx = i2 - i1 + 1 + call malloc (bufpm, nx, TY_INT) + call malloc (bufref, nc, TY_INT) + vold[1] = i1 + vnew[1] = 1 + do j = 1, nl { + y1 = mw_c1trand (cty, j-0.5D0) + y2 = mw_c1trand (cty, j+0.5D0) + j1 = max (1, nint(min(y1,y2)+1D-5)) + j2 = min (nlpm, nint(max(y1,y2)-1D-5)) + if (j2 < j1) + next + + vnew[2] = j + call aclri (Memi[bufref], nc) + do l = j1, j2 { + vold[2] = l + if (!pm_linenotempty (pm, vold)) + next + call pmglpi (pm, vold, Memi[bufpm], 0, nx, 0) + do i = 1, nc { + x1 = mw_c1trand (ctx, i-0.5D0) + x2 = mw_c1trand (ctx, i+0.5D0) + i1 = max (1, nint(min(x1,x2)+1D-5)) + i2 = min (ncpm, nint(max(x1,x2)-1D-5)) + if (i2 < i1) + next + val = Memi[bufref+i-1] + do k = i1-vold[1], i2-vold[1] + val = max (val, Memi[bufpm+k]) + Memi[bufref+i-1] = val + } + } + call pmplpi (pmnew, vnew, Memi[bufref], 0, nc, PIX_SRC) + } + call mfree (bufref, TY_INT) + call mfree (bufpm, TY_INT) + } + + call mw_close (mw) + call yt_pmunmap (im) + im = imnew + call imseti (im, IM_PMDES, pmnew) +end |