IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
Aug 9, 2007, 10:25:52 AM (19 years ago)
Author:
Paul Price
Message:

Extensive changes to the way spatial variation of the kernel is implemented. I was doing it the stupid way, rather than the smart way outlined in Alard 2000 (A&ASS, 144, 363). Fixed up the normalisation of the kernels (essential for proper flux conservation with spatial variation). Put in support for dividing an image up into regions.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/psModules/src/imcombine/pmSubtraction.c

    r14420 r14455  
    44 *  @author GLG, MHPCC
    55 *
    6  *  @version $Revision: 1.33 $ $Name: not supported by cvs2svn $
    7  *  @date $Date: 2007-08-07 19:02:55 $
     6 *  @version $Revision: 1.34 $ $Name: not supported by cvs2svn $
     7 *  @date $Date: 2007-08-09 20:25:52 $
    88 *
    99 *  Copyright 2004-2007 Institute for Astronomy, University of Hawaii
     
    3030// Private (file-static) functions
    3131//////////////////////////////////////////////////////////////////////////////////////////////////////////////
     32
     33// Return the number of polynomial terms there are for a given order
     34static inline long polyTerms(int order  // Order of polynomial
     35                             )
     36{
     37    return (order + 1) * (order + 2) / 2;
     38}
    3239
    3340// Given a stamp coordinates (x,y), generate a matrix where the elements (i,j) are x^i * y^j
     
    160167          case PM_SUBTRACTION_KERNEL_ISIS: { \
    161168              psKernel *preCalc = (KERNELS)->preCalc->data[i]; /* Precalculated values */ \
    162               psKernel *subKernel = (KERNELS)->preCalc->data[(KERNELS)->subIndex]; /* Kernel to subtract */ \
    163169              for (int v = -size; v <= size; v++) { \
    164170                  for (int u = -size; u <= size; u++) { \
    165171                      (TARGET)->kernel[v][u] += value * FUNC(preCalc->kernel[v][u]); \
    166                       /* Subtract (0,0) kernel from other kernels to preserve photometric scaling */ \
    167                       if ((KERNELS)->spatialOrder > 0 && i != (KERNELS)->subIndex) { \
    168                           (TARGET)->kernel[v][u] += subValue * FUNC(subKernel->kernel[v][u]); \
    169                       } \
     172                      /* Photometric scaling is already built in to the precalculated kernel */ \
    170173                  } \
    171174              } \
     
    207210    )
    208211{
    209     int numKernels = solution->n - 1;   // Number of kernel basis functions
     212    int numKernels = kernels->num;      // Number of kernel basis functions
    210213    assert(kernels->u->n == numKernels);
    211214    assert(kernels->v->n == numKernels);
    212     assert(kernels->xOrder->n == numKernels);
    213     assert(kernels->yOrder->n == numKernels);
     215    int spatialOrder = kernels->spatialOrder; // Maximum spatial polynomial order
     216    assert(solution->n == numKernels * polyTerms(spatialOrder) + polyTerms(kernels->bgOrder));
    214217
    215218    // Ensure the subIndex for POIS kernels is what is expected
    216219    assert((kernels->type != PM_SUBTRACTION_KERNEL_POIS &&
    217220            kernels->type != PM_SUBTRACTION_KERNEL_SPAM &&
    218             kernels->type != PM_SUBTRACTION_KERNEL_FRIES) ||
    219            (kernels->u->data.S32[kernels->subIndex] == 0 && kernels->v->data.S32[kernels->subIndex] == 0 &&
    220             kernels->xOrder->data.S32[kernels->subIndex] == 0 &&
    221             kernels->yOrder->data.S32[kernels->subIndex] == 0));
     221            kernels->type != PM_SUBTRACTION_KERNEL_FRIES &&
     222            kernels->type != PM_SUBTRACTION_KERNEL_GUNK &&
     223            kernels->type != PM_SUBTRACTION_KERNEL_RINGS) ||
     224           (kernels->u->data.S32[kernels->subIndex] == 0 && kernels->v->data.S32[kernels->subIndex] == 0));
    222225
    223226    int size = kernels->size;           // Kernel half-size
     
    228231
    229232    for (int i = 0; i < numKernels; i++) {
    230         int xOrder = kernels->xOrder->data.S32[i]; // Polynomial order in x
    231         int yOrder = kernels->yOrder->data.S32[i]; // Polynomial order in y
    232         float value = weightFunc(polyValues->data.F64[yOrder][xOrder] *
    233                                  solution->data.F64[i]); // Value to sum
    234         float subValue = weightFunc(-solution->data.F64[i]); // Value to subtract (actually add, because of -)
     233        double value = 0.0;              // Value of kernel coefficient
     234        for (int yOrder = 0, index = i; yOrder <= spatialOrder; yOrder++) {
     235            for (int xOrder = 0; xOrder <= spatialOrder - yOrder; xOrder++, index += numKernels) {
     236                value += polyValues->data.F64[yOrder][xOrder] * solution->data.F64[index];
     237            }
     238        }
     239
    235240        switch (kernels->type) {
    236241          case PM_SUBTRACTION_KERNEL_POIS: {
    237242              int u = kernels->u->data.S32[i]; // Offset in x
    238243              int v = kernels->v->data.S32[i]; // Offset in y
    239               kernel->kernel[v][u] += value;
     244              kernel->kernel[v][u] += weightFunc(value);
    240245              if (kernels->spatialOrder > 0 && i != kernels->subIndex) {
    241246                  // The (0,0) element is subtracted from most kernels to preserve photometric scaling
    242                   kernel->kernel[0][0] += subValue;
     247                  kernel->kernel[0][0] += weightFunc(- value);
    243248              }
    244249              break;
     
    253258
    254259              // Normalising sum of kernel component to unity
    255               value /= weightFunc((uStop - uStart) * (vStop - vStart));
     260              float norm = 1.0 / weightFunc((uStop - uStart) * (vStop - vStart));
    256261
    257262              for (int v = vStart; v <= vStop; v++) {
    258263                  for (int u = uStart; u <= uStop; u++) {
    259                       kernel->kernel[v][u] += value;
     264                      kernel->kernel[v][u] += norm * weightFunc(value);
     265                      if (kernels->spatialOrder > 0 && i != kernels->subIndex) {
     266                          // The (0,0) element is subtracted from most kernels to preserve photometric scaling
     267                          kernel->kernel[0][0] += weightFunc(- value);
     268                      }
    260269                  }
    261               }
    262               if (kernels->spatialOrder > 0 && i != kernels->subIndex) {
    263                   /* The (0,0) element is subtracted from most kernels to preserve photometric scaling */
    264                   kernel->kernel[0][0] += subValue;
    265270              }
    266271              break;
     
    270275                  // Using pre-calculated function
    271276                  psKernel *preCalc = kernels->preCalc->data[i]; // Precalculated values
     277                  // Iterating over the kernel
    272278                  for (int v = -size; v <= size; v++) {
    273279                      for (int u = -size; u <= size; u++) {
    274                           kernel->kernel[v][u] += value * weightFunc(preCalc->kernel[v][u]);
     280                          kernel->kernel[v][u] += weightFunc(preCalc->kernel[v][u] * value);
     281                          // Photometric scaling is built into the preCalc kernel --- no subtraction!
    275282                      }
    276283                  }
    277284              } else {
    278285                  // Using delta function
     286                  bool subtract = (kernels->spatialOrder > 0 && i != kernels->subIndex); // Subtract (0,0)?
    279287                  int u = kernels->u->data.S32[i]; // Offset in x
    280288                  int v = kernels->v->data.S32[i]; // Offset in y
    281                   kernel->kernel[v][u] += value;
    282               }
    283               // The (0,0) kernel is subtracted from other kernels to preserve photometric scaling
    284               if (kernels->spatialOrder > 0 && i != kernels->subIndex) {
    285                   kernel->kernel[0][0] += subValue;
    286               }
    287               break;
    288           }
    289           case PM_SUBTRACTION_KERNEL_ISIS: {
    290               psKernel *preCalc = kernels->preCalc->data[i];// Precalculated values
    291               psKernel *subKernel = kernels->preCalc->data[kernels->subIndex]; // Kernel to subtract
    292               for (int v = -size; v <= size; v++) {
    293                   for (int u = -size; u <= size; u++) {
    294                       kernel->kernel[v][u] += value * weightFunc(preCalc->kernel[v][u]);
    295                       // The (0,0) kernel is subtracted from other kernels to preserve photometric scaling
    296                       if (kernels->spatialOrder > 0 && i != kernels->subIndex) {
    297                           kernel->kernel[v][u] += subValue * weightFunc(subKernel->kernel[v][u]);
    298                       }
     289                  kernel->kernel[v][u] += weightFunc(value);
     290                  if (subtract) {
     291                      // The (0,0) element is subtracted from most kernels to preserve photometric scaling
     292                      kernel->kernel[0][0] += weightFunc(- value);
    299293                  }
    300294              }
    301295              break;
    302296          }
     297          case PM_SUBTRACTION_KERNEL_ISIS: {
     298              psKernel *preCalc = kernels->preCalc->data[i]; // Precalculated values
     299              // Iterating over the kernel
     300              for (int v = -size; v <= size; v++) {
     301                  for (int u = -size; u <= size; u++) {
     302                      kernel->kernel[v][u] += weightFunc(preCalc->kernel[v][u] * value);
     303                      // Photometric scaling is built into the preCalc kernel --- no subtraction!
     304                  }
     305              }
     306              break;
     307          }
    303308          case PM_SUBTRACTION_KERNEL_RINGS: {
    304309              if (i == kernels->subIndex) {
    305                   kernel->kernel[0][0] += value;
     310                  kernel->kernel[0][0] += weightFunc(value);
    306311                  break;
    307312              }
     
    311316              psVector *poly = preCalc->data[2]; // Polynomial values
    312317              int num = uCoords->n;     // Number of pixels
    313               value /= weightFunc(num); // Normalising sum of kernel component to unity
     318
    314319              for (int j = 0; j < num; j++) {
    315320                  int u = uCoords->data.S32[j], v = vCoords->data.S32[j]; // Kernel coordinates
    316                   kernel->kernel[v][u] += value * weightFunc(poly->data.F32[j]);
     321                  kernel->kernel[v][u] += weightFunc(value * poly->data.F32[j]);
    317322              }
    318 
    319               // The (0,0) kernel is subtracted from other kernels to preserve photometric scaling
    320               if (kernels->spatialOrder > 0) {
    321                   kernel->kernel[0][0] += subValue;
    322               }
     323              kernel->kernel[0][0] += weightFunc(- value * num);
    323324              break;
    324325          }
     
    336337                                   int index, // Kernel basis function index
    337338                                   int x, int y, // Pixel around which to convolve
    338                                    const psImage *image, // Image to convolve
    339                                    const psImage *polyValues // Spatial polynomial values
     339                                   const psImage *image // Image to convolve
    340340                                   )
    341341{
    342     int xOrder = kernels->xOrder->data.S32[index]; // Polynomial order in x
    343     int yOrder = kernels->yOrder->data.S32[index]; // Polynomial order in y
    344     double polyValue = polyValues->data.F64[yOrder][xOrder]; // Value of spatial polynomial
    345 
    346342    switch (kernels->type) {
    347343      case PM_SUBTRACTION_KERNEL_POIS: {
     
    349345          int u = kernels->u->data.S32[index]; // Offset in x
    350346          int v = kernels->v->data.S32[index]; // Offset in y
    351           double value = polyValue * image->data.F32[y + v][x + u]; // Value of convolution
     347          float value = image->data.F32[y + v][x + u]; // Value of convolution
    352348          if (kernels->spatialOrder > 0 && index != kernels->subIndex) {
    353349              // The (0,0) element is subtracted from most kernels to preserve photometric scaling
     
    366362          for (int v = vStart; v <= vStop; v++) {
    367363              for (int u = uStart; u <= uStop; u++) {
    368                   sum += polyValue * image->data.F32[y + v][x + u];
     364                  sum += image->data.F32[y + v][x + u];
    369365              }
    370366          }
     
    377373      }
    378374      case PM_SUBTRACTION_KERNEL_GUNK: {
    379           double value;                 // The value to return
    380375          if (index < kernels->inner) {
    381376              // Using pre-calculated function
     
    388383                  }
    389384              }
    390               value = polyValue * sum;
    391           } else {
    392               // Using delta function
    393               int u = kernels->u->data.S32[index]; // Offset in x
    394               int v = kernels->v->data.S32[index]; // Offset in y
    395               value = polyValue * image->data.F32[y + v][x + u]; // Value of convolution
    396           }
     385              return sum;
     386          }
     387          // Using delta function
     388          int u = kernels->u->data.S32[index]; // Offset in x
     389          int v = kernels->v->data.S32[index]; // Offset in y
     390          float value = image->data.F32[y + v][x + u]; // Value of convolution
    397391          // The (0,0) delta function is subtracted from most kernels to preserve photometric scaling
    398392          if (kernels->spatialOrder > 0 && index != kernels->subIndex) {
     
    403397      case PM_SUBTRACTION_KERNEL_ISIS: {
    404398          psKernel *kernel = kernels->preCalc->data[index]; // The convolution kernel
    405           psKernel *subKernel = kernels->preCalc->data[kernels->subIndex]; // Kernel to subtract
    406399          int size = kernels->size;     // Kernel half-size
    407400          double sum = 0.0;             // Accumulated sum from convolution
    408           double sub = 0.0;             // Accumulated sum to subtract
    409401          for (int v = -size; v <= size; v++) {
    410402              for (int u = -size; u <= size; u++) {
    411403                  sum += kernel->kernel[v][u] * image->data.F32[y + v][x + u];
    412                   // The (0,0) kernel is subtracted from other kernels to preserve photometric scaling
    413                   if (kernels->spatialOrder > 0 && index != kernels->subIndex) {
    414                       sub += subKernel->kernel[v][u] * image->data.F32[y + v][x + u];
    415                   }
     404                  // Photometric scaling is already built in to the precalculated kernel
    416405              }
    417406          }
    418           return polyValue * sum - sub;
     407          return sum;
    419408      }
    420409      case PM_SUBTRACTION_KERNEL_RINGS: {
    421410          if (index == kernels->subIndex) {
    422               return image->data.F32[0][0];
     411              return image->data.F32[y][x];
    423412          }
    424413          psArray *preCalc = kernels->preCalc->data[index]; // Precalculated data
     
    432421              sum += image->data.F32[y + v][x + u] * poly->data.F32[j];
    433422          }
    434           sum /= (double)num;           // Normalising sum of kernel component to unity
    435423          // The (0,0) kernel is subtracted from other kernels to preserve photometric scaling
    436           return polyValue * sum - image->data.F32[0][0];
     424          return sum - num * image->data.F32[y][x];
    437425      }
    438426      default:
     
    592580    PS_ASSERT_PTR_NON_NULL(kernels, false);
    593581    PS_ASSERT_VECTORS_SIZE_EQUAL(kernels->u, kernels->v, false);
    594     PS_ASSERT_VECTORS_SIZE_EQUAL(kernels->u, kernels->xOrder, false);
    595     PS_ASSERT_VECTORS_SIZE_EQUAL(kernels->u, kernels->yOrder, false);
    596582    if (weight) {
    597583        PS_ASSERT_IMAGE_NON_NULL(weight, false);
     
    599585        PS_ASSERT_IMAGE_TYPE(weight, PS_TYPE_F32, false);
    600586    }
    601     if (kernels->type == PM_SUBTRACTION_KERNEL_ISIS) {
    602         PS_ASSERT_VECTORS_SIZE_EQUAL(kernels->u, kernels->preCalc, false);
    603     }
    604587    PS_ASSERT_INT_NONNEGATIVE(footprint, false);
    605588
     
    609592
    610593    int spatialOrder = kernels->spatialOrder; // Maximum order of spatial variation
    611     int numKernels = kernels->u->n;     // Number of kernel basis functions
    612     int numParams = numKernels + 1;     // Total number of parameters to solve for: coefficient of each kernel
    613                                         // basis function, and a constant background offset.
    614     int bgIndex = numKernels;           // Index in matrix for the background
    615     psVector *convolutions = psVectorAlloc(numKernels, PS_TYPE_F64); // Convolutions for each kernel
     594    int numKernels = kernels->num;      // Number of kernel basis functions
     595    int numSpatial = polyTerms(spatialOrder); // Number of spatial variations
     596    int numBackground = polyTerms(kernels->bgOrder); // Number of background terms
     597
     598    // Total number of parameters to solve for: coefficient of each kernel basis function, multipled by the
     599    // number of coefficients for the spatial polynomial, and a constant background offset.
     600    int numParams = numKernels * numSpatial + numBackground;
     601    int bgIndex = numParams - numBackground; // Index in matrix for the background
     602    psVector *convolutions = psVectorAlloc(numKernels * numSpatial, PS_TYPE_F64); // Convolutions
    616603
    617604    // We iterate over each stamp, allocate the matrix and vectors if
     
    637624            psVectorInit(stampVector, 0.0);
    638625
    639             // Pre-evaluated spatial polynomial values
    640             psImage *polyValues = spatialPolyValues(spatialOrder,
    641                                                     2.0 * (float)(stamp->x - numCols/2.0) / (float)numCols,
    642                                                     2.0 * (float)(stamp->y - numRows/2.0) / (float)numRows);
     626            float xNorm = 2.0 * (float)(stamp->x - numCols/2.0) / (float)numCols; // Normalised x coord
     627            float yNorm = 2.0 * (float)(stamp->y - numRows/2.0) / (float)numRows; // Normalised y coord
     628            psImage *polyValues = spatialPolyValues(spatialOrder, xNorm, yNorm); // Spatial polynomial terms
    643629
    644630            for (int y = stamp->y - footprint; y <= stamp->y + footprint; y++) {
     
    648634
    649635                    // Generate the convolutions
    650                     for (int i = 0; i < numKernels; i++) {
    651                         convolutions->data.F64[i] = convolvePixel(kernels, i, x, y, reference, polyValues);
     636                    for (int j = 0; j < numKernels; j++) {
     637                        double value = convolvePixel(kernels, j, x, y, reference); // Value from convolution
     638                        // Generate the pseudo-convolutions from the spatial polynomial terms
     639                        for (int yOrder = 0, index = j; yOrder <= spatialOrder; yOrder++) {
     640                            for (int xOrder = 0; xOrder <= spatialOrder - yOrder;
     641                                 xOrder++, index += numKernels) {
     642                                convolutions->data.F64[index] = value * polyValues->data.F64[yOrder][xOrder];
     643                            }
     644                        }
    652645                    }
    653646
    654647                    // Generate the least-squares matrix and vector
    655648                    // Upper diagonal only
    656                     for (int i = 0; i < numKernels; i++) {
    657                         for (int j = i; j < numKernels; j++) {
     649                    for (int i = 0; i < bgIndex; i++) {
     650                        for (int j = i; j < bgIndex; j++) {
    658651                            stampMatrix->data.F64[i][j] += convolutions->data.F64[i] *
    659652                                convolutions->data.F64[j] * invNoise2;
     
    674667            // Fill in lower diagonal of symmetric matrix, while checking for bad values
    675668            bool bad = false;           // Are there bad values?
    676             for (int i = 0; i < numKernels; i++) {
     669            for (int i = 0; i < bgIndex; i++) {
    677670                for (int j = 0; j < i; j++) {
    678671                    stampMatrix->data.F64[i][j] = stampMatrix->data.F64[j][i];
     
    694687            if (bad) {
    695688                stamp->status = PM_SUBTRACTION_STAMP_REJECTED;
    696                 psTrace("psModules.imcombine", 3, "Rejecting stamp %d because of bad equation\n", i);
     689                psTrace("psModules.imcombine", 3, "Rejecting stamp %d (%d,%d) because of bad equation\n",
     690                        i, stamp->x, stamp->y);
    697691            } else {
    698692                stamp->status = PM_SUBTRACTION_STAMP_USED;
     
    807801    PS_ASSERT_VECTOR_TYPE(solution, PS_TYPE_F64, -1);
    808802    PS_ASSERT_PTR_NON_NULL(kernels, -1);
    809     PS_ASSERT_VECTOR_SIZE(kernels->u, solution->n - 1, -1);
     803    PS_ASSERT_VECTOR_SIZE(solution, kernels->num * polyTerms(kernels->spatialOrder) +
     804                          polyTerms(kernels->bgOrder), -1);
     805    PS_ASSERT_VECTOR_SIZE(kernels->u, kernels->num, -1);
    810806    PS_ASSERT_VECTORS_SIZE_EQUAL(kernels->u, kernels->v, -1);
    811     PS_ASSERT_VECTORS_SIZE_EQUAL(kernels->u, kernels->xOrder, -1);
    812     PS_ASSERT_VECTORS_SIZE_EQUAL(kernels->u, kernels->yOrder, -1);
    813     if (kernels->type == PM_SUBTRACTION_KERNEL_ISIS) {
    814         PS_ASSERT_ARRAY_NON_EMPTY(kernels->preCalc, -1);
    815         PS_ASSERT_ARRAY_SIZE(kernels->preCalc, solution->n - 1, -1);
    816     }
    817807
    818808    // Measure deviations
     
    836826            int xStamp = stamp->x, yStamp = stamp->y; // Coordinates of stamp
    837827
    838             // Precalulate polynomial values
    839             psImage *polyValues = spatialPolyValues(kernels->spatialOrder,
    840                                                     2.0 * (float)(stamp->x - numCols/2.0) / (float)numCols,
    841                                                     2.0 * (float)(stamp->y - numRows/2.0) / (float)numRows);
     828            float xNorm = 2.0 * (float)(stamp->x - numCols/2.0) / (float)numCols; // Normalised x coord
     829            float yNorm = 2.0 * (float)(stamp->y - numRows/2.0) / (float)numRows; // Normalised y coord
     830            psImage *polyValues = spatialPolyValues(kernels->spatialOrder, xNorm, yNorm); // Polynomial terms
    842831
    843832#ifdef USE_FUNCTIONS_INSTEAD_OF_MACROS
     
    878867            }
    879868            deviations->data.F32[i] = sqrt(stats->sampleMean / 2.0);
    880             psTrace("psModules.imcombine", 1, "Deviation for stamp %d: %f\n", i, deviations->data.F32[i]);
     869            psTrace("psModules.imcombine", 1, "Deviation for stamp %d (%d,%d): %f\n",
     870                    i, stamp->x, stamp->y, deviations->data.F32[i]);
    881871            totalSquareDev += PS_SQR(deviations->data.F32[i]);
    882872            numStamps++;
     
    896886        if (stamp->status == PM_SUBTRACTION_STAMP_USED && deviations->data.F32[i] > limit) {
    897887            // Mask out the stamp in the image so you it's not found again
    898             psTrace("psModules.imcombine", 3, "Rejecting stamp %d\n", i);
     888            psTrace("psModules.imcombine", 3, "Rejecting stamp %d (%d,%d)\n", i, stamp->x, stamp->y);
    899889            numRejected++;
    900890            for (int y = stamp->y - footprint; y <= stamp->y + footprint; y++) {
     
    922912    PS_ASSERT_VECTOR_NON_NULL(solution, NULL);
    923913    PS_ASSERT_PTR_NON_NULL(kernels, NULL);
     914    PS_ASSERT_VECTOR_SIZE(solution, kernels->num * polyTerms(kernels->spatialOrder) +
     915                          polyTerms(kernels->bgOrder), NULL);
    924916    PS_ASSERT_FLOAT_WITHIN_RANGE(x, -1.0, 1.0, NULL);
    925917    PS_ASSERT_FLOAT_WITHIN_RANGE(y, -1.0, 1.0, NULL);
    926     PS_ASSERT_VECTOR_SIZE(kernels->u, solution->n - 1, false);
     918    PS_ASSERT_VECTOR_SIZE(kernels->u, kernels->num, false);
    927919    PS_ASSERT_VECTORS_SIZE_EQUAL(kernels->u, kernels->v, NULL);
    928     PS_ASSERT_VECTORS_SIZE_EQUAL(kernels->u, kernels->xOrder, NULL);
    929     PS_ASSERT_VECTORS_SIZE_EQUAL(kernels->u, kernels->yOrder, NULL);
    930     if (kernels->type == PM_SUBTRACTION_KERNEL_ISIS) {
    931         PS_ASSERT_ARRAY_NON_NULL(kernels->preCalc, NULL);
    932         PS_ASSERT_ARRAY_SIZE(kernels->preCalc, solution->n - 1, NULL);
    933     }
    934920
    935921    // Precalulate polynomial values
     
    958944    PS_ASSERT_VECTOR_NON_NULL(solution, NULL);
    959945    PS_ASSERT_PTR_NON_NULL(kernels, NULL);
     946    PS_ASSERT_VECTOR_SIZE(solution, kernels->num * polyTerms(kernels->spatialOrder) +
     947                          polyTerms(kernels->bgOrder), NULL);
    960948    PS_ASSERT_FLOAT_WITHIN_RANGE(x, -1.0, 1.0, NULL);
    961949    PS_ASSERT_FLOAT_WITHIN_RANGE(y, -1.0, 1.0, NULL);
    962     PS_ASSERT_VECTOR_SIZE(kernels->u, solution->n - 1, false);
     950    PS_ASSERT_VECTOR_SIZE(kernels->u, kernels->num, false);
    963951    PS_ASSERT_VECTORS_SIZE_EQUAL(kernels->u, kernels->v, NULL);
    964     PS_ASSERT_VECTORS_SIZE_EQUAL(kernels->u, kernels->xOrder, NULL);
    965     PS_ASSERT_VECTORS_SIZE_EQUAL(kernels->u, kernels->yOrder, NULL);
    966     if (kernels->type == PM_SUBTRACTION_KERNEL_ISIS) {
    967         PS_ASSERT_ARRAY_NON_NULL(kernels->preCalc, NULL);
    968         PS_ASSERT_ARRAY_SIZE(kernels->preCalc, solution->n - 1, NULL);
    969     }
    970952
    971953    psArray *images = psArrayAlloc(solution->n - 1); // Images of each kernel to return
     
    987969bool pmSubtractionConvolve(psImage **outImage, psImage **outWeight, psImage **outMask,
    988970                           const psImage *inImage, const psImage *inWeight, const psImage *subMask,
    989                            psMaskType blank, const psVector *solution, const pmSubtractionKernels *kernels)
     971                           psMaskType blank, const psRegion *region, const psVector *solution,
     972                           const pmSubtractionKernels *kernels)
    990973{
    991974    PS_ASSERT_IMAGE_NON_NULL(inImage, false);
     
    10221005    PS_ASSERT_VECTOR_TYPE(solution, PS_TYPE_F64, false);
    10231006    PS_ASSERT_PTR_NON_NULL(kernels, false);
    1024     PS_ASSERT_VECTOR_SIZE(kernels->u, solution->n - 1, false);
     1007    PS_ASSERT_VECTOR_SIZE(solution, kernels->num * polyTerms(kernels->spatialOrder) +
     1008                          polyTerms(kernels->bgOrder), -1);
     1009    PS_ASSERT_VECTOR_SIZE(kernels->u, kernels->num, false);
    10251010    PS_ASSERT_VECTORS_SIZE_EQUAL(kernels->u, kernels->v, false);
    1026     PS_ASSERT_VECTORS_SIZE_EQUAL(kernels->u, kernels->xOrder, false);
    1027     PS_ASSERT_VECTORS_SIZE_EQUAL(kernels->u, kernels->yOrder, false);
    1028     if (kernels->type == PM_SUBTRACTION_KERNEL_ISIS) {
    1029         PS_ASSERT_ARRAY_NON_NULL(kernels->preCalc, false);
    1030         PS_ASSERT_ARRAY_SIZE(kernels->preCalc, solution->n - 1, false);
    1031     }
    1032 
    1033     int size = kernels->size;           // Half-size of kernel
     1011    if (region) {
     1012        if (psRegionIsNaN(*region)) {
     1013            psString string = psRegionToString(*region);
     1014            psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Input region (%s) contains NAN values", string);
     1015            psFree(string);
     1016            return false;
     1017        }
     1018        if (region->x0 < 0 || region->x1 > inImage->numCols ||
     1019            region->y0 < 0 || region->y1 > inImage->numRows) {
     1020            psString string = psRegionToString(*region);
     1021            psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Input region (%s) does not fit in image (%dx%d)",
     1022                    string, inImage->numCols, inImage->numRows);
     1023            psFree(string);
     1024            return false;
     1025        }
     1026    }
     1027
    10341028    float background = solution->data.F64[solution->n-1]; // The difference in background
    10351029    int numCols = inImage->numCols, numRows = inImage->numRows; // Image dimensions
     
    10571051    }
    10581052
     1053    int size = kernels->size;           // Half-size of kernel
     1054    int fullSize = 2 * size + 1;        // Full size of kernel
    10591055    psImage *polyValues = NULL;         // Pre-calculated polynomial values
    1060     int fullSize = 2 * size + 1;        // Full size of kernel
    10611056
    10621057    psKernel *kernelImage = NULL;       // Kernel for the image
    10631058    psKernel *kernelWeight = NULL;      // Kernel for the weight map
    10641059
    1065     for (int j = size; j < inImage->numRows - size; j += fullSize) {
    1066         for (int i = size; i < inImage->numCols - size; i += fullSize) {
     1060    // Get region for convolution: [xMin:xMax,yMin:yMax]
     1061    int xMin = size, xMax = numCols - size;
     1062    int yMin = size, yMax = numRows - size;
     1063    if (region) {
     1064        xMin = PS_MAX(region->x0, xMin);
     1065        xMax = PS_MIN(region->x1, xMax);
     1066        yMin = PS_MAX(region->y0, yMin);
     1067        yMax = PS_MIN(region->y1, yMax);
     1068    }
     1069
     1070    for (int j = yMin; j < yMax; j += fullSize) {
     1071        for (int i = xMin; i < xMax; i += fullSize) {
    10671072
    10681073            // Only generate polynomial values every kernel footprint, since we have already assumed
     
    10851090#endif
    10861091
    1087             for (int y = j; y < PS_MIN(j + fullSize, numRows - size); y++) {
    1088                 for (int x = i; x < PS_MIN(i + fullSize, numCols - size); x++) {
     1092            for (int y = j; y < PS_MIN(j + fullSize, yMax); y++) {
     1093                for (int x = i; x < PS_MIN(i + fullSize, xMax); x++) {
    10891094                    // Check and propagate the kernel footprint, if required
    10901095                    if (subMask && (subMask->data.PS_TYPE_MASK_DATA[y][x] &
     
    11231128    psFree(polyValues);
    11241129
    1125     // Mark the non-convolved part as blank
    1126     for (int y = size; y < inImage->numRows - size; y++) {
     1130    return true;
     1131}
     1132
     1133bool pmSubtractionBorder(psImage *image, psImage *weight, psImage *mask,
     1134                         const pmSubtractionKernels *kernels, psMaskType blank)
     1135{
     1136    PS_ASSERT_IMAGE_NON_NULL(image, false);
     1137    PS_ASSERT_IMAGE_TYPE(image, PS_TYPE_F32, false);
     1138    if (mask) {
     1139        PS_ASSERT_IMAGE_NON_NULL(mask, false);
     1140        PS_ASSERT_IMAGES_SIZE_EQUAL(mask, image, false);
     1141        PS_ASSERT_IMAGE_TYPE(mask, PS_TYPE_MASK, false);
     1142    }
     1143    if (weight) {
     1144        PS_ASSERT_IMAGE_NON_NULL(weight, false);
     1145        PS_ASSERT_IMAGES_SIZE_EQUAL(weight, image, false);
     1146        PS_ASSERT_IMAGE_TYPE(weight, PS_TYPE_F32, false);
     1147    }
     1148
     1149    int numCols = image->numCols, numRows = image->numRows; // Image dimensions
     1150
     1151    int size = kernels->size;           // Half-size of kernel
     1152    for (int y = size; y < numRows - size; y++) {
    11271153        for (int x = 0; x < size; x++) {
    1128             markBlank(convImage, convMask, convWeight, x, y, blank);
     1154            markBlank(image, mask, weight, x, y, blank);
    11291155        }
    11301156        for (int x = numCols - size; x < numCols; x++) {
    1131             markBlank(convImage, convMask, convWeight, x, y, blank);
     1157            markBlank(image, mask, weight, x, y, blank);
    11321158        }
    11331159    }
    11341160    for (int y = 0; y < size; y++) {
    11351161        for (int x = 0; x < numCols; x++) {
    1136             markBlank(convImage, convMask, convWeight, x, y, blank);
     1162            markBlank(image, mask, weight, x, y, blank);
    11371163        }
    11381164    }
    11391165    for (int y = numRows - size; y < numRows; y++) {
    11401166        for (int x = 0; x < numCols; x++) {
    1141             markBlank(convImage, convMask, convWeight, x, y, blank);
     1167            markBlank(image, mask, weight, x, y, blank);
    11421168        }
    11431169    }
Note: See TracChangeset for help on using the changeset viewer.