IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 13870


Ignore:
Timestamp:
Jun 18, 2007, 5:40:48 PM (19 years ago)
Author:
Paul Price
Message:

Splitting out shutter correction so that it can run as we read in bits and pieces.

Location:
trunk/psModules/src/detrend
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/psModules/src/detrend/pmShutterCorrection.c

    r13700 r13870  
    1313#include "psVectorBracket.h"
    1414#include "pmConceptsAverage.h"
     15#include "pmReadoutStack.h"
    1516
    1617#include "pmShutterCorrection.h"
     
    5859
    5960
     61#define MEASURE_SAMPLES 4               // Number of samples to make over the image.  This should only be
     62                                        // changed with great caution, since assumptions on its value are in
     63                                        // the code (see pmShutterCorrectionDataAlloc).
     64
     65
    6066static void pmShutterCorrectionFree(pmShutterCorrection *pars)
    6167{
     
    346352
    347353//////////////////////////////////////////////////////////////////////////////////////////////////////////////
    348 
    349 #define MEASURE_SAMPLES 4
    350354
    351355bool pmShutterCorrectionMeasure(pmReadout *output, const psArray *readouts, int size, psStatsOptions meanStat,
     
    680684
    681685    if (exptime <= 0.0) {
    682         // In the extreme case that we have exptime <= 0.0, we correct the image to
    683         // counts-per-second, rather than counts in the nominal exposure time
    684         for (int y = 0; y < image->numRows; y++) {
    685             for (int x = 0; x < image->numCols; x++) {
    686                 image->data.F32[y][x] *= 1.0 / (exptime + shutterImage->data.F32[y][x]);
    687             }
    688         }
    689         psMetadataAddF32 (cell->concepts, PS_LIST_TAIL, "CELL.EXPOSURE", PS_META_REPLACE, "exposure time re-normalized to 1.0", 1.0); // Exposure time
    690         psString line = NULL;
    691         psStringAppend (&line, "extreme exposure time %f, re-normalized to 1.0", exptime);
    692         psMetadataAddStr(hdu->header, PS_LIST_TAIL, "HISTORY", PS_META_DUPLICATE_OK, line, "");
    693         psFree (line);
     686        // In the extreme case that we have exptime <= 0.0, we correct the image to
     687        // counts-per-second, rather than counts in the nominal exposure time
     688        for (int y = 0; y < image->numRows; y++) {
     689            for (int x = 0; x < image->numCols; x++) {
     690                image->data.F32[y][x] *= 1.0 / (exptime + shutterImage->data.F32[y][x]);
     691            }
     692        }
     693        psMetadataAddF32 (cell->concepts, PS_LIST_TAIL, "CELL.EXPOSURE", PS_META_REPLACE, "exposure time re-normalized to 1.0", 1.0); // Exposure time
     694        psString line = NULL;
     695        psStringAppend (&line, "extreme exposure time %f, re-normalized to 1.0", exptime);
     696        psMetadataAddStr(hdu->header, PS_LIST_TAIL, "HISTORY", PS_META_DUPLICATE_OK, line, "");
     697        psFree (line);
    694698    } else {
    695         for (int y = 0; y < image->numRows; y++) {
    696             for (int x = 0; x < image->numCols; x++) {
    697                 image->data.F32[y][x] *= exptime / (exptime + shutterImage->data.F32[y][x]);
    698             }
    699         }
     699        for (int y = 0; y < image->numRows; y++) {
     700            for (int x = 0; x < image->numCols; x++) {
     701                image->data.F32[y][x] *= exptime / (exptime + shutterImage->data.F32[y][x]);
     702            }
     703        }
    700704    }
    701705    psFree(shutterImage);
     
    712716    return true;
    713717}
     718
     719//////////////////////////////////////////////////////////////////////////////////////////////////////////////
     720
     721
     722#define IMAGES_BUFFER 10                // Allocate space for this many images at a time
     723
     724static void shutterCorrectionDataFree(pmShutterCorrectionData *data)
     725{
     726    psFree(data->regions);
     727    psFree(data->mean);
     728    psFree(data->stdev);
     729
     730    psFree(data->exptimes);
     731    psFree(data->refs);
     732
     733    return;
     734}
     735
     736pmShutterCorrectionData *pmShutterCorrectionDataAlloc(int numCols, int numRows, int size)
     737{
     738    pmShutterCorrectionData *data = psAlloc(sizeof(pmShutterCorrectionData));
     739    psMemSetDeallocator(data, (psFreeFunc)shutterCorrectionDataFree);
     740
     741    data->num = 0;
     742    data->numCols = 0;
     743    data->numRows = 0;
     744
     745    data->regions = psArrayAlloc(MEASURE_SAMPLES);
     746    for (int j = 0; j < MEASURE_SAMPLES; j++) {
     747        int x = (j % 2) ? size : numCols - size - 1;
     748        int y = (j > 1) ? size : numRows - size - 1;
     749        psRegion region = psRegionForSquare(x, y, size);
     750        data->regions->data[j] = psRegionAlloc(region.x0, region.x1, region.y0, region.y1);
     751    }
     752
     753    data->mean = psArrayAlloc(MEASURE_SAMPLES);
     754    data->stdev = psArrayAlloc(MEASURE_SAMPLES);
     755    for (int i = 0; i < MEASURE_SAMPLES; i++) {
     756        data->mean->data[i] = psVectorAllocEmpty(IMAGES_BUFFER, PS_TYPE_F32);
     757        data->stdev->data[i] = psVectorAllocEmpty(IMAGES_BUFFER, PS_TYPE_F32);
     758    }
     759
     760    data->exptimes = psVectorAllocEmpty(IMAGES_BUFFER, PS_TYPE_F32);
     761    data->refs = psVectorAllocEmpty(IMAGES_BUFFER, PS_TYPE_F32);
     762
     763    return data;
     764}
     765
     766bool pmShutterCorrectionAddReadout(pmShutterCorrectionData *data,
     767                                   const pmReadout *readout, ///< Readout to add
     768                                   psStatsOptions meanStat, ///< Statistic to use for mean
     769                                   psStatsOptions stdevStat, ///< Statistic to use for stdev
     770                                   psMaskType maskVal, ///< Mask value
     771                                   psRandom *rng ///< Random number generator
     772    )
     773{
     774    PS_ASSERT_PTR_NON_NULL(data, NULL);
     775    PS_ASSERT_PTR_NON_NULL(readout, NULL);
     776    PS_ASSERT_IMAGE_NON_NULL(readout->image, NULL);
     777    PS_ASSERT_IMAGE_TYPE(readout->image, PS_TYPE_F32, NULL);
     778    if (data->num == 0) {
     779        data->numCols = readout->image->numCols;
     780        data->numRows = readout->image->numRows;
     781    } else {
     782        PS_ASSERT_IMAGE_SIZE(readout->image, data->numCols, data->numRows, NULL);
     783    }
     784    if (readout->mask) {
     785        PS_ASSERT_IMAGE_NON_NULL(readout->mask, NULL);
     786        PS_ASSERT_IMAGE_TYPE(readout->mask, PS_TYPE_MASK, NULL);
     787        PS_ASSERT_IMAGE_SIZE(readout->mask, data->numCols, data->numRows, NULL);
     788    }
     789    if (readout->weight) {
     790        PS_ASSERT_IMAGE_NON_NULL(readout->weight, NULL);
     791        PS_ASSERT_IMAGE_TYPE(readout->weight, PS_TYPE_F32, NULL);
     792        PS_ASSERT_IMAGE_SIZE(readout->weight, data->numCols, data->numRows, NULL);
     793    }
     794
     795    // Add the exposure time
     796    float exptime = psMetadataLookupF32(NULL, readout->parent->concepts, "CELL.EXPOSURE"); // Exp. time
     797    if (!isfinite(exptime)) {
     798        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Exposure time is not set.");
     799        return false;
     800    }
     801    data->exptimes->data.F32[data->exptimes->n] = exptime;
     802    data->exptimes = psVectorExtend(data->exptimes, IMAGES_BUFFER, 1);
     803
     804    // Add the statistics
     805
     806    // Add the reference value
     807    psStats *stats = psStatsAlloc(meanStat | stdevStat); // Statistics to apply
     808    if (!rng) {
     809        rng = psRandomAlloc(PS_RANDOM_TAUS, 0);
     810    } else {
     811        psMemIncrRefCounter(rng);
     812    }
     813    if (!psImageBackground(stats, readout->image, readout->mask, maskVal, rng)) {
     814        psError(PS_ERR_UNKNOWN, false, "Unable to measure reference statistics.\n");
     815        psFree(stats);
     816        psFree(rng);
     817        return false;
     818    }
     819    psFree(rng);
     820    float refValue = psStatsGetValue(stats, meanStat); // Reference value
     821    psTrace("psModules.detrend", 3, "Reference value for shutter image = %f\n", refValue);
     822    if (refValue <= 0.0) {
     823        psError(PS_ERR_UNKNOWN, true, "Measured non-positive reference value.\n");
     824        psFree(stats);
     825        return false;
     826    }
     827    refValue = 1.0 / refValue;
     828    data->refs->data.F32[data->refs->n] = refValue;
     829    data->refs = psVectorExtend(data->refs, IMAGES_BUFFER, 1);
     830
     831    // Add the region statistics
     832    for (int j = 0; j < MEASURE_SAMPLES; j++) {
     833        psRegion *region = data->regions->data[j]; // Region of interest
     834        psImage *subImage = psImageSubset(readout->image, *region); // Sub-image
     835        psImage *subMask = NULL;        // Sub-image of mask
     836        if (readout->mask) {
     837            subMask = psImageSubset(readout->mask, *region);
     838        }
     839        if (!psImageStats(stats, subImage, subMask, maskVal)) {
     840            psString regionString = psRegionToString(*region);
     841            psWarning("Unable to measure sample statistics at %s in image.\n",
     842                      regionString);
     843            psFree(regionString);
     844        }
     845        psFree(subImage);
     846        psFree(subMask);
     847
     848        psVector *mean = data->mean->data[j]; // Vector of means for this region
     849        psVector *stdev = data->stdev->data[j]; // Vector of standard deviations for this region
     850
     851        mean->data.F32[mean->n] = psStatsGetValue(stats, meanStat) * refValue;
     852        stdev->data.F32[stdev->n] = psStatsGetValue(stats, stdevStat) * refValue;
     853        data->mean->data[j] = psVectorExtend(mean, IMAGES_BUFFER, 1);
     854        data->stdev->data[j] = psVectorExtend(stdev, IMAGES_BUFFER, 1);
     855    }
     856
     857    data->num++;
     858
     859    return true;
     860}
     861
     862float pmShutterCorrectionReference(const pmShutterCorrectionData *data)
     863{
     864    PS_ASSERT_PTR_NON_NULL(data, NAN);
     865    PS_ASSERT_INT_POSITIVE(data->num, NAN);
     866
     867    float meanRef = 0.0;                // Mean reference offset
     868    int numGood = 0;                    // Number of good measurements
     869    for (int i = 0; i < MEASURE_SAMPLES; i++) {
     870        psVector *counts = data->mean->data[i]; // Mean for each image
     871        psVector *errors = data->stdev->data[i]; // Stdev for each image
     872        pmShutterCorrection *guess = pmShutterCorrectionGuess(data->exptimes, counts); // Guess at correction
     873        pmShutterCorrection *corr = pmShutterCorrectionFullFit(data->exptimes, counts,
     874                                                               errors, guess); // The actual correction
     875        psFree(guess);
     876        if (corr && isfinite(corr->offref)) {
     877            psTrace("psModules.detrend", 5, "Sample reference value: %f\n", corr->offref);
     878            meanRef += corr->offref;
     879            numGood++;
     880        }
     881        psFree(corr);
     882    }
     883
     884    if (numGood == 0) {
     885        psError(PS_ERR_UNKNOWN, true, "Unable to measure mean reference offset.\n");
     886        return false;
     887    }
     888    meanRef /= (float)numGood;
     889    psTrace("psModules.detrend", 3, "Mean reference value: %f\n", meanRef);
     890    return meanRef;
     891}
     892
     893bool pmShutterCorrectionGenerate(pmReadout *shutter, pmReadout *pattern, const psArray *inputs,
     894                                 float reference, const pmShutterCorrectionData *data,
     895                                 int nIter, float rej, psMaskType maskVal)
     896{
     897    PS_ASSERT_PTR_NON_NULL(shutter, false);
     898    PS_ASSERT_ARRAY_NON_NULL(inputs, false);
     899    PS_ASSERT_INT_EQUAL(data->num, inputs->n, false);
     900
     901    int minInputCols, maxInputCols, minInputRows, maxInputRows; // Smallest and largest values to combine
     902    int xSize, ySize;                   // Size of the output image
     903    if (!pmReadoutStackValidate(&minInputCols, &maxInputCols, &minInputRows, &maxInputRows, &xSize, &ySize,
     904                                inputs)) {
     905        psError(PS_ERR_UNKNOWN, false, "No valid input readouts.");
     906        return false;
     907    }
     908
     909    pmReadoutUpdateSize(shutter, minInputCols, minInputRows, xSize, ySize, false);
     910    if (pattern) {
     911        pmReadoutUpdateSize(pattern, minInputCols, minInputRows, xSize, ySize, false);
     912    }
     913
     914    psImage *shutterImage = shutter->image; // Shutter correction image
     915    psImage *patternImage; // Illumination pattern
     916    if (pattern) {
     917        patternImage = psMemIncrRefCounter(pattern->image);
     918    } else {
     919        patternImage = psImageAlloc(xSize, ySize, PS_TYPE_F32);
     920    }
     921
     922    int num = data->num;                // Number of images
     923    psVector *counts = psVectorAlloc(num, PS_TYPE_F32); // Counts in each image
     924    psVector *errors = psVectorAlloc(num, PS_TYPE_F32); // Counts in each image
     925    psVector *mask = psVectorAlloc(num, PS_TYPE_MASK); // Mask for each image
     926    psTrace("psModules.detrend", 2, "Performing linear fit on individual pixels...\n");
     927    for (int i = minInputRows; i < maxInputRows; i++) {
     928        int yOut = i - shutter->row0; // y position on output readout
     929        for (int j = minInputCols; j < maxInputCols; j++) {
     930            int xOut = j - shutter->col0; // x position on output readout
     931
     932            psVectorInit(mask, 0);
     933            for (int r = 0; r < num; r++) {
     934                pmReadout *readout = inputs->data[r]; // Readout of interest
     935                int yIn = i - readout->row0; // y position on input readout
     936                int xIn = j - readout->col0; // x position on input readout
     937                psImage *image = readout->image; // Image of interest
     938                float ref = data->refs->data.F32[r]; // (Inverse) reference value
     939                counts->data.F32[r] = image->data.F32[yIn][xIn] * ref;
     940                if (readout->mask) {
     941                    mask->data.PS_TYPE_MASK_DATA[r] = readout->mask->data.PS_TYPE_MASK_DATA[yIn][xIn];
     942                }
     943                if (readout->weight) {
     944                    errors->data.F32[r] = sqrtf(readout->weight->data.F32[yIn][xIn]) * ref;
     945                } else {
     946                    errors->data.F32[r] = sqrtf(image->data.F32[yIn][xIn]) * ref;
     947                }
     948            }
     949
     950            pmShutterCorrection *corr = pmShutterCorrectionLinFit(data->exptimes, counts, errors, mask,
     951                                                                  reference, nIter, rej, maskVal);
     952            shutterImage->data.F32[yOut][xOut] = corr->offset;
     953            patternImage->data.F32[yOut][xOut] = corr->scale;
     954            psFree(corr);
     955        }
     956    }
     957    psFree(mask);
     958    psFree(errors);
     959    psFree(counts);
     960
     961    // Update the "concepts"
     962    psList *inputCells = psListAlloc(NULL); // List of cells
     963    for (long i = 0; i < inputs->n; i++) {
     964        pmReadout *readout = inputs->data[i]; // Readout of interest
     965        psListAdd(inputCells, PS_LIST_TAIL, readout->parent);
     966    }
     967    bool success = pmConceptsAverageCells(shutter->parent, inputCells, NULL, NULL, true);
     968    psFree(inputCells);
     969
     970    // Correct the exposure times --- they don't make sense any more.
     971    psMetadataItem *item = psMetadataLookup(shutter->parent->concepts, "CELL.EXPOSURE");
     972    item->data.F32 = NAN;
     973    item = psMetadataLookup(shutter->parent->concepts, "CELL.DARKTIME");
     974    item->data.F32 = NAN;
     975
     976    shutter->data_exists = true;
     977    shutter->parent->data_exists = true;
     978    shutter->parent->parent->data_exists = true;
     979
     980    if (pattern) {
     981        pattern->data_exists = true;
     982        pattern->parent->data_exists = true;
     983        pattern->parent->parent->data_exists = true;
     984    }
     985
     986    return success;
     987}
  • trunk/psModules/src/detrend/pmShutterCorrection.h

    r12988 r13870  
    55 * @author Paul Price, IfA
    66 *
    7  * @version $Revision: 1.13 $ $Name: not supported by cvs2svn $
    8  * @date $Date: 2007-04-24 21:17:19 $
     7 * @version $Revision: 1.14 $ $Name: not supported by cvs2svn $
     8 * @date $Date: 2007-06-19 03:40:48 $
    99 * Copyright 2006 Institute for Astronomy, University of Hawaii
    1010 */
     
    128128                             );
    129129
     130//////////////////////////////////////////////////////////////////////////////////////////////////////////////
     131
     132// Functions for doing the shutter correction piece-meal (don't have to read entire image stack into memory at
     133// once).  A single read run through the stack is required, calling pmShutterCorrectionAddReadout on each.
     134// Then pmShutterCorrectionReference provides the required reference shutter time, so that
     135// pmShutterCorrectionGenerate can generate a shutter correction piece by piece as overlapping pixels from
     136// each input are read in.
     137
     138
     139/// Data for measuring the shutter correction
     140typedef struct {
     141    int num;                            ///< Number of images
     142    int numCols, numRows;               ///< Size of images
     143    psArray *regions;                   ///< Regions at which to measure statistics
     144    psArray *mean;                      ///< Vector of means at each region
     145    psArray *stdev;                     ///< Vector of standard deviations at each region
     146    psVector *exptimes;                 ///< Exposure times for each image
     147    psVector *refs;                     ///< Reference fluxes
     148} pmShutterCorrectionData;
     149
     150/// Allocator for pmShutterCorrectionData
     151pmShutterCorrectionData *pmShutterCorrectionDataAlloc(int numCols, int numRows, ///< Size of images
     152                                                      int size ///< Size of regions
     153    );
     154
     155/// Add a readout to the correction data
     156///
     157/// Performs statistics on the readout, recording the data
     158bool pmShutterCorrectionAddReadout(pmShutterCorrectionData *data, ///< Correction data
     159                                   const pmReadout *readout, ///< Readout to add
     160                                   psStatsOptions meanStat, ///< Statistic to use for mean
     161                                   psStatsOptions stdevStat, ///< Statistic to use for stdev
     162                                   psMaskType maskVal, ///< Mask value
     163                                   psRandom *rng ///< Random number generator
     164    );
     165
     166/// Calculate the reference shutter time from the correction data
     167float pmShutterCorrectionReference(const pmShutterCorrectionData *data ///< Correction data
     168    );
     169
     170/// Generate a shutter correction
     171///
     172/// Performs the linear fit to each pixel in the stack.
     173bool pmShutterCorrectionGenerate(pmReadout *shutter, ///< Shutter correction
     174                                 pmReadout *pattern, ///< Background pattern (or NULL)
     175                                 const psArray *inputs, ///< Stack of input pmReadouts
     176                                 float reference, ///< Reference shutter time (from pmShutterCorrectionRef)
     177                                 const pmShutterCorrectionData *data, ///< Correction data
     178                                 int nIter, ///< Number of iterations
     179                                 float rej, ///< Rejection threshold (sigma)
     180                                 psMaskType maskVal ///< Mask value
     181    );
     182
     183
     184
    130185/// @}
    131186#endif
Note: See TracChangeset for help on using the changeset viewer.