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/mim.x | |
download | iraf-linux-fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4.tar.gz |
Initial commit
Diffstat (limited to 'noao/nproto/ace/mim.x')
-rw-r--r-- | noao/nproto/ace/mim.x | 544 |
1 files changed, 544 insertions, 0 deletions
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 |