IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
May 3, 2010, 8:45:22 AM (16 years ago)
Author:
eugene
Message:

updates from trunk

Location:
branches/simmosaic_branches
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • branches/simmosaic_branches

  • branches/simmosaic_branches/psModules

  • branches/simmosaic_branches/psModules/src/imcombine/pmSubtractionMatch.c

    r24292 r27839  
    1010#include "pmHDU.h"
    1111#include "pmFPA.h"
     12#include "pmHDUUtils.h"
    1213#include "pmSubtractionParams.h"
    1314#include "pmSubtractionKernels.h"
     
    2728static bool useFFT = true;              // Do convolutions using FFT
    2829
     30# define SEPARATE 0
     31# if (SEPARATE)
     32# define SUBMODE PM_SUBTRACTION_EQUATION_NORM
     33# else
     34# define SUBMODE PM_SUBTRACTION_EQUATION_ALL
     35# endif
    2936
    3037//#define TESTING
     
    5865
    5966
    60 static bool getStamps(pmSubtractionStampList **stamps, // Stamps to read
    61                       const pmReadout *ro1, // Readout 1
    62                       const pmReadout *ro2, // Readout 2
    63                       const psImage *subMask, // Mask for subtraction, or NULL
    64                       psImage *variance,  // Variance map
    65                       const psRegion *region, // Region of interest, or NULL
    66                       float thresh1,  // Threshold for stamp finding on readout 1
    67                       float thresh2,  // Threshold for stamp finding on readout 2
    68                       float stampSpacing, // Spacing between stamps
    69                       int size,         // Kernel half-size
    70                       int footprint,     // Convolution footprint for stamps
    71                       pmSubtractionMode mode // Mode for subtraction
     67static bool subtractionGetStamps(pmSubtractionStampList **stamps, // Stamps to read
     68                                 const pmReadout *ro1, // Readout 1
     69                                 const pmReadout *ro2, // Readout 2
     70                                 const psImage *subMask, // Mask for subtraction, or NULL
     71                                 psImage *variance,  // Variance map
     72                                 const psRegion *region, // Region of interest
     73                                 float thresh1,  // Threshold for stamp finding on readout 1
     74                                 float thresh2,  // Threshold for stamp finding on readout 2
     75                                 float stampSpacing, // Spacing between stamps
     76                                 float normFrac,     // Fraction of flux in window for normalisation window
     77                                 float sysError,     // Relative systematic error in images
     78                                 float skyError,     // Relative systematic error in images
     79                                 int size,         // Kernel half-size
     80                                 int footprint,     // Convolution footprint for stamps
     81                                 pmSubtractionMode mode // Mode for subtraction
    7282    )
    7383{
     84    PS_ASSERT_PTR_NON_NULL(stamps, false);
     85    PM_ASSERT_READOUT_NON_NULL(ro1, false);
     86    PM_ASSERT_READOUT_NON_NULL(ro2, false);
     87    PS_ASSERT_IMAGE_NON_NULL(subMask, false);
     88    PS_ASSERT_IMAGE_NON_NULL(variance, false);
     89    PS_ASSERT_PTR_NON_NULL(region, false);
     90
    7491    psTrace("psModules.imcombine", 3, "Finding stamps...\n");
    7592
     
    7794
    7895    *stamps = pmSubtractionStampsFind(*stamps, image1, image2, subMask, region, thresh1, thresh2,
    79                                       size, footprint, stampSpacing, mode);
     96                                      size, footprint, stampSpacing, normFrac, sysError, skyError, mode);
    8097    if (!*stamps) {
    8198        psError(psErrorCodeLast(), false, "Unable to find stamps.");
     
    86103
    87104    psTrace("psModules.imcombine", 3, "Extracting stamps...\n");
    88     if (!pmSubtractionStampsExtract(*stamps, ro1->image, ro2 ? ro2->image : NULL, variance, size)) {
    89         psError(PS_ERR_UNKNOWN, false, "Unable to extract stamps.");
     105    if (!pmSubtractionStampsExtract(*stamps, ro1->image, ro2->image, variance, size, *region)) {
     106        psError(psErrorCodeLast(), false, "Unable to extract stamps.");
    90107        return false;
    91108    }
     
    100117                                  const pmReadout *ro1, const pmReadout *ro2, // Input images
    101118                                  int stride, // Size for convolution patches
    102                                   float sysError, // Relative systematic error
     119                                  float normFrac,           // Fraction of window for normalisation window
     120                                  float sysError,           // Systematic error in images
     121                                  float skyError,           // Systematic error in images
     122                                  float kernelError, // Systematic error in kernel
     123                                  float covarFrac,   // Fraction for kernel truncation before covariance
    103124                                  psImageMaskType maskVal, // Value to mask for input
    104125                                  psImageMaskType maskBad, // Mask for output bad pixels
     
    111132    if (subMode != PM_SUBTRACTION_MODE_2) {
    112133        PM_ASSERT_READOUT_NON_NULL(conv1, false);
     134        PM_ASSERT_READOUT_NON_NULL(ro1, false);
     135        PM_ASSERT_READOUT_IMAGE(ro1, false);
    113136        if (conv1->image) {
    114137            psFree(conv1->image);
     
    126149    if (subMode != PM_SUBTRACTION_MODE_1) {
    127150        PM_ASSERT_READOUT_NON_NULL(conv2, false);
     151        PM_ASSERT_READOUT_NON_NULL(ro2, false);
     152        PM_ASSERT_READOUT_IMAGE(ro2, false);
    128153        if (conv2->image) {
    129154            psFree(conv2->image);
     
    140165    }
    141166
    142     PM_ASSERT_READOUT_NON_NULL(ro1, false);
    143     PM_ASSERT_READOUT_NON_NULL(ro2, false);
    144     PM_ASSERT_READOUT_IMAGE(ro1, false);
    145     PM_ASSERT_READOUT_IMAGE(ro2, false);
    146     PS_ASSERT_IMAGES_SIZE_EQUAL(ro1->image, ro2->image, false);
     167    if (ro1 && ro2) {
     168        PS_ASSERT_IMAGES_SIZE_EQUAL(ro1->image, ro2->image, false);
     169    }
    147170    PS_ASSERT_INT_NONNEGATIVE(stride, false);
     171    if (isfinite(normFrac)) {
     172        PS_ASSERT_FLOAT_LARGER_THAN(normFrac, 0.0, false);
     173        PS_ASSERT_FLOAT_LESS_THAN(normFrac, 1.0, false);
     174    }
    148175    if (isfinite(sysError)) {
    149176        PS_ASSERT_FLOAT_LARGER_THAN_OR_EQUAL(sysError, 0.0, false);
    150177        PS_ASSERT_FLOAT_LESS_THAN(sysError, 1.0, false);
    151178    }
     179    if (isfinite(sysError)) {
     180        PS_ASSERT_FLOAT_LARGER_THAN_OR_EQUAL(skyError, 0.0, false);
     181    }
     182    if (isfinite(kernelError)) {
     183        PS_ASSERT_FLOAT_LARGER_THAN_OR_EQUAL(kernelError, 0.0, false);
     184        PS_ASSERT_FLOAT_LESS_THAN(kernelError, 1.0, false);
     185    }
     186    PS_ASSERT_FLOAT_LARGER_THAN_OR_EQUAL(covarFrac, 0.0, false);
     187    PS_ASSERT_FLOAT_LESS_THAN(covarFrac, 1.0, false);
    152188    // Don't care about maskVal
    153189    // Don't care about maskBad
     
    164200
    165201
     202/// Allocate images, as required
     203static void subtractionMatchAlloc(pmReadout *conv1, pmReadout *conv2, // Output readouts
     204                                  const pmReadout *ro1, const pmReadout *ro2, // Input readouts
     205                                  const psImage *subMask,                     // Subtraction mask
     206                                  psImageMaskType maskBad,                    // Mask value for bad pixels
     207                                  pmSubtractionMode subMode,          // Subtraction mode
     208                                  int numCols, int numRows            // Size of image
     209    )
     210{
     211    if (subMode == PM_SUBTRACTION_MODE_1 || subMode == PM_SUBTRACTION_MODE_UNSURE ||
     212        subMode == PM_SUBTRACTION_MODE_DUAL) {
     213        if (!conv1->image) {
     214            conv1->image = psImageAlloc(numCols, numRows, PS_TYPE_F32);
     215        }
     216        psImageInit(conv1->image, NAN);
     217        if (ro1->variance) {
     218            if (!conv1->variance) {
     219                conv1->variance = psImageAlloc(numCols, numRows, PS_TYPE_F32);
     220            }
     221            psImageInit(conv1->variance, NAN);
     222        }
     223        if (subMask) {
     224            if (!conv1->mask) {
     225                conv1->mask = psImageAlloc(numCols, numRows, PS_TYPE_IMAGE_MASK);
     226            }
     227            psImageInit(conv1->mask, maskBad);
     228        }
     229    }
     230    if (subMode == PM_SUBTRACTION_MODE_2 || subMode == PM_SUBTRACTION_MODE_UNSURE ||
     231        subMode == PM_SUBTRACTION_MODE_DUAL) {
     232        if (!conv2->image) {
     233            conv2->image = psImageAlloc(numCols, numRows, PS_TYPE_F32);
     234        }
     235        psImageInit(conv2->image, NAN);
     236        if (ro2->variance) {
     237            if (!conv2->variance) {
     238                conv2->variance = psImageAlloc(numCols, numRows, PS_TYPE_F32);
     239            }
     240            psImageInit(conv2->variance, NAN);
     241        }
     242        if (subMask) {
     243            if (!conv2->mask) {
     244                conv2->mask = psImageAlloc(numCols, numRows, PS_TYPE_IMAGE_MASK);
     245            }
     246            psImageInit(conv2->mask, maskBad);
     247        }
     248    }
     249
     250    return;
     251}
     252
     253
     254static void subtractionAnalysisUpdate(pmReadout *conv1, pmReadout *conv2, // Convolved images
     255                                      const psMetadata *analysis, // Analysis metadata
     256                                      const psMetadata *header // Header metadata
     257    )
     258{
     259    if (conv1) {
     260        conv1->analysis = psMetadataCopy(conv1->analysis, analysis);
     261    }
     262    if (conv2) {
     263        conv2->analysis = psMetadataCopy(conv2->analysis, analysis);
     264    }
     265
     266    if (conv1 && conv1->parent) {
     267        pmHDU *hdu = pmHDUFromCell(conv1->parent);
     268        if (hdu) {
     269            hdu->header = psMetadataCopy(hdu->header, header);
     270        }
     271    }
     272    if (conv2 && conv2->parent) {
     273        pmHDU *hdu = pmHDUFromCell(conv2->parent);
     274        if (hdu) {
     275            hdu->header = psMetadataCopy(hdu->header, header);
     276        }
     277    }
     278
     279    return;
     280}
     281
     282bool pmSubtractionMaskInvalid (const pmReadout *readout, psImageMaskType maskVal) {
     283
     284    if (!readout) return true;
     285
     286    psImage *image = readout->image;
     287    psImage *mask  = readout->mask;
     288    psImage *variance = readout->variance;
     289    for (int y = 0; y < image->numRows; y++) {
     290        for (int x = 0; x < image->numCols; x++) {
     291            if (mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & maskVal) continue;
     292            bool valid = false;
     293            valid = isfinite(image->data.F32[y][x]);
     294            if (variance) {
     295                valid &= isfinite(variance->data.F32[y][x]);
     296            }
     297            if (valid) continue;
     298            mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] = maskVal;
     299        }
     300    }
     301
     302    return true;
     303}
    166304
    167305bool pmSubtractionMatchPrecalc(pmReadout *conv1, pmReadout *conv2, const pmReadout *ro1, const pmReadout *ro2,
    168                                psMetadata *analysis, int stride, float sysError,
     306                               psMetadata *analysis, int stride, float kernelError, float covarFrac,
    169307                               psImageMaskType maskVal, psImageMaskType maskBad, psImageMaskType maskPoor,
    170308                               float poorFrac, float badFrac)
     
    182320        while ((item = psMetadataGetAndIncrement(iter))) {
    183321            if (item->type != PS_DATA_UNKNOWN) {
    184                 psError(PS_ERR_BAD_PARAMETER_TYPE, true, "Unexpected type for kernel.");
     322                psError(PM_ERR_PROG, true, "Unexpected type for kernel.");
    185323                psFree(iter);
    186324                psFree(kernelList);
     
    202340    }
    203341    if (psListLength(kernelList) == 0) {
    204         psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Unable to find kernels");
     342        psError(PM_ERR_PROG, true, "Unable to find kernels");
    205343        psFree(kernelList);
    206344        return false;
     
    217355        while ((item = psMetadataGetAndIncrement(iter))) {
    218356            if (item->type != PS_DATA_REGION) {
    219                 psError(PS_ERR_BAD_PARAMETER_TYPE, true, "Unexpected type for region.");
     357                psError(PM_ERR_PROG, true, "Unexpected type for region.");
    220358                psFree(iter);
    221359                psFree(kernels);
     
    229367    }
    230368    if (regions->n != kernels->n) {
    231         psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Differing number of kernels (%ld) and regions (%ld)",
     369        psError(PM_ERR_PROG, true, "Differing number of kernels (%ld) and regions (%ld)",
    232370                kernels->n, regions->n);
    233371        psFree(regions);
     
    236374    }
    237375
    238     if (!subtractionMatchCheck(conv1, conv2, ro1, ro2, stride, sysError, maskVal, maskBad, maskPoor,
    239                                poorFrac, badFrac, mode)) {
     376    if (!subtractionMatchCheck(conv1, conv2, ro1, ro2, stride, NAN, NAN, NAN, kernelError, covarFrac,
     377                               maskVal, maskBad, maskPoor, poorFrac, badFrac, mode)) {
    240378        psFree(kernels);
    241379        psFree(regions);
     
    243381    }
    244382
    245     psImage *subMask = pmSubtractionMask(ro1->mask, ro2 ? ro2->mask : NULL, maskVal, size, 0,
     383    int numCols, numRows;       // Size of image
     384    if (ro1) {
     385        numCols = ro1->image->numCols;
     386        numRows = ro1->image->numRows;
     387    } else if (ro2) {
     388        numCols = ro2->image->numCols;
     389        numRows = ro2->image->numRows;
     390    } else {
     391        psAbort("No input image provided.");
     392    }
     393
     394    pmSubtractionMaskInvalid(ro1, maskVal);
     395    pmSubtractionMaskInvalid(ro2, maskVal);
     396
     397    // General background subtraction, since this is done in pmSubtractionMatch
     398    {
     399        psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS); // Random number generator
     400        psStats *bg = psStatsAlloc(PS_STAT_ROBUST_MEDIAN); // Statistics for background
     401        if (ro1) {
     402            psStatsInit(bg);
     403            if (!psImageBackground(bg, NULL, ro1->image, ro1->mask, maskVal, rng)) {
     404                psError(PM_ERR_DATA, false, "Unable to measure background statistics.");
     405                psFree(bg);
     406                psFree(rng);
     407                return false;
     408            }
     409            psBinaryOp(ro1->image, ro1->image, "-", psScalarAlloc((float)bg->robustMedian, PS_TYPE_F32));
     410        }
     411        if (ro2) {
     412            psStatsInit(bg);
     413            if (!psImageBackground(bg, NULL, ro2->image, ro2->mask, maskVal, rng)) {
     414                psError(PM_ERR_DATA, false, "Unable to measure background statistics.");
     415                psFree(bg);
     416                psFree(rng);
     417                return false;
     418            }
     419            psBinaryOp(ro2->image, ro2->image, "-", psScalarAlloc((float)bg->robustMedian, PS_TYPE_F32));
     420        }
     421        psFree(bg);
     422        psFree(rng);
     423    }
     424
     425    psRegion bounds = psRegionSet(NAN, NAN, NAN, NAN); // Bounds of valid pixels
     426
     427    psImage *subMask = pmSubtractionMask(&bounds, ro1, ro2, maskVal, size, 0,
    246428                                         badFrac, mode); // Subtraction mask
    247429    if (!subMask) {
     
    253435
    254436    psMetadata *outAnalysis = psMetadataAlloc(); // Output analysis values
     437    psMetadata *outHeader = psMetadataAlloc(); // Output header values
     438
     439    subtractionMatchAlloc(conv1, conv2, ro1, ro2, subMask, maskBad, mode, numCols, numRows);
    255440
    256441    psTrace("psModules.imcombine", 2, "Convolving...\n");
     
    259444        psRegion *region = regions->data[i]; // Region of interest
    260445
    261         if (!pmSubtractionAnalysis(outAnalysis, kernel, region, ro1->image->numCols, ro1->image->numRows)) {
    262             psError(PS_ERR_UNKNOWN, false, "Unable to generate QA data");
     446        if (!pmSubtractionAnalysis(outAnalysis, outHeader, kernel, region, numCols, numRows)) {
     447            psError(psErrorCodeLast(), false, "Unable to generate QA data");
    263448            psFree(outAnalysis);
     449            psFree(outHeader);
    264450            psFree(subMask);
    265451            psFree(kernels);
     
    269455
    270456        if (!pmSubtractionConvolve(conv1, conv2, ro1, ro2, subMask, stride, maskBad, maskPoor, poorFrac,
    271                                    sysError, region, kernel, true, useFFT)) {
    272             psError(PS_ERR_UNKNOWN, false, "Unable to convolve image.");
     457                                   kernelError, covarFrac, region, kernel, true, useFFT)) {
     458            psError(psErrorCodeLast(), false, "Unable to convolve image.");
    273459            psFree(outAnalysis);
     460            psFree(outHeader);
    274461            psFree(subMask);
    275462            psFree(kernels);
     
    283470    psFree(regions);
    284471
    285     if (conv1) {
    286         psMetadataCopy(conv1->analysis, outAnalysis);
    287     }
    288     if (conv2) {
    289         psMetadataCopy(conv2->analysis, outAnalysis);
    290     }
     472    subtractionAnalysisUpdate(conv1, conv2, outAnalysis, outHeader);
    291473    psFree(outAnalysis);
     474    psFree(outHeader);
    292475
    293476    return true;
     
    302485                        int inner, int ringsOrder, int binning, float penalty,
    303486                        bool optimum, const psVector *optFWHMs, int optOrder, float optThreshold,
    304                         int iter, float rej, float sysError, psImageMaskType maskVal, psImageMaskType maskBad,
     487                        int iter, float rej, float normFrac, float sysError, float skyError,
     488                        float kernelError, float covarFrac, psImageMaskType maskVal, psImageMaskType maskBad,
    305489                        psImageMaskType maskPoor, float poorFrac, float badFrac, pmSubtractionMode subMode)
    306490{
    307     if (!subtractionMatchCheck(conv1, conv2, ro1, ro2, stride, sysError, maskVal, maskBad, maskPoor,
    308                                poorFrac, badFrac, subMode)) {
     491    if (!subtractionMatchCheck(conv1, conv2, ro1, ro2, stride, normFrac, sysError, skyError, kernelError,
     492                               covarFrac, maskVal, maskBad, maskPoor, poorFrac, badFrac, subMode)) {
    309493        return false;
    310494    }
     495
     496    // We need both inputs
     497    PM_ASSERT_READOUT_NON_NULL(ro1, false);
     498    PM_ASSERT_READOUT_NON_NULL(ro2, false);
    311499
    312500    PS_ASSERT_INT_NONNEGATIVE(footprint, false);
     
    364552    // Putting important variable declarations here, since they are freed after a "goto" if there is an error.
    365553    psImage *subMask = NULL;            // Mask for subtraction
    366     psRegion *region = NULL;            // Iso-kernel region
     554    psRegion *region = psRegionAlloc(NAN, NAN, NAN, NAN); // Iso-kernel region
    367555    psString regionString = NULL;       // String for region
    368556    pmSubtractionStampList *stamps = NULL; // Stamps for matching PSF
    369557    pmSubtractionKernels *kernels = NULL; // Kernel basis functions
    370558    psMetadata *analysis = psMetadataAlloc(); // QA data
     559    psMetadata *header = psMetadataAlloc(); // QA data for header
    371560
    372561    int numCols = ro1->image->numCols, numRows = ro1->image->numRows; // Image dimensions
     
    376565    memCheck("start");
    377566
    378     subMask = pmSubtractionMask(ro1->mask, ro2 ? ro2->mask : NULL, maskVal, size, footprint,
    379                                 badFrac, subMode);
     567    pmSubtractionMaskInvalid(ro1, maskVal);
     568    pmSubtractionMaskInvalid(ro2, maskVal);
     569
     570    psRegion bounds = psRegionSet(NAN, NAN, NAN, NAN); // Bounds of valid pixels
     571
     572    subMask = pmSubtractionMask(&bounds, ro1, ro2, maskVal, size, footprint, badFrac, subMode);
    380573    if (!subMask) {
    381574        psError(psErrorCodeLast(), false, "Unable to generate subtraction mask.");
     
    387580    // Get region of interest
    388581    int xRegions = 1, yRegions = 1;     // Number of iso-kernel regions
    389     float xRegionSize = 0, yRegionSize = 0; // Size of iso-kernel regions
     582    float xRegionSize = NAN, yRegionSize = NAN; // Size of iso-kernel regions
    390583    if (isfinite(regionSize) && regionSize != 0.0) {
    391         xRegions = numCols / regionSize + 1;
    392         yRegions = numRows / regionSize + 1;
    393         xRegionSize = (float)numCols / (float)xRegions;
    394         yRegionSize = (float)numRows / (float)yRegions;
    395         region = psRegionAlloc(NAN, NAN, NAN, NAN);
    396     }
    397 
     584        xRegions = (bounds.x1 - bounds.x0) / regionSize + 1;
     585        yRegions = (bounds.y1 - bounds.y0) / regionSize + 1;
     586        xRegionSize = (float)(bounds.x1 - bounds.x0) / (float)xRegions;
     587        yRegionSize = (float)(bounds.y1 - bounds.y0) / (float)yRegions;
     588    } else {
     589        xRegionSize = bounds.x1 - bounds.x0;
     590        yRegionSize = bounds.y1 - bounds.y0;
     591    }
     592
     593    // General background subtraction and measurement of stamp threshold
    398594    float stampThresh1 = NAN, stampThresh2 = NAN; // Stamp thresholds for images
    399595    {
    400         psStats *bg = psStatsAlloc(PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV); // Statistics for backgroun
     596        psStats *bg = psStatsAlloc(PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV); // Statistics for background
    401597        if (ro1) {
     598            psStatsInit(bg);
    402599            if (!psImageBackground(bg, NULL, ro1->image, ro1->mask, maskVal, rng)) {
    403                 psError(PS_ERR_UNKNOWN, false, "Unable to measure background statistics.");
     600                psError(PM_ERR_DATA, false, "Unable to measure background statistics.");
    404601                psFree(bg);
    405602                goto MATCH_ERROR;
    406603            }
    407             stampThresh1 = bg->robustMedian + threshold * bg->robustStdev;
     604            stampThresh1 = threshold * bg->robustStdev;
     605            psBinaryOp(ro1->image, ro1->image, "-", psScalarAlloc((float)bg->robustMedian, PS_TYPE_F32));
    408606        }
    409607        if (ro2) {
     608            psStatsInit(bg);
    410609            if (!psImageBackground(bg, NULL, ro2->image, ro2->mask, maskVal, rng)) {
    411                 psError(PS_ERR_UNKNOWN, false, "Unable to measure background statistics.");
     610                psError(PM_ERR_DATA, false, "Unable to measure background statistics.");
    412611                psFree(bg);
    413612                goto MATCH_ERROR;
    414613            }
    415             stampThresh2 = bg->robustMedian + threshold * bg->robustStdev;
     614            stampThresh2 = threshold * bg->robustStdev;
     615            psBinaryOp(ro2->image, ro2->image, "-", psScalarAlloc((float)bg->robustMedian, PS_TYPE_F32));
    416616        }
    417617        psFree(bg);
    418618    }
     619
     620    subtractionMatchAlloc(conv1, conv2, ro1, ro2, subMask, maskBad, subMode, numCols, numRows);
    419621
    420622    // Iterate over iso-kernel regions
     
    423625            psTrace("psModules.imcombine", 1, "Subtracting region %d of %d...\n",
    424626                    j * xRegions + i + 1, xRegions * yRegions);
    425             if (region) {
    426                 *region = psRegionSet((int)(i * xRegionSize), (int)((i + 1) * xRegionSize),
    427                                       (int)(j * yRegionSize), (int)((j + 1) * yRegionSize));
    428                 psFree(regionString);
    429                 regionString = psRegionToString(*region);
    430                 psTrace("psModules.imcombine", 3, "Iso-kernel region: %s out of %d,%d\n",
    431                         regionString, numCols, numRows);
    432             }
     627            *region = psRegionSet(bounds.x0 + (int)(i * xRegionSize),
     628                                  bounds.x0 + (int)((i + 1) * xRegionSize),
     629                                  bounds.y0 + (int)(j * yRegionSize),
     630                                  bounds.y0 + (int)((j + 1) * yRegionSize));
     631            psFree(regionString);
     632            regionString = psRegionToString(*region);
     633            psLogMsg("psModules.imcombine", PS_LOG_DETAIL, "Iso-kernel region: %s out of %d,%d\n",
     634                    regionString, numCols, numRows);
    433635
    434636            if (stampsName && strlen(stampsName) > 0) {
    435637                stamps = pmSubtractionStampsSetFromFile(stampsName, ro1->image, subMask, region, size,
    436                                                         footprint, stampSpacing, subMode);
     638                                                        footprint, stampSpacing, normFrac,
     639                                                        sysError, skyError, subMode);
    437640            } else if (sources) {
    438641                stamps = pmSubtractionStampsSetFromSources(sources, ro1->image, subMask, region, size,
    439                                                            footprint, stampSpacing, subMode);
     642                                                           footprint, stampSpacing, normFrac,
     643                                                           sysError, skyError, subMode);
    440644            }
    441645
    442646            // We get the stamps here; we will also attempt to get stamps at the first iteration, but it
    443647            // doesn't matter.
    444             if (!getStamps(&stamps, ro1, ro2, subMask, variance, NULL, stampThresh1, stampThresh2,
    445                            stampSpacing, size, footprint, subMode)) {
     648            if (!subtractionGetStamps(&stamps, ro1, ro2, subMask, variance, region, stampThresh1, stampThresh2,
     649                                      stampSpacing, normFrac, sysError, skyError, size, footprint, subMode)) {
    446650                goto MATCH_ERROR;
    447651            }
    448652
     653
     654            // generate the window function from the set of stamps
     655            if (!pmSubtractionStampsGetWindow(stamps, size)) {
     656                psError(psErrorCodeLast(), false, "Unable to get stamp window.");
     657                goto MATCH_ERROR;
     658            }
     659
     660            // Define kernel basis functions
     661            if (optimum && (type == PM_SUBTRACTION_KERNEL_ISIS || type == PM_SUBTRACTION_KERNEL_GUNK)) {
     662                kernels = pmSubtractionKernelsOptimumISIS(type, size, inner, spatialOrder,
     663                                                          optFWHMs, optOrder, stamps, footprint,
     664                                                          optThreshold, penalty, bounds, subMode);
     665                if (!kernels) {
     666                    psErrorClear();
     667                    psWarning("Unable to derive optimum ISIS kernel --- switching to default.");
     668                }
     669            }
     670            if (kernels == NULL) {
     671                // Not an ISIS/GUNK kernel, or the optimum kernel search failed
     672                kernels = pmSubtractionKernelsGenerate(type, size, spatialOrder, isisWidths, isisOrders,
     673                                                       inner, binning, ringsOrder, penalty, bounds, subMode);
     674                // pmSubtractionVisualShowKernels(kernels);
     675            }
     676
     677            memCheck("kernels");
     678
    449679            if (subMode == PM_SUBTRACTION_MODE_UNSURE) {
     680#if 0
    450681                // Get backgrounds
    451682                psStats *bgStats = psStatsAlloc(BG_STAT); // Statistics for background
    452683                psVector *buffer = NULL;// Buffer for stats
    453684                if (!psImageBackground(bgStats, &buffer, ro1->image, ro1->mask, maskVal, rng)) {
    454                     psError(PS_ERR_UNKNOWN, false, "Unable to measure background of image 1.");
     685                    psError(PM_ERR_DATA, false, "Unable to measure background of image 1.");
    455686                    psFree(bgStats);
    456687                    psFree(buffer);
     
    459690                float bg1 = psStatsGetValue(bgStats, BG_STAT); // Background for image 1
    460691                if (!psImageBackground(bgStats, &buffer, ro2->image, ro2->mask, maskVal, rng)) {
    461                     psError(PS_ERR_UNKNOWN, false, "Unable to measure background of image 2.");
     692                    psError(PM_ERR_DATA, false, "Unable to measure background of image 2.");
    462693                    psFree(bgStats);
    463694                    psFree(buffer);
     
    469700
    470701                pmSubtractionMode newMode = pmSubtractionOrder(stamps, bg1, bg2); // Subtraction mode to use
     702#endif
     703                pmSubtractionMode newMode = pmSubtractionBestMode(&stamps, &kernels, subMask, rej);
    471704                switch (newMode) {
    472705                  case PM_SUBTRACTION_MODE_1:
     
    477710                    break;
    478711                  default:
    479                     psError(PS_ERR_UNKNOWN, false, "Unable to determine subtraction order.");
     712                    psError(psErrorCodeLast(), false, "Unable to determine subtraction order.");
    480713                    goto MATCH_ERROR;
    481714                }
    482715                subMode = newMode;
    483716            }
    484 
    485             // Define kernel basis functions
    486             if (optimum && (type == PM_SUBTRACTION_KERNEL_ISIS || type == PM_SUBTRACTION_KERNEL_GUNK)) {
    487                 kernels = pmSubtractionKernelsOptimumISIS(type, size, inner, spatialOrder, optFWHMs, optOrder,
    488                                                           stamps, footprint, optThreshold, penalty, subMode);
    489                 if (!kernels) {
    490                     psErrorClear();
    491                     psWarning("Unable to derive optimum ISIS kernel --- switching to default.");
    492                 }
    493             }
    494             if (kernels == NULL) {
    495                 // Not an ISIS/GUNK kernel, or the optimum kernel search failed
    496                 kernels = pmSubtractionKernelsGenerate(type, size, spatialOrder, isisWidths, isisOrders,
    497                                                        inner, binning, ringsOrder, penalty, subMode);
    498             }
    499 
    500             memCheck("kernels");
    501717
    502718            int numRejected = -1;       // Number of rejected stamps in each iteration
     
    504720                psLogMsg("psModules.imcombine", PS_LOG_INFO, "Iteration %d.", k);
    505721
    506                 if (!getStamps(&stamps, ro1, ro2, subMask, variance, region, stampThresh1, stampThresh2,
    507                                stampSpacing, size, footprint, subMode)) {
    508                     goto MATCH_ERROR;
    509                 }
    510 
    511                 psTrace("psModules.imcombine", 3, "Calculating equation...\n");
    512                 if (!pmSubtractionCalculateEquation(stamps, kernels)) {
    513                     psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation.");
    514                     goto MATCH_ERROR;
    515                 }
    516 
     722                if (!subtractionGetStamps(&stamps, ro1, ro2, subMask, variance, region,
     723                                          stampThresh1, stampThresh2, stampSpacing, normFrac,
     724                                          sysError, skyError, size, footprint, subMode)) {
     725                    goto MATCH_ERROR;
     726                }
     727
     728                // generate the window function from the set of stamps
     729                if (!pmSubtractionStampsGetWindow(stamps, size)) {
     730                    psError(psErrorCodeLast(), false, "Unable to get stamps window.");
     731                    goto MATCH_ERROR;
     732                }
     733
     734                // XXX step 1: calculate normalization
     735                psTrace("psModules.imcombine", 3, "Calculating equation for normalization...\n");
     736                if (!pmSubtractionCalculateEquation(stamps, kernels, SUBMODE)) {
     737                    psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation.");
     738                    goto MATCH_ERROR;
     739                }
     740
     741                psTrace("psModules.imcombine", 3, "Solving equation for normalization...\n");
     742                if (!pmSubtractionSolveEquation(kernels, stamps, SUBMODE)) {
     743                    psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation.");
     744                    goto MATCH_ERROR;
     745                }
     746                memCheck("  solve equation");
     747
     748# if (SEPARATE)
     749                // set USED -> CALCULATE
     750                pmSubtractionStampsResetStatus (stamps);
     751
     752                // XXX step 2: calculate kernel parameters
     753                psTrace("psModules.imcombine", 3, "Calculating equation for kernels...\n");
     754                if (!pmSubtractionCalculateEquation(stamps, kernels, PM_SUBTRACTION_EQUATION_KERNELS)) {
     755                    psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation.");
     756                    goto MATCH_ERROR;
     757                }
    517758                memCheck("  calculate equation");
    518759
    519                 psTrace("psModules.imcombine", 3, "Solving equation...\n");
    520 
    521                 if (!pmSubtractionSolveEquation(kernels, stamps)) {
    522                     psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation.");
    523                     goto MATCH_ERROR;
    524                 }
    525 
     760                psTrace("psModules.imcombine", 3, "Solving equation for kernels...\n");
     761                if (!pmSubtractionSolveEquation(kernels, stamps, PM_SUBTRACTION_EQUATION_KERNELS)) {
     762                    psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation.");
     763                    goto MATCH_ERROR;
     764                }
    526765                memCheck("  solve equation");
    527 
     766# endif
    528767                psVector *deviations = pmSubtractionCalculateDeviations(stamps, kernels); // Stamp deviations
    529768                if (!deviations) {
    530                     psError(PS_ERR_UNKNOWN, false, "Unable to calculate deviations.");
     769                    psError(psErrorCodeLast(), false, "Unable to calculate deviations.");
    531770                    goto MATCH_ERROR;
    532771                }
     
    535774
    536775                psTrace("psModules.imcombine", 3, "Rejecting stamps...\n");
    537                 numRejected = pmSubtractionRejectStamps(kernels, stamps, deviations, subMask, rej, footprint);
     776                numRejected = pmSubtractionRejectStamps(kernels, stamps, deviations, subMask, rej);
    538777                if (numRejected < 0) {
    539                     psError(PS_ERR_UNKNOWN, false, "Unable to reject stamps.");
     778                    psError(psErrorCodeLast(), false, "Unable to reject stamps.");
    540779                    psFree(deviations);
    541780                    goto MATCH_ERROR;
     
    546785            }
    547786
     787            // if we hit the max number of iterations and we have rejected stamps, re-solve
    548788            if (numRejected > 0) {
    549                 psTrace("psModules.imcombine", 3, "Solving equation...\n");
    550                 if (!pmSubtractionSolveEquation(kernels, stamps)) {
    551                     psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation.");
    552                     goto MATCH_ERROR;
    553                 }
     789                // XXX step 1: calculate normalization
     790                psTrace("psModules.imcombine", 3, "Calculating equation for normalization...\n");
     791                if (!pmSubtractionCalculateEquation(stamps, kernels, SUBMODE)) {
     792                    psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation.");
     793                    goto MATCH_ERROR;
     794                }
     795
     796                // solve normalization
     797                psTrace("psModules.imcombine", 3, "Solving equation for kernels...\n");
     798                if (!pmSubtractionSolveEquation(kernels, stamps, SUBMODE)) {
     799                    psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation.");
     800                    goto MATCH_ERROR;
     801                }
     802
     803# if (SEPARATE)
     804                // set USED -> CALCULATE
     805                pmSubtractionStampsResetStatus (stamps);
     806
     807                // XXX step 2: calculate kernel parameters
     808                psTrace("psModules.imcombine", 3, "Calculating equation for normalization...\n");
     809                if (!pmSubtractionCalculateEquation(stamps, kernels, PM_SUBTRACTION_EQUATION_KERNELS)) {
     810                    psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation.");
     811                    goto MATCH_ERROR;
     812                }
     813
     814                // solve kernel parameters
     815                psTrace("psModules.imcombine", 3, "Solving equation for kernels...\n");
     816                if (!pmSubtractionSolveEquation(kernels, stamps, PM_SUBTRACTION_EQUATION_KERNELS)) {
     817                    psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation.");
     818                    goto MATCH_ERROR;
     819                }
     820                memCheck("  solve equation");
     821# endif
    554822                psVector *deviations = pmSubtractionCalculateDeviations(stamps, kernels); // Stamp deviations
    555823                if (!deviations) {
    556                     psError(PS_ERR_UNKNOWN, false, "Unable to calculate deviations.");
    557                     goto MATCH_ERROR;
    558                 }
    559                 pmSubtractionRejectStamps(kernels, stamps, deviations, subMask, NAN, footprint);
     824                    psError(psErrorCodeLast(), false, "Unable to calculate deviations.");
     825                    goto MATCH_ERROR;
     826                }
     827                pmSubtractionRejectStamps(kernels, stamps, deviations, subMask, NAN);
    560828                psFree(deviations);
    561829            }
     
    565833            memCheck("solution");
    566834
    567             if (!pmSubtractionAnalysis(analysis, kernels, region, numCols, numRows)) {
    568                 psError(PS_ERR_UNKNOWN, false, "Unable to generate QA data");
     835            if (!pmSubtractionAnalysis(analysis, header, kernels, region, numCols, numRows)) {
     836                psError(psErrorCodeLast(), false, "Unable to generate QA data");
    569837                goto MATCH_ERROR;
    570838            }
     
    574842            psTrace("psModules.imcombine", 2, "Convolving...\n");
    575843            if (!pmSubtractionConvolve(conv1, conv2, ro1, ro2, subMask, stride, maskBad, maskPoor, poorFrac,
    576                                        sysError, region, kernels, true, useFFT)) {
    577                 psError(PS_ERR_UNKNOWN, false, "Unable to convolve image.");
     844                                       kernelError, covarFrac, region, kernels, true, useFFT)) {
     845                psError(psErrorCodeLast(), false, "Unable to convolve image.");
    578846                goto MATCH_ERROR;
    579847            }
     
    594862    variance = NULL;
    595863
    596     if (!pmSubtractionBorder(conv1->image, conv1->variance, conv1->mask, size, maskBad)) {
    597         psError(PS_ERR_UNKNOWN, false, "Unable to set border of convolved image.");
     864    if (conv1 && !pmSubtractionBorder(conv1->image, conv1->variance, conv1->mask, size, maskBad)) {
     865        psError(psErrorCodeLast(), false, "Unable to set border of convolved image.");
    598866        goto MATCH_ERROR;
    599867    }
     868    if (conv2 && !pmSubtractionBorder(conv2->image, conv2->variance, conv2->mask, size, maskBad)) {
     869        psError(psErrorCodeLast(), false, "Unable to set border of convolved image.");
     870        goto MATCH_ERROR;
     871    }
    600872
    601873    memCheck("convolution");
    602874
    603     if (conv1) {
    604         psMetadataCopy(conv1->analysis, analysis);
    605     }
    606     if (conv2) {
    607         psMetadataCopy(conv2->analysis, analysis);
    608     }
     875    subtractionAnalysisUpdate(conv1, conv2, analysis, header);
    609876    psFree(analysis);
     877    psFree(header);
    610878
    611879#ifdef TESTING
     
    629897MATCH_ERROR:
    630898    psFree(analysis);
     899    psFree(header);
    631900    psFree(region);
    632901    psFree(regionString);
     
    7971066        } else {
    7981067            if (!pmSubtractionOrderStamp(ratios, mask, stamps, models, modelSums, i, bg1, bg2)) {
    799                 psError(PS_ERR_UNKNOWN, false, "Unable to measure PSF width for stamp %d", i);
     1068                psError(psErrorCodeLast(), false, "Unable to measure PSF width for stamp %d", i);
    8001069                psFree(models);
    8011070                psFree(modelSums);
     
    8081077
    8091078    if (!psThreadPoolWait(true)) {
    810         psError(PS_ERR_UNKNOWN, false, "Error waiting for threads.");
     1079        psError(psErrorCodeLast(), false, "Error waiting for threads.");
    8111080        psFree(models);
    8121081        psFree(modelSums);
     
    8211090    psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN);
    8221091    if (!psVectorStats(stats, ratios, NULL, mask, 0xff)) {
    823         psError(PS_ERR_UNKNOWN, false, "Unable to calculate statistics for moments ratio.");
     1092        psError(psErrorCodeLast(), false, "Unable to calculate statistics for moments ratio.");
    8241093        psFree(mask);
    8251094        psFree(ratios);
     
    8421111    return mode;
    8431112}
     1113
     1114
     1115// Test a subtraction mode by performing a single iteration
     1116static bool subtractionModeTest(pmSubtractionStampList *stamps, // Stamps to use to find best mode
     1117                                pmSubtractionKernels *kernels, // Kernel description
     1118                                const char *description, // Description for trace
     1119                                psImage *subMask,  // Subtraction mask
     1120                                float rej               // Rejection threshold
     1121                                )
     1122{
     1123    assert(stamps);
     1124    assert(kernels);
     1125
     1126    psTrace("psModules.imcombine", 3, "Calculating %s normalization equation...\n", description);
     1127    if (!pmSubtractionCalculateEquation(stamps, kernels, SUBMODE)) {
     1128        psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation.");
     1129        return false;
     1130    }
     1131
     1132    psTrace("psModules.imcombine", 3, "Solving %s normalization equation...\n", description);
     1133    if (!pmSubtractionSolveEquation(kernels, stamps, SUBMODE)) {
     1134        psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation.");
     1135        return false;
     1136    }
     1137
     1138# if (SEPARATE)
     1139    // set USED -> CALCULATE
     1140    pmSubtractionStampsResetStatus (stamps);
     1141
     1142    psTrace("psModules.imcombine", 3, "Calculating %s kernel coeffs equation...\n", description);
     1143    if (!pmSubtractionCalculateEquation(stamps, kernels, PM_SUBTRACTION_EQUATION_KERNELS)) {
     1144        psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation.");
     1145        return false;
     1146    }
     1147
     1148    psTrace("psModules.imcombine", 3, "Solving %s kernel coeffs equation...\n", description);
     1149    if (!pmSubtractionSolveEquation(kernels, stamps, PM_SUBTRACTION_EQUATION_KERNELS)) {
     1150        psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation.");
     1151        return false;
     1152    }
     1153# endif
     1154
     1155    psTrace("psModules.imcombine", 3, "Calculate %s deviations...\n", description);
     1156    psVector *deviations = pmSubtractionCalculateDeviations(stamps, kernels); // Stamp deviations
     1157    if (!deviations) {
     1158        psError(psErrorCodeLast(), false, "Unable to calculate deviations.");
     1159        return false;
     1160    }
     1161
     1162    psTrace("psModules.imcombine", 3, "Rejecting %s stamps...\n", description);
     1163    long numRejected = pmSubtractionRejectStamps(kernels, stamps, deviations, subMask, rej);
     1164    if (numRejected < 0) {
     1165        psError(psErrorCodeLast(), false, "Unable to reject stamps.");
     1166        psFree(deviations);
     1167        return false;
     1168    }
     1169    psFree(deviations);
     1170
     1171    if (numRejected > 0) {
     1172        // Allow re-fit with reduced stamps set
     1173        psTrace("psModules.imcombine", 3, "Calculating %s normalization equation...\n", description);
     1174        if (!pmSubtractionCalculateEquation(stamps, kernels, PM_SUBTRACTION_EQUATION_ALL)) {
     1175            psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation.");
     1176            return false;
     1177        }
     1178
     1179        psTrace("psModules.imcombine", 3, "Resolving %s equation...\n", description);
     1180        if (!pmSubtractionSolveEquation(kernels, stamps, PM_SUBTRACTION_EQUATION_ALL)) {
     1181            psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation.");
     1182            return false;
     1183        }
     1184        psTrace("psModules.imcombine", 3, "Recalculate %s deviations...\n", description);
     1185
     1186# if (SEPARATE)
     1187        // set USED -> CALCULATE
     1188        pmSubtractionStampsResetStatus (stamps);
     1189
     1190        psTrace("psModules.imcombine", 3, "Calculating %s normalization equation...\n", description);
     1191        if (!pmSubtractionCalculateEquation(stamps, kernels, PM_SUBTRACTION_EQUATION_KERNELS)) {
     1192            psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation.");
     1193            return false;
     1194        }
     1195
     1196        psTrace("psModules.imcombine", 3, "Resolving %s equation...\n", description);
     1197        if (!pmSubtractionSolveEquation(kernels, stamps, PM_SUBTRACTION_EQUATION_KERNELS)) {
     1198            psError(psErrorCodeLast(), false, "Unable to calculate least-squares equation.");
     1199            return false;
     1200        }
     1201        psTrace("psModules.imcombine", 3, "Recalculate %s deviations...\n", description);
     1202# endif
     1203
     1204        psVector *deviations = pmSubtractionCalculateDeviations(stamps, kernels); // Stamp deviations
     1205        if (!deviations) {
     1206            psError(psErrorCodeLast(), false, "Unable to calculate deviations.");
     1207            return false;
     1208        }
     1209        psTrace("psModules.imcombine", 3, "Measuring %s quality...\n", description);
     1210        long numRejected = pmSubtractionRejectStamps(kernels, stamps, deviations, subMask, NAN);
     1211        if (numRejected < 0) {
     1212            psError(psErrorCodeLast(), false, "Unable to reject stamps.");
     1213            psFree(deviations);
     1214            return false;
     1215        }
     1216        psFree(deviations);
     1217    }
     1218
     1219    return true;
     1220}
     1221
     1222
     1223pmSubtractionMode pmSubtractionBestMode(pmSubtractionStampList **stamps, pmSubtractionKernels **kernels,
     1224                                        const psImage *subMask, float rej)
     1225{
     1226    PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(*stamps, PM_SUBTRACTION_MODE_ERR);
     1227    PM_ASSERT_SUBTRACTION_KERNELS_NON_NULL(*kernels, PM_SUBTRACTION_MODE_ERR);
     1228
     1229    // Copies of the inputs
     1230    pmSubtractionStampList *stamps1 = pmSubtractionStampListCopy(*stamps);
     1231    pmSubtractionKernels *kernels1 = pmSubtractionKernelsCopy(*kernels);
     1232    psImage *subMask1 = psImageCopy(NULL, subMask, subMask->type.type);
     1233    kernels1->mode = PM_SUBTRACTION_MODE_1;
     1234
     1235    if (!subtractionModeTest(stamps1, kernels1, "convolve 1", subMask1, rej)) {
     1236        psError(psErrorCodeLast(), false, "Unable to test subtraction with convolution of image 1");
     1237        psFree(stamps1);
     1238        psFree(kernels1);
     1239        psFree(subMask1);
     1240        return PM_SUBTRACTION_MODE_ERR;
     1241    }
     1242    psFree(subMask1);
     1243
     1244    // Copies of the inputs
     1245    pmSubtractionStampList *stamps2 = pmSubtractionStampListCopy(*stamps);
     1246    pmSubtractionKernels *kernels2 = pmSubtractionKernelsCopy(*kernels);
     1247    psImage *subMask2 = psImageCopy(NULL, subMask, subMask->type.type);
     1248    kernels2->mode = PM_SUBTRACTION_MODE_2;
     1249
     1250    if (!subtractionModeTest(stamps2, kernels2, "convolve 2", subMask2, rej)) {
     1251        psError(psErrorCodeLast(), false, "Unable to test subtraction with convolution of image 2");
     1252        psFree(stamps2);
     1253        psFree(kernels2);
     1254        psFree(subMask2);
     1255        psFree(stamps1);
     1256        psFree(kernels1);
     1257        return PM_SUBTRACTION_MODE_ERR;
     1258    }
     1259    psFree(subMask2);
     1260
     1261
     1262    pmSubtractionStampList *bestStamps = NULL; // Best choice for stamps
     1263    pmSubtractionKernels *bestKernels = NULL; // Best choice for kernels
     1264    psLogMsg("psModules.imcombine", PS_LOG_INFO,
     1265             "Image 1: %f +/- %f from %d stamps\nImage 2: %f +/- %f from %d stamps\n",
     1266             kernels1->mean, kernels1->rms, kernels1->numStamps,
     1267             kernels2->mean, kernels2->rms, kernels2->numStamps);
     1268
     1269    if (kernels1->mean < kernels2->mean) {
     1270        bestStamps = stamps1;
     1271        bestKernels = kernels1;
     1272    } else {
     1273        bestStamps = stamps2;
     1274        bestKernels = kernels2;
     1275    }
     1276
     1277    psFree(*stamps);
     1278    psFree(*kernels);
     1279    *stamps = psMemIncrRefCounter(bestStamps);
     1280    *kernels = psMemIncrRefCounter(bestKernels);
     1281
     1282    psFree(stamps1);
     1283    psFree(stamps2);
     1284    psFree(kernels1);
     1285    psFree(kernels2);
     1286
     1287    return bestKernels->mode;
     1288}
     1289
     1290
     1291bool pmSubtractionParamsScale(int *kernelSize, int *stampSize, psVector *widths,
     1292                              float fwhm1, float fwhm2, float scaleRef, float scaleMin, float scaleMax)
     1293{
     1294    PS_ASSERT_PTR_NON_NULL(kernelSize, false);
     1295    PS_ASSERT_PTR_NON_NULL(stampSize, false);
     1296    PS_ASSERT_VECTOR_NON_NULL(widths, false);
     1297    PS_ASSERT_VECTOR_TYPE(widths, PS_TYPE_F32, false);
     1298    PS_ASSERT_FLOAT_LARGER_THAN(fwhm1, 0.0, false);
     1299    PS_ASSERT_FLOAT_LARGER_THAN(fwhm2, 0.0, false);
     1300    PS_ASSERT_FLOAT_LARGER_THAN(scaleRef, 0.0, false);
     1301    PS_ASSERT_FLOAT_LARGER_THAN(scaleMin, 0.0, false);
     1302    PS_ASSERT_FLOAT_LARGER_THAN(scaleMax, 0.0, false);
     1303    PS_ASSERT_FLOAT_LARGER_THAN(scaleMax, scaleMin, false);
     1304
     1305//    float diff = sqrtf(PS_SQR(PS_MAX(fwhm1, fwhm2)) - PS_SQR(PS_MIN(fwhm1, fwhm2))); // Difference
     1306    float scale = PS_MAX(fwhm1, fwhm2) / scaleRef;      // Scaling factor
     1307
     1308    if (isfinite(scaleMin) && scale < scaleMin) {
     1309        scale = scaleMin;
     1310    }
     1311    if (isfinite(scaleMax) && scale > scaleMax) {
     1312        scale = scaleMax;
     1313    }
     1314
     1315    for (int i = 0; i < widths->n; i++) {
     1316        widths->data.F32[i] *= scale;
     1317    }
     1318    *kernelSize = *kernelSize * scale + 0.5;
     1319    *stampSize = *stampSize * scale + 0.5;
     1320
     1321    psLogMsg("psModules.imcombine", PS_LOG_INFO,
     1322             "Scaling kernel parameters by %f: %d %d", scale, *kernelSize, *stampSize);
     1323
     1324    return true;
     1325}
Note: See TracChangeset for help on using the changeset viewer.