IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
Nov 15, 2005, 10:09:03 AM (20 years ago)
Author:
gusciora
Message:

SubtractBias was recoded. Significant mods to removeBadPixels.
Additional mods to other files.

Location:
trunk/psModules/src/imsubtract
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/psModules/src/imsubtract/pmSubtractBias.c

    r5435 r5516  
    66 *  @author GLG, MHPCC
    77 *
    8  *  @version $Revision: 1.4 $ $Name: not supported by cvs2svn $
    9  *  @date $Date: 2005-10-20 23:06:24 $
     8 *  @version $Revision: 1.5 $ $Name: not supported by cvs2svn $
     9 *  @date $Date: 2005-11-15 20:09:03 $
    1010 *
    1111 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
    1212 *
    1313 */
    14 
     14/*****************************************************************************/
     15/* INCLUDE FILES                                                             */
     16/*****************************************************************************/
     17#include <stdio.h>
     18#include <math.h>
     19#include <string.h>
     20#include "pslib.h"
    1521#if HAVE_CONFIG_H
    1622#include <config.h>
    1723#endif
    18 
    1924#include "pmSubtractBias.h"
    2025
    21 #define PM_SUBTRACT_BIAS_POLYNOMIAL_ORDER 2
    22 #define PM_SUBTRACT_BIAS_SPLINE_ORDER 3
    23 
     26/*****************************************************************************/
     27/* DEFINE STATEMENTS                                                         */
     28/*****************************************************************************/
    2429// XXX: put these in psConstants.h
    25 void PS_POLY1D_PRINT(psPolynomial1D *poly)
     30void PS_POLY1D_PRINT(
     31    psPolynomial1D *poly)
    2632{
    2733    printf("-------------- PS_POLY1D_PRINT() --------------\n");
     
    5157}\
    5258
    53 /******************************************************************************
    54 psSubtractFrame(): this routine will take as input a readout for the input
    55 image and a readout for the bias image.  The bias image is subtracted in
    56 place from the input image.
     59/*****************************************************************************/
     60/* TYPE DEFINITIONS                                                          */
     61/*****************************************************************************/
     62
     63/*****************************************************************************/
     64/* GLOBAL VARIABLES                                                          */
     65/*****************************************************************************/
     66psS32 currentId = 0;                // XXX: remove
     67psS32 memLeaks = 0;                 // XXX: remove
     68//PRINT_MEMLEAKS(8); XXX
     69/*****************************************************************************/
     70/* FILE STATIC VARIABLES                                                     */
     71/*****************************************************************************/
     72
     73/*****************************************************************************/
     74/* FUNCTION IMPLEMENTATION - LOCAL                                           */
     75/*****************************************************************************/
     76
     77/******************************************************************************
     78psSubtractFrame(): this routine will take as input the pmReadout for the input
     79image and a pmReadout for the bias image.  The bias image is subtracted in
     80place from the input image.  We assume that sizes and types are checked
     81elsewhere.
     82 
     83XXX: Verify that the image and readout offsets are being used the right way.
     84 
     85XXX: Ensure that it does the correct thing with image size.
    5786*****************************************************************************/
    58 static pmReadout *SubtractFrame(pmReadout *in,
    59                                 const pmReadout *bias)
    60 {
    61     psS32 i;
    62     psS32 j;
    63 
    64     if (bias == NULL) {
    65         psLogMsg(__func__, PS_LOG_WARN,
    66                  "WARNING: pmSubtractBias.c: SubtractFrame(): bias frame is NULL.  Returning original image.\n");
    67         return(in);
    68     }
    69 
    70 
    71     if ((in->image->numRows + in->row0 - bias->row0) > bias->image->numRows) {
    72         psError(PS_ERR_UNKNOWN,true, "bias image does not have enough rows.  Returning in image\n");
    73         return(in);
    74     }
    75     if ((in->image->numCols + in->col0 - bias->col0) > bias->image->numCols) {
    76         psError(PS_ERR_UNKNOWN,true, "bias image does not have enough columns.  Returning in image\n");
    77         return(in);
    78     }
    79 
    80     for (i=0;i<in->image->numRows;i++) {
    81         for (j=0;j<in->image->numCols;j++) {
     87static pmReadout *SubtractFrame(
     88    pmReadout *in,
     89    const pmReadout *bias)
     90{
     91    // XXX: When did the ->row0 and ->col0 offsets get coded?
     92    for (psS32 i=0;i<in->image->numRows;i++) {
     93        for (psS32 j=0;j<in->image->numCols;j++) {
    8294            in->image->data.F32[i][j]-=
    8395                bias->image->data.F32[i+in->row0-bias->row0][j+in->col0-bias->col0];
     96
    8497            if ((in->mask != NULL) && (bias->mask != NULL)) {
    8598                (in->mask->data.U8[i][j])|=
     
    92105}
    93106
     107
     108/******************************************************************************
     109psSubtractDarkFrame(): this routine will take as input the pmReadout for the
     110input image and a pmReadout for the dark image.  The dark image is scaled and
     111subtracted in place from the input image.
     112 
     113XXX: Verify that the image and readout offsets are being used the right way.
     114 
     115XXX: Ensure that it does the correct thing with image size.
     116*****************************************************************************/
     117static pmReadout *SubtractDarkFrame(
     118    pmReadout *in,
     119    const pmReadout *dark,
     120    psF32 scale)
     121{
     122    // XXX: When did the ->row0 and ->col0 offsets get coded?
     123    if (fabs(scale) > FLT_EPSILON) {
     124        for (psS32 i=0;i<in->image->numRows;i++) {
     125            for (psS32 j=0;j<in->image->numCols;j++) {
     126                in->image->data.F32[i][j]-=
     127                    (scale * dark->image->data.F32[i+in->row0-dark->row0][j+in->col0-dark->col0]);
     128
     129                if ((in->mask != NULL) && (dark->mask != NULL)) {
     130                    (in->mask->data.U8[i][j])|=
     131                        dark->mask->data.U8[i+in->row0-dark->row0][j+in->col0-dark->col0];
     132                }
     133            }
     134        }
     135    } else {
     136        for (psS32 i=0;i<in->image->numRows;i++) {
     137            for (psS32 j=0;j<in->image->numCols;j++) {
     138                in->image->data.F32[i][j]-=
     139                    dark->image->data.F32[i+in->row0-dark->row0][j+in->col0-dark->col0];
     140
     141                if ((in->mask != NULL) && (dark->mask != NULL)) {
     142                    (in->mask->data.U8[i][j])|=
     143                        dark->mask->data.U8[i+in->row0-dark->row0][j+in->col0-dark->col0];
     144                }
     145            }
     146        }
     147    }
     148
     149    return(in);
     150}
     151
    94152/******************************************************************************
    95153ImageSubtractScalar(): subtract a scalar from the input image.
    96154 
    97 XXX: Use a psLib function for this.
    98  
    99 XXX: This should
    100  *****************************************************************************/
    101 static psImage *ImageSubtractScalar(psImage *image,
    102                                     psF32 scalar)
     155XXX: Is there a psLib function for this?
     156 *****************************************************************************/
     157static psImage *ImageSubtractScalar(
     158    psImage *image,
     159    psF32 scalar)
    103160{
    104161    for (psS32 i=0;i<image->numRows;i++) {
     
    164221
    165222    if (numOptions == 0) {
    166         psError(PS_ERR_UNKNOWN,true, "No statistics options have been specified.\n");
     223        psError(PS_ERR_UNKNOWN,true, "No allowable statistics options have been specified.\n");
    167224    }
    168225    if (numOptions != 1) {
     
    173230}
    174231
    175 
     232/******************************************************************************
     233Polynomial1DCopy(): This private function copies the members of the existing
     234psPolynomial1D "in" into the existing psPolynomial1D "out".  The previous
     235members of the existing psPolynomial1D "out" are psFree'ed.
     236 *****************************************************************************/
     237static psBool Polynomial1DCopy(
     238    psPolynomial1D *out,
     239    psPolynomial1D *in)
     240{
     241    psFree(out->coeff);
     242    psFree(out->coeffErr);
     243    psFree(out->mask);
     244
     245    out->type = in->type;
     246    out->nX = in->nX;
     247
     248    out->coeff = (psF64 *) psAlloc((in->nX + 1) * sizeof(psF64));
     249    // XXX: use memcpy
     250    for (psS32 i = 0 ; i < (in->nX + 1) ; i++) {
     251        out->coeff[i] = in->coeff[i];
     252    }
     253
     254    out->coeffErr = (psF64 *) psAlloc((in->nX + 1) * sizeof(psF64));
     255    // XXX: use memcpy
     256    for (psS32 i = 0 ; i < (in->nX + 1) ; i++) {
     257        out->coeffErr[i] = in->coeffErr[i];
     258    }
     259
     260    out->mask = (psMaskType *) psAlloc((in->nX + 1) * sizeof(psMaskType));
     261    // XXX: use memcpy
     262    for (psS32 i = 0 ; i < (in->nX + 1) ; i++) {
     263        out->mask[i] = in->mask[i];
     264    }
     265
     266    return(true);
     267}
     268
     269/******************************************************************************
     270Polynomial1DDup(): This private function duplicates and then returns the input
     271psPolynomial1D "in".
     272 *****************************************************************************/
     273static psPolynomial1D *Polynomial1DDup(
     274    psPolynomial1D *in)
     275{
     276    psPolynomial1D *out = psPolynomial1DAlloc(in->nX, in->type);
     277    Polynomial1DCopy(out, in);
     278    return(out);
     279}
     280
     281
     282/******************************************************************************
     283SplineCopy(): This private function copies the members of the existing
     284psSpline in into the existing psSpline out.
     285 *****************************************************************************/
     286static psBool SplineCopy(
     287    psSpline1D *out,
     288    psSpline1D *in)
     289{
     290    PS_ASSERT_PTR_NON_NULL(out, false);
     291    PS_ASSERT_PTR_NON_NULL(in, false);
     292
     293    for (psS32 i = 0 ; i < out->n ; i++) {
     294        psFree(out->spline[i]);
     295    }
     296    psFree(out->spline);
     297    psFree(out->knots);
     298    psFree(out->p_psDeriv2);
     299
     300    out->n = in->n;
     301    out->spline = (psPolynomial1D **) psAlloc(in->n * sizeof(psPolynomial1D *));
     302    for (psS32 i = 0 ; i < in->n ; i++) {
     303        out->spline[i] = Polynomial1DDup(in->spline[i]);
     304    }
     305
     306    out->knots = psVectorCopy(out->knots, in->knots, in->knots->type.type);
     307
     308    out->p_psDeriv2 = (psF32 *) psAlloc((in->n + 1) * sizeof(psF32));
     309    // XXX: use memcpy
     310    for (psS32 i = 0 ; i < (in->n + 1) ; i++) {
     311        out->p_psDeriv2[i] = in->p_psDeriv2[i];
     312    }
     313
     314    return(true);
     315}
    176316
    177317/******************************************************************************
     
    181321    PM_FIT_POLYNOMIAL: fit a polynomial to the entire input vector data.
    182322    PM_FIT_SPLINE: fit splines to the input vector data.
    183 XXX: Doesn't it make more sense to do polynomial interpolation on a few
    184 elements of the input vector, rather than fit a polynomial to the entire
    185 vector?
    186  *****************************************************************************/
    187 static psVector *ScaleOverscanVector(psVector *overscanVector,
    188                                      psS32 n,
    189                                      void *fitSpec,
    190                                      pmFit fit)
     323The resulting spline or polynomial is set in the fitSpec argument.
     324 *****************************************************************************/
     325static psVector *ScaleOverscanVector(
     326    psVector *overscanVector,
     327    psS32 n,
     328    void *fitSpec,
     329    pmFit fit)
    191330{
    192331    psTrace(".psModule.pmSubtracBias.ScaleOverscanVector", 4,
    193332            "---- ScaleOverscanVector() begin (%d -> %d) ----\n", overscanVector->n, n);
    194     //    PS_VECTOR_PRINT_F32(overscanVector);
    195333
    196334    if (NULL == overscanVector) {
     
    205343    //
    206344    if (n == overscanVector->n) {
    207         for (psS32 i = 0 ; i < n ; i++) {
    208             newVec->data.F32[i] = overscanVector->data.F32[i];
    209         }
    210         return(newVec);
    211     }
    212     psPolynomial1D *myPoly;
    213     psSpline1D *mySpline;
     345        return(psVectorCopy(newVec, overscanVector, PS_TYPE_F32));
     346    }
    214347    psF32 x;
    215     psS32 i;
    216348
    217349    if (fit == PM_FIT_POLYNOMIAL) {
    218350        // Fit a polynomial to the old overscan vector.
    219         myPoly = (psPolynomial1D *) fitSpec;
     351        psPolynomial1D *myPoly = (psPolynomial1D *) fitSpec;
    220352        PS_ASSERT_POLY_NON_NULL(myPoly, NULL);
     353        PS_ASSERT_POLY1D(myPoly, NULL);
    221354        myPoly = psVectorFitPolynomial1D(myPoly, NULL, 0, overscanVector, NULL, NULL);
    222355        if (myPoly == NULL) {
    223             psError(PS_ERR_UNKNOWN, false, "ScaleOverscanVector()(1): Could not fit a polynomial to the psVector.\n");
     356            psError(PS_ERR_UNKNOWN, false, "Could not fit a polynomial to the psVector.\n");
    224357            return(NULL);
    225358        }
     
    228361        // of the old vector, use the fitted polynomial to determine the
    229362        // interpolated value at that point, and set the new vector.
    230         for (i=0;i<n;i++) {
     363        for (psS32 i=0;i<n;i++) {
    231364            x = ((psF32) i) * ((psF32) overscanVector->n) / ((psF32) n);
    232365            newVec->data.F32[i] = psPolynomial1DEval(myPoly, x);
    233366        }
    234367    } else if (fit == PM_FIT_SPLINE) {
    235         psS32 mustFreeSpline = 0;
    236         // Fit a spline to the old overscan vector.
    237         mySpline = (psSpline1D *) fitSpec;
    238         // XXX: Does it make any sense to have a psSpline argument?
    239         if (mySpline == NULL) {
    240             mustFreeSpline = 1;
    241         }
    242 
    243368        //
    244369        // NOTE: Since the X arg in the psVectorFitSpline1D() function is NULL,
     
    246371        // properly when doing the spline eval.
    247372        //
    248         //        mySpline = psVectorFitSpline1D(mySpline, NULL, overscanVector, NULL);
    249         mySpline = psVectorFitSpline1D(NULL, overscanVector);
     373        psSpline1D *mySpline = psVectorFitSpline1D(NULL, overscanVector);
    250374        if (mySpline == NULL) {
    251             psError(PS_ERR_UNKNOWN, false, "ScaleOverscanVector()(2): Could not fit a spline to the psVector.\n");
     375            psError(PS_ERR_UNKNOWN, false, "Could not fit a spline to the psVector.\n");
    252376            return(NULL);
    253377        }
    254         //        PS_PRINT_SPLINE(mySpline);
    255378
    256379        // For each element of the new vector, convert the x-ordinate to that
    257         // of the old vector, use the fitted polynomial to determine the
     380        // of the old vector, use the fitted spline to determine the
    258381        // interpolated value at that point, and set the new vector.
    259         for (i=0;i<n;i++) {
     382        for (psS32 i=0;i<n;i++) {
    260383            // Scale to [0 : overscanVector->n - 1]
    261384            x = ((psF32) i) * ((psF32) (overscanVector->n-1)) / ((psF32) n);
    262385            newVec->data.F32[i] = psSpline1DEval(mySpline, x);
    263386        }
    264         if (mustFreeSpline ==1) {
    265             psFree(mySpline);
    266         }
    267         //        PS_VECTOR_PRINT_F32(newVec);
    268 
    269 
     387
     388        psSpline1D *ptrSpline = (psSpline1D *) fitSpec;
     389        if (ptrSpline != NULL) {
     390            // Copy the resulting spline fit into ptrSpline.
     391            PS_ASSERT_SPLINE(ptrSpline, NULL);
     392            SplineCopy(ptrSpline, mySpline);
     393        }
     394        psFree(mySpline);
    270395    } else {
    271396        psError(PS_ERR_UNKNOWN, true, "unknown fit type.  Returning NULL.\n");
     
    280405
    281406/******************************************************************************
    282 XXX: The SDRS does not specify type support.  F32 is implemented here.
     407 *****************************************************************************/
     408static psS32 GetOverscanSize(
     409    psImage *inImg,
     410    pmOverscanAxis overScanAxis)
     411{
     412    if (overScanAxis == PM_OVERSCAN_ROWS) {
     413        return(inImg->numCols);
     414    } else if (overScanAxis == PM_OVERSCAN_COLUMNS) {
     415        return(inImg->numRows);
     416    } else if (overScanAxis == PM_OVERSCAN_ALL) {
     417        return(1);
     418    }
     419    return(0);
     420}
     421
     422/******************************************************************************
     423GetOverscanAxis(in) this private routine determines the appropiate overscan
     424axis from the parent cell metadata.
     425 
     426XXX: Verify the READDIR corresponds with my overscan axis.
     427 *****************************************************************************/
     428static pmOverscanAxis GetOverscanAxis(pmReadout *in)
     429{
     430    psBool rc;
     431    if ((in->parent != NULL) && (in->parent->concepts)) {
     432        psS32 dir = psMetadataLookupS32(&rc, in->parent->concepts, "CELL.READDIR");
     433        if (rc == true) {
     434            if (dir == 1) {
     435                return(PM_OVERSCAN_ROWS);
     436            } else if (dir == 2) {
     437                return(PM_OVERSCAN_COLUMNS);
     438            } else if (dir == 3) {
     439                return(PM_OVERSCAN_ALL);
     440            }
     441        }
     442    }
     443
     444    psLogMsg(__func__, PS_LOG_WARN,
     445             "WARNING: pmSubtractBias.(): could not determine CELL.READDIR from in->parent metadata.  Setting overscan axis to PM_OVERSCAN_NONE.\n");
     446    return(PM_OVERSCAN_NONE);
     447}
     448
     449/******************************************************************************
     450psListLength(list): determine the length of a psList.
     451 
     452XXX: Put this elsewhere.
     453 *****************************************************************************/
     454static psS32 psListLength(
     455    psList *list)
     456{
     457    psS32 length = 0;
     458    psListElem *tmpElem = (psListElem *) list->head;
     459    while (NULL != tmpElem) {
     460        tmpElem = tmpElem->next;
     461        length++;
     462    }
     463    return(length);
     464}
     465
     466/******************************************************************************
     467Note: this isn't needed anymore as of psModule SDRS 12-09.
     468 *****************************************************************************/
     469static psBool OverscanReducePixel(
     470    psImage *in,
     471    psList *bias,
     472    psStats *myStats)
     473{
     474    PS_ASSERT_PTR_NON_NULL(in, NULL);
     475    PS_ASSERT_PTR_NON_NULL(bias, NULL);
     476    PS_ASSERT_PTR_NON_NULL(bias->head, NULL);
     477    PS_ASSERT_PTR_NON_NULL(myStats, NULL);
     478
     479    // Allocate a psVector with one element per overscan image.
     480    psS32 numOverscanImages = psListLength(bias);
     481    psVector *statsAll = psVectorAlloc(numOverscanImages, PS_TYPE_F32);
     482    psListElem *tmpOverscan = (psListElem *) bias->head;
     483    psS32 i = 0;
     484    psF64 statValue;
     485    //
     486    // We loop through each overscan image, calculating the specified
     487    // statistic on that image.
     488    //
     489    while (NULL != tmpOverscan) {
     490        psImage *myOverscanImage = (psImage *) tmpOverscan->data;
     491
     492        PS_ASSERT_IMAGE_TYPE(myOverscanImage, PS_TYPE_F32, NULL);
     493        myStats = psImageStats(myStats, myOverscanImage, NULL, (psMaskType)0xffffffff);
     494        if (myStats == NULL) {
     495            psError(PS_ERR_UNKNOWN, false, "psImageStats(): could not perform requested statistical operation.  Returning in image.\n");
     496            psFree(statsAll);
     497            return(false);
     498        }
     499        if (false == p_psGetStatValue(myStats, &statValue)) {
     500            psError(PS_ERR_UNKNOWN, false, "p_psGetStatValue(): could not determine result from requested statistical operation.  Returning in image.\n");
     501            psFree(statsAll);
     502            return(false);
     503        }
     504        statsAll->data.F32[i] = statValue;
     505        i++;
     506        tmpOverscan = tmpOverscan->next;
     507    }
     508
     509    //
     510    // We reduce the individual stats for each overscan image to
     511    // a single psF32.
     512    //
     513    myStats = psVectorStats(myStats, statsAll, NULL, NULL, 0);
     514    if (myStats == NULL) {
     515        psError(PS_ERR_UNKNOWN, false, "psImageStats(): could not perform requested statistical operation.  Returning in image.\n");
     516        psFree(statsAll);
     517        return(false);
     518    }
     519    if (false == p_psGetStatValue(myStats, &statValue)) {
     520        psError(PS_ERR_UNKNOWN, false, "p_psGetStatValue(): could not determine result from requested statistical operation.  Returning in image.\n");
     521        psFree(statsAll);
     522        return(false);
     523    }
     524
     525    //
     526    // Subtract the result and return.
     527    //
     528    ImageSubtractScalar(in, statValue);
     529    psFree(statsAll);
     530    return(in);
     531}
     532
     533/******************************************************************************
     534ReduceOverscanImageToCol(overscanImage, myStats): This private routine reduces
     535a single psImage to a column by combining all pixels from each row into a
     536single pixel via requested statistic in myStats.
     537 *****************************************************************************/
     538static psVector *ReduceOverscanImageToCol(
     539    psImage *overscanImage,
     540    psStats *myStats)
     541{
     542    psF64 statValue;
     543    psVector *tmpRow = psVectorAlloc(overscanImage->numCols, PS_TYPE_F32);
     544    psVector *tmpCol = psVectorAlloc(overscanImage->numRows, PS_TYPE_F32);
     545
     546    //
     547    // For each row, we store all pixels in that row into a temporary psVector,
     548    // then we run psVectorStats() on that vector.
     549    //
     550    for (psS32 i=0;i<overscanImage->numRows;i++) {
     551        for (psS32 j=0;j<overscanImage->numCols;j++) {
     552            tmpRow->data.F32[j] = overscanImage->data.F32[i][j];
     553        }
     554
     555        psStats *rc = psVectorStats(myStats, tmpRow, NULL, NULL, 0);
     556        if (rc == NULL) {
     557            psError(PS_ERR_UNKNOWN, true, "psVectorStats() could not perform requested statistical operation.  Returning in image.\n");
     558            return(NULL);
     559        }
     560
     561        if (false ==  p_psGetStatValue(rc, &statValue)) {
     562            psError(PS_ERR_UNKNOWN, true, "p_psGetStatValue() could not determine result from requested statistical operation.  Returning in image.\n");
     563            return(NULL);
     564        }
     565
     566        tmpCol->data.F32[i] = (psF32) statValue;
     567    }
     568    psFree(tmpRow);
     569
     570    return(tmpCol);
     571}
     572
     573/******************************************************************************
     574ReduceOverscanImageToCol(overscanImage, myStats): This private routine reduces
     575a single psImage to a row by combining all pixels from each column into a
     576single pixel via requested statistic in myStats.
     577 *****************************************************************************/
     578static psVector *ReduceOverscanImageToRow(
     579    psImage *overscanImage,
     580    psStats *myStats)
     581{
     582    psF64 statValue;
     583    psVector *tmpRow = psVectorAlloc(overscanImage->numCols, PS_TYPE_F32);
     584    psVector *tmpCol = psVectorAlloc(overscanImage->numRows, PS_TYPE_F32);
     585
     586    //
     587    // For each column, we store all pixels in that column into a temporary psVector,
     588    // then we run psVectorStats() on that vector.
     589    //
     590    for (psS32 i=0;i<overscanImage->numCols;i++) {
     591        for (psS32 j=0;j<overscanImage->numRows;j++) {
     592            tmpCol->data.F32[j] = overscanImage->data.F32[j][i];
     593        }
     594
     595        psStats *rc = psVectorStats(myStats, tmpCol, NULL, NULL, 0);
     596        if (rc == NULL) {
     597            psError(PS_ERR_UNKNOWN, true, "psVectorStats() could not perform requested statistical operation.  Returning in image.\n");
     598            return(NULL);
     599        }
     600
     601        if (false ==  p_psGetStatValue(rc, &statValue)) {
     602            psError(PS_ERR_UNKNOWN, true, "p_psGetStatValue() could not determine result from requested statistical operation.  Returning in image.\n");
     603            return(NULL);
     604        }
     605
     606        tmpRow->data.F32[i] = (psF32) statValue;
     607    }
     608    psFree(tmpCol);
     609
     610    return(tmpRow);
     611}
     612
     613/******************************************************************************
     614OverscanReduce(vecSize, bias, myStats): This private routine takes a psList of
     615overscan images (in bias) and reduces them to a single psVector via the
     616specified psStats struct.  The vector is then scaled to the length or the
     617row/column in inImg.
     618 *****************************************************************************/
     619static psVector* OverscanReduce(
     620    psImage *inImg,
     621    pmOverscanAxis overScanAxis,
     622    psList *bias,
     623    void *fitSpec,
     624    pmFit fit,
     625    psStats *myStats)
     626{
     627    if ((overScanAxis != PM_OVERSCAN_ROWS) && (overScanAxis != PM_OVERSCAN_COLUMNS)) {
     628        psError(PS_ERR_UNKNOWN, true, "overScanAxis must be PM_OVERSCAN_ROWS or PM_OVERSCAN_COLUMNS\n");
     629        return(NULL);
     630    }
     631    PS_ASSERT_PTR_NON_NULL(inImg, NULL);
     632    PS_ASSERT_PTR_NON_NULL(bias, NULL);
     633    PS_ASSERT_PTR_NON_NULL(bias->head, NULL);
     634    PS_ASSERT_PTR_NON_NULL(myStats, NULL);
     635    //
     636    // Allocate a psVector for the output of this routine.
     637    //
     638    psS32 vecSize = GetOverscanSize(inImg, overScanAxis);
     639    psVector *overscanVector = psVectorAlloc(vecSize, PS_TYPE_F32);
     640
     641    //
     642    // Allocate an array of psVectors with one psVector per element of the
     643    // final oversan column vector.  These psVectors will be used with
     644    // psStats to reduce the multiple elements from each overscan column
     645    // vector to a single final column vector.
     646    //
     647    psS32 numOverscanImages = psListLength(bias);
     648    psVector **overscanVectors = (psVector **) psAlloc(numOverscanImages * sizeof(psVector *));
     649    for (psS32 i = 0 ; i < numOverscanImages ; i++) {
     650        overscanVectors[i] = NULL;
     651    }
     652
     653    //
     654    // We iterate through the list of overscan images.  For each image,
     655    // we reduce it to a single column or row.  Save the overscan vector
     656    // in overscanVectors[].
     657    //
     658    psListElem *tmpOverscan = (psListElem *) bias->head;
     659    psS32 overscanID = 0;
     660    while (tmpOverscan != NULL) {
     661        psImage *tmpOverscanImage = (psImage *) tmpOverscan->data;
     662        if (overScanAxis == PM_OVERSCAN_ROWS) {
     663            overscanVectors[overscanID] = ReduceOverscanImageToRow(tmpOverscanImage, myStats);
     664        } else if (overScanAxis == PM_OVERSCAN_COLUMNS) {
     665            overscanVectors[overscanID] = ReduceOverscanImageToCol(tmpOverscanImage, myStats);
     666        }
     667
     668        tmpOverscan = tmpOverscan->next;
     669        overscanID++;
     670    }
     671
     672    //
     673    // For each overscan vector, if necessary, we scale that column or
     674    // row to vecSize.  Note: we should have already ensured that the
     675    // fit is poly or spline.
     676    //
     677    for (psS32 i = 0 ; i < numOverscanImages ; i++) {
     678        psVector *tmpOverscanVector = overscanVectors[i];
     679
     680        if (tmpOverscanVector->n != vecSize) {
     681            overscanVectors[i] = ScaleOverscanVector(tmpOverscanVector, vecSize, fitSpec, fit);
     682            if (overscanVectors[i] == NULL) {
     683                psError(PS_ERR_UNKNOWN, false, "ScaleOverscanVector(): could not scale the overscan vector.\n");
     684                for (psS32 i = 0 ; i < numOverscanImages ; i++) {
     685                    psFree(overscanVectors[i]);
     686                }
     687                psFree(overscanVectors);
     688                psFree(tmpOverscanVector);
     689                return(NULL);
     690            }
     691            psFree(tmpOverscanVector);
     692        }
     693    }
     694
     695    //
     696    // We collect all elements in the overscan vectors for the various
     697    // overscan images into a single psVector (tmpVec).  Then we call
     698    // psStats on that vector to determine the final values for the
     699    // overscan vector.
     700    //
     701    psVector *tmpVec = psVectorAlloc(numOverscanImages, PS_TYPE_F32);
     702    psF64 statValue;
     703    for (psS32 i = 0 ; i < vecSize ; i++) {
     704        // Collect the i-th elements from each overscan vector into a single vector.
     705        for (psS32 j = 0 ; j < numOverscanImages ; j++) {
     706            tmpVec->data.F32[j] = overscanVectors[j]->data.F32[i];
     707        }
     708
     709        if (NULL == psVectorStats(myStats, tmpVec, NULL, NULL, 0)) {
     710            psError(PS_ERR_UNKNOWN, false, "psVectorStats(): could not perform requested statistical operation.  Returning in image.\n");
     711            for (psS32 i = 0 ; i < numOverscanImages ; i++) {
     712                psFree(overscanVectors[i]);
     713            }
     714            psFree(overscanVectors);
     715            psFree(tmpVec);
     716            return(NULL);
     717        }
     718        if (false == p_psGetStatValue(myStats, &statValue)) {
     719            psError(PS_ERR_UNKNOWN, false, "p_psGetStatValue(): could not determine result from requested statistical operation.  Returning in image.\n");
     720            for (psS32 i = 0 ; i < numOverscanImages ; i++) {
     721                psFree(overscanVectors[i]);
     722            }
     723            psFree(overscanVectors);
     724            psFree(tmpVec);
     725            return(NULL);
     726        }
     727
     728        overscanVector->data.F32[i] = (psF32) statValue;
     729    }
     730
     731    //
     732    // We're done.  Free the intermediate overscan vectors.
     733    //
     734    psFree(tmpVec);
     735    for (psS32 i = 0 ; i < numOverscanImages ; i++) {
     736        psFree(overscanVectors[i]);
     737    }
     738    psFree(overscanVectors);
     739
     740    //
     741    // Return the computed overscanVector
     742    //
     743    return(overscanVector);
     744}
     745
     746/******************************************************************************
     747RebinOverscanVector(overscanVector, nBinOrig, myStats): this private routine
     748takes groups of nBinOrig elements in the input vector, combines them into a
     749single pixel via myStats and psVectorStats(), and then outputs a vector of
     750those pixels.
     751 *****************************************************************************/
     752static psS32 RebinOverscanVector(
     753    psVector *overscanVector,
     754    psS32 nBinOrig,
     755    psStats *myStats)
     756{
     757    psF64 statValue;
     758    psS32 nBin;
     759    if ((nBinOrig > 1) && (nBinOrig < overscanVector->n)) {
     760        psS32 numBins = 1+((overscanVector->n)/nBinOrig);
     761        psVector *myBin = psVectorAlloc(numBins, PS_TYPE_F32);
     762        psVector *binVec = psVectorAlloc(nBinOrig, PS_TYPE_F32);
     763
     764        for (psS32 i=0;i<numBins;i++) {
     765            for(psS32 j=0;j<nBinOrig;j++) {
     766                if (overscanVector->n > ((i*nBinOrig)+j)) {
     767                    binVec->data.F32[j] = overscanVector->data.F32[(i*nBinOrig)+j];
     768                } else {
     769                    // XXX: we get here if nBinOrig does not evenly divide
     770                    // the overscanVector vector.  This is the last bin.  Should
     771                    // we change the binVec->n to acknowledge that?
     772                    binVec->n = j;
     773                }
     774            }
     775            psStats *rc = psVectorStats(myStats, binVec, NULL, NULL, 0);
     776            if (rc == NULL) {
     777                psError(PS_ERR_UNKNOWN, false, "psVectorStats(): could not perform requested statistical operation.  Returning in image.\n");
     778                return(-1);
     779            }
     780            if (false ==  p_psGetStatValue(rc, &statValue)) {
     781                psError(PS_ERR_UNKNOWN, false, "p_psGetStatValue(): could not determine result from requested statistical operation.  Returning in image.\n");
     782                return(-1);
     783            }
     784            myBin->data.F32[i] = statValue;
     785        }
     786
     787        // Change the effective size of overscanVector.
     788        overscanVector->n = numBins;
     789        for (psS32 i=0;i<numBins;i++) {
     790            overscanVector->data.F32[i] = myBin->data.F32[i];
     791        }
     792        psFree(binVec);
     793        psFree(myBin);
     794        nBin = nBinOrig;
     795    } else {
     796        nBin = 1;
     797    }
     798
     799    return(nBin);
     800}
     801
     802/******************************************************************************
     803FitOverscanVectorAndUnbin(inImg, overscanVector, overScanAxis, fitSpec, fit,
     804nBin):  this private routine fits a psPolynomial or psSpline to the overscan
     805vector.  It then creates a new vector, with a size determined by the input
     806image, evaluates the psPolynomial or psSpline at each element in that vector,
     807then returns that vector.
     808 *****************************************************************************/
     809static psVector *FitOverscanVectorAndUnbin(
     810    psImage *inImg,
     811    psVector *overscanVector,
     812    pmOverscanAxis overScanAxis,
     813    void *fitSpec,
     814    pmFit fit,
     815    psS32 nBin)
     816{
     817    psPolynomial1D* myPoly = NULL;
     818    psSpline1D *mySpline = NULL;
     819    //
     820    // Fit a polynomial or spline to the overscan vector.
     821    //
     822    if (fit == PM_FIT_POLYNOMIAL) {
     823        myPoly = (psPolynomial1D *) fitSpec;
     824        PS_ASSERT_POLY_NON_NULL(myPoly, NULL);
     825        PS_ASSERT_POLY1D(myPoly, NULL);
     826        myPoly = psVectorFitPolynomial1D(myPoly, NULL, 0, overscanVector, NULL, NULL);
     827        if (myPoly == NULL) {
     828            psError(PS_ERR_UNKNOWN, false, "Could not fit a polynomial to overscan vector.  Returning NULL.\n");
     829            return(NULL);
     830        }
     831    } else if (fit == PM_FIT_SPLINE) {
     832        mySpline = psVectorFitSpline1D(NULL, overscanVector);
     833        if (mySpline == NULL) {
     834            psError(PS_ERR_UNKNOWN, false, "Could not fit a spline to overscan vector.  Returning NULL.\n");
     835            return(NULL);
     836        }
     837        if (fitSpec != NULL) {
     838            // Copy the resulting spline fit into fitSpec.
     839            psSpline1D *ptrSpline = (psSpline1D *) fitSpec;
     840            PS_ASSERT_SPLINE(ptrSpline, NULL);
     841            SplineCopy(ptrSpline, mySpline);
     842        }
     843    }
     844
     845    //
     846    // Evaluate the poly/spline at each pixel in the overscan row/column.
     847    //
     848    psS32 vecSize = GetOverscanSize(inImg, overScanAxis);
     849    psVector *newVec = psVectorAlloc(vecSize, PS_TYPE_F32);
     850    if ((nBin > 1) && (nBin < overscanVector->n)) {
     851        for (psS32 i = 0 ; i < vecSize ; i++) {
     852            if (fit == PM_FIT_POLYNOMIAL) {
     853                newVec->data.F32[i] = psPolynomial1DEval(myPoly, ((psF32) i) / ((psF32) nBin));
     854            } else if (fit == PM_FIT_SPLINE) {
     855                newVec->data.F32[i] = psSpline1DEval(mySpline, ((psF32) i) / ((psF32) nBin));
     856            }
     857        }
     858    } else {
     859        for (psS32 i = 0 ; i < vecSize ; i++) {
     860            if (fit == PM_FIT_POLYNOMIAL) {
     861                newVec->data.F32[i] = psPolynomial1DEval(myPoly, (psF32) i);
     862            } else if (fit == PM_FIT_SPLINE) {
     863                newVec->data.F32[i] = psSpline1DEval(mySpline, (psF32) i);
     864            }
     865        }
     866    }
     867
     868    psFree(mySpline);
     869    psFree(overscanVector);
     870    return(newVec);
     871}
     872
     873
     874
     875/******************************************************************************
     876UnbinOverscanVector(inImg, overscanVector, overScanAxis, nBin):  this private
     877routine takes a psVector overscanVector that was previously binned by a factor
     878of nBin, and then expands it to its original size, duplicated elements nBin
     879times for each element in the input vector overscanVector.
     880 *****************************************************************************/
     881static psVector *UnbinOverscanVector(
     882    psImage *inImg,
     883    psVector *overscanVector,
     884    pmOverscanAxis overScanAxis,
     885    psS32 nBin)
     886{
     887    psS32 vecSize;
     888
     889    if (overScanAxis == PM_OVERSCAN_ROWS) {
     890        vecSize = inImg->numCols;
     891    } else if (overScanAxis == PM_OVERSCAN_COLUMNS) {
     892        vecSize = inImg->numRows;
     893    }
     894
     895    psVector *newVec = psVectorAlloc(vecSize, PS_TYPE_F32);
     896    for (psS32 i = 0 ; i < vecSize ; i++) {
     897        newVec->data.F32[i] = overscanVector->data.F32[i/nBin];
     898    }
     899
     900    psFree(overscanVector);
     901    return(newVec);
     902}
     903
     904
     905/******************************************************************************
     906SubtractVectorFromImage(inImg, overscanVector, overScanAxis):  this private
     907routine subtracts the overscanVector column-wise or row-wise from inImg.
     908 *****************************************************************************/
     909static psImage *SubtractVectorFromImage(
     910    psImage *inImg,
     911    psVector *overscanVector,
     912    pmOverscanAxis overScanAxis)
     913{
     914    //
     915    // Subtract overscan vector row-wise from the image.
     916    //
     917    if (overScanAxis == PM_OVERSCAN_ROWS) {
     918        for (psS32 i=0;i<inImg->numCols;i++) {
     919            for (psS32 j=0;j<inImg->numRows;j++) {
     920                inImg->data.F32[j][i]-= overscanVector->data.F32[i];
     921            }
     922        }
     923    }
     924
     925    //
     926    // Subtract overscan vector column-wise from the image.
     927    //
     928    if (overScanAxis == PM_OVERSCAN_COLUMNS) {
     929        for (psS32 i=0;i<inImg->numRows;i++) {
     930            for (psS32 j=0;j<inImg->numCols;j++) {
     931                inImg->data.F32[i][j]-= overscanVector->data.F32[i];
     932            }
     933        }
     934    }
     935
     936    return(inImg);
     937}
     938
     939
     940
     941typedef enum {
     942    PM_ERROR_NO_SUBTRACTION,
     943    PM_WARNING_NO_SUBTRACTION,
     944    PM_ERROR_NO_BIAS_SUBTRACT,
     945    PM_WARNING_NO_BIAS_SUBTRACT,
     946    PM_ERROR_NO_DARK_SUBTRACT,
     947    PM_WARNING_NO_DARK_SUBTRACT,
     948    PM_OKAY
     949} pmSubtractBiasAssertStatus;
     950/******************************************************************************
     951AssertCodeOverscan(....) this private routine verifies that the various input
     952parameters to pmSubtractBias() are correct for overscan subtraction.
     953 *****************************************************************************/
     954pmSubtractBiasAssertStatus AssertCodeOverscan(
     955    pmReadout *in,
     956    void *fitSpec,
     957    pmFit fit,
     958    bool overscan,
     959    psStats *stat,
     960    int nBinOrig,
     961    const pmReadout *bias,
     962    const pmReadout *dark)
     963{
     964
     965    PS_ASSERT_READOUT_NON_NULL(in, PM_ERROR_NO_SUBTRACTION);
     966    PS_ASSERT_READOUT_NON_EMPTY(in, PM_ERROR_NO_SUBTRACTION);
     967    PS_ASSERT_READOUT_TYPE(in, PS_TYPE_F32, PM_ERROR_NO_SUBTRACTION);
     968    PS_WARN_PTR_NON_NULL(in->parent);
     969    if (in->parent != NULL) {
     970        PS_WARN_PTR_NON_NULL(in->parent->concepts);
     971    }
     972
     973    if (overscan == true) {
     974        pmOverscanAxis overScanAxis = GetOverscanAxis(in);
     975        PS_ASSERT_PTR_NON_NULL(stat, PM_ERROR_NO_SUBTRACTION);
     976        PS_ASSERT_PTR_NON_NULL(in->bias, PM_ERROR_NO_SUBTRACTION);
     977        PS_ASSERT_PTR_NON_NULL(in->bias->head, PM_ERROR_NO_SUBTRACTION);
     978        //
     979        // Check the type, size of each bias image.
     980        //
     981        psListElem *tmpOverscan = (psListElem *) in->bias->head;
     982        psS32 numOverscans = 0;
     983        while (NULL != tmpOverscan) {
     984            numOverscans++;
     985            psImage *myOverscanImage = (psImage *) tmpOverscan->data;
     986            PS_ASSERT_IMAGE_TYPE(myOverscanImage, PS_TYPE_F32, PM_ERROR_NO_SUBTRACTION);
     987            // XXX: Get this right with the rows and columns.
     988            if (overScanAxis == PM_OVERSCAN_ROWS) {
     989                if (myOverscanImage->numRows != in->image->numRows) {
     990                    psLogMsg(__func__, PS_LOG_WARN,
     991                             "WARNING: pmSubtractBias.(): overscan image (# %d) has %d rows, input image has %d rows\n",
     992                             numOverscans, myOverscanImage->numCols, in->image->numRows);
     993                    if (fit == PM_FIT_NONE) {
     994                        psError(PS_ERR_UNKNOWN, true, "Don't know how to scale the overscan vectors.  Set fit to PM_FIT_POLYNOMIAL or PM_FIT_SPLINE.\n");
     995                        return(PM_ERROR_NO_SUBTRACTION);
     996                    }
     997                }
     998            } else if (overScanAxis == PM_OVERSCAN_COLUMNS) {
     999                if (myOverscanImage->numCols != in->image->numCols) {
     1000                    psLogMsg(__func__, PS_LOG_WARN,
     1001                             "WARNING: pmSubtractBias.(): overscan image (# %d) has %d columns, input image has %d columns\n",
     1002                             numOverscans, myOverscanImage->numCols, in->image->numCols);
     1003                    if (fit == PM_FIT_NONE) {
     1004                        psError(PS_ERR_UNKNOWN, true, "Don't know how to scale the overscan vectors.  Set fit to PM_FIT_POLYNOMIAL or PM_FIT_SPLINE.\n");
     1005                        return(PM_ERROR_NO_SUBTRACTION);
     1006                    }
     1007                }
     1008            } else if (overScanAxis != PM_OVERSCAN_ALL) {
     1009                psError(PS_ERR_UNKNOWN, true, "Must specify and overscan axis.\n");
     1010                return(PM_ERROR_NO_SUBTRACTION);
     1011            }
     1012            tmpOverscan = tmpOverscan->next;
     1013        }
     1014    } else {
     1015        if (fit != PM_FIT_NONE) {
     1016            psLogMsg(__func__, PS_LOG_WARN,
     1017                     "WARNING: pmSubtractBias.(): overscan is FALSE and fit is not PM_FIT_NONE.\n");
     1018            return(PM_WARNING_NO_SUBTRACTION);
     1019        }
     1020    }
     1021
     1022    // XXX: I do not like the following spec since it's useless to specify
     1023    // a psSpline as the fitSpec.
     1024    if (0) {
     1025        if ((fitSpec == NULL) &&
     1026                ((fit != PM_FIT_NONE) || (overscan == true))) {
     1027            psError(PS_ERR_UNKNOWN, true, "fitSpec is NULL and fit is not PM_FIT_NONE or overscan is TRUE.\n");
     1028            return(PM_ERROR_NO_SUBTRACTION);
     1029        }
     1030    }
     1031
     1032    return(PM_OKAY);
     1033}
     1034
     1035/******************************************************************************
     1036AssertCodeBias(....) this private routine verifies that the various input
     1037parameters to pmSubtractBias() are correct for bias subtraction.
     1038 *****************************************************************************/
     1039static pmSubtractBiasAssertStatus AssertCodeBias(
     1040    pmReadout *in,
     1041    void *fitSpec,
     1042    pmFit fit,
     1043    bool overscan,
     1044    psStats *stat,
     1045    int nBinOrig,
     1046    const pmReadout *bias,
     1047    const pmReadout *dark)
     1048{
     1049    if ((in->image->numRows + in->row0 - bias->row0) > bias->image->numRows) {
     1050        psError(PS_ERR_UNKNOWN,true, "bias image does not have enough rows.  Returning in image\n");
     1051        return(PM_ERROR_NO_BIAS_SUBTRACT);
     1052    }
     1053    if ((in->image->numCols + in->col0 - bias->col0) > bias->image->numCols) {
     1054        psError(PS_ERR_UNKNOWN,true, "bias image does not have enough columns.  Returning in image\n");
     1055        return(PM_ERROR_NO_BIAS_SUBTRACT);
     1056    }
     1057
     1058    if (bias != NULL) {
     1059        PS_ASSERT_READOUT_NON_EMPTY(bias, PM_ERROR_NO_BIAS_SUBTRACT);
     1060        PS_ASSERT_READOUT_TYPE(bias, PS_TYPE_F32, PM_ERROR_NO_DARK_SUBTRACT);
     1061    }
     1062    return(PM_OKAY);
     1063}
     1064
     1065/******************************************************************************
     1066AssertCodeDark(....) this private routine verifies that the various input
     1067parameters to pmSubtractBias() are correct for dark subtraction.
     1068 *****************************************************************************/
     1069pmSubtractBiasAssertStatus AssertCodeDark(
     1070    pmReadout *in,
     1071    void *fitSpec,
     1072    pmFit fit,
     1073    bool overscan,
     1074    psStats *stat,
     1075    int nBinOrig,
     1076    const pmReadout *bias,
     1077    const pmReadout *dark)
     1078{
     1079    if ((in->image->numRows + in->row0 - dark->row0) > dark->image->numRows) {
     1080        psError(PS_ERR_UNKNOWN, true, "dark image does not have enough rows.  Returning in image\n");
     1081        return(PM_ERROR_NO_DARK_SUBTRACT);
     1082    }
     1083    if ((in->image->numCols + in->col0 - dark->col0) > dark->image->numCols) {
     1084        psError(PS_ERR_UNKNOWN, true, "dark image does not have enough columns.  Returning in image\n");
     1085        return(PM_ERROR_NO_DARK_SUBTRACT);
     1086    }
     1087
     1088    if (dark != NULL) {
     1089        PS_ASSERT_READOUT_NON_EMPTY(dark, PM_ERROR_NO_DARK_SUBTRACT);
     1090        PS_ASSERT_READOUT_TYPE(dark, PS_TYPE_F32, PM_ERROR_NO_DARK_SUBTRACT);
     1091    }
     1092    return(PM_OKAY);
     1093}
     1094
     1095/******************************************************************************
     1096p_psDetermineTrimmedImage(): global routine: determines the region of the
     1097input pmReadout which will be operated on by the various detrend modules.  It
     1098does a metadata fetch on "CELL.TRIMSEC" for the parent cell of the pmReadout.
     1099 
     1100Use it this way:
     1101    PS_WARN_PTR_NON_NULL(in->parent);
     1102    if (in->parent != NULL) {
     1103        PS_WARN_PTR_NON_NULL(in->parent->concepts);
     1104    }
     1105    //
     1106    // Determine trimmed image from metadata.
     1107    //
     1108    psImage *trimmedImg = p_psDetermineTrimmedImage(in);
     1109 
     1110XXX: Create a pmUtils.c file and put this routine there.
     1111 *****************************************************************************/
     1112psImage *p_psDetermineTrimmedImage(pmReadout *in)
     1113{
     1114    if ((in->parent == NULL) || (in->parent->concepts == NULL)) {
     1115        psLogMsg(__func__, PS_LOG_WARN,
     1116                 "WARNING: could not determine CELL.TRIMSEC from parent cell Metadata (NULL).\n");
     1117        return(in->image);
     1118    }
     1119
     1120    psBool rc = false;
     1121    psImage *trimmedImg = NULL;
     1122    psRegion *trimRegion = psMetadataLookupPtr(&rc, in->parent->concepts,
     1123                           "CELL.TRIMSEC");
     1124    if (rc == false) {
     1125        psLogMsg(__func__, PS_LOG_WARN,
     1126                 "WARNING: could not determine CELL.TRIMSEC from parent cell Metadata.\n");
     1127        trimmedImg = in->image;
     1128    } else {
     1129        trimmedImg = psImageSubset(in->image, *trimRegion);
     1130    }
     1131
     1132    return(trimmedImg);
     1133}
     1134
     1135
     1136
     1137
     1138
     1139
     1140
     1141
     1142
     1143
     1144
     1145
     1146
     1147
     1148
     1149
     1150
     1151
     1152/******************************************************************************
     1153pmSubtractBias(....): see SDRS for complete specification.
     1154 
     1155XXX: Code and assert type support: U16, S32, F32.
     1156XXX: Add trace messages.
    2831157 *****************************************************************************/
    2841158pmReadout *pmSubtractBias(
     
    2901164    int nBin,
    2911165    const pmReadout *bias,
    292     const pmReadout *dark
    293 )
     1166    const pmReadout *dark)
    2941167{
    2951168    psTrace(".psModule.pmSubtracBias.pmSubtractBias", 4,
    2961169            "---- pmSubtractBias() begin ----\n");
    297     PS_ASSERT_READOUT_NON_NULL(in, NULL);
    298     PS_ASSERT_READOUT_NON_EMPTY(in, NULL);
    299     PS_ASSERT_READOUT_TYPE(in, PS_TYPE_F32, NULL);
    300 
    301     //
    302     // If the overscans != NULL, then check the type of each image.
    303     //
    304     if (overscans != NULL) {
    305         psListElem *tmpOverscan = (psListElem *) overscans->head;
    306         while (NULL != tmpOverscan) {
    307             psImage *myOverscanImage = (psImage *) tmpOverscan->data;
    308             PS_ASSERT_IMAGE_TYPE(myOverscanImage, PS_TYPE_F32, NULL);
    309             tmpOverscan = tmpOverscan->next;
    310         }
    311     }
    312 
    313     if ((overscans == NULL) && (overScanAxis != PM_OVERSCAN_NONE)) {
    314         psError(PS_ERR_UNKNOWN,true, "(overscans == NULL) && (overScanAxis != PM_OVERSCAN_NONE).  Returning in image\n");
     1170    //
     1171    // Check input parameters, generate warnings and errors.
     1172    //
     1173    if (PM_OKAY != AssertCodeOverscan(in, fitSpec, fit, overscan, stat, nBin, bias, dark)) {
    3151174        return(in);
    3161175    }
    317 
    318     // Check for an unallowable pmFit.
    319     if ((fit != PM_OVERSCAN_NONE) &&
    320             (fit != PM_OVERSCAN_ROWS) &&
    321             (fit != PM_OVERSCAN_COLUMNS) &&
    322             (fit != PM_OVERSCAN_ALL)) {
    323         psError(PS_ERR_UNKNOWN, true, "fit is unallowable (%d).  Returning in image.\n", fit);
    324         return(in);
    325     }
    326     // Check for an unallowable pmOverscanAxis.
    327     if ((overScanAxis != PM_OVERSCAN_NONE) &&
    328             (overScanAxis != PM_OVERSCAN_ROWS) &&
    329             (overScanAxis != PM_OVERSCAN_COLUMNS) &&
    330             (overScanAxis != PM_OVERSCAN_ALL)) {
    331         psError(PS_ERR_UNKNOWN, true, "overScanAxis is unallowable (%d).  Returning in image.\n", overScanAxis);
    332         return(in);
    333     }
    334     psS32 i;
    335     psS32 j;
    336     psS32 numBins = 0;
    337     static psVector *overscanVector = NULL;
    338     psVector *tmpRow = NULL;
    339     psVector *tmpCol = NULL;
    340     psVector *myBin = NULL;
    341     psVector *binVec = NULL;
    342     psListElem *tmpOverscan = NULL;
    343     double statValue;
    344     psImage *myOverscanImage = NULL;
    345     psPolynomial1D *myPoly = NULL;
    346     psSpline1D *mySpline = NULL;
    347     psS32 nBin;
    348 
    349     //
    350     //  Create a static stats data structure and determine the highest
    351     //  priority stats option.
    352     //
    353     static psStats *myStats = NULL;
    354     if (myStats == NULL) {
    355         myStats = psStatsAlloc(PS_STAT_SAMPLE_MEAN);
    356         p_psMemSetPersistent(myStats, true);
    357     }
    358     if (stat != NULL) {
    359         myStats->options = GenNewStatOptions(stat);
    360     }
    361 
    362 
    363     if (overScanAxis == PM_OVERSCAN_NONE) {
    364         if (fit != PM_FIT_NONE) {
    365             psLogMsg(__func__, PS_LOG_WARN,
    366                      "WARNING: pmSubtractBias.(): overScanAxis equals NONE, and fit does not equal NONE.  Proceeding to full fram subtraction.\n");
    367         }
    368 
    369         if (overscans != NULL) {
    370             psLogMsg(__func__, PS_LOG_WARN,
    371                      "WARNING: pmSubtractBias.(): overScanAxis equals NONE and overscans does not equal NULL.  Proceeding to full fram subtraction.\n");
    372         }
    373         return(SubtractFrame(in, bias));
    374     }
    375 
    376     if ((overScanAxis == PM_OVERSCAN_ALL) && (fit != PM_FIT_NONE)) {
    377         psLogMsg(__func__, PS_LOG_WARN,
    378                  "WARNING: pmSubtractBias.(): overScanAxis equals ALL, and fit does not equal NONE.  Proceeding with the rest of the module.\n");
    379     }
    380 
    381 
    382     //
    383     // We subtract each overscan region from the image data.
    384     // If we get here we know that overscans != NULL.
    385     //
    386 
    387     if (overScanAxis == PM_OVERSCAN_ALL) {
    388         tmpOverscan = (psListElem *) overscans->head;
    389         while (NULL != tmpOverscan) {
    390             myOverscanImage = (psImage *) tmpOverscan->data;
    391 
    392             PS_ASSERT_IMAGE_TYPE(myOverscanImage, PS_TYPE_F32, NULL);
    393             psStats *rc = psImageStats(myStats, myOverscanImage, NULL, (psMaskType)0xffffffff);
    394             if (rc == NULL) {
    395                 psError(PS_ERR_UNKNOWN, false, "psImageStats(): could not perform requested statistical operation.  Returning in image.\n");
     1176    //
     1177    // Determine trimmed image from metadata.
     1178    //
     1179    psImage *trimmedImg = p_psDetermineTrimmedImage(in);
     1180
     1181    //
     1182    // Subtract overscan frames if necessary.
     1183    //
     1184    if (overscan == true) {
     1185        pmOverscanAxis overScanAxis = GetOverscanAxis(in);
     1186
     1187        //
     1188        //  Create a psStats data structure and determine the highest
     1189        //  priority stats option.
     1190        //
     1191        psStats *myStats = psStatsAlloc(PS_STAT_SAMPLE_MEAN);
     1192        if (stat != NULL) {
     1193            myStats->options = GenNewStatOptions(stat);
     1194        }
     1195
     1196        //
     1197        // Reduce overscan images to a single pixel, then subtract.
     1198        // This code is no longer required as of SDRS 12-09.
     1199        //
     1200        if (overScanAxis == PM_OVERSCAN_ALL) {
     1201            if (false == OverscanReducePixel(trimmedImg, in->bias, myStats)) {
    3961202                return(in);
    3971203            }
    398             if (false == p_psGetStatValue(myStats, &statValue)) {
    399                 psError(PS_ERR_UNKNOWN, false, "p_psGetStatValue(): could not determine result from requested statistical operation.  Returning in image.\n");
     1204            psFree(myStats);
     1205        } else {
     1206            //
     1207            // Reduce the overscan images to a single overscan vector.
     1208            //
     1209            psVector *overscanVector = OverscanReduce(in->image, overScanAxis,
     1210                                       in->bias, fitSpec,
     1211                                       fit, myStats);
     1212            if (overscanVector == NULL) {
     1213                psError(PS_ERR_UNKNOWN, false, "Could not reduce overscan images to a single overscan vector.  Returning in image\n");
     1214                psFree(myStats);
    4001215                return(in);
    4011216            }
    402             ImageSubtractScalar(in->image, statValue);
    403 
    404             tmpOverscan = tmpOverscan->next;
    405         }
    406         return(in);
    407     }
    408 
    409     // This check is redundant with above code.
    410     if (!((overScanAxis == PM_OVERSCAN_ROWS) || (overScanAxis == PM_OVERSCAN_COLUMNS))) {
    411         psError(PS_ERR_UNKNOWN, true, "overScanAxis is unallowable (%d).\nReturning in image.\n", overScanAxis);
    412         return(in);
    413     }
    414 
    415     tmpOverscan = (psListElem *) overscans->head;
    416     while (NULL != tmpOverscan) {
    417         //        PS_IMAGE_PRINT_F32_HIDEF(in->image);
    418         myOverscanImage = (psImage *) tmpOverscan->data;
    419 
    420         if (overScanAxis == PM_OVERSCAN_ROWS) {
    421             if (myOverscanImage->numCols != (in->image)->numCols) {
    422                 psLogMsg(__func__, PS_LOG_WARN,
    423                          "WARNING: pmSubtractBias.(): overscan image has %d columns, input image has %d columns\n",
    424                          myOverscanImage->numCols, in->image->numCols);
    425             }
    426 
    427             // We create a row vector and subtract this vector from image.
    428             // XXX: Is there a better way to extract a psVector from a psImage without
    429             // having to copy every element in that vector?
    430             overscanVector = psVectorAlloc(myOverscanImage->numCols, PS_TYPE_F32);
    431             for (i=0;i<overscanVector->n;i++) {
    432                 overscanVector->data.F32[i] = 0.0;
    433             }
    434             tmpRow = psVectorAlloc(myOverscanImage->numRows, PS_TYPE_F32);
    435 
    436             // For each column of the input image, loop through every row,
    437             // collect the pixel in that row, then performed the specified
    438             // statistical op on those pixels.  Store this in overscanVector.
    439             for (i=0;i<myOverscanImage->numCols;i++) {
    440                 for (j=0;j<myOverscanImage->numRows;j++) {
    441                     tmpRow->data.F32[j] = myOverscanImage->data.F32[j][i];
    442                 }
    443                 psStats *rc = psVectorStats(myStats, tmpRow, NULL, NULL, 0);
    444                 if (rc == NULL) {
    445                     psError(PS_ERR_UNKNOWN, false, "psVectorStats(): could not perform requested statistical operation.  Returning in image.\n");
     1217
     1218            //
     1219            // Rebin the overscan vector if necessary.
     1220            //
     1221            psS32 newBin = RebinOverscanVector(overscanVector, nBin, myStats);
     1222            if (newBin < 0) {
     1223                psError(PS_ERR_UNKNOWN, false, "Could rebin the overscan vector.  Returning in image\n");
     1224                psFree(myStats);
     1225                return(in);
     1226            }
     1227
     1228            //
     1229            // If necessary, fit a psPolynomial or psSpline to the overscan vector.
     1230            // Then, unbin the overscan vector to appropriate length for the in image.
     1231            //
     1232            if ((fit == PM_FIT_POLYNOMIAL) || (fit == PM_FIT_SPLINE)) {
     1233                overscanVector = FitOverscanVectorAndUnbin(trimmedImg, overscanVector, overScanAxis, fitSpec, fit, newBin);
     1234                if (overscanVector == NULL) {
     1235                    psError(PS_ERR_UNKNOWN, false, "Could not fit the polynomial or spline to the overscan vector.  Returning in image\n");
     1236                    psFree(myStats);
    4461237                    return(in);
    4471238                }
    448                 if (false ==  p_psGetStatValue(rc, &statValue)) {
    449                     psError(PS_ERR_UNKNOWN, false, "p_psGetStatValue(): could not determine result from requested statistical operation.  Returning in image.\n");
    450                     return(in);
     1239            } else {
     1240                overscanVector = UnbinOverscanVector(trimmedImg, overscanVector, overScanAxis, newBin);
     1241            }
     1242
     1243            //
     1244            // Subtract the overscan vector from the input image.
     1245            //
     1246            SubtractVectorFromImage(trimmedImg, overscanVector, overScanAxis);
     1247            psFree(myStats);
     1248            psFree(overscanVector);
     1249        }
     1250    }
     1251
     1252    //
     1253    // Perform bias subtraction if necessary.
     1254    //
     1255    if (bias != NULL) {
     1256        if (PM_OKAY == AssertCodeBias(in, fitSpec, fit, overscan, stat, nBin, bias, dark)) {
     1257            SubtractFrame(in, bias);
     1258        }
     1259    }
     1260
     1261    //
     1262    // Perform dark subtraction if necessary.
     1263    //
     1264    if (dark != NULL) {
     1265        if (PM_OKAY == AssertCodeDark(in, fitSpec, fit, overscan, stat, nBin, bias, dark)) {
     1266            psBool rc;
     1267            psF32 scale = 0.0;
     1268            if (in->parent != NULL) {
     1269                scale = psMetadataLookupS32(&rc, in->parent->concepts, "CELL.DARKTIME");
     1270                if (rc == false) {
     1271                    psLogMsg(__func__, PS_LOG_WARN,
     1272                             "WARNING: pmSubtractBias.(): could not determine CELL.FARKTIME from in->parent metadata.\n");
    4511273                }
    452                 overscanVector->data.F32[i] = statValue;
    453             }
    454             psFree(tmpRow);
    455 
    456             // Scale the overscan vector to the size of the input image.
    457             if (overscanVector->n != in->image->numCols) {
    458                 if ((fit == PM_FIT_POLYNOMIAL) || (fit == PM_FIT_SPLINE)) {
    459                     psVector *newVec = ScaleOverscanVector(overscanVector,
    460                                                            in->image->numCols,
    461                                                            fitSpec, fit);
    462                     if (newVec == NULL) {
    463                         psError(PS_ERR_UNKNOWN, false, "ScaleOverscanVector(): could not scale the overscan vector.  Returning in image.\n");
    464                         return(in);
    465                     }
    466                     psFree(overscanVector);
    467                     overscanVector = newVec;
    468                 } else {
    469                     psError(PS_ERR_UNKNOWN, true, "Don't know how to scale the overscan vector.  Set fit to PM_FIT_SPLINE or PM_FIT_POLYNOMIAL.  Returning in image.\n");
    470                     psFree(overscanVector);
    471                     return(in);
    472                 }
    473             }
    474         }
    475 
    476         if (overScanAxis == PM_OVERSCAN_COLUMNS) {
    477             if (myOverscanImage->numRows != (in->image)->numRows) {
    478                 psLogMsg(__func__, PS_LOG_WARN,
    479                          "WARNING: pmSubtractBias.(): overscan image has %d rows, input image has %d rows\n",
    480                          myOverscanImage->numRows, in->image->numRows);
    481             }
    482 
    483             // We create a column vector and subtract this vector from image.
    484             overscanVector = psVectorAlloc(myOverscanImage->numRows, PS_TYPE_F32);
    485             for (i=0;i<overscanVector->n;i++) {
    486                 overscanVector->data.F32[i] = 0.0;
    487             }
    488             tmpCol = psVectorAlloc(myOverscanImage->numCols, PS_TYPE_F32);
    489 
    490             // For each row of the input image, loop through every column,
    491             // collect the pixel in that row, then performed the specified
    492             // statistical op on those pixels.  Store this in overscanVector.
    493             for (i=0;i<myOverscanImage->numRows;i++) {
    494                 for (j=0;j<myOverscanImage->numCols;j++) {
    495                     tmpCol->data.F32[j] = myOverscanImage->data.F32[i][j];
    496                 }
    497                 psStats *rc = psVectorStats(myStats, tmpCol, NULL, NULL, 0);
    498                 if (rc == NULL) {
    499                     psError(PS_ERR_UNKNOWN, false, "psVectorStats(): could not perform requested statistical operation.  Returning in image.\n");
    500                     return(in);
    501                 }
    502                 if (false ==  p_psGetStatValue(rc, &statValue)) {
    503                     psError(PS_ERR_UNKNOWN, false, "p_psGetStatValue(): could not determine result from requested statistical operation.  Returning in image.\n");
    504                     return(in);
    505                 }
    506                 overscanVector->data.F32[i] = statValue;
    507             }
    508             psFree(tmpCol);
    509 
    510             // Scale the overscan vector to the size of the input image.
    511             if (overscanVector->n != in->image->numRows) {
    512                 if ((fit == PM_FIT_POLYNOMIAL) || (fit == PM_FIT_SPLINE)) {
    513                     psVector *newVec = ScaleOverscanVector(overscanVector,
    514                                                            in->image->numRows,
    515                                                            fitSpec, fit);
    516                     if (newVec == NULL) {
    517                         psError(PS_ERR_UNKNOWN, false, "ScaleOverscanVector(): could not scale the overscan vector.  Returning in image.\n");
    518                         return(in);
    519                     }
    520                     psFree(overscanVector);
    521                     overscanVector = newVec;
    522                 } else {
    523                     psError(PS_ERR_UNKNOWN, true, "Don't know how to scale the overscan vector.  Set fit to PM_FIT_SPLINE or PM_FIT_POLYNOMIAL.  Returning in image.\n");
    524                     psFree(overscanVector);
    525                     return(in);
    526                 }
    527             }
    528         }
    529 
    530         //
    531         // Re-bin the overscan vector (change its length).
    532         //
    533         // Only if nBinOrig > 1.
    534         if ((nBinOrig > 1) && (nBinOrig < overscanVector->n)) {
    535             numBins = 1+((overscanVector->n)/nBinOrig);
    536             myBin = psVectorAlloc(numBins, PS_TYPE_F32);
    537             binVec = psVectorAlloc(nBinOrig, PS_TYPE_F32);
    538 
    539             for (i=0;i<numBins;i++) {
    540                 for(j=0;j<nBinOrig;j++) {
    541                     if (overscanVector->n > ((i*nBinOrig)+j)) {
    542                         binVec->data.F32[j] = overscanVector->data.F32[(i*nBinOrig)+j];
    543                     } else {
    544                         // XXX: we get here if nBinOrig does not evenly divide
    545                         // the overscanVector vector.  This is the last bin.  Should
    546                         // we change the binVec->n to acknowledge that?
    547                         binVec->n = j;
    548                     }
    549                 }
    550                 psStats *rc = psVectorStats(myStats, binVec, NULL, NULL, 0);
    551                 if (rc == NULL) {
    552                     psError(PS_ERR_UNKNOWN, false, "psVectorStats(): could not perform requested statistical operation.  Returning in image.\n");
    553                     return(in);
    554                 }
    555                 if (false ==  p_psGetStatValue(rc, &statValue)) {
    556                     psError(PS_ERR_UNKNOWN, false, "p_psGetStatValue(): could not determine result from requested statistical operation.  Returning in image.\n");
    557                     return(in);
    558                 }
    559                 myBin->data.F32[i] = statValue;
    560             }
    561 
    562             // Change the effective size of overscanVector.
    563             overscanVector->n = numBins;
    564             for (i=0;i<numBins;i++) {
    565                 overscanVector->data.F32[i] = myBin->data.F32[i];
    566             }
    567             psFree(binVec);
    568             psFree(myBin);
    569             nBin = nBinOrig;
    570         } else {
    571             nBin = 1;
    572         }
    573 
    574         // At this point the number of data points in overscanVector should be
    575         // equal to the number of rows/columns (whatever is appropriate) in the
    576         // image divided by numBins.
    577         //
    578 
    579 
    580         //
    581         // This doesn't seem right.  The only way to do a spline fit is if,
    582         // by SDRS requirements, fitSpec is not-NULL>  But in order for it
    583         // to be non-NULL, someone must have called psSpline1DAlloc() with
    584         // the min, max, and number of splines.
    585         //
    586         if (!((fitSpec == NULL) || (fit == PM_FIT_NONE))) {
    587             //
    588             // Fit a polynomial or spline to the overscan vector.
    589             //
    590             if (fit == PM_FIT_POLYNOMIAL) {
    591                 myPoly = (psPolynomial1D *) fitSpec;
    592                 myPoly = psVectorFitPolynomial1D(myPoly, NULL, 0, overscanVector, NULL, NULL);
    593                 if (myPoly == NULL) {
    594                     psError(PS_ERR_UNKNOWN, false, "(3) Could not fit a polynomial to overscan vector.  Returning in image.\n");
    595                     psFree(overscanVector);
    596                     return(in);
    597                 }
    598             } else if (fit == PM_FIT_SPLINE) {
    599                 // XXX: This makes no sense
    600                 // XXX: must free mySpline?
    601                 mySpline = (psSpline1D *) fitSpec;
    602                 mySpline = psVectorFitSpline1D(NULL, overscanVector);
    603                 if (mySpline == NULL) {
    604                     psError(PS_ERR_UNKNOWN, false, "Could not fit a spline to overscan vector.  Returning in image.\n");
    605                     psFree(overscanVector);
    606                     return(in);
    607                 }
    608             }
    609 
    610             //
    611             // Subtract fitted overscan vector row-wise from the image.
    612             //
    613             if (overScanAxis == PM_OVERSCAN_ROWS) {
    614                 for (i=0;i<(in->image)->numCols;i++) {
    615                     psF32 tmpF32 = 0.0;
    616                     if (fit == PM_FIT_POLYNOMIAL) {
    617                         tmpF32 = psPolynomial1DEval(myPoly, ((psF32) i) / ((psF32) nBin));
    618                     } else if (fit == PM_FIT_SPLINE) {
    619                         tmpF32 = psSpline1DEval(mySpline, ((psF32) i) / ((psF32) nBin));
    620                     }
    621                     for (j=0;j<(in->image)->numRows;j++) {
    622                         (in->image)->data.F32[j][i]-= tmpF32;
    623                     }
    624                 }
    625             }
    626 
    627             //
    628             // Subtract fitted overscan vector column-wise from the image.
    629             //
    630             if (overScanAxis == PM_OVERSCAN_COLUMNS) {
    631                 for (i=0;i<(in->image)->numRows;i++) {
    632                     psF32 tmpF32 = 0.0;
    633                     if (fit == PM_FIT_POLYNOMIAL) {
    634                         tmpF32 = psPolynomial1DEval(myPoly, ((psF32) i) / ((psF32) nBin));
    635                     } else if (fit == PM_FIT_SPLINE) {
    636                         tmpF32 = psSpline1DEval(mySpline, ((psF32) i) / ((psF32) nBin));
    637                     }
    638 
    639                     for (j=0;j<(in->image)->numCols;j++) {
    640                         (in->image)->data.F32[i][j]-= tmpF32;
    641                     }
    642                 }
    643             }
    644         } else {
    645             //
    646             // If we get here, then no polynomials were fit to the overscan
    647             // vector.  We simply subtract it, taking into account binning,
    648             // from the image.
    649             //
    650 
    651             //
    652             // Subtract overscan vector row-wise from the image.
    653             //
    654             if (overScanAxis == PM_OVERSCAN_ROWS) {
    655                 for (i=0;i<(in->image)->numCols;i++) {
    656                     for (j=0;j<(in->image)->numRows;j++) {
    657                         (in->image)->data.F32[j][i]-= overscanVector->data.F32[i/nBin];
    658                     }
    659                 }
    660             }
    661 
    662             //
    663             // Subtract overscan vector column-wise from the image.
    664             //
    665             if (overScanAxis == PM_OVERSCAN_COLUMNS) {
    666                 for (i=0;i<(in->image)->numRows;i++) {
    667                     for (j=0;j<(in->image)->numCols;j++) {
    668                         (in->image)->data.F32[i][j]-= overscanVector->data.F32[i/nBin];
    669                     }
    670                 }
    671             }
    672         }
    673 
    674         psFree(overscanVector);
    675 
    676         tmpOverscan = tmpOverscan->next;
    677     }
    678 
     1274            }
     1275            SubtractDarkFrame(in, dark, scale);
     1276        }
     1277    }
     1278
     1279    //
     1280    // All done.
     1281    //
    6791282    psTrace(".psModule.pmSubtracBias.pmSubtractBias", 4,
    6801283            "---- pmSubtractBias() exit ----\n");
    681 
    682     if (bias != NULL) {
    683         return(SubtractFrame(in, bias));
    684     }
    6851284    return(in);
    6861285}
  • trunk/psModules/src/imsubtract/pmSubtractBias.h

    r5435 r5516  
    66 *  @author GLG, MHPCC
    77 *
    8  *  @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
    9  *  @date $Date: 2005-10-20 23:06:24 $
     8 *  @version $Revision: 1.3 $ $Name: not supported by cvs2svn $
     9 *  @date $Date: 2005-11-15 20:09:03 $
    1010 *
    1111 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
     
    4747    const pmReadout *bias,              ///< A possibly NULL bias pmReadout which is to be subtracted
    4848    const pmReadout *dark               ///< A possibly NULL bias pmReadout which is to be subtracted
    49 )
     49);
    5050// OLD: remove this
    5151//    const psList *overscans,      ///< A psList of overscan images
    5252//    pmOverscanAxis overScanAxis,  ///< Defines how overscans are applied
    5353
     54/******************************************************************************
     55DetermineTrimmedImageg() This private routine determines the region of the
     56input pmReadout which will be operated on by the various detrend modules.  It
     57does a metadata fetch on "CELL.TRIMSEC" for the parent cell of the pmReadout.
     58 
     59XXX: Consider making a pmUtils.c file and put this routine there.
     60 *****************************************************************************/
     61psImage *p_psDetermineTrimmedImage(
     62    pmReadout *in
     63);
     64
    5465#endif
  • trunk/psModules/src/imsubtract/pmSubtractSky.c

    r5294 r5516  
    66 *  @author GLG, MHPCC
    77 *
    8  *  @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
    9  *  @date $Date: 2005-10-12 21:02:04 $
     8 *  @version $Revision: 1.3 $ $Name: not supported by cvs2svn $
     9 *  @date $Date: 2005-11-15 20:09:03 $
    1010 *
    1111 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
     
    1818#include<math.h>
    1919#include "pslib.h"
    20 #include "psConstants.h"
    2120#include "pmSubtractSky.h"
     21
     22// XXX: Get rid of the.  Create pmUtils.h
     23psImage *p_psDetermineTrimmedImage(
     24    pmReadout *in
     25);
    2226
    2327/******************************************************************************
     
    152156 
    153157XXX: Use your brain and figure out the analytical expression.
     158 
     159XXX: Why isn't it simply (xOrder+1) * (yOrder+1)?
    154160 *****************************************************************************/
    155161static psS32 CalculatePolyTerms(psS32 xOrder, psS32 yOrder)
     
    170176        }
    171177    }
    172 
    173178    psTrace("SubtractSky.CalculatePolyTerms", 4,
    174179            "Exiting CalculatePolyTerms(%d, %d) -> %d\n", xOrder, yOrder, localPolyTerms);
    175180    return(localPolyTerms);
     181
     182    //    return((xOrder+1) * (yOrder+1));
    176183}
    177184
     
    283290XXX: Different trace message facilities in use here.
    284291 *****************************************************************************/
    285 static psPolynomial2D *ImageFitPolynomial(psPolynomial2D *myPoly,
    286         psImage *dataImage,
    287         psImage *maskImage)
     292static psPolynomial2D *ImageFitPolynomial(
     293    psPolynomial2D *myPoly,
     294    psImage *dataImage,
     295    psImage *maskImage)
    288296{
    289297    psTrace("SubtractSky.ImageFitPolynomial", 4,
     
    471479    PS_ASSERT_READOUT_NON_EMPTY(in, NULL);
    472480    PS_ASSERT_READOUT_TYPE(in, PS_TYPE_F32, NULL);
     481    PS_WARN_PTR_NON_NULL(in->parent);
     482    if (in->parent != NULL) {
     483        PS_WARN_PTR_NON_NULL(in->parent->concepts);
     484    }
    473485    psTrace(".psModule.pmSubtractSky", 4,
    474486            "---- pmSubtractSky() begin ----\n");
     
    492504        return(in);
    493505    }
    494     psImage *origImage = in->image;
     506
     507    //
     508    // Determine trimmed image from metadata.
     509    //
     510
     511    psImage *trimmedImg = p_psDetermineTrimmedImage(in);
    495512    psImage *binnedImage = NULL;
    496513    psPolynomial2D *myPoly = NULL;
     
    539556        // No binning is required here.  Simply create a copy of the image
    540557        // and a mask.
    541         binnedImage = psImageCopy(binnedImage, origImage, PS_TYPE_F32);
     558        binnedImage = psImageCopy(binnedImage, trimmedImg, PS_TYPE_F32);
    542559        if (binnedImage == NULL) {
    543560            psError(PS_ERR_UNKNOWN, false, "psImageCopy() returned NULL.  Returning in image.\n");
     
    559576        }
    560577    } else {
    561         binnedImage = psImageRebin(NULL, origImage, in->mask, 0, binFactor, stats);
     578        binnedImage = psImageRebin(NULL, trimmedImg, in->mask, 0, binFactor, stats);
    562579        if (binnedImage == NULL) {
    563580            psError(PS_ERR_UNKNOWN, false, "psImageRebin() returned NULL.  Returning in image.\n");
     
    677694    if (binFactor <= 1) {
    678695        // The binned image is the same size as the original image.
    679         for (psS32 row = 0; row < origImage->numRows ; row++) {
    680             for (psS32 col = 0; col < origImage->numCols ; col++) {
    681                 origImage->data.F32[row][col]-= binnedImage->data.F32[row][col];
     696        for (psS32 row = 0; row < trimmedImg->numRows ; row++) {
     697            for (psS32 col = 0; col < trimmedImg->numCols ; col++) {
     698                trimmedImg->data.F32[row][col]-= binnedImage->data.F32[row][col];
    682699            }
    683700        }
    684701    } else {
    685         for (psS32 row = 0; row < origImage->numRows ; row++) {
    686             for (psS32 col = 0; col < origImage->numCols ; col++) {
     702        for (psS32 row = 0; row < trimmedImg->numRows ; row++) {
     703            for (psS32 col = 0; col < trimmedImg->numCols ; col++) {
    687704                // We calculate the F32 value of the pixel coordinates in the
    688705                // binned image and then use a pixel interpolation routine to
     
    700717                                     binnedImage, binColF64, binRowF64,
    701718                                     NULL, 0, 0.0, PS_INTERPOLATE_BILINEAR);
    702                 origImage->data.F32[row][col]-= binPixel;
     719                trimmedImg->data.F32[row][col]-= binPixel;
    703720
    704721                psTrace(".psModule.pmSubtractSky", 8,
Note: See TracChangeset for help on using the changeset viewer.