IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 15756


Ignore:
Timestamp:
Dec 6, 2007, 3:57:15 PM (18 years ago)
Author:
Paul Price
Message:

Implementing dual-convolution. This required reworking those
functions involved with calculating and solving the equations; moved
these into a separate file and made various other cleanups (e.g.,
assertions for pmSubtractionKernels). Removed the normalisation
(central pixel) term from all kernels, because this shouldn't be in
the second kernel (there's only one normalisation term between the two
kernels); the normalisation is treated explicitly in the equations,
along with the background (still only a constant background is
supported for now, but there's a lot of support for a polynomial
background for when I get around to putting it in the equations).
Tested the single convolution, and it's working; same results as
before, apparently. Haven't tested dual convolution yet.

Location:
trunk/psModules/src
Files:
4 added
14 edited

Legend:

Unmodified
Added
Removed
  • trunk/psModules/src/camera/pmReadoutFake.c

    r15424 r15756  
    2020#include "pmSource.h"
    2121#include "pmSourceUtils.h"
     22#include "pmModelUtils.h"
    2223
    2324#define MODEL_TYPE "PS_MODEL_RGAUSS"     // Type of model to use
    2425
    2526
    26 pmReadout *pmReadoutFakeFromSources(int numCols, int numRows, const psArray *sources,
    27                                     float fwhm, float minFlux)
     27bool pmReadoutFakeFromSources(pmReadout *readout, int numCols, int numRows, const psArray *sources,
     28                              const psVector *xOffset, const psVector *yOffset, pmPSF *psf, float minFlux,
     29                              int radius)
    2830{
    29     PS_ASSERT_INT_LARGER_THAN(numCols, 0, NULL);
    30     PS_ASSERT_INT_LARGER_THAN(numRows, 0, NULL);
    31     PS_ASSERT_ARRAY_NON_NULL(sources, NULL);
    32     PS_ASSERT_FLOAT_LARGER_THAN(fwhm, 0.0, NULL);
    33     PS_ASSERT_FLOAT_LARGER_THAN(minFlux, 0.0, NULL);
     31    PS_ASSERT_PTR_NON_NULL(readout, false);
     32    PS_ASSERT_INT_LARGER_THAN(numCols, 0, false);
     33    PS_ASSERT_INT_LARGER_THAN(numRows, 0, false);
     34    PS_ASSERT_ARRAY_NON_NULL(sources, false);
     35    if (xOffset || yOffset) {
     36        PS_ASSERT_VECTOR_NON_NULL(xOffset, false);
     37        PS_ASSERT_VECTOR_NON_NULL(yOffset, false);
     38        PS_ASSERT_VECTORS_SIZE_EQUAL(xOffset, yOffset, false);
     39        PS_ASSERT_VECTOR_TYPE(xOffset, PS_TYPE_S32, false);
     40        PS_ASSERT_VECTOR_TYPE_EQUAL(xOffset, yOffset, false);
     41        if (xOffset->n != sources->n) {
     42            psError(PS_ERR_BAD_PARAMETER_SIZE, true,
     43                    "Number of offset vectors (%ld) and sources (%ld) doesn't match",
     44                    xOffset->n, sources->n);
     45            return false;
     46        }
     47    }
     48    PS_ASSERT_PTR_NON_NULL(psf, false);
     49    if (radius > 0 && isfinite(minFlux) && minFlux > 0.0) {
     50        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Cannot define both minimum flux and fixed radius.");
     51        return false;
     52    }
    3453
    35     pmReadout *readout = pmReadoutAlloc(NULL); // Output readout
    36     readout->image = psImageAlloc(numCols, numRows, PS_TYPE_F32);
     54
     55    readout->image = psImageRecycle(readout->image, numCols, numRows, PS_TYPE_F32);
    3756    psImageInit(readout->image, 0);
    3857
    3958    int numSources = sources->n;          // Number of stars
    4059
     60#if 0
    4161    pmModelType modelType = pmModelClassGetType(MODEL_TYPE); // Type of PSF model
    4262    assert(modelType >= 0);
     
    6585        psAbort("Unsupported model type: %d", modelType);
    6686    }
     87#endif
    6788
     89    pmModel *fakeModel = pmModelFromPSFforXY(psf, (float)numCols / 2.0, (float)numRows / 2.0,
     90                                             1.0); // Fake model, with central intensity of 1.0
    6891    float flux0 = fakeModel->modelFlux(fakeModel->params); // Flux for central intensity of 1.0
    69 
    7092
    7193    for (int i = 0; i < numSources; i++) {
     
    93115        pmSource *fakeSource = pmSourceAlloc(); // Fake source to generate
    94116        fakeSource->peak = pmPeakAlloc(x, y, fakeModel->params->data.F32[PM_PAR_I0], PM_PEAK_LONE);
    95         float radius = fakeModel->modelRadius(fakeModel->params, minFlux); // Radius of interest for source
     117        float fakeRadius = radius > 0 ? radius : fakeModel->modelRadius(fakeModel->params, minFlux); // Radius
    96118
    97         if (!pmSourceDefinePixels(fakeSource, readout, x, y, radius)) {
    98             psError(PS_ERR_UNKNOWN, false, "Unable to define pixels for source.");
    99             psFree(readout);
    100             psFree(fakeModel);
    101             return NULL;
    102         }
    103 
    104         if (!pmModelAdd(fakeSource->pixels, NULL, fakeModel, PM_MODEL_OP_FULL, 0)) {
    105             psError(PS_ERR_UNKNOWN, false, "Unable to add model of source to image.");
    106             psFree(readout);
    107             psFree(fakeModel);
    108             return NULL;
     119        if (xOffset) {
     120            if (!pmSourceDefinePixels(fakeSource, readout, x + xOffset->data.S32[i],
     121                                      y + yOffset->data.S32[i], fakeRadius)) {
     122                psError(PS_ERR_UNKNOWN, false, "Unable to define pixels for source.");
     123                psFree(readout);
     124                psFree(fakeModel);
     125                return false;
     126            }
     127            if (!pmModelAddWithOffset(fakeSource->pixels, NULL, fakeModel, PM_MODEL_OP_FULL, 0,
     128                                      - xOffset->data.S32[i], - yOffset->data.S32[i])) {
     129                psError(PS_ERR_UNKNOWN, false, "Unable to add model of source to image.");
     130                psFree(readout);
     131                psFree(fakeModel);
     132                return false;
     133            }
     134        } else {
     135            if (!pmSourceDefinePixels(fakeSource, readout, x, y, fakeRadius)) {
     136                psError(PS_ERR_UNKNOWN, false, "Unable to define pixels for source.");
     137                psFree(readout);
     138                psFree(fakeModel);
     139                return false;
     140            }
     141            if (!pmModelAdd(fakeSource->pixels, NULL, fakeModel, PM_MODEL_OP_FULL, 0)) {
     142                psError(PS_ERR_UNKNOWN, false, "Unable to add model of source to image.");
     143                psFree(readout);
     144                psFree(fakeModel);
     145                return false;
     146            }
    109147        }
    110148        psFree(fakeSource);
     
    113151    psFree(fakeModel);
    114152
    115     return readout;
     153    return true;
    116154}
  • trunk/psModules/src/camera/pmReadoutFake.h

    r15362 r15756  
    66#include <pmFPA.h>
    77
    8 // Generate a fake readout from an array of sources
    9 pmReadout *pmReadoutFakeFromSources(int numCols, int numRows, ///< Dimension of image
    10                                     const psArray *sources, ///< Array of pmSource
    11                                     float fwhm, ///< FWHM for sources
    12                                     float minFlux ///< Minimum flux to bother about; for setting object size
     8#include <pmMoments.h>
     9#include <pmResiduals.h>
     10#include <pmGrowthCurve.h>
     11#include <pmTrend2D.h>
     12#include <pmPSF.h>
     13
     14
     15/// Generate a fake readout from an array of sources
     16bool pmReadoutFakeFromSources(pmReadout *readout, ///< Output readout, or NULL
     17                              int numCols, int numRows, ///< Dimension of image
     18                              const psArray *sources, ///< Array of pmSource
     19                              const psVector *xOffset, ///< x offsets for sources (source -> img), or NULL
     20                              const psVector *yOffset, ///< y offsets for sources (source -> img), or NULL
     21                              pmPSF *psf, ///< PSF for sources
     22                              float minFlux, ///< Minimum flux to bother about; for setting source radius
     23                              int radius ///< Fixed radius for sources
    1324    );
    1425
    15 
    16 
    17 
    1826#endif
  • trunk/psModules/src/imcombine/Makefile.am

    r14886 r15756  
    99        pmStackReject.c         \
    1010        pmSubtraction.c         \
     11        pmSubtractionEquation.c \
    1112        pmSubtractionKernels.c  \
     13        pmSubtractionMask.c     \
     14        pmSubtractionMatch.c    \
     15        pmSubtractionParams.c   \
    1216        pmSubtractionStamps.c   \
    13         pmSubtractionMatch.c    \
    14         pmSubtractionParams.c
     17        pmPSFEnvelope.c
    1518
    1619pkginclude_HEADERS = \
     
    2023        pmStackReject.h         \
    2124        pmSubtraction.h         \
     25        pmSubtractionEquation.h \
    2226        pmSubtractionKernels.h  \
     27        pmSubtractionMask.h     \
     28        pmSubtractionMatch.h    \
     29        pmSubtractionParams.h   \
    2330        pmSubtractionStamps.h   \
    24         pmSubtractionMatch.h    \
    25         pmSubtractionParams.h
     31        pmPSFEnvelope.h
    2632
    2733CLEANFILES = *~
  • trunk/psModules/src/imcombine/pmStackReject.c

    r15449 r15756  
    5757    for (int i = 0; i < numRegions; i++) {
    5858        psRegion *region = regions->data[i]; // Region of interest
    59         psVector *solution = solutions->data[i]; // Solution of interest
    60         if (!pmSubtractionConvolve(convRO, inRO, NULL, NULL, 0, region, solution, kernels,
    61                                    PM_SUBTRACTION_MODE_1, true)) {
     59        if (!pmSubtractionConvolve(convRO, NULL, inRO, NULL, NULL, 0, region, kernels, true)) {
    6260            psError(PS_ERR_UNKNOWN, false, "Unable to convolve mask image in region %d.", i);
    6361            psFree(convRO);
     
    7270        float xNorm = (region->x0 + 0.5 * (region->x1 - region->x0) - numCols/2.0) / (float)numCols;
    7371        float yNorm = (region->y0 + 0.5 * (region->y1 - region->y0) - numRows/2.0) / (float)numRows;
    74         psImage *kernel = pmSubtractionKernelImage(solution, kernels, xNorm, yNorm);
     72        psImage *kernel = pmSubtractionKernelImage(kernels, xNorm, yNorm, false);
    7573        if (!kernel) {
    7674            psError(PS_ERR_UNKNOWN, false, "Unable to generate kernel image.");
  • trunk/psModules/src/imcombine/pmSubtraction.c

    r15455 r15756  
    44 *  @author GLG, MHPCC
    55 *
    6  *  @version $Revision: 1.73 $ $Name: not supported by cvs2svn $
    7  *  @date $Date: 2007-11-05 23:43:38 $
     6 *  @version $Revision: 1.74 $ $Name: not supported by cvs2svn $
     7 *  @date $Date: 2007-12-07 01:57:15 $
    88 *
    99 *  Copyright 2004-2007 Institute for Astronomy, University of Hawaii
     
    2323#include "pmFPA.h"
    2424#include "pmSubtractionStamps.h"
     25#include "pmSubtractionEquation.h"
    2526
    2627#include "pmSubtraction.h"
     
    3435// Private (file-static) functions
    3536//////////////////////////////////////////////////////////////////////////////////////////////////////////////
    36 
    37 // Return the number of polynomial terms there are for a given order
    38 static inline long polyTerms(int order  // Order of polynomial
    39                              )
    40 {
    41     return (order + 1) * (order + 2) / 2;
    42 }
    43 
    44 // Given a stamp coordinates (x,y), generate a matrix where the elements (i,j) are x^i * y^j
    45 static psImage *spatialPolyValues(int spatialOrder, // Maximum spatial polynomial order
    46                                   float x, float y // Normalised position of interest, [-1,1]
    47     )
    48 {
    49     assert(spatialOrder >= 0);
    50     assert(x >= -1 && x <= 1);
    51     assert(y >= -1 && y <= 1);
    52 
    53     psImage *polyValues = psImageAlloc(spatialOrder + 1, spatialOrder + 1, PS_TYPE_F64); // Matrix to return
    54     polyValues->data.F64[0][0] = 1.0;
    55 
    56     double value = 1.0;
    57     for (int i = 1; i <= spatialOrder; i++) {
    58         value *= x;
    59         polyValues->data.F64[0][i] = value;
    60     }
    61 
    62     value = 1.0;
    63     for (int j = 1; j <= spatialOrder; j++) {
    64         value *= y;
    65         polyValues->data.F64[j][0] = value;
    66     }
    67 
    68     for (int j = 1; j <= spatialOrder; j++) {
    69         for (int i = 1; i <= spatialOrder - j; i++) {
    70             polyValues->data.F64[j][i] = polyValues->data.F64[j][0] * polyValues->data.F64[0][i];
    71         }
    72     }
    73 
    74     return polyValues;
    75 }
    7637
    7738// Generate the kernel to apply to the variance from the normal kernel
     
    10869
    10970// Generate an image of the solved kernel
    110 static inline psKernel *solvedKernel(psKernel *kernel, // Kernel, to return
    111                                      const psVector *solution, // Solution to the least-squares problem
    112                                      const pmSubtractionKernels *kernels, // Kernel basis functions
    113                                      const psImage *polyValues // Spatial polynomial values
    114                                      )
    115 {
     71static psKernel *solvedKernel(psKernel *kernel, // Kernel, to return
     72                              const pmSubtractionKernels *kernels, // Kernel basis functions
     73                              const psImage *polyValues, // Spatial polynomial values
     74                              bool wantDual // Want the dual (second) kernel?
     75                              )
     76{
     77    assert(kernels);
     78    assert(polyValues);
     79
    11680    int numKernels = kernels->num;      // Number of kernel basis functions
    117     assert(kernels->u->n == numKernels);
    118     assert(kernels->v->n == numKernels);
    119     int spatialOrder = kernels->spatialOrder; // Maximum spatial polynomial order
    120     assert(solution->n == numKernels * polyTerms(spatialOrder) + polyTerms(kernels->bgOrder));
    121 
    122     // Ensure the subIndex for POIS kernels is what is expected
    123     assert((kernels->type != PM_SUBTRACTION_KERNEL_POIS &&
    124             kernels->type != PM_SUBTRACTION_KERNEL_SPAM &&
    125             kernels->type != PM_SUBTRACTION_KERNEL_FRIES &&
    126             kernels->type != PM_SUBTRACTION_KERNEL_GUNK &&
    127             kernels->type != PM_SUBTRACTION_KERNEL_RINGS) ||
    128            (kernels->u->data.S32[kernels->subIndex] == 0 && kernels->v->data.S32[kernels->subIndex] == 0));
    129 
    13081    int size = kernels->size;           // Kernel half-size
    13182    if (!kernel) {
     
    13586
    13687    for (int i = 0; i < numKernels; i++) {
    137         double value = 0.0;             // Value of this component, from the sum of multiple polynomial terms
    138         for (int yOrder = 0, index = i; yOrder <= spatialOrder; yOrder++) {
    139             for (int xOrder = 0; xOrder <= spatialOrder - yOrder; xOrder++, index += numKernels) {
    140                 value += polyValues->data.F64[yOrder][xOrder] * solution->data.F64[index];
    141             }
    142         }
     88        double value = p_pmSubtractionSolutionCoeff(kernels, polyValues, i, wantDual); // Polynomial value
    14389
    14490        switch (kernels->type) {
     
    14793              int v = kernels->v->data.S32[i]; // Offset in y
    14894              kernel->kernel[v][u] += value;
    149               if (kernels->spatialOrder > 0 && i != kernels->subIndex) {
    150                   // The (0,0) element is subtracted from most kernels to preserve photometric scaling
    151                   kernel->kernel[0][0] -= value;
    152               }
     95              kernel->kernel[0][0] -= value;
    15396              break;
    15497          }
     
    167110                  for (int u = uStart; u <= uStop; u++) {
    168111                      kernel->kernel[v][u] += norm * value;
    169                       if (kernels->spatialOrder > 0 && i != kernels->subIndex) {
    170                           // The (0,0) element is subtracted from most kernels to preserve photometric scaling
    171                           kernel->kernel[0][0] -= value;
    172                       }
     112                      kernel->kernel[0][0] -= value;
    173113                  }
    174114              }
     
    188128              } else {
    189129                  // Using delta function
    190                   bool subtract = (kernels->spatialOrder > 0 && i != kernels->subIndex); // Subtract (0,0)?
    191130                  int u = kernels->u->data.S32[i]; // Offset in x
    192131                  int v = kernels->v->data.S32[i]; // Offset in y
    193132                  kernel->kernel[v][u] += value;
    194                   if (subtract) {
    195                       // The (0,0) element is subtracted from most kernels to preserve photometric scaling
    196                       kernel->kernel[0][0] -= value;
    197                   }
     133                  kernel->kernel[0][0] -= value;
    198134              }
    199135              break;
     
    211147          }
    212148          case PM_SUBTRACTION_KERNEL_RINGS: {
    213               if (i == kernels->subIndex) {
    214                   kernel->kernel[0][0] += value;
    215                   break;
    216               }
    217149              psArray *preCalc = kernels->preCalc->data[i]; // Precalculated data
    218150              psVector *uCoords = preCalc->data[0]; // u coordinates
     
    232164        }
    233165    }
     166
     167    if (!wantDual) {
     168        // Put in the normalisation component
     169        kernel->kernel[0][0] += p_pmSubtractionSolutionNorm(kernels);
     170    }
     171
    234172
    235173    return kernel;
     
    328266}
    329267
    330 // Mark a pixel as blank in the image, mask and weight
    331 static inline void markBlank(psImage *image, // Image to mark as blank
    332                              psImage *mask, // Mask to mark as blank (or NULL)
    333                              psImage *weight, // Weight map to mark as blank (or NULL)
    334                              int x, int y, // Coordinates to mark blank
    335                              psMaskType blank // Blank mask value
     268// Convolve a region of an image
     269static inline void convolveRegion(psImage *convImage, // Convolved image (output)
     270                                  psImage *convWeight, // Convolved weight map (output), or NULL
     271                                  psKernel **kernelImage, // Convolution kernel for the image
     272                                  psKernel **kernelWeight, // Convolution kernel for the weight map, or NULL
     273                                  const psImage *image, // Image to convolve
     274                                  const psImage *weight, // Weight map to convolve, or NULL
     275                                  const psImage *subMask, // Subtraction mask
     276                                  psMaskType maskVal, // Mask value to apply in convolution
     277                                  const pmSubtractionKernels *kernels, // Kernels
     278                                  psImage *polyValues, // Polynomial values
     279                                  float background, // Background value to apply
     280                                  psRegion region, // Region to convolve
     281                                  bool useFFT  // Use FFT to convolve?
    336282    )
    337283{
    338     image->data.F32[y][x] = NAN;
    339     if (mask) {
    340         mask->data.PS_TYPE_MASK_DATA[y][x] |= blank;
    341     }
     284    *kernelImage = solvedKernel(*kernelImage, kernels, polyValues, false);
    342285    if (weight) {
    343         weight->data.F32[y][x] = NAN;
    344     }
     286        *kernelWeight = varianceKernel(*kernelWeight, *kernelImage);
     287    }
     288
     289    if (useFFT) {
     290        // Use Fast Fourier Transform to do the convolution
     291        // This provides a big speed-up for large kernels
     292        convolveFFT(convImage, image, subMask, maskVal, *kernelImage, region, background, kernels->size);
     293        if (weight) {
     294            convolveFFT(convWeight, weight, subMask, maskVal, *kernelWeight, region, 0.0, kernels->size);
     295        }
     296    } else {
     297        convolveDirect(convImage, image, *kernelImage, region, background, kernels->size);
     298        if (weight) {
     299            convolveDirect(convWeight, weight, *kernelWeight, region, 0.0, kernels->size);
     300        }
     301    }
     302
    345303    return;
    346304}
     
    350308//////////////////////////////////////////////////////////////////////////////////////////////////////////////
    351309
    352 // Generate the convolution given a precalculated kernel
    353310psKernel *p_pmSubtractionConvolveStampPrecalc(const psKernel *image, const psKernel *kernel)
    354311{
     
    363320}
    364321
     322psImage *p_pmSubtractionPolynomial(psImage *output, int spatialOrder, float x, float y)
     323{
     324    assert(spatialOrder >= 0);
     325    assert(x >= -1 && x <= 1);
     326    assert(y >= -1 && y <= 1);
     327
     328    output = psImageRecycle(output, spatialOrder + 1, spatialOrder + 1, PS_TYPE_F64);
     329    output->data.F64[0][0] = 1.0;
     330
     331    double value = 1.0;
     332    for (int i = 1; i <= spatialOrder; i++) {
     333        value *= x;
     334        output->data.F64[0][i] = value;
     335    }
     336
     337    value = 1.0;
     338    for (int j = 1; j <= spatialOrder; j++) {
     339        value *= y;
     340        output->data.F64[j][0] = value;
     341    }
     342
     343    for (int j = 1; j <= spatialOrder; j++) {
     344        for (int i = 1; i <= spatialOrder - j; i++) {
     345            output->data.F64[j][i] = output->data.F64[j][0] * output->data.F64[0][i];
     346        }
     347    }
     348
     349    return output;
     350}
    365351
    366352//////////////////////////////////////////////////////////////////////////////////////////////////////////////
     
    368354//////////////////////////////////////////////////////////////////////////////////////////////////////////////
    369355
    370 psImage *pmSubtractionMask(const psImage *mask1, const psImage *mask2, psMaskType maskVal,
    371                            int size, int footprint, float badFrac, bool useFFT)
    372 {
    373     PS_ASSERT_IMAGE_NON_NULL(mask1, NULL);
    374     PS_ASSERT_IMAGE_TYPE(mask1, PS_TYPE_MASK, NULL);
    375     if (mask2) {
    376         PS_ASSERT_IMAGE_NON_NULL(mask2, NULL);
    377         PS_ASSERT_IMAGE_TYPE(mask2, PS_TYPE_MASK, NULL);
    378         PS_ASSERT_IMAGES_SIZE_EQUAL(mask2, mask1, NULL);
    379     }
    380     PS_ASSERT_INT_NONNEGATIVE(size, NULL);
    381     PS_ASSERT_INT_NONNEGATIVE(footprint, NULL);
    382     if (isfinite(badFrac)) {
    383         PS_ASSERT_FLOAT_LARGER_THAN(badFrac, 0.0, NULL);
    384         PS_ASSERT_FLOAT_LESS_THAN_OR_EQUAL(badFrac, 1.0, NULL);
    385     }
    386 
    387     int numCols = mask1->numCols, numRows = mask1->numRows; // Size of the images
    388 
    389     // Dereference inputs for convenience
    390     psMaskType **data1 = mask1->data.PS_TYPE_MASK_DATA;
    391     psMaskType **data2 = NULL;
    392     if (mask2) {
    393         data2 = mask2->data.PS_TYPE_MASK_DATA;
    394     }
    395 
    396     // First, a pass through to determine the fraction of bad pixels
    397     if (isfinite(badFrac) && badFrac != 1.0) {
    398         int numBad = 0;                 // Number of bad pixels
    399         for (int y = 0; y < numRows; y++) {
    400             for (int x = 0; x < numCols; x++) {
    401                 if (data1[y][x] & maskVal) {
    402                     numBad++;
    403                     continue;
    404                 }
    405                 if (data2 && data2[y][x] & maskVal) {
    406                     numBad++;
    407                 }
    408             }
    409         }
    410         if (numBad > badFrac * numCols * numRows) {
    411             psError(PS_ERR_BAD_PARAMETER_VALUE, true,
    412                     "Fraction of bad pixels (%d/%d=%f) exceeds limit (%f)\n",
    413                     numBad, numCols * numRows, (float)numBad/(float)(numCols * numRows), badFrac);
    414             return NULL;
    415         }
    416     }
    417 
    418     // Worried about the masks for bad pixels and bad stamps colliding, so make our own mask
    419     psImage *mask = psImageAlloc(numCols, numRows, PS_TYPE_MASK); // The global mask
    420     psImageInit(mask, 0);
    421     psMaskType **maskData = mask->data.PS_TYPE_MASK_DATA; // Dereference for convenience
    422 
    423     // Block out a border around the edge of the image
    424 
    425     // Bottom stripe
    426     for (int y = 0; y < PS_MIN(size + footprint, numRows); y++) {
    427         for (int x = 0; x < numCols; x++) {
    428             maskData[y][x] |= PM_SUBTRACTION_MASK_BORDER;
    429         }
    430     }
    431     // Either side
    432     for (int y = PS_MIN(size + footprint, numRows); y < numRows - size - footprint; y++) {
    433         for (int x = 0; x < PS_MIN(size + footprint, numCols); x++) {
    434             maskData[y][x] |= PM_SUBTRACTION_MASK_BORDER;
    435         }
    436         for (int x = PS_MAX(numCols - size - footprint, 0); x < numCols; x++) {
    437             maskData[y][x] |= PM_SUBTRACTION_MASK_BORDER;
    438         }
    439     }
    440     // Top stripe
    441     for (int y = PS_MAX(numRows - size - footprint, 0); y < numRows; y++) {
    442         for (int x = 0; x < numCols; x++) {
    443             maskData[y][x] |= PM_SUBTRACTION_MASK_BORDER;
    444         }
    445     }
    446 
    447     // XXX Could do something smarter here --- we will get images that are predominantly masked (where the
    448     // skycell isn't overlapped by a large fraction by the observation), so that convolving around every bad
    449     // pixel is wasting time.  As a first cut, I've put in a check on the fraction of bad pixels, but we could
    450     // imagine looking for the edge of big regions and convolving just at the edge.  As a second cut, allow
    451     // use of FFT convolution.
    452 
    453     for (int y = 0; y < numRows; y++) {
    454         for (int x = 0; x < numCols; x++) {
    455             if (data1[y][x] & maskVal) {
    456                 maskData[y][x] |= PM_SUBTRACTION_MASK_BAD_1;
    457             }
    458             if (data2 && data2[y][x] & maskVal) {
    459                 maskData[y][x] |= PM_SUBTRACTION_MASK_BAD_2;
    460             }
    461         }
    462     }
    463 
    464     // Block out the entire stamp footprint around bad input pixels.
    465 
    466     // We want to block out with the CONVOLVE mask anything that would be bad if we convolved with a bad
    467     // reference pixel (within 'size').  Then we want to block out with the FOOTPRINT mask everything within a
    468     // footprint's distance of those (within 'footprint').
    469 
    470     if (useFFT) {
    471         if (!psImageConvolveMaskFFT(mask, mask, PM_SUBTRACTION_MASK_BAD_1 | PM_SUBTRACTION_MASK_BAD_2,
    472                                     PM_SUBTRACTION_MASK_CONVOLVE_1 | PM_SUBTRACTION_MASK_FOOTPRINT_1,
    473                                     -size, size, -size, size, 0.5)) {
    474             psError(PS_ERR_UNKNOWN, false, "Unable to convolve bad pixels from mask 1.");
    475             psFree(mask);
    476             return NULL;
    477         }
    478         if (!psImageConvolveMaskFFT(mask, mask, PM_SUBTRACTION_MASK_BAD_2,
    479                                     PM_SUBTRACTION_MASK_CONVOLVE_2 | PM_SUBTRACTION_MASK_FOOTPRINT_2,
    480                                     -size, size, -size, size, 0.5)) {
    481             psError(PS_ERR_UNKNOWN, false, "Unable to convolve bad pixels from mask 2.");
    482             psFree(mask);
    483             return NULL;
    484         }
    485         if (!psImageConvolveMaskFFT(mask, mask, PM_SUBTRACTION_MASK_CONVOLVE_1,
    486                                     PM_SUBTRACTION_MASK_FOOTPRINT_1,
    487                                     -footprint, footprint, -footprint, footprint, 0.5)) {
    488             psError(PS_ERR_UNKNOWN, false, "Unable to reconvolve bad pixels from mask 1.");
    489             psFree(mask);
    490             return NULL;
    491         }
    492         if (!psImageConvolveMaskFFT(mask, mask, PM_SUBTRACTION_MASK_CONVOLVE_2,
    493                                     PM_SUBTRACTION_MASK_FOOTPRINT_2,
    494                                     -footprint, footprint, -footprint, footprint, 0.5)) {
    495             psError(PS_ERR_UNKNOWN, false, "Unable to reconvolve bad pixels from mask 2.");
    496             psFree(mask);
    497             return NULL;
    498         }
    499     } else {
    500         if (!psImageConvolveMaskDirect(mask, mask, PM_SUBTRACTION_MASK_BAD_1,
    501                                        PM_SUBTRACTION_MASK_CONVOLVE_1 | PM_SUBTRACTION_MASK_FOOTPRINT_1,
    502                                        -size, size, -size, size)) {
    503             psError(PS_ERR_UNKNOWN, false, "Unable to convolve bad pixels from mask 1.");
    504             psFree(mask);
    505             return NULL;
    506         }
    507         if (!psImageConvolveMaskDirect(mask, mask, PM_SUBTRACTION_MASK_BAD_2,
    508                                        PM_SUBTRACTION_MASK_CONVOLVE_2 | PM_SUBTRACTION_MASK_FOOTPRINT_2,
    509                                        -size, size, -size, size)) {
    510             psError(PS_ERR_UNKNOWN, false, "Unable to convolve bad pixels from mask 2.");
    511             psFree(mask);
    512             return NULL;
    513         }
    514         if (!psImageConvolveMaskDirect(mask, mask, PM_SUBTRACTION_MASK_CONVOLVE_1,
    515                                        PM_SUBTRACTION_MASK_FOOTPRINT_1,
    516                                        -footprint, footprint, -footprint, footprint)) {
    517             psError(PS_ERR_UNKNOWN, false, "Unable to reconvolve bad pixels from mask 1.");
    518             psFree(mask);
    519             return NULL;
    520         }
    521         if (!psImageConvolveMaskDirect(mask, mask, PM_SUBTRACTION_MASK_CONVOLVE_2,
    522                                        PM_SUBTRACTION_MASK_FOOTPRINT_2,
    523                                        -footprint, footprint, -footprint, footprint)) {
    524             psError(PS_ERR_UNKNOWN, false, "Unable to reconvolve bad pixels from mask 2.");
    525             psFree(mask);
    526             return NULL;
    527         }
    528     }
    529 
    530     return mask;
    531 }
    532356
    533357// Convolve a stamp by a single kernel basis function
     
    538362    )
    539363{
     364#if 0
     365    if (index == kernels->num) {
     366        // Normalisation component
     367        return convolveOffset(image, 0, 0, footprint);
     368    }
     369#endif
     370
    540371    switch (kernels->type) {
    541372      case PM_SUBTRACTION_KERNEL_POIS: {
     
    543374          int v = kernels->v->data.S32[index]; // Offset in y
    544375          psKernel *convolved = convolveOffset(image, u, v, footprint); // Convolved image
    545           if (kernels->spatialOrder > 0 && index != kernels->subIndex) {
    546               convolveSub(convolved, image, footprint);
    547           }
     376          convolveSub(convolved, image, footprint);
    548377          return convolved;
    549378      }
     
    569398              }
    570399          }
    571           if (kernels->spatialOrder > 0 && index != kernels->subIndex) {
    572               convolveSub(convolved, image, footprint);
    573           }
     400          convolveSub(convolved, image, footprint);
    574401          return convolved;
    575402      }
     
    583410          int v = kernels->v->data.S32[index]; // Offset in y
    584411          psKernel *convolved = convolveOffset(image, u, v, footprint); // Convolved image
    585           if (kernels->spatialOrder > 0 && index != kernels->subIndex) {
    586               convolveSub(convolved, image, footprint);
    587           }
     412          convolveSub(convolved, image, footprint);
    588413          return convolved;
    589414      }
     
    593418      }
    594419      case PM_SUBTRACTION_KERNEL_RINGS: {
    595           if (index == kernels->subIndex) {
    596               // Simply copying over the image
    597               return convolveOffset(image, 0, 0, footprint);
    598           }
    599420          psKernel *convolved = psKernelAlloc(-footprint, footprint,
    600421                                              -footprint, footprint); // Convolved image
     
    650471
    651472
    652 bool pmSubtractionConvolveStamp(pmSubtractionStamp *stamp, const pmSubtractionKernels *kernels, int footprint,
    653                                 pmSubtractionMode mode)
     473bool pmSubtractionConvolveStamp(pmSubtractionStamp *stamp, const pmSubtractionKernels *kernels, int footprint)
    654474{
    655475    PS_ASSERT_PTR_NON_NULL(stamp, false);
    656     PS_ASSERT_PTR_NON_NULL(kernels, false);
    657     PS_ASSERT_VECTORS_SIZE_EQUAL(kernels->u, kernels->v, false);
     476    PM_ASSERT_SUBTRACTION_KERNELS_NON_NULL(kernels, false);
    658477    PS_ASSERT_INT_NONNEGATIVE(footprint, false);
    659478
     
    663482    }
    664483
    665     switch (mode) {
     484    switch (kernels->mode) {
    666485      case PM_SUBTRACTION_MODE_TARGET:
    667486      case PM_SUBTRACTION_MODE_1:
     
    677496        break;
    678497      default:
    679         psAbort("Unsupported subtraction mode: %x", mode);
     498        psAbort("Unsupported subtraction mode: %x", kernels->mode);
    680499    }
    681500
     
    684503
    685504
    686 bool pmSubtractionCalculateEquation(pmSubtractionStampList *stamps, const pmSubtractionKernels *kernels,
    687                                     int footprint, pmSubtractionMode mode)
    688 {
    689     PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, false);
    690     PS_ASSERT_PTR_NON_NULL(kernels, false);
    691     PS_ASSERT_VECTORS_SIZE_EQUAL(kernels->u, kernels->v, false);
    692     PS_ASSERT_INT_NONNEGATIVE(footprint, false);
    693 
    694     int spatialOrder = kernels->spatialOrder; // Maximum order of spatial variation
    695     int numKernels = kernels->num;      // Number of kernel basis functions
    696     int numSpatial = polyTerms(spatialOrder); // Number of spatial variations
    697     int numBackground = polyTerms(kernels->bgOrder); // Number of background terms
    698 
    699     // Total number of parameters to solve for: coefficient of each kernel basis function, multipled by the
    700     // number of coefficients for the spatial polynomial, and a constant background offset.
    701     int numParams = numKernels * numSpatial + numBackground;
    702     int bgIndex = numParams - numBackground; // Index in matrix for the background
    703 
    704     // We iterate over each stamp, allocate the matrix and vectors if
    705     // necessary, and then calculate those matrix/vectors.
    706     for (int i = 0; i < stamps->num; i++) {
    707         pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest
    708         if (stamp->status != PM_SUBTRACTION_STAMP_CALCULATE) {
    709             continue;
    710         }
    711 
    712         psImage *stampMatrix = stamp->matrix; // Least-squares matrix for this stamp
    713         psVector *stampVector = stamp->vector; // Least-squares vector for this stamp
    714 
    715         if (!stampMatrix) {
    716             stamp->matrix = stampMatrix = psImageAlloc(numParams, numParams, PS_TYPE_F64);
    717         }
    718         assert(stampMatrix->type.type == PS_TYPE_F64);
    719         assert(stampMatrix->numCols == numParams && stampMatrix->numRows == numParams);
    720         psImageInit(stampMatrix, 0.0);
    721 
    722         if (!stampVector) {
    723             stamp->vector = stampVector = psVectorAlloc(numParams, PS_TYPE_F64);
    724         }
    725         assert(stampVector->type.type == PS_TYPE_F64);
    726         assert(stampVector->n == numParams);
    727         psVectorInit(stampVector, 0.0);
    728 
    729         // Generate convolutions
    730         if (!pmSubtractionConvolveStamp(stamp, kernels, footprint, mode)) {
    731             psError(PS_ERR_UNKNOWN, false, "Unable to convolve stamp %d.", i);
    732             return NULL;
    733         }
    734 
    735         psKernel *weight = stamp->weight; // Weight map postage stamp
    736         psKernel *target;               // Target postage stamp
    737         psArray *convolutions;          // Convolutions for each kernel
    738 
    739         switch (mode) {
    740           case PM_SUBTRACTION_MODE_TARGET:
    741           case PM_SUBTRACTION_MODE_1:
    742             target = stamp->image2;
    743             convolutions = stamp->convolutions1;
    744             break;
    745           case PM_SUBTRACTION_MODE_2:
    746             target = stamp->image1;
    747             convolutions = stamp->convolutions2;
    748             break;
    749           default:
    750             psAbort("Unsupported subtraction mode: %x", mode);
    751         }
    752 
    753         psImage *polyValues = spatialPolyValues(spatialOrder, stamp->xNorm, stamp->yNorm); // Polynomial terms
    754 
    755 #ifdef TESTING
    756         for (int j = 0; j < numKernels; j++) {
    757             psKernel *conv = convolutions->data[j]; // Convolution of interest
    758             psString filename = NULL; // Filename for output
    759             psStringAppend(&filename, "conv_%03d_%03d.fits", i, j);
    760             psFits *fits = psFitsOpen(filename, "w"); // FITS file pointer
    761             psFree(filename);
    762             psFitsWriteImage(fits, NULL, conv->image, 0, NULL);
    763             psFitsClose(fits);
    764         }
    765 #endif
    766 
    767         // Generate least-squares vector and matrix
    768         bool bad = false;               // Are there bad values?
    769         psString badString = NULL;      // Details on bad values
    770         for (int j = 0; j < numKernels && !bad; j++) {
    771             psKernel *jConv = convolutions->data[j]; // Convolution for j-th element
    772 
    773             // Generate matrix
    774             for (int k = j; k < numKernels && !bad; k++) {
    775                 psKernel *kConv = convolutions->data[k]; // Convolution for k-th element
    776                 double sumCC = 0.0; // Sum of the convolution products
    777                 for (int y = - footprint; y <= footprint; y++) {
    778                     for (int x = - footprint; x <= footprint; x++) {
    779                         sumCC += jConv->kernel[y][x] * kConv->kernel[y][x] / weight->kernel[y][x];
    780                     }
    781                 }
    782                 if (!isfinite(sumCC)) {
    783                     psStringAppend(&badString, "\nBad sumCC at %d, %d", j, k);
    784                     bad = true;
    785                     continue;
    786                 }
    787                 // Generate the pseudo-convolutions from the spatial polynomial terms
    788                 for (int jyOrder = 0, jIndex = j; jyOrder <= spatialOrder; jyOrder++) {
    789                     for (int jxOrder = 0; jxOrder <= spatialOrder - jyOrder;
    790                          jxOrder++, jIndex += numKernels) {
    791                         for (int kyOrder = 0, kIndex = k; kyOrder <= spatialOrder; kyOrder++) {
    792                             for (int kxOrder = 0; kxOrder <= spatialOrder - kyOrder;
    793                                  kxOrder++, kIndex += numKernels) {
    794                                 double convPoly = sumCC * polyValues->data.F64[jyOrder][jxOrder] *
    795                                     polyValues->data.F64[kyOrder][kxOrder]; // Temporary value
    796                                 stampMatrix->data.F64[jIndex][kIndex] = convPoly;
    797                                 stampMatrix->data.F64[kIndex][jIndex] = convPoly;
    798                             }
    799                         }
    800                     }
    801                 }
    802             }
    803 
    804             // Vector and background term for matrix
    805             double sumC = 0.0;      // Sum of the convolution
    806             double sumTC = 0.0;     // Sum of the convolution/target product
    807             for (int y = - footprint; y <= footprint; y++) {
    808                 for (int x = - footprint; x <= footprint; x++) {
    809                     double convProduct = jConv->kernel[y][x] / weight->kernel[y][x]; // Convolution / noise^2
    810                     sumC += convProduct;
    811                     sumTC += target->kernel[y][x] * convProduct;
    812                 }
    813             }
    814             if (!isfinite(sumC)) {
    815                 psStringAppend(&badString, "\nBad sumC at %d", j);
    816                 bad = true;
    817                 continue;
    818             }
    819             if (!isfinite(sumTC)) {
    820                 psStringAppend(&badString, "\nBad sumIC detected at %d", j);
    821                 bad = true;
    822                 continue;
    823             }
    824 
    825             for (int jyOrder = 0, jIndex = j; jyOrder <= spatialOrder; jyOrder++) {
    826                 for (int jxOrder = 0; jxOrder <= spatialOrder - jyOrder;
    827                      jxOrder++, jIndex += numKernels) {
    828                     stampVector->data.F64[jIndex] = sumTC * polyValues->data.F64[jyOrder][jxOrder];
    829 
    830                     double convPoly = sumC * polyValues->data.F64[jyOrder][jxOrder]; // Value
    831                     stampMatrix->data.F64[jIndex][bgIndex] = convPoly;
    832                     stampMatrix->data.F64[bgIndex][jIndex] = convPoly;
    833                 }
    834             }
    835 
    836         }
    837         psFree(polyValues);
    838 
    839         // Background only terms
    840         double sum1 = 0.0;              // Sum of the weighting
    841         double sumT = 0.0;              // Sum of the target
    842         for (int y = - footprint; y <= footprint; y++) {
    843             for (int x = - footprint; x <= footprint; x++) {
    844                 double invNoise2 = 1.0 / weight->kernel[y][x]; // Inverse noise, squared
    845                 sum1 += invNoise2;
    846                 sumT += target->kernel[y][x] * invNoise2;
    847             }
    848         }
    849         if (!isfinite(sum1)) {
    850             psStringAppend(&badString, "\nBad sum1 detected");
    851             bad = true;
    852         } else if (!isfinite(sumT)) {
    853             psStringAppend(&badString, "\nBad sumI detected");
    854             bad = true;
    855         }
    856 
    857         stampMatrix->data.F64[bgIndex][bgIndex] = sum1;
    858         stampVector->data.F64[bgIndex] = sumT;
    859 
    860         if (bad) {
    861             stamp->status = PM_SUBTRACTION_STAMP_REJECTED;
    862             psWarning("Rejecting stamp %d (%d,%d) because of bad equation:%s",
    863                       i, (int)(stamp->x + 0.5), (int)(stamp->y + 0.5), badString);
    864             psFree(badString);
    865         } else {
    866             stamp->status = PM_SUBTRACTION_STAMP_USED;
    867         }
    868 
    869         if (psTraceGetLevel("psModules.imcombine.equation") >= 10) {
    870             psString matrixName = NULL;
    871             psStringAppend(&matrixName, "matrix%d.fits", i);
    872             psFits *matrixFile = psFitsOpen(matrixName, "w");
    873             psFree(matrixName);
    874             psFitsWriteImage(matrixFile, NULL, stampMatrix, 0, NULL);
    875             psFitsClose(matrixFile);
    876         }
    877 
    878     }
    879 
    880     return true;
    881 }
    882 
    883 
    884 psVector *pmSubtractionSolveEquation(psVector *solution, const pmSubtractionStampList *stamps)
    885 {
    886     PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, NULL);
    887 
    888     // Check inputs, while summing the stamp matrices and vectors
    889     long numParams = -1;                // Number of parameters
    890     for (int i = 0; i < stamps->num; i++) {
    891         pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest
    892         PS_ASSERT_PTR_NON_NULL(stamp, NULL);
    893         if (stamp->status != PM_SUBTRACTION_STAMP_USED) {
    894             continue;
    895         }
    896         if (numParams == -1) {
    897             numParams = stamp->vector->n;
    898         } else {
    899             PS_ASSERT_VECTOR_SIZE(stamp->vector, numParams, NULL);
    900         }
    901         PS_ASSERT_VECTOR_TYPE(stamp->vector, PS_TYPE_F64, NULL);
    902         PS_ASSERT_IMAGE_TYPE(stamp->matrix, PS_TYPE_F64, NULL);
    903         PS_ASSERT_IMAGE_SIZE(stamp->matrix, numParams, numParams, NULL);
    904     }
    905     if (numParams == -1) {
    906         psError(PS_ERR_BAD_PARAMETER_VALUE, true, "No suitable stamps found.");
    907         return NULL;
    908     }
    909 
    910     if (solution) {
    911         PS_ASSERT_VECTOR_TYPE(solution, PS_TYPE_F64, NULL);
    912         PS_ASSERT_VECTOR_SIZE(solution, numParams, NULL);
    913     }
    914 
    915     // Accumulate the least-squares matricies and vectors
    916     psImage *sumMatrix = psImageAlloc(numParams, numParams, PS_TYPE_F64); // Combined matrix for all stamps
    917     psVector *sumVector = psVectorAlloc(numParams, PS_TYPE_F64); // Combined vector for all stamps
    918     psVectorInit(sumVector, 0.0);
    919     psImageInit(sumMatrix, 0.0);
    920     for (int i = 0; i < stamps->num; i++) {
    921         pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest
    922         if (stamp->status == PM_SUBTRACTION_STAMP_USED) {
    923             (void)psBinaryOp(sumMatrix, sumMatrix, "+", stamp->matrix);
    924             (void)psBinaryOp(sumVector, sumVector, "+", stamp->vector);
    925         }
    926     }
    927 
    928     psVector *permutation = NULL;       // Permutation vector, required for LU decomposition
    929     psImage *luMatrix = psMatrixLUD(NULL, &permutation, sumMatrix);
    930     psFree(sumMatrix);
    931     if (!luMatrix) {
    932         psError(PS_ERR_UNKNOWN, true, "LU Decomposition of least-squares matrix failed.\n");
    933         psFree(sumVector);
    934         psFree(luMatrix);
    935         psFree(permutation);
    936         return NULL;
    937     }
    938 
    939     solution = psMatrixLUSolve(solution, luMatrix, sumVector, permutation);
    940     psFree(sumVector);
    941     psFree(luMatrix);
    942     psFree(permutation);
    943     if (!solution) {
    944         psError(PS_ERR_UNKNOWN, true, "Failed to solve the least-squares system.\n");
    945         return NULL;
    946     }
    947 
    948     if (psTraceGetLevel("psModules.imcombine") >= 7) {
    949         for (int i = 0; i < solution->n; i++) {
    950             psTrace("psModules.imcombine", 7, "Solution %d: %f\n", i, solution->data.F64[i]);
    951         }
    952     }
    953 
    954     return solution;
    955 }
    956 
    957 psVector *pmSubtractionCalculateDeviations(pmSubtractionStampList *stamps, const psVector *solution,
    958                                            int footprint, const pmSubtractionKernels *kernels,
    959                                            pmSubtractionMode mode)
    960 {
    961     PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, NULL);
    962     PS_ASSERT_VECTOR_NON_NULL(solution, NULL);
    963     PS_ASSERT_VECTOR_TYPE(solution, PS_TYPE_F64, NULL);
    964     PS_ASSERT_PTR_NON_NULL(kernels, NULL);
    965     PS_ASSERT_VECTOR_SIZE(solution, kernels->num * polyTerms(kernels->spatialOrder) +
    966                           polyTerms(kernels->bgOrder), NULL);
    967     PS_ASSERT_VECTOR_SIZE(kernels->u, kernels->num, NULL);
    968     PS_ASSERT_VECTORS_SIZE_EQUAL(kernels->u, kernels->v, NULL);
    969 
    970     psVector *deviations = psVectorAlloc(stamps->num, PS_TYPE_F32); // Mean deviation for stamps
    971     double devNorm = 1.0 / PS_SQR(2 * footprint + 1); // Normalisation for deviations
    972     int numKernels = kernels->num;      // Number of kernels
    973     int spatialOrder = kernels->spatialOrder; // Order of kernel spatial variations
    974     float background = solution->data.F64[solution->n-1]; // The difference in background
    975 
    976     psVector *coeff = psVectorAlloc(numKernels, PS_TYPE_F64); // Coefficients for the kernel basis functions
    977 
    978     for (int i = 0; i < stamps->num; i++) {
    979         pmSubtractionStamp *stamp = stamps->stamps->data[i]; // The stamp of interest
    980         if (stamp->status != PM_SUBTRACTION_STAMP_USED) {
    981             deviations->data.F32[i] = NAN;
    982             continue;
    983         }
    984 
    985         // Calculate coefficients of the kernel basis functions
    986         psImage *polyValues = spatialPolyValues(kernels->spatialOrder,
    987                                                 stamp->xNorm, stamp->yNorm); // Polynomial terms
    988         for (int j = 0; j < numKernels; j++) {
    989             double polynomial = 0.0; // Value of the polynomial
    990             for (int yOrder = 0, index = j; yOrder <= spatialOrder; yOrder++) {
    991                 for (int xOrder = 0; xOrder <= spatialOrder - yOrder; xOrder++, index += numKernels) {
    992                     polynomial += solution->data.F64[index] * polyValues->data.F64[yOrder][xOrder];
    993                 }
    994             }
    995             coeff->data.F64[j] = polynomial;
    996         }
    997         psFree(polyValues);
    998 
    999         // Calculate residuals
    1000         psKernel *weight = stamp->weight; // Weight postage stamp
    1001         psKernel *target;               // Target postage stamp
    1002         psArray *convolutions;          // Convolution postage stamps for each kernel basis function
    1003         switch (mode) {
    1004           case PM_SUBTRACTION_MODE_TARGET:
    1005           case PM_SUBTRACTION_MODE_1:
    1006             target = stamp->image2;
    1007             convolutions = stamp->convolutions1;
    1008             break;
    1009           case PM_SUBTRACTION_MODE_2:
    1010             target = stamp->image1;
    1011             convolutions = stamp->convolutions2;
    1012             break;
    1013           default:
    1014             psAbort("Unsupported subtraction mode: %x", mode);
    1015         }
    1016 
    1017 #ifdef TESTING
    1018         psKernel *residual = psKernelAlloc(-footprint, footprint, -footprint, footprint);
    1019 #endif
    1020         float deviation = 0.0;      // Deviation for this stamp
    1021         for (int y = - footprint; y <= footprint; y++) {
    1022             for (int x = - footprint; x <= footprint; x++) {
    1023                 float conv = background; // The value of the convolution
    1024                 for (int j = 0; j < numKernels; j++) {
    1025                     psKernel *convolution = convolutions->data[j]; // Convolution
    1026                     conv += convolution->kernel[y][x] * coeff->data.F64[j];
    1027                 }
    1028                 float diff = target->kernel[y][x] - conv;
    1029                 deviation += PS_SQR(diff) / weight->kernel[y][x];
    1030 #ifdef TESTING
    1031                 residual->kernel[y][x] = diff;
    1032 #endif
    1033             }
    1034         }
    1035 
    1036         deviations->data.F32[i] = sqrtf(devNorm * deviation);
    1037         psTrace("psModules.imcombine", 5, "Deviation for stamp %d (%d,%d): %f\n",
    1038                 i, (int)(stamp->x + 0.5), (int)(stamp->y + 0.5), deviations->data.F32[i]);
    1039         if (!isfinite(deviations->data.F32[i])) {
    1040             stamp->status = PM_SUBTRACTION_STAMP_REJECTED;
    1041             psTrace("psModules.imcombine", 5,
    1042                     "Rejecting stamp %d (%d,%d) because of non-finite deviation\n",
    1043                     i, (int)(stamp->x + 0.5), (int)(stamp->y + 0.5));
    1044             continue;
    1045         }
    1046 
    1047 #ifdef TESTING
    1048         {
    1049             psString filename = NULL;
    1050             psStringAppend(&filename, "resid_%03d.fits", i);
    1051             psFits *fits = psFitsOpen(filename, "w");
    1052             psFree(filename);
    1053             psFitsWriteImage(fits, NULL, residual->image, 0, NULL);
    1054             psFitsClose(fits);
    1055         }
    1056         psFree(residual);
    1057 #endif
    1058 
    1059     }
    1060     psFree(coeff);
    1061 
    1062     return deviations;
    1063 }
    1064505
    1065506
     
    1148589}
    1149590
    1150 psImage *pmSubtractionKernelImage(const psVector *solution, const pmSubtractionKernels *kernels,
    1151                                   float x, float y
    1152                                  )
    1153 {
    1154     PS_ASSERT_VECTOR_NON_NULL(solution, NULL);
    1155     PS_ASSERT_PTR_NON_NULL(kernels, NULL);
    1156     PS_ASSERT_VECTOR_SIZE(solution, kernels->num * polyTerms(kernels->spatialOrder) +
    1157                           polyTerms(kernels->bgOrder), NULL);
     591psImage *pmSubtractionKernelImage(const pmSubtractionKernels *kernels, float x, float y, bool wantDual)
     592{
     593    PM_ASSERT_SUBTRACTION_KERNELS_NON_NULL(kernels, NULL);
     594    PM_ASSERT_SUBTRACTION_KERNELS_SOLUTION(kernels, NULL);
    1158595    PS_ASSERT_FLOAT_WITHIN_RANGE(x, -1.0, 1.0, NULL);
    1159596    PS_ASSERT_FLOAT_WITHIN_RANGE(y, -1.0, 1.0, NULL);
    1160     PS_ASSERT_VECTOR_SIZE(kernels->u, kernels->num, false);
    1161     PS_ASSERT_VECTORS_SIZE_EQUAL(kernels->u, kernels->v, NULL);
    1162597
    1163598    // Precalulate polynomial values
    1164     psImage *polyValues = spatialPolyValues(kernels->spatialOrder, x, y);
     599    psImage *polyValues = p_pmSubtractionPolynomial(NULL, kernels->spatialOrder, x, y);
    1165600
    1166601    // The appropriate kernel
    1167     psKernel *kernel = solvedKernel(NULL, solution, kernels, polyValues);
     602    psKernel *kernel = solvedKernel(NULL, kernels, polyValues, wantDual);
    1168603
    1169604    psFree(polyValues);
     
    1175610}
    1176611
    1177 psArray *pmSubtractionKernelSolutions(const psVector *solution, const pmSubtractionKernels *kernels,
    1178                                       float x, float y
    1179                                       )
    1180 {
    1181     PS_ASSERT_VECTOR_NON_NULL(solution, NULL);
    1182     PS_ASSERT_PTR_NON_NULL(kernels, NULL);
    1183     PS_ASSERT_VECTOR_SIZE(solution, kernels->num * polyTerms(kernels->spatialOrder) +
    1184                           polyTerms(kernels->bgOrder), NULL);
     612#if 0
     613psArray *pmSubtractionKernelSolutions(const pmSubtractionKernels *kernels, float x, float y, bool wantDual)
     614{
     615    PM_ASSERT_SUBTRACTION_KERNELS_NON_NULL(kernels, NULL);
     616    PM_ASSERT_SUBTRACTION_KERNELS_SOLUTION(kernels, NULL);
    1185617    PS_ASSERT_FLOAT_WITHIN_RANGE(x, -1.0, 1.0, NULL);
    1186618    PS_ASSERT_FLOAT_WITHIN_RANGE(y, -1.0, 1.0, NULL);
    1187     PS_ASSERT_VECTOR_SIZE(kernels->u, kernels->num, false);
    1188     PS_ASSERT_VECTORS_SIZE_EQUAL(kernels->u, kernels->v, NULL);
    1189619
    1190620    psArray *images = psArrayAlloc(solution->n - 1); // Images of each kernel to return
     
    1194624    for (int i = 0; i < solution->n - 1; i++) {
    1195625        fakeSolution->data.F64[i] = solution->data.F64[i];
    1196         images->data[i] = pmSubtractionKernelImage(fakeSolution, kernels, x, y);
     626        images->data[i] = pmSubtractionKernelImage(kernels, x, y, wantDual);
    1197627        fakeSolution->data.F64[i] = 0.0;
    1198628    }
     
    1202632    return images;
    1203633}
    1204 
    1205 bool pmSubtractionConvolve(pmReadout *out, const pmReadout *ro1, const pmReadout *ro2,
     634#endif
     635
     636
     637
     638bool pmSubtractionConvolve(pmReadout *out1, pmReadout *out2, const pmReadout *ro1, const pmReadout *ro2,
    1206639                           const psImage *subMask, psMaskType blank, const psRegion *region,
    1207                            const psVector *solution, const pmSubtractionKernels *kernels,
    1208                            pmSubtractionMode mode, bool useFFT)
    1209 {
    1210     PS_ASSERT_PTR_NON_NULL(out, false);
     640                           const pmSubtractionKernels *kernels, bool useFFT)
     641{
     642    PS_ASSERT_PTR_NON_NULL(out1, false);
    1211643    PS_ASSERT_PTR_NON_NULL(ro1, false);
    1212644    PS_ASSERT_IMAGE_NON_NULL(ro1->image, false);
     
    1217649        PS_ASSERT_IMAGES_SIZE_EQUAL(ro1->weight, ro1->image, false);
    1218650    }
    1219     if (mode != PM_SUBTRACTION_MODE_1) {
     651    PM_ASSERT_SUBTRACTION_KERNELS_NON_NULL(kernels, false);
     652    PM_ASSERT_SUBTRACTION_KERNELS_SOLUTION(kernels, false);
     653    if (kernels->mode != PM_SUBTRACTION_MODE_1) {
     654        PS_ASSERT_PTR_NON_NULL(out2, false);
    1220655        PS_ASSERT_PTR_NON_NULL(ro2, false);
    1221656        PS_ASSERT_IMAGE_NON_NULL(ro2->image, false);
     
    1232667        PS_ASSERT_IMAGES_SIZE_EQUAL(subMask, ro1->image, false);
    1233668    }
    1234     if (out->image) {
    1235         PS_ASSERT_IMAGE_NON_NULL(out->image, false);
    1236         PS_ASSERT_IMAGES_SIZE_EQUAL(out->image, ro1->image, false);
    1237         PS_ASSERT_IMAGE_TYPE(out->image, PS_TYPE_F32, false);
    1238     }
    1239     if (out->mask) {
    1240         PS_ASSERT_IMAGE_NON_NULL(out->mask, false);
    1241         PS_ASSERT_IMAGES_SIZE_EQUAL(out->mask, ro1->image, false);
    1242         PS_ASSERT_IMAGE_TYPE(out->mask, PS_TYPE_MASK, false);
     669    if (out1->image) {
     670        PS_ASSERT_IMAGE_NON_NULL(out1->image, false);
     671        PS_ASSERT_IMAGES_SIZE_EQUAL(out1->image, ro1->image, false);
     672        PS_ASSERT_IMAGE_TYPE(out1->image, PS_TYPE_F32, false);
     673    }
     674    if (out1->mask) {
     675        PS_ASSERT_IMAGE_NON_NULL(out1->mask, false);
     676        PS_ASSERT_IMAGES_SIZE_EQUAL(out1->mask, ro1->image, false);
     677        PS_ASSERT_IMAGE_TYPE(out1->mask, PS_TYPE_MASK, false);
    1243678        PS_ASSERT_IMAGE_NON_NULL(subMask, false);
    1244679    }
    1245     if (out->weight) {
    1246         PS_ASSERT_IMAGE_NON_NULL(out->weight, false);
    1247         PS_ASSERT_IMAGES_SIZE_EQUAL(out->weight, ro1->image, false);
    1248         PS_ASSERT_IMAGE_TYPE(out->weight, PS_TYPE_F32, false);
    1249     }
    1250     PS_ASSERT_VECTOR_NON_NULL(solution, false);
    1251     PS_ASSERT_VECTOR_TYPE(solution, PS_TYPE_F64, false);
    1252     PS_ASSERT_PTR_NON_NULL(kernels, false);
    1253     PS_ASSERT_VECTOR_SIZE(solution, kernels->num * polyTerms(kernels->spatialOrder) +
    1254                           polyTerms(kernels->bgOrder), -1);
    1255     PS_ASSERT_VECTOR_SIZE(kernels->u, kernels->num, false);
    1256     PS_ASSERT_VECTORS_SIZE_EQUAL(kernels->u, kernels->v, false);
     680    if (out1->weight) {
     681        PS_ASSERT_IMAGE_NON_NULL(out1->weight, false);
     682        PS_ASSERT_IMAGES_SIZE_EQUAL(out1->weight, ro1->image, false);
     683        PS_ASSERT_IMAGE_TYPE(out1->weight, PS_TYPE_F32, false);
     684    }
    1257685    if (region) {
    1258686        if (psRegionIsNaN(*region)) {
     
    1273701
    1274702    psImage *image, *weight;            // Image and weight map to convolve
    1275     switch (mode) {
     703    switch (kernels->mode) {
    1276704      case PM_SUBTRACTION_MODE_TARGET:
    1277705      case PM_SUBTRACTION_MODE_1:
     706      case PM_SUBTRACTION_MODE_DUAL:
    1278707        image = ro1->image;
    1279708        weight = ro1->weight;
     
    1281710      case PM_SUBTRACTION_MODE_2:
    1282711        image = ro2->image;
    1283         weight = ro2->image;
     712        weight = ro2->weight;
    1284713        break;
    1285714      default:
    1286         psAbort("Unsupported subtraction mode: %x", mode);
    1287     }
    1288 
    1289     int numBackground = polyTerms(kernels->bgOrder); // Number of background terms
    1290     float background = solution->data.F64[solution->n - numBackground]; // The difference in background
     715        psAbort("Unsupported subtraction mode: %x", kernels->mode);
     716    }
     717
    1291718    int numCols = ro1->image->numCols, numRows = ro1->image->numRows; // Image dimensions
    1292719
    1293     psImage *convImage = out->image;   // Convolved image
    1294     if (!convImage) {
    1295         out->image = psImageAlloc(numCols, numRows, PS_TYPE_F32);
    1296         convImage = out->image;
     720    psImage *convImage1 = out1->image;   // Convolved image
     721    if (!convImage1) {
     722        convImage1 = out1->image = psImageAlloc(numCols, numRows, PS_TYPE_F32);
    1297723    }
    1298724    psImage *convMask = NULL;           // Convolved mask image
    1299725    if (subMask) {
    1300         if (!out->mask) {
    1301             out->mask = psImageAlloc(numCols, numRows, PS_TYPE_MASK);
    1302         }
    1303         convMask = out->mask;
     726        if (!out1->mask) {
     727            out1->mask = psImageAlloc(numCols, numRows, PS_TYPE_MASK);
     728        }
     729        convMask = out1->mask;
    1304730        psImageInit(convMask, 0);
    1305731    }
    1306     psImage *convWeight = NULL;         // Convolved weight (variance) image
     732    psImage *convWeight1 = NULL;         // Convolved weight (variance) image
    1307733    if (weight) {
    1308         if (!out->weight) {
    1309             out->weight = psImageAlloc(numCols, numRows, PS_TYPE_F32);
    1310         }
    1311         convWeight = out->weight;
    1312         psImageInit(convWeight, 0.0);
     734        if (!out1->weight) {
     735            out1->weight = psImageAlloc(numCols, numRows, PS_TYPE_F32);
     736        }
     737        convWeight1 = out1->weight;
     738        psImageInit(convWeight1, 0.0);
     739    }
     740
     741    psImage *convImage2, *convWeight2;   // Convolved products for dual mode
     742    if (kernels->mode == PM_SUBTRACTION_MODE_DUAL) {
     743        convImage2 = out2->image;
     744        if (!convImage2) {
     745            convImage2 = out2->image = psImageAlloc(numCols, numRows, PS_TYPE_F32);
     746        }
     747        convWeight2 = NULL;         // Convolved weight (variance) image
     748        if (ro2->weight) {
     749            if (!out2->weight) {
     750                out2->weight = psImageAlloc(numCols, numRows, PS_TYPE_F32);
     751            }
     752            convWeight2 = out2->weight;
     753            psImageInit(convWeight2, 0.0);
     754        }
     755        if (subMask) {
     756            // Copying mask --- they're the same!
     757            psFree(out2->mask);
     758            out2->mask = psMemIncrRefCounter(convMask);
     759        }
    1313760    }
    1314761
    1315762    int size = kernels->size;           // Half-size of kernel
    1316763    int fullSize = 2 * size + 1;        // Full size of kernel
    1317     psImage *polyValues = NULL;         // Pre-calculated polynomial values
    1318 
    1319     psKernel *kernelImage = NULL;       // Kernel for the image
    1320     psKernel *kernelWeight = NULL;      // Kernel for the weight map
    1321764
    1322765    // Get region for convolution: [xMin:xMax,yMin:yMax]
     
    1330773    }
    1331774
    1332     psMaskType maskSource, maskTarget;  // Mask values for source and target
    1333     switch (mode) {
     775    psMaskType maskSource;              // Mask these pixels when convolving
     776    psMaskType maskTarget;              // Mark these pixels as bad when propagating the subtractionMask
     777    switch (kernels->mode) {
    1334778      case PM_SUBTRACTION_MODE_TARGET:
    1335779      case PM_SUBTRACTION_MODE_1:
     
    1341785        maskTarget = PM_SUBTRACTION_MASK_BAD_1 | PM_SUBTRACTION_MASK_CONVOLVE_2;
    1342786        break;
     787      case PM_SUBTRACTION_MODE_DUAL:
     788        maskSource = PM_SUBTRACTION_MASK_BAD_1 | PM_SUBTRACTION_MASK_BAD_2;
     789        maskTarget = PM_SUBTRACTION_MASK_CONVOLVE_1 | PM_SUBTRACTION_MASK_CONVOLVE_2;
     790        break;
    1343791      default:
    1344         psAbort("Unsupported subtraction mode: %x", mode);
    1345     }
     792        psAbort("Unsupported subtraction mode: %x", kernels->mode);
     793    }
     794
     795    psImage *polyValues = NULL;         // Pre-calculated polynomial values
     796    psKernel *kernelImage = NULL;       // Kernel for the images
     797    psKernel *kernelWeight = NULL;      // Kernel for the weight maps
    1346798
    1347799    for (int j = yMin; j < yMax; j += fullSize) {
    1348800        int ySubMax = PS_MIN(j + fullSize, yMax); // Range for subregion of interest
     801        float yNorm = 2.0 * (float)(j + size + 1 - numRows/2.0) / (float)numRows; // Normalised coordinate
    1349802        for (int i = xMin; i < xMax; i += fullSize) {
    1350803            int xSubMax = PS_MIN(i + fullSize, xMax); // Range for subregion of interest
     804            float xNorm = 2.0 * (float)(i + size + 1 - numCols/2.0) / (float)numCols; // Normalised coordinate
    1351805
    1352806            // Only generate polynomial values every kernel footprint, since we have already assumed
    1353807            // (with the stamps) that it does not vary rapidly on this scale.
    1354             psFree(polyValues);
    1355             polyValues = spatialPolyValues(kernels->spatialOrder,
    1356                                            2.0 * (float)(i + size + 1 - numCols/2.0) / (float)numCols,
    1357                                            2.0 * (float)(j + size + 1 - numRows/2.0) / (float)numRows);
    1358 
    1359             kernelImage = solvedKernel(kernelImage, solution, kernels, polyValues);
    1360             if (weight) {
    1361                 kernelWeight = varianceKernel(kernelWeight, kernelImage);
    1362             }
     808            polyValues = p_pmSubtractionPolynomial(polyValues, kernels->spatialOrder, xNorm, yNorm);
     809            float background = p_pmSubtractionSolutionBackground(kernels, polyValues); // Background term
    1363810
    1364811            psRegion subRegion = psRegionSet(i, xSubMax, j, ySubMax); // Sub-region to convolve
    1365             if (useFFT) {
    1366                 // Use Fast Fourier Transform to do the convolution
    1367                 // This provides a big speed-up for large kernels
    1368                 convolveFFT(convImage, image, subMask, maskSource, kernelImage, subRegion,
    1369                             background, size);
    1370                 if (weight) {
    1371                     convolveFFT(convWeight, weight, subMask, maskSource, kernelWeight, subRegion,
    1372                                 0.0, size);
    1373                 }
    1374             } else {
    1375                 convolveDirect(convImage, image, kernelImage, subRegion, background, size);
    1376                 if (weight) {
    1377                     convolveDirect(convWeight, weight, kernelWeight, subRegion, 0.0, size);
    1378                 }
     812
     813            convolveRegion(convImage1, convWeight1, &kernelImage, &kernelWeight, image, weight,
     814                           subMask, maskSource, kernels, polyValues, background, subRegion, useFFT);
     815
     816            if (kernels->mode == PM_SUBTRACTION_MODE_DUAL) {
     817                convolveRegion(convImage2, convWeight2, &kernelImage, &kernelWeight, ro2->image, ro2->weight,
     818                               subMask, maskSource, kernels, polyValues, background, subRegion, useFFT);
    1379819            }
    1380820
     
    1385825                        if (subMask->data.PS_TYPE_MASK_DATA[y][x] & maskTarget) {
    1386826                            convMask->data.PS_TYPE_MASK_DATA[y][x] |= blank;
    1387                             convImage->data.F32[y][x] = NAN;
     827                            convImage1->data.F32[y][x] = NAN;
    1388828                            if (weight) {
    1389                                 convWeight->data.F32[y][x] = NAN;
     829                                convWeight1->data.F32[y][x] = NAN;
    1390830                            }
    1391831                        }
     
    1402842    return true;
    1403843}
    1404 
    1405 bool pmSubtractionBorder(psImage *image, psImage *weight, psImage *mask,
    1406                          int size, psMaskType blank)
    1407 {
    1408     PS_ASSERT_IMAGE_NON_NULL(image, false);
    1409     PS_ASSERT_IMAGE_TYPE(image, PS_TYPE_F32, false);
    1410     if (mask) {
    1411         PS_ASSERT_IMAGE_NON_NULL(mask, false);
    1412         PS_ASSERT_IMAGES_SIZE_EQUAL(mask, image, false);
    1413         PS_ASSERT_IMAGE_TYPE(mask, PS_TYPE_MASK, false);
    1414     }
    1415     if (weight) {
    1416         PS_ASSERT_IMAGE_NON_NULL(weight, false);
    1417         PS_ASSERT_IMAGES_SIZE_EQUAL(weight, image, false);
    1418         PS_ASSERT_IMAGE_TYPE(weight, PS_TYPE_F32, false);
    1419     }
    1420 
    1421     int numCols = image->numCols, numRows = image->numRows; // Image dimensions
    1422 
    1423     for (int y = size; y < numRows - size; y++) {
    1424         for (int x = 0; x < size; x++) {
    1425             markBlank(image, mask, weight, x, y, blank);
    1426         }
    1427         for (int x = numCols - size; x < numCols; x++) {
    1428             markBlank(image, mask, weight, x, y, blank);
    1429         }
    1430     }
    1431     for (int y = 0; y < size; y++) {
    1432         for (int x = 0; x < numCols; x++) {
    1433             markBlank(image, mask, weight, x, y, blank);
    1434         }
    1435     }
    1436     for (int y = numRows - size; y < numRows; y++) {
    1437         for (int x = 0; x < numCols; x++) {
    1438             markBlank(image, mask, weight, x, y, blank);
    1439         }
    1440     }
    1441 
    1442     return true;
    1443 }
    1444 
    1445 
  • trunk/psModules/src/imcombine/pmSubtraction.h

    r15562 r15756  
    66 * @author GLG, MHPCC
    77 *
    8  * @version $Revision: 1.21 $ $Name: not supported by cvs2svn $
    9  * @date $Date: 2007-11-10 01:09:20 $
     8 * @version $Revision: 1.22 $ $Name: not supported by cvs2svn $
     9 * @date $Date: 2007-12-07 01:57:15 $
    1010 * Copyright 2004-207 Institute for Astronomy, University of Hawaii
    1111 */
     
    3737} pmSubtractionMasks;
    3838
    39 /// Generate a mask for use in the subtraction process
    40 psImage *pmSubtractionMask(const psImage *refMask, ///< Mask for the reference image (will be convolved)
    41                            const psImage *inMask, ///< Mask for the input image, or NULL
    42                            psMaskType maskVal, ///< Value to mask out
    43                            int size, ///< Half-size of the kernel (pmSubtractionKernels.size)
    44                            int footprint, ///< Half-size of the kernel footprint
    45                            float badFrac, ///< Maximum fraction of bad input pixels to accept
    46                            bool useFFT  ///< Use FFT to do convolution?
    47     );
     39
     40/// Number of terms in a polynomial
     41#define PM_SUBTRACTION_POLYTERMS(ORDER) (((ORDER) + 1) * ((ORDER) + 2) / 2)
     42
     43/// Set the indices for the normalisation and background terms
     44#define PM_SUBTRACTION_INDICES(NORM,BG,KERNELS) { \
     45    int numSpatial = PM_SUBTRACTION_POLYTERMS((KERNELS)->spatialOrder); /* Number of spatial terms */ \
     46    NORM = (KERNELS)->num * numSpatial; \
     47    BG = NORM + 1; \
     48}
     49
     50/// Return the index for the start of the normalisation terms
     51#define PM_SUBTRACTION_INDEX_NORM(KERNELS) \
     52    ((KERNELS)->num * PM_SUBTRACTION_POLYTERMS((KERNELS)->spatialOrder))
     53
     54/// Return the index for the start of the background terms
     55#define PM_SUBTRACTION_INDEX_BG(KERNELS) \
     56    (((KERNELS)->num * PM_SUBTRACTION_POLYTERMS((KERNELS)->spatialOrder)) + 1)
     57
    4858
    4959/// Convolve the reference stamp with the kernel components
    5060bool pmSubtractionConvolveStamp(pmSubtractionStamp *stamp, ///< Stamp to convolve
    5161                                const pmSubtractionKernels *kernels, ///< Kernel parameters
    52                                 int footprint, ///< Half-size of region over which to calculate equation
    53                                 pmSubtractionMode mode ///< Mode for subtraction (which to convolve)
    54     );
    55 
    56 /// Calculate the least-squares equation to match the image quality
    57 bool pmSubtractionCalculateEquation(pmSubtractionStampList *stamps, ///< Stamps
    58                                     const pmSubtractionKernels *kernels, ///< Kernel parameters
    59                                     int footprint, ///< Half-size of region over which to calculate equation
    60                                     pmSubtractionMode mode ///< Mode for subtraction (which to convolve)
    61                                     );
    62 
    63 /// Solve the least-squares equation to match the image quality
    64 psVector *pmSubtractionSolveEquation(psVector *solution, ///< Solution vector, or NULL
    65                                      const pmSubtractionStampList *stamps ///< Stamps
    66                                      );
    67 
    68 /// Calculate deviations
    69 psVector *pmSubtractionCalculateDeviations(pmSubtractionStampList *stamps, ///< Stamps
    70                                            const psVector *solution, ///< Solution vector
    71                                            int footprint, ///< Half-size of stamp
    72                                            const pmSubtractionKernels *kernels, ///< Kernel parameters
    73                                            pmSubtractionMode mode ///< Mode for subtraction
     62                                int footprint ///< Half-size of region over which to calculate equation
    7463    );
    7564
     
    8372
    8473/// Generate an image of the convolution kernel
    85 psImage *pmSubtractionKernelImage(const psVector *solution, ///< Solution vector
    86                                   const pmSubtractionKernels *kernels, ///< Kernel parameters
    87                                   float x, float y ///< Normalised position [-1,1] for which to generate image
     74psImage *pmSubtractionKernelImage(const pmSubtractionKernels *kernels, ///< Kernel parameters
     75                                  float x, float y,///< Normalised position [-1,1] for which to generate image
     76                                  bool wantDual ///< Calculate for the dual kernel?
    8877                                  );
    8978
     
    9584
    9685/// Convolve image in preparation for subtraction
    97 bool pmSubtractionConvolve(pmReadout *out, ///< Output image
     86bool pmSubtractionConvolve(pmReadout *out1, ///< Output image 1
     87                           pmReadout *out2, ///< Output image 2 (DUAL mode only)
    9888                           const pmReadout *ro1, // Input image 1
    9989                           const pmReadout *ro2, // Input image 2
     
    10191                           psMaskType blank, ///< Mask value for blank regions
    10292                           const psRegion *region, ///< Region to convolve (or NULL)
    103                            const psVector *solution, ///< The solution vector
    10493                           const pmSubtractionKernels *kernels, ///< Kernel parameters
    105                            pmSubtractionMode mode, ///< Mode for subtraction
    10694                           bool useFFT  ///< Use Fast Fourier Transform for the convolution?
    107     );
    108 
    109 /// Mark the non-convolved part of the image as blank
    110 bool pmSubtractionBorder(psImage *image,///< Image
    111                          psImage *weight, ///< Weight map (or NULL)
    112                          psImage *mask, ///< Mask (or NULL)
    113                          int size,      ///< Kernel half-size
    114                          psMaskType blank ///< Mask value for blank regions
    11595    );
    11696
     
    122102    );
    123103
     104/// Given (normalised) coordinates (x,y), generate a matrix where the elements (i,j) are x^i * y^j
     105psImage *p_pmSubtractionPolynomial(psImage *output, ///< Output matrix, or NULL
     106                                   int spatialOrder, ///< Maximum spatial polynomial order
     107                                   float x, float y ///< Normalised position of interest, [-1,1]
     108    );
     109
    124110/// @}
    125111#endif
  • trunk/psModules/src/imcombine/pmSubtractionKernels.c

    r15432 r15756  
    44
    55#include <stdio.h>
     6#include <string.h>
    67#include <strings.h>
    78#include <pslib.h>
    89
     10#include "pmSubtraction.h"
    911#include "pmSubtractionKernels.h"
    1012
     
    2224    psFree(kernels->vStop);
    2325    psFree(kernels->preCalc);
    24 }
    25 
    26 // Raise a number to an integer power
     26    psFree(kernels->solution1);
     27    psFree(kernels->solution2);
     28}
     29
     30// Raise an integer to an integer power
    2731static inline long power(int value,     // Value
    2832                         int exp        // Exponent
     
    4549bool p_pmSubtractionKernelsAddGrid(pmSubtractionKernels *kernels, int start, int size)
    4650{
    47     PS_ASSERT_PTR_NON_NULL(kernels, false);
    48     PS_ASSERT_VECTOR_NON_NULL(kernels->u, false);
    49     PS_ASSERT_VECTOR_NON_NULL(kernels->v, false);
    50     PS_ASSERT_VECTOR_NON_NULL(kernels->widths, false);
    51     PS_ASSERT_VECTOR_TYPE(kernels->u, PS_TYPE_S32, false);
    52     PS_ASSERT_VECTOR_TYPE(kernels->v, PS_TYPE_S32, false);
    53     PS_ASSERT_VECTOR_TYPE(kernels->widths, PS_TYPE_F32, false);
    54     PS_ASSERT_ARRAY_NON_NULL(kernels->preCalc, false);
     51    PM_ASSERT_SUBTRACTION_KERNELS_NON_NULL(kernels, false);
    5552    PS_ASSERT_INT_NONNEGATIVE(start, false);
    5653    PS_ASSERT_INT_NONNEGATIVE(size, false);
    5754
    58     int numNew = PS_SQR(2 * size + 1);  // Number of new kernel parameters to add
     55    int numNew = PS_SQR(2 * size + 1) - 1;  // Number of new kernel parameters to add
    5956
    6057    // Ensure the sizes match
     
    6865    for (int v = - size, index = start; v <= size; v++) {
    6966        for (int u = - size; u <= size; u++, index++) {
     67            if (v == 0 && u == 0) {
     68                // Skip normalisation component: added explicitly
     69                index--;
     70                continue;
     71            }
    7072            kernels->widths->data.F32[index] = NAN;
    7173            kernels->u->data.S32[index] = u;
     
    8183
    8284pmSubtractionKernels *p_pmSubtractionKernelsRawISIS(int size, int spatialOrder,
    83                                                   const psVector *fwhms, const psVector *orders)
     85                                                    const psVector *fwhms, const psVector *orders,
     86                                                    pmSubtractionMode mode)
    8487{
    8588    PS_ASSERT_VECTOR_NON_NULL(fwhms, NULL);
     
    97100    for (int i = 0; i < numGaussians; i++) {
    98101        int gaussOrder = orders->data.S32[i]; // Polynomial order to apply to Gaussian
    99         psStringAppend(&params, "(%.2f,%d)", fwhms->data.F32[i], orders->data.S32[i]);
     102        psStringAppend(&params, "(%.1f,%d)", fwhms->data.F32[i], orders->data.S32[i]);
    100103        num += (gaussOrder + 1) * (gaussOrder + 2) / 2;
    101104    }
    102105
    103106    pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_ISIS,
    104                                                               size, spatialOrder); // The kernels
     107                                                              size, spatialOrder, mode); // The kernels
    105108    psStringAppend(&kernels->description, "ISIS(%d,%s,%d)", size, params, spatialOrder);
    106109
     
    149152    }
    150153
    151     kernels->subIndex = -1;
    152 
    153154    return kernels;
    154155}
     
    159160
    160161pmSubtractionKernels *pmSubtractionKernelsAlloc(int numBasisFunctions, pmSubtractionKernelsType type,
    161                                                 int size, int spatialOrder)
     162                                                int size, int spatialOrder, pmSubtractionMode mode)
    162163{
    163164    pmSubtractionKernels *kernels = psAlloc(sizeof(pmSubtractionKernels)); // Kernels, to return
     
    173174    kernels->uStop = NULL;
    174175    kernels->vStop = NULL;
    175     kernels->subIndex = 0;
    176176    kernels->size = size;
    177177    kernels->inner = 0;
    178178    kernels->spatialOrder = spatialOrder;
    179179    kernels->bgOrder = 0;
    180 
    181     return kernels;
    182 }
    183 
    184 pmSubtractionKernels *pmSubtractionKernelsPOIS(int size, int spatialOrder)
     180    kernels->mode = mode;
     181    kernels->solution1 = NULL;
     182    kernels->solution2 = NULL;
     183
     184    return kernels;
     185}
     186
     187pmSubtractionKernels *pmSubtractionKernelsPOIS(int size, int spatialOrder, pmSubtractionMode mode)
    185188{
    186189    PS_ASSERT_INT_POSITIVE(size, NULL);
    187190    PS_ASSERT_INT_NONNEGATIVE(spatialOrder, NULL);
    188191
    189     int num = PS_SQR(2 * size + 1); // Number of basis functions
     192    int num = PS_SQR(2 * size + 1) - 1; // Number of basis functions
    190193
    191194    pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_POIS,
    192                                                               size, spatialOrder); // The kernels
     195                                                              size, spatialOrder, mode); // The kernels
    193196    psStringAppend(&kernels->description, "POIS(%d,%d)", size, spatialOrder);
    194197    psLogMsg("psModules.imcombine", PS_LOG_INFO, "POIS kernel: %d,%d --> %d elements",
     
    199202    }
    200203
    201     kernels->subIndex = num / 2;
    202     assert(kernels->u->data.S32[kernels->subIndex] == 0 &&
    203            kernels->v->data.S32[kernels->subIndex] == 0);
    204 
    205204    return kernels;
    206205}
     
    208207
    209208pmSubtractionKernels *pmSubtractionKernelsISIS(int size, int spatialOrder,
    210                                                const psVector *fwhms, const psVector *orders)
     209                                               const psVector *fwhms, const psVector *orders,
     210                                               pmSubtractionMode mode)
    211211{
    212212    pmSubtractionKernels *kernels = p_pmSubtractionKernelsRawISIS(size, spatialOrder,
    213                                                                   fwhms, orders); // Kernels
     213                                                                  fwhms, orders, mode); // Kernels
    214214    if (!kernels) {
    215215        return NULL;
    216216    }
    217217
    218     // Subtract a reference kernel from all the others to maintain flux scaling
     218    // Subtract normalisation from all the others to maintain flux scaling
    219219    if (spatialOrder > 0) {
    220         int subIndex = 0;                   // Index of kernel to subtract from others
    221         psKernel *subtract = kernels->preCalc->data[subIndex]; // Kernel to subtract from others
    222220        int numGaussians = fwhms->n;       // Number of Gaussians
    223221        for (int i = 0, index = 0; i < numGaussians; i++) {
    224222            for (int uOrder = 0; uOrder <= orders->data.S32[i]; uOrder++) {
    225223                for (int vOrder = 0; vOrder <= orders->data.S32[i] - uOrder; vOrder++, index++) {
    226                     if (uOrder % 2 == 0 && vOrder % 2 == 0 && index != subIndex) {
     224                    if (uOrder % 2 == 0 && vOrder % 2 == 0) {
    227225                        psKernel *kernel = kernels->preCalc->data[index]; // Kernel to subtract
    228                         psBinaryOp(kernel->image, kernel->image, "-", subtract->image);
     226                        kernel->kernel[0][0] -= 1.0;
    229227                    }
    230228                }
     
    242240            psFitsWriteImage(kernelFile, NULL, kernel->image, 0, NULL);
    243241            psFitsClose(kernelFile);
    244         }
    245     }
    246 
    247     return kernels;
    248 }
    249 
    250 /// Generate SPAM kernels
    251 pmSubtractionKernels *pmSubtractionKernelsSPAM(int size, ///< Half-size of the kernel
    252                                                int spatialOrder, ///< Order of spatial variations
    253                                                int inner, ///< Inner radius to preserve unbinned
    254                                                int binning ///< Kernel binning factor
    255     )
     242            double sum = 0.0;
     243            for (int y = 0; y < kernel->image->numRows; y++) {
     244                for (int x = 0; x < kernel->image->numCols; x++) {
     245                    sum += kernel->image->data.F32[y][x];
     246                }
     247            }
     248            psTrace("psModules.imcombine.kernel", 10, "Kernel %d sum: %lf\n", i, sum);
     249        }
     250    }
     251
     252    return kernels;
     253}
     254
     255pmSubtractionKernels *pmSubtractionKernelsSPAM(int size, int spatialOrder, int inner, int binning,
     256                                               pmSubtractionMode mode)
    256257{
    257258    PS_ASSERT_INT_POSITIVE(size, NULL);
     
    269270    psTrace("psModules.imcombine", 3, "Inner: %d Outer: %d\n", numInner, numOuter);
    270271
    271     int num = PS_SQR(2 * numTotal + 1); // Number of basis functions
     272    int num = PS_SQR(2 * numTotal + 1) - 1; // Number of basis functions
    272273
    273274    psTrace("psModules.imcombine", 3, "Number of basis functions: %d\n", num);
    274275
    275276    pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_SPAM,
    276                                                               size, spatialOrder); // The kernels
     277                                                              size, spatialOrder, mode); // The kernels
    277278    psStringAppend(&kernels->description, "SPAM(%d,%d,%d,%d)", size, inner, binning, spatialOrder);
    278279
     
    280281             size, inner, binning, spatialOrder, num);
    281282
    282     kernels->uStop = psVectorAlloc(num, PS_TYPE_F32);
    283     kernels->vStop = psVectorAlloc(num, PS_TYPE_F32);
     283    kernels->uStop = psVectorAlloc(num, PS_TYPE_S32);
     284    kernels->vStop = psVectorAlloc(num, PS_TYPE_S32);
    284285
    285286    psVector *locations = psVectorAlloc(2 * numTotal + 1, PS_TYPE_S32); // Locations for each kernel element
     
    314315
    315316        for (int j = - numTotal; j <= numTotal; j++, index++) {
     317            if (i == 0 && j == 0) {
     318                // Skip normalisation component: added explicitly
     319                index--;
     320                continue;
     321            }
    316322            int v = locations->data.S32[numTotal + j]; // Location of pixel
    317323            int vStop = v + widths->data.S32[numTotal + j]; // Width of pixel
     
    327333    }
    328334
    329     kernels->subIndex = num / 2;
    330     assert(kernels->u->data.S32[kernels->subIndex] == 0 &&
    331            kernels->v->data.S32[kernels->subIndex] == 0 &&
    332            kernels->uStop->data.S32[kernels->subIndex] == 0 &&
    333            kernels->vStop->data.S32[kernels->subIndex] == 0);
    334 
    335335    psFree(locations);
    336336    psFree(widths);
     
    340340
    341341
    342 /// Generate FRIES kernels
    343 pmSubtractionKernels *pmSubtractionKernelsFRIES(int size, ///< Half-size of the kernel
    344                                                 int spatialOrder, ///< Order of spatial variations
    345                                                 int inner ///< Inner radius to preserve unbinned
    346     )
     342pmSubtractionKernels *pmSubtractionKernelsFRIES(int size, int spatialOrder, int inner, pmSubtractionMode mode)
    347343{
    348344    PS_ASSERT_INT_POSITIVE(size, NULL);
     
    366362    psTrace("psModules.imcombine", 3, "Inner: %d Outer: %d\n", numInner, numOuter);
    367363
    368     int num = PS_SQR(2 * numTotal + 1); // Number of basis functions
     364    int num = PS_SQR(2 * numTotal + 1) - 1; // Number of basis functions
    369365
    370366    psTrace("psModules.imcombine", 3, "Number of basis functions: %d\n", num);
    371367
    372368    pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_FRIES,
    373                                                               size, spatialOrder); // The kernels
     369                                                              size, spatialOrder, mode); // The kernels
    374370    psStringAppend(&kernels->description, "FRIES(%d,%d,%d)", size, inner, spatialOrder);
    375371
     
    377373             size, inner, spatialOrder, num);
    378374
    379     kernels->uStop = psVectorAlloc(num, PS_TYPE_F32);
    380     kernels->vStop = psVectorAlloc(num, PS_TYPE_F32);
     375    kernels->uStop = psVectorAlloc(num, PS_TYPE_S32);
     376    kernels->vStop = psVectorAlloc(num, PS_TYPE_S32);
    381377
    382378    psVector *start = psVectorAlloc(2 * numTotal + 1, PS_TYPE_S32);
     
    409405        int uStop = stop->data.S32[numTotal + i]; // Width of pixel
    410406        for (int j = - numTotal; j <= numTotal; j++, index++) {
     407            if (i == 0 && j == 0) {
     408                // Skip normalisation component: added explicitly
     409                index--;
     410                continue;
     411            }
    411412            int v = start->data.S32[numTotal + j]; // Location of pixel
    412413            int vStop = stop->data.S32[numTotal + j]; // Width of pixel
     
    422423    }
    423424
    424     kernels->subIndex = num / 2;
    425     assert(kernels->u->data.S32[kernels->subIndex] == 0 &&
    426            kernels->v->data.S32[kernels->subIndex] == 0 &&
    427            kernels->uStop->data.S32[kernels->subIndex] == 0 &&
    428            kernels->vStop->data.S32[kernels->subIndex] == 0);
    429 
    430425    psFree(start);
    431426    psFree(stop);
     
    436431// Grid United with Normal Kernel
    437432pmSubtractionKernels *pmSubtractionKernelsGUNK(int size, int spatialOrder, const psVector *fwhms,
    438                                                const psVector *orders, int inner)
     433                                               const psVector *orders, int inner, pmSubtractionMode mode)
    439434{
    440435    PS_ASSERT_INT_POSITIVE(size, NULL);
     
    449444
    450445    pmSubtractionKernels *kernels = p_pmSubtractionKernelsRawISIS(size, spatialOrder,
    451                                                                   fwhms, orders); // Kernels
     446                                                                  fwhms, orders, mode); // Kernels
    452447    psStringPrepend(&kernels->description, "GUNK=");
    453448    psStringAppend(&kernels->description, "+POIS(%d,%d)", inner, spatialOrder);
     
    469464
    470465    int numISIS = kernels->num;         // Number of ISIS kernels
    471     int numInner = PS_SQR(2 * inner + 1); // Number of inner kernel elements
    472466
    473467    if (!p_pmSubtractionKernelsAddGrid(kernels, numISIS, inner)) {
     
    475469    }
    476470
    477     kernels->subIndex = numInner/2 + numISIS;
    478     assert(kernels->u->data.S32[kernels->subIndex] == 0 &&
    479            kernels->v->data.S32[kernels->subIndex] == 0);
    480 
    481471    return kernels;
    482472}
    483473
    484474// RINGS --- just what it says
    485 pmSubtractionKernels *pmSubtractionKernelsRINGS(int size, int spatialOrder, int inner, int ringsOrder)
     475pmSubtractionKernels *pmSubtractionKernelsRINGS(int size, int spatialOrder, int inner, int ringsOrder,
     476                                                pmSubtractionMode mode)
    486477{
    487478    PS_ASSERT_INT_POSITIVE(size, NULL);
     
    505496    }
    506497
    507     int numInner = inner;               // Number of pixels in the inner region
     498    int numInner = inner - 1;           // Number of pixels in the inner region
    508499    int numOuter = fibNum;              // Number of summed pixels in the outer region
    509500
    510501    int numRings = numOuter + numInner; // Number of rings (not including the central pixel)
    511     int numPoly = (ringsOrder + 1) * (ringsOrder + 2) / 2; // Number of polynomial variants of each ring
    512 
    513     int num = numRings * numPoly + 1; // Total number of basis functions
     502    int numPoly = PM_SUBTRACTION_POLYTERMS(ringsOrder); // Number of polynomial variants of each ring
     503
     504    int num = numRings * numPoly; // Total number of basis functions
    514505
    515506    pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_RINGS,
    516                                                               size, spatialOrder); // The kernels
     507                                                              size, spatialOrder, mode); // The kernels
    517508    psStringAppend(&kernels->description, "RINGS(%d,%d,%d,%d)", size, inner, ringsOrder, spatialOrder);
    518509
     
    522513    // Set the Gaussian kernel parameters
    523514    int fibIndex = 1, fibIndexMinus1 = 0; // Fibonnacci parameters
    524     int radiusLast = 0;                 // Last radius
    525     for (int i = 0, index = 0; i < numRings + 1; i++) {
    526 
     515    int radiusLast = 1;                 // Last radius
     516    for (int i = 1, index = 0; i < numRings + 1; i++) {
    527517        float lower2;                   // Lower limit of radius^2
    528518        float upper2;                   // Upper limit of radius^2
    529         if (i == 0) {
    530             lower2 = 0;
    531             upper2 = PS_SQR(0.5);
    532         } else if (i <= numInner) {
     519        if (i <= inner) {
    533520            // A ring every pixel width
    534521            float radius = i;
     
    572559                    for (int v = -size; v <= size; v++) {
    573560                        int v2 = PS_SQR(v);   // Square of v
    574 //                        float vPoly = power(v, vOrder); // Value of v^vOrder
    575561                        float vPoly = powf(v/(float)size, vOrder); // Value of v^vOrder
    576562
     
    579565                            int distance2 = u2 + v2; // Distance from the centre
    580566                            if (distance2 > lower2 && distance2 < upper2) {
    581 //                                float uPoly = power(u, uOrder); // Value of u^uOrder
    582567                                float uPoly = powf(u/(float)size, uOrder); // Value of u^uOrder
    583568
     
    627612    }
    628613
    629     kernels->subIndex = 0;
    630 
    631614    return kernels;
    632615}
     
    634617pmSubtractionKernels *pmSubtractionKernelsGenerate(pmSubtractionKernelsType type, int size, int spatialOrder,
    635618                                                   const psVector *fwhms, const psVector *orders, int inner,
    636                                                    int binning, int ringsOrder)
     619                                                   int binning, int ringsOrder, pmSubtractionMode mode)
    637620{
    638621    switch (type) {
    639622      case PM_SUBTRACTION_KERNEL_POIS:
    640         return pmSubtractionKernelsPOIS(size, spatialOrder);
     623        return pmSubtractionKernelsPOIS(size, spatialOrder, mode);
    641624      case PM_SUBTRACTION_KERNEL_ISIS:
    642         return pmSubtractionKernelsISIS(size, spatialOrder, fwhms, orders);
     625        return pmSubtractionKernelsISIS(size, spatialOrder, fwhms, orders, mode);
    643626      case PM_SUBTRACTION_KERNEL_SPAM:
    644         return pmSubtractionKernelsSPAM(size, spatialOrder, inner, binning);
     627        return pmSubtractionKernelsSPAM(size, spatialOrder, inner, binning, mode);
    645628      case PM_SUBTRACTION_KERNEL_FRIES:
    646         return pmSubtractionKernelsFRIES(size, spatialOrder, inner);
     629        return pmSubtractionKernelsFRIES(size, spatialOrder, inner, mode);
    647630      case PM_SUBTRACTION_KERNEL_GUNK:
    648         return pmSubtractionKernelsGUNK(size, spatialOrder, fwhms, orders, inner);
     631        return pmSubtractionKernelsGUNK(size, spatialOrder, fwhms, orders, inner, mode);
    649632      case PM_SUBTRACTION_KERNEL_RINGS:
    650         return pmSubtractionKernelsRINGS(size, spatialOrder, inner, ringsOrder);
     633        return pmSubtractionKernelsRINGS(size, spatialOrder, inner, ringsOrder, mode);
    651634      default:
    652635        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Unknown kernel type: %x", type);
  • trunk/psModules/src/imcombine/pmSubtractionKernels.h

    r15443 r15756  
    3131    long num;                           ///< Number of kernel components (not including the spatial ones)
    3232    psVector *u, *v;                    ///< Offset (for POIS) or polynomial order (for ISIS)
    33     psVector *widths;                   ///< Gaussian FWHMs (ISIS) or ring radius (RINGS)
     33    psVector *widths;                   ///< Gaussian FWHMs (ISIS)
    3434    psVector *uStop, *vStop;            ///< Width of kernel element (SPAM,FRIES only)
    35     int subIndex;                       ///< Index of kernel to be subtracted (to maintain flux conservation)
    3635    psArray *preCalc;                   ///< Array of images containing pre-calculated kernel (for ISIS)
    3736    int size;                           ///< The half-size of the kernel
     
    3938    int spatialOrder;                   ///< The spatial order of the kernels
    4039    int bgOrder;                        ///< The order for the background fitting
     40    pmSubtractionMode mode;             ///< Mode for subtraction
     41    psVector *solution1, *solution2;    ///< Solution for the PSF matching
    4142} pmSubtractionKernels;
     43
     44// Assertion to check pmSubtractionKernels
     45#define PM_ASSERT_SUBTRACTION_KERNELS_NON_NULL(KERNELS, RETURNVALUE) { \
     46    PS_ASSERT_PTR_NON_NULL(KERNELS, RETURNVALUE); \
     47    PS_ASSERT_STRING_NON_EMPTY((KERNELS)->description, RETURNVALUE); \
     48    PS_ASSERT_INT_POSITIVE((KERNELS)->num, RETURNVALUE); \
     49    PS_ASSERT_VECTOR_NON_NULL((KERNELS)->u, RETURNVALUE); \
     50    PS_ASSERT_VECTOR_NON_NULL((KERNELS)->v, RETURNVALUE); \
     51    PS_ASSERT_VECTOR_TYPE((KERNELS)->u, PS_TYPE_S32, RETURNVALUE); \
     52    PS_ASSERT_VECTOR_TYPE((KERNELS)->v, PS_TYPE_S32, RETURNVALUE); \
     53    PS_ASSERT_VECTOR_SIZE((KERNELS)->u, (KERNELS)->num, RETURNVALUE); \
     54    PS_ASSERT_VECTOR_SIZE((KERNELS)->v, (KERNELS)->num, RETURNVALUE); \
     55    if ((KERNELS)->type == PM_SUBTRACTION_KERNEL_ISIS) { \
     56        PS_ASSERT_VECTOR_NON_NULL((KERNELS)->widths, RETURNVALUE); \
     57        PS_ASSERT_VECTOR_TYPE((KERNELS)->widths, PS_TYPE_F32, RETURNVALUE); \
     58        PS_ASSERT_VECTOR_SIZE((KERNELS)->widths, (KERNELS)->num, RETURNVALUE); \
     59    } \
     60    if ((KERNELS)->uStop || (KERNELS)->vStop) { \
     61        PS_ASSERT_VECTOR_NON_NULL((KERNELS)->uStop, RETURNVALUE); \
     62        PS_ASSERT_VECTOR_NON_NULL((KERNELS)->vStop, RETURNVALUE); \
     63        PS_ASSERT_VECTOR_TYPE((KERNELS)->uStop, PS_TYPE_S32, RETURNVALUE); \
     64        PS_ASSERT_VECTOR_TYPE((KERNELS)->vStop, PS_TYPE_S32, RETURNVALUE); \
     65        PS_ASSERT_VECTOR_SIZE((KERNELS)->uStop, (KERNELS)->num, RETURNVALUE); \
     66        PS_ASSERT_VECTOR_SIZE((KERNELS)->vStop, (KERNELS)->num, RETURNVALUE); \
     67    } \
     68    if ((KERNELS)->preCalc) { \
     69        PS_ASSERT_ARRAY_NON_NULL((KERNELS)->preCalc, RETURNVALUE); \
     70        PS_ASSERT_ARRAY_SIZE((KERNELS)->preCalc, (KERNELS)->num, RETURNVALUE); \
     71    } \
     72    PS_ASSERT_INT_NONNEGATIVE((KERNELS)->size, RETURNVALUE); \
     73    PS_ASSERT_INT_NONNEGATIVE((KERNELS)->inner, RETURNVALUE); \
     74    PS_ASSERT_INT_NONNEGATIVE((KERNELS)->spatialOrder, RETURNVALUE); \
     75    PS_ASSERT_INT_NONNEGATIVE((KERNELS)->bgOrder, RETURNVALUE); \
     76}
     77
     78// Assertion to check that the solution is attached
     79#define PM_ASSERT_SUBTRACTION_KERNELS_SOLUTION(KERNELS, RETURNVALUE) { \
     80    PS_ASSERT_VECTOR_NON_NULL((KERNELS)->solution1, RETURNVALUE); \
     81    PS_ASSERT_VECTOR_TYPE((KERNELS)->solution1, PS_TYPE_F64, RETURNVALUE); \
     82    PS_ASSERT_VECTOR_SIZE((KERNELS)->solution1, \
     83                          (KERNELS)->num * PM_SUBTRACTION_POLYTERMS((KERNELS)->spatialOrder) + 1 + \
     84                              PM_SUBTRACTION_POLYTERMS((KERNELS)->bgOrder), \
     85                          RETURNVALUE); \
     86    if (kernels->mode == PM_SUBTRACTION_MODE_DUAL) { \
     87        PS_ASSERT_VECTOR_NON_NULL(kernels->solution2, RETURNVALUE); \
     88        PS_ASSERT_VECTOR_TYPE((KERNELS)->solution2, PS_TYPE_F64, RETURNVALUE); \
     89        PS_ASSERT_VECTOR_SIZE((KERNELS)->solution2, \
     90                              (KERNELS)->num * PM_SUBTRACTION_POLYTERMS((KERNELS)->spatialOrder), \
     91                               RETURNVALUE); \
     92    } \
     93}
    4294
    4395/// Generate a delta-function grid for subtraction kernels (like the POIS kernel)
     
    54106                                                pmSubtractionKernelsType type, ///< Kernel type
    55107                                                int size, ///< Half-size of kernel
    56                                                 int spatialOrder ///< Order of spatial variations
     108                                                int spatialOrder, ///< Order of spatial variations
     109                                                pmSubtractionMode mode ///< Mode for subtraction
    57110    );
    58111
    59112/// Generate POIS kernels
    60113pmSubtractionKernels *pmSubtractionKernelsPOIS(int size, ///< Half-size of the kernel (in both dims)
    61                                                int spatialOrder ///< Order of spatial variations
     114                                               int spatialOrder, ///< Order of spatial variations
     115                                               pmSubtractionMode mode ///< Mode for subtraction
    62116    );
    63117
     
    66120                                                    int spatialOrder, ///< Order of spatial variations
    67121                                                    const psVector *fwhms, ///< Gaussian FWHMs
    68                                                     const psVector *orders ///< Polynomial order of gaussians
     122                                                    const psVector *orders, ///< Polynomial order of gaussians
     123                                                    pmSubtractionMode mode ///< Mode for subtraction
    69124    );
    70125
     
    73128                                               int spatialOrder, ///< Order of spatial variations
    74129                                               const psVector *fwhms, ///< Gaussian FWHMs
    75                                                const psVector *orders ///< Polynomial order of gaussians
     130                                               const psVector *orders, ///< Polynomial order of gaussians
     131                                               pmSubtractionMode mode ///< Mode for subtraction
    76132                                               );
    77133
     
    80136                                               int spatialOrder, ///< Order of spatial variations
    81137                                               int inner, ///< Inner radius to preserve unbinned
    82                                                int binning ///< Kernel binning factor
     138                                               int binning, ///< Kernel binning factor
     139                                               pmSubtractionMode mode ///< Mode for subtraction
    83140    );
    84141
     
    86143pmSubtractionKernels *pmSubtractionKernelsFRIES(int size, ///< Half-size of the kernel
    87144                                                int spatialOrder, ///< Order of spatial variations
    88                                                 int inner ///< Inner radius to preserve unbinned
     145                                                int inner, ///< Inner radius to preserve unbinned
     146                                                pmSubtractionMode mode ///< Mode for subtraction
    89147    );
    90148
     
    94152                                               const psVector *fwhms, ///< Gaussian FWHMs
    95153                                               const psVector *orders, ///< Polynomial order of gaussians
    96                                                int inner ///< Inner radius containing grid of delta functions
     154                                               int inner, ///< Inner radius containing grid of delta functions
     155                                               pmSubtractionMode mode ///< Mode for subtraction
    97156    );
    98157
     
    101160                                                int spatialOrder, ///< Order of spatial variations
    102161                                                int inner, ///< Inner radius to preserve unbinned
    103                                                 int ringsOrder ///< Polynomial order
     162                                                int ringsOrder, ///< Polynomial order
     163                                                pmSubtractionMode mode ///< Mode for subtraction
    104164    );
    105165
     
    113173                                                   int inner, ///< Inner radius to preserve unbinned
    114174                                                   int binning, ///< Kernel binning factor
    115                                                    int ringsOrder ///< Polynomial order for RINGS
     175                                                   int ringsOrder, ///< Polynomial order for RINGS
     176                                                   pmSubtractionMode mode ///< Mode for subtraction
    116177    );
    117178
  • trunk/psModules/src/imcombine/pmSubtractionMatch.c

    r15447 r15756  
    1313#include "pmSubtractionKernels.h"
    1414#include "pmSubtractionStamps.h"
     15#include "pmSubtractionEquation.h"
    1516#include "pmSubtraction.h"
     17#include "pmSubtractionMask.h"
    1618#include "pmSubtractionMatch.h"
    1719
     20#define TOL 1.0e-3                      // Tolerance for subtraction solution
     21#define KERNEL_MOSAIC 2                 // Half-number of kernel instances in the mosaic image
    1822
    1923static bool useFFT = true;              // Do convolutions using FFT
     
    6367{
    6468    psTrace("psModules.imcombine", 3, "Finding stamps...\n");
    65     *stamps = pmSubtractionStampsFind(*stamps, ro1->image, subMask, region, threshold, stampSpacing, mode);
     69    *stamps = pmSubtractionStampsFind(*stamps, ro1->image, subMask, region, threshold, footprint,
     70                                      stampSpacing, mode);
    6671    if (!*stamps) {
    6772        psError(PS_ERR_UNKNOWN, false, "Unable to find stamps.");
     
    7277
    7378    psTrace("psModules.imcombine", 3, "Extracting stamps...\n");
    74     if (!pmSubtractionStampsExtract(*stamps, ro1->image, ro2 ? ro2->image : NULL, weight, footprint, size)) {
     79    if (!pmSubtractionStampsExtract(*stamps, ro1->image, ro2 ? ro2->image : NULL, weight, size)) {
    7580        psError(PS_ERR_UNKNOWN, false, "Unable to extract stamps.");
    7681        return false;
     
    8691
    8792
    88 bool pmSubtractionMatch(pmReadout *convolved, const pmReadout *ro1, const pmReadout *ro2,
     93bool pmSubtractionMatch(pmReadout *conv1, pmReadout *conv2, const pmReadout *ro1, const pmReadout *ro2,
    8994                        int footprint, float regionSize, float stampSpacing, float threshold,
    9095                        const psArray *sources, const char *stampsName,
     
    95100                        psMaskType maskBlank, float badFrac, pmSubtractionMode mode)
    96101{
    97     PS_ASSERT_PTR_NON_NULL(convolved, false);
     102    PS_ASSERT_PTR_NON_NULL(conv1, false);
     103    if (mode == PM_SUBTRACTION_MODE_DUAL) {
     104        PS_ASSERT_PTR_NON_NULL(conv2, false);
     105    }
    98106    PS_ASSERT_PTR_NON_NULL(ro1, false);
    99107    PS_ASSERT_IMAGE_NON_NULL(ro1->image, false);
     
    174182
    175183    // Reset the output readout, just in case
    176     if (convolved->image) {
    177         psFree(convolved->image);
    178         convolved->image = NULL;
    179     }
    180     if (convolved->mask) {
    181         psFree(convolved->mask);
    182         convolved->mask = NULL;
    183     }
    184     if (convolved->weight) {
    185         psFree(convolved->weight);
    186         convolved->weight = NULL;
     184    if (conv1->image) {
     185        psFree(conv1->image);
     186        conv1->image = NULL;
     187    }
     188    if (conv1->mask) {
     189        psFree(conv1->mask);
     190        conv1->mask = NULL;
     191    }
     192    if (conv1->weight) {
     193        psFree(conv1->weight);
     194        conv1->weight = NULL;
    187195    }
    188196
     
    250258
    251259            if (sources) {
    252                 stamps = pmSubtractionStampsSetFromSources(sources, subMask, region, stampSpacing, mode);
     260                stamps = pmSubtractionStampsSetFromSources(sources, subMask, region, footprint,
     261                                                           stampSpacing, mode);
    253262            } else if (stampsName && strlen(stampsName) > 0) {
    254                 stamps = pmSubtractionStampsSetFromFile(stampsName, subMask, region, stampSpacing, mode);
     263                stamps = pmSubtractionStampsSetFromFile(stampsName, subMask, region, footprint,
     264                                                        stampSpacing, mode);
    255265            }
    256266
     
    295305                // Not an ISIS/GUNK kernel, or the optimum kernel search failed
    296306                kernels = pmSubtractionKernelsGenerate(type, size, spatialOrder, isisWidths, isisOrders,
    297                                                        inner, binning, ringsOrder);
    298             }
    299             psMetadataAddPtr(convolved->analysis, PS_LIST_TAIL, "SUBTRACTION.KERNEL",
     307                                                       inner, binning, ringsOrder, mode);
     308            }
     309            psMetadataAddPtr(conv1->analysis, PS_LIST_TAIL, "SUBTRACTION.KERNEL",
    300310                             PS_DATA_UNKNOWN | PS_META_DUPLICATE_OK, "Subtraction kernels", kernels);
    301311
     
    312322
    313323                psTrace("psModules.imcombine", 3, "Calculating equation...\n");
    314                 if (!pmSubtractionCalculateEquation(stamps, kernels, footprint, mode)) {
     324                if (!pmSubtractionCalculateEquation(stamps, kernels)) {
    315325                    psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation.");
    316326                    goto MATCH_ERROR;
     
    320330
    321331                psTrace("psModules.imcombine", 3, "Solving equation...\n");
    322                 solution = pmSubtractionSolveEquation(solution, stamps);
    323                 if (!solution) {
     332
     333                if (!pmSubtractionSolveEquation(kernels, stamps, TOL)) {
    324334                    psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation.");
    325335                    goto MATCH_ERROR;
     
    328338                memCheck("  solve equation");
    329339
    330                 psVector *deviations = pmSubtractionCalculateDeviations(stamps, solution, footprint, kernels,
    331                                                                         mode); // Deviations for each stamp
     340                psVector *deviations = pmSubtractionCalculateDeviations(stamps, kernels); // Stamp deviations
    332341                if (!deviations) {
    333342                    psError(PS_ERR_UNKNOWN, false, "Unable to calculate deviations.");
     
    351360            if (numRejected > 0) {
    352361                psTrace("psModules.imcombine", 3, "Solving equation...\n");
    353                 solution = pmSubtractionSolveEquation(solution, stamps);
    354                 if (!solution) {
     362                if (!pmSubtractionSolveEquation(kernels, stamps, TOL)) {
    355363                    psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation.");
    356364                    goto MATCH_ERROR;
    357365                }
    358                 psVector *deviations = pmSubtractionCalculateDeviations(stamps, solution, footprint, kernels,
    359                                                                         mode); // Deviations for each stamp
     366                psVector *deviations = pmSubtractionCalculateDeviations(stamps, kernels); // Stamp deviations
    360367                if (!deviations) {
    361368                    psError(PS_ERR_UNKNOWN, false, "Unable to calculate deviations.");
     
    376383                psImage *convKernels = psImageAlloc(5 * fullSize - 1, 5 * fullSize - 1, PS_TYPE_F32);
    377384                psImageInit(convKernels, NAN);
    378                 for (int j = -2; j <= 2; j++) {
    379                     for (int i = -2; i <= 2; i++) {
    380                         psImage *kernel = pmSubtractionKernelImage(solution, kernels, (float)i / 2.0,
    381                                                                    (float)j / 2.0); // Image of the kernel
     385                for (int j = -KERNEL_MOSAIC; j <= KERNEL_MOSAIC; j++) {
     386                    for (int i = -KERNEL_MOSAIC; i <= KERNEL_MOSAIC; i++) {
     387                        psImage *kernel = pmSubtractionKernelImage(kernels, (float)i / (float)KERNEL_MOSAIC,
     388                                                                   (float)j / (float)KERNEL_MOSAIC,
     389                                                                   false); // Image of the kernel
    382390                        if (!kernel) {
    383391                            psError(PS_ERR_UNKNOWN, false, "Unable to generate kernel image.");
     
    386394                        }
    387395
    388                         if (psImageOverlaySection(convKernels, kernel, (i + 2) * fullSize,
    389                                                   (j + 2) * fullSize, "=") == 0) {
     396                        if (psImageOverlaySection(convKernels, kernel, (i + KERNEL_MOSAIC) * fullSize,
     397                                                  (j + KERNEL_MOSAIC) * fullSize, "=") == 0) {
    390398                            psError(PS_ERR_UNKNOWN, false, "Unable to overlay kernel image.");
    391399                            psFree(kernel);
     
    399407                psString comment = NULL; // Comment for metadata
    400408                psStringAppend(&comment, "Subtraction kernel for region %s", regionString);
    401                 psMetadataAddImage(convolved->analysis, PS_LIST_TAIL, "SUBTRACTION.KERNEL.IMAGE",
     409                psMetadataAddImage(conv1->analysis, PS_LIST_TAIL, "SUBTRACTION.KERNEL.IMAGE",
    402410                                   PS_META_DUPLICATE_OK, comment, convKernels);
    403411                psFree(comment);
     
    427435
    428436            psTrace("psModules.imcombine", 2, "Convolving...\n");
    429             if (!pmSubtractionConvolve(convolved, ro1, ro2, subMask, maskBlank, region,
    430                                        solution, kernels, mode, useFFT)) {
     437            if (!pmSubtractionConvolve(conv1, conv2, ro1, ro2, subMask, maskBlank, region, kernels, useFFT)) {
    431438                psError(PS_ERR_UNKNOWN, false, "Unable to convolve image.");
    432439                goto MATCH_ERROR;
     
    439446                psString comment = NULL; // Comment for metadata
    440447                psStringAppend(&comment, "Subtraction solution for region %s", regionString);
    441                 psMetadataAddVector(convolved->analysis, PS_LIST_TAIL, "SUBTRACTION.SOLUTION",
     448                psMetadataAddVector(conv1->analysis, PS_LIST_TAIL, "SUBTRACTION.SOLUTION",
    442449                                    PS_META_DUPLICATE_OK, comment, solution);
    443450                psFree(comment);
    444451                if (region) {
    445                     psMetadataAddPtr(convolved->analysis, PS_LIST_TAIL, "SUBTRACTION.REGION",
     452                    psMetadataAddPtr(conv1->analysis, PS_LIST_TAIL, "SUBTRACTION.REGION",
    446453                                     PS_META_DUPLICATE_OK | PS_DATA_REGION, comment, region);
    447454                } else {
    448455                    region = psRegionAlloc(0, numCols, 0, numRows);
    449                     psMetadataAddPtr(convolved->analysis, PS_LIST_TAIL, "SUBTRACTION.REGION",
     456                    psMetadataAddPtr(conv1->analysis, PS_LIST_TAIL, "SUBTRACTION.REGION",
    450457                                     PS_META_DUPLICATE_OK | PS_DATA_REGION, comment, region);
    451458                    psFree(region);
     
    458465
    459466            // There is data in the readout now
    460             convolved->data_exists = true;
    461             if (convolved->parent) {
    462                 convolved->parent->data_exists = true;
    463                 convolved->parent->parent->data_exists = true;
     467            conv1->data_exists = true;
     468            if (conv1->parent) {
     469                conv1->parent->data_exists = true;
     470                conv1->parent->parent->data_exists = true;
     471            }
     472            if (mode == PM_SUBTRACTION_MODE_DUAL) {
     473                conv2->data_exists = true;
     474                if (conv2->parent) {
     475                    conv2->parent->data_exists = true;
     476                    conv2->parent->parent->data_exists = true;
     477                }
    464478            }
    465479        }
     
    474488    weight = NULL;
    475489
    476     if (!pmSubtractionBorder(convolved->image, convolved->weight, convolved->mask, size, maskBlank)) {
     490    if (!pmSubtractionBorder(conv1->image, conv1->weight, conv1->mask, size, maskBlank)) {
    477491        psError(PS_ERR_UNKNOWN, false, "Unable to set border of convolved image.");
    478492        goto MATCH_ERROR;
  • trunk/psModules/src/imcombine/pmSubtractionMatch.h

    r15443 r15756  
    1010
    1111/// Match two images
    12 bool pmSubtractionMatch(pmReadout *convolved, ///< Output convolved data
     12bool pmSubtractionMatch(pmReadout *conv1, ///< Output convolved data for image 1
     13                        pmReadout *conv2, ///< Output convolved data for image 2
    1314                        const pmReadout *ro1, ///< Image 1
    1415                        const pmReadout *ro2, ///< Image 2
  • trunk/psModules/src/imcombine/pmSubtractionParams.c

    r15443 r15756  
    232232    psVectorInit(orders, maxOrder);
    233233    pmSubtractionKernels *kernels = p_pmSubtractionKernelsRawISIS(size, spatialOrder,
    234                                                                   fwhms, orders); // Kernels
     234                                                                  fwhms, orders, mode); // Kernels
    235235    psFree(orders);
    236236    psFree(kernels->description);
     
    279279            continue;
    280280        }
    281         if (!pmSubtractionConvolveStamp(stamp, kernels, footprint, mode)) {
     281        if (!pmSubtractionConvolveStamp(stamp, kernels, footprint)) {
    282282            psError(PS_ERR_UNKNOWN, false, "Unable to convolve stamp %d.", i);
    283283            psFree(targets);
     
    505505
    506506        kernels->type = PM_SUBTRACTION_KERNEL_GUNK;
    507 
    508         kernels->subIndex = PS_SQR(2 * inner + 1) / 2 + numGaussians;
    509         assert(kernels->u->data.S32[kernels->subIndex] == 0 &&
    510                kernels->v->data.S32[kernels->subIndex] == 0);
    511507    }
    512508
  • trunk/psModules/src/imcombine/pmSubtractionStamps.c

    r15745 r15756  
    4444                                 )
    4545{
    46     psFree(stamp->matrix);
    47     psFree(stamp->vector);
    4846    psFree(stamp->image1);
    4947    psFree(stamp->image2);
     
    5149    psFree(stamp->convolutions1);
    5250    psFree(stamp->convolutions2);
     51
     52    psFree(stamp->matrix1);
     53    psFree(stamp->matrix2);
     54    psFree(stamp->matrixX);
     55    psFree(stamp->vector);
     56
    5357}
    5458
     
    103107
    104108pmSubtractionStampList *pmSubtractionStampListAlloc(int numCols, int numRows, const psRegion *region,
    105                                                     float spacing)
     109                                                    int footprint, float spacing)
    106110{
    107111    pmSubtractionStampList *list = psAlloc(sizeof(pmSubtractionStampList)); // Stamp list to return
     
    124128
    125129    for (int y = 0, index = 0; y < yStamps; y++) {
    126         int yStart = yMin + y * ySize / (yStamps + 1); // Subregion starts here
    127         int yStop = yMin + (y + 1) * ySize / (yStamps + 1) - 1; // Subregion stops here
     130        int yStart = yMin + y * ((float)ySize / (float)(yStamps + 1)); // Subregion starts here
     131        int yStop = yMin + (y + 1) * ((float)ySize / (float)(yStamps + 1)) - 1; // Subregion stops here
    128132        assert(yStart >= yMin && yStop < yMax);
    129133
    130134        for (int x = 0; x < xStamps; x++, index++) {
    131             int xStart = xMin + x * xSize / (xStamps + 1); // Subregion starts here
    132             int xStop = xMin + (x + 1) * xSize / (xStamps + 1) - 1; // Subregion stops here
     135            int xStart = xMin + x * ((float)xSize / (float)(xStamps + 1)); // Subregion starts here
     136            int xStop = xMin + (x + 1) * ((float)xSize / (float)(xStamps + 1)) - 1; // Subregion stops here
    133137            assert(xStart >= xMin && xStop < xMax);
    134138
    135139            list->stamps->data[index] = pmSubtractionStampAlloc();
     140            psTrace("psModules.imcombine", 6, "Stamp region %d: [%d:%d,%d:%d]\n",
     141                    index, xStart, xStop, yStart, yStop);
    136142            list->regions->data[index] = psRegionAlloc(xStart, xStop, yStart, yStop);
    137143        }
     
    141147    list->y = NULL;
    142148    list->flux = NULL;
     149    list->footprint = footprint;
    143150
    144151    return list;
     
    155162    stamp->xNorm = NAN;
    156163    stamp->yNorm = NAN;
    157     stamp->matrix = NULL;
    158     stamp->vector = NULL;
    159164    stamp->status = PM_SUBTRACTION_STAMP_INIT;
    160165
     
    165170    stamp->convolutions2 = NULL;
    166171
     172    stamp->matrix1 = NULL;
     173    stamp->matrix2 = NULL;
     174    stamp->matrixX = NULL;
     175    stamp->vector = NULL;
     176
    167177    return stamp;
    168178}
     
    171181pmSubtractionStampList *pmSubtractionStampsFind(pmSubtractionStampList *stamps, const psImage *image,
    172182                                                const psImage *subMask, const psRegion *region,
    173                                                 float threshold, float spacing, pmSubtractionMode mode)
     183                                                float threshold, int footprint, float spacing,
     184                                                pmSubtractionMode mode)
    174185{
    175186    PS_ASSERT_IMAGE_NON_NULL(image, NULL);
     
    180191        PS_ASSERT_IMAGE_TYPE(subMask, PS_TYPE_MASK, NULL);
    181192    }
     193    PS_ASSERT_INT_NONNEGATIVE(footprint, NULL);
    182194    PS_ASSERT_FLOAT_LARGER_THAN(spacing, 0.0, NULL);
    183195    if (region) {
     
    201213
    202214    if (!stamps) {
    203         stamps = pmSubtractionStampListAlloc(numCols, numRows, region, spacing);
     215        stamps = pmSubtractionStampListAlloc(numCols, numRows, region, footprint, spacing);
    204216    }
    205217
     
    244256            fluxStamp = threshold;
    245257            psRegion *subRegion = stamps->regions->data[i]; // Sub-region of interest
    246             for (int y = subRegion->y0; y <= subRegion->y1 ; y++) {
    247                 for (int x = subRegion->x0; x <= subRegion->x1 ; x++) {
     258            for (int y = subRegion->y0; y <= subRegion->y1; y++) {
     259                for (int x = subRegion->x0; x <= subRegion->x1; x++) {
    248260                    if (checkStampMask(x, y, subMask, mode) && image->data.F32[y][x] > fluxStamp) {
    249261                        fluxStamp = image->data.F32[y][x];
     
    289301pmSubtractionStampList *pmSubtractionStampsSet(const psVector *x, const psVector *y, const psVector *flux,
    290302                                               const psImage *image, const psImage *subMask,
    291                                                const psRegion *region, float spacing, pmSubtractionMode mode)
     303                                               const psRegion *region, int footprint, float spacing,
     304                                               pmSubtractionMode mode)
    292305
    293306{
     
    316329    int numStars = x->n;                // Number of stars
    317330    pmSubtractionStampList *stamps = pmSubtractionStampListAlloc(subMask->numCols, subMask->numRows,
    318                                                                  region, spacing); // Stamp list
     331                                                                 region, footprint, spacing); // Stamp list
    319332    int numStamps = stamps->num;        // Number of stamps
    320333
     
    401414
    402415bool pmSubtractionStampsExtract(pmSubtractionStampList *stamps, psImage *image1, psImage *image2,
    403                                 psImage *weight, int footprint, int kernelSize)
     416                                psImage *weight, int kernelSize)
    404417{
    405418    PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, false);
     
    414427    PS_ASSERT_IMAGES_SIZE_EQUAL(weight, image1, false);
    415428    PS_ASSERT_IMAGE_TYPE(weight, PS_TYPE_F32, false);
    416     PS_ASSERT_INT_NONNEGATIVE(footprint, false);
    417429    PS_ASSERT_INT_NONNEGATIVE(kernelSize, false);
    418430
    419431    int numCols = image1->numCols, numRows = image1->numRows; // Size of images
    420     int size = kernelSize + footprint; // Size of postage stamps
     432    int size = kernelSize + stamps->footprint; // Size of postage stamps
    421433
    422434    for (int i = 0; i < stamps->num; i++) {
     
    467479
    468480#if 0
    469 bool pmSubtractionStampsGenerate(pmSubtractionStampList *stamps, float fwhm, int footprint, int kernelSize)
     481bool pmSubtractionStampsGenerate(pmSubtractionStampList *stamps, float fwhm, int kernelSize)
    470482{
    471483    PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, false);
    472484    PS_ASSERT_FLOAT_LARGER_THAN(fwhm, 0.0, false);
    473     PS_ASSERT_INT_NONNEGATIVE(footprint, false);
    474485    PS_ASSERT_INT_NONNEGATIVE(kernelSize, false);
    475486
    476     int size = kernelSize + footprint; // Size of postage stamps
     487    int size = kernelSize + stamps->footprint; // Size of postage stamps
    477488    int num = stamps->num;              // Number of stamps
    478489    float sigma = fwhm / (2.0 * sqrtf(2.0 * log(2.0))); // Gaussian sigma
     
    514525
    515526pmSubtractionStampList *pmSubtractionStampsSetFromSources(const psArray *sources, const psImage *subMask,
    516                                                           const psRegion *region, float spacing,
    517                                                           pmSubtractionMode mode)
     527                                                          const psRegion *region, int footprint,
     528                                                          float spacing, pmSubtractionMode mode)
    518529{
    519530    PS_ASSERT_ARRAY_NON_NULL(sources, NULL);
     
    539550
    540551    pmSubtractionStampList *stamps = pmSubtractionStampsSet(x, y, flux, NULL, subMask, region,
    541                                                             spacing, mode); // Stamps to return
     552                                                            footprint, spacing, mode); // Stamps to return
    542553    psFree(x);
    543554    psFree(y);
     
    553564
    554565pmSubtractionStampList *pmSubtractionStampsSetFromFile(const char *filename, const psImage *subMask,
    555                                                        const psRegion *region, float spacing,
     566                                                       const psRegion *region, int footprint, float spacing,
    556567                                                       pmSubtractionMode mode)
    557568{
     
    572583    psBinaryOp(y, y, "-", psScalarAlloc(1.0, PS_TYPE_F32));
    573584
    574     pmSubtractionStampList *stamps = pmSubtractionStampsSet(x, y, flux, NULL, subMask, region, spacing,
    575                                                             mode);
     585    pmSubtractionStampList *stamps = pmSubtractionStampsSet(x, y, flux, NULL, subMask, region, footprint,
     586                                                            spacing, mode);
    576587    psFree(data);
    577588
  • trunk/psModules/src/imcombine/pmSubtractionStamps.h

    r15443 r15756  
    2323    psArray *x, *y;                     ///< Coordinates for possible stamps (or NULL)
    2424    psArray *flux;                      ///< Fluxes for possible stamps (or NULL)
     25    int footprint;                      ///< Half-size of stamps
    2526} pmSubtractionStampList;
    2627
     
    2930                                                    int numRows, // Number of rows in image
    3031                                                    const psRegion *region, // Region for stamps, or NULL
     32                                                    int footprint, // Half-size of stamps
    3133                                                    float spacing // Rough average spacing between stamps
    3234    );
     
    4042    PS_ASSERT_ARRAY_SIZE((LIST)->stamps, (LIST)->num, RETURNVALUE); \
    4143    PS_ASSERT_ARRAY_SIZE((LIST)->regions, (LIST)->num, RETURNVALUE); \
     44    PS_ASSERT_INT_NONNEGATIVE((LIST)->footprint, RETURNVALUE); \
    4245    if ((LIST)->x || (LIST)->y || (LIST)->flux) { \
    4346        PS_ASSERT_ARRAY_NON_NULL((LIST)->x, RETURNVALUE); \
     
    5760    psKernel *image1;                   ///< Reference image postage stamp
    5861    psKernel *image2;                   ///< Input image postage stamp
    59     psKernel *weight;                   ///< Weight image postage stamp
    60     psArray *convolutions1;             ///< Convolutions of image 1 for each kernel component
    61     psArray *convolutions2;             ///< Convolutions of image 2 for each kernel component
    62     psImage *matrix;                    ///< Associated matrix
    63     psVector *vector;                   ///< Assoicated vector
     62    psKernel *weight;                   ///< Weight image postage stamp, or NULL
     63    psArray *convolutions1;             ///< Convolutions of image 1 for each kernel component, or NULL
     64    psArray *convolutions2;             ///< Convolutions of image 2 for each kernel component, or NULL
     65    psImage *matrix1, *matrix2;         ///< Matrices for each image, or NULL
     66    psImage *matrixX;                   ///< Cross-matrix (for mode DUAL), or NULL
     67    psVector *vector;                   ///< Associated vector (when mode not DUAL), or NULL
    6468    pmSubtractionStampStatus status;    ///< Status of stamp
    6569} pmSubtractionStamp;
     
    7478                                                const psRegion *region, ///< Region to search, or NULL
    7579                                                float threshold, ///< Threshold for stamps in the image
     80                                                int footprint, ///< Half-size for stamps
    7681                                                float spacing, ///< Rough spacing for stamps
    7782                                                pmSubtractionMode mode ///< Mode for subtraction
     
    8590                                               const psImage *mask, ///< Mask, or NULL
    8691                                               const psRegion *region, ///< Region to search, or NULL
     92                                               int footprint, ///< Half-size for stamps
    8793                                               float spacing, ///< Rough spacing for stamps
    8894                                               pmSubtractionMode mode ///< Mode for subtraction
     
    94100    const psImage *subMask,             ///< Mask, or NULL
    95101    const psRegion *region,             ///< Region to search, or NULL
     102    int footprint,                      ///< Half-size for stamps
    96103    float spacing,                      ///< Rough spacing for stamps
    97104    pmSubtractionMode mode              ///< Mode for subtraction
     
    103110    const psImage *subMask,             ///< Mask, or NULL
    104111    const psRegion *region,             ///< Region to search, or NULL
     112    int footprint,                      ///< Half-size for stamps
    105113    float spacing,                      ///< Rough spacing for stamps
    106114    pmSubtractionMode mode              ///< Mode for subtraction
     
    109117/// Extract stamps from the images
    110118bool pmSubtractionStampsExtract(pmSubtractionStampList *stamps, ///< Stamps
    111                                 psImage *reference, ///< Reference image
    112                                 psImage *input, ///< Input image (or NULL)
     119                                psImage *image1, ///< Reference image
     120                                psImage *image2, ///< Input image (or NULL)
    113121                                psImage *weight, ///< Weight (variance) map
    114                                 int footprint, ///< Stamp footprint size
    115122                                int kernelSize ///< Kernel half-size
    116123    );
  • trunk/psModules/src/psmodules.h

    r15362 r15756  
    8282#include <pmSubtractionMatch.h>
    8383#include <pmSubtractionParams.h>
     84#include <pmSubtractionMask.h>
     85#include <pmSubtractionEquation.h>
    8486#include <pmReadoutCombine.h>
    8587
Note: See TracChangeset for help on using the changeset viewer.