IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 14106


Ignore:
Timestamp:
Jul 10, 2007, 1:54:26 PM (19 years ago)
Author:
Paul Price
Message:

Adding additional convolution kernels: SPAM (binned pixels around a central single-pixel core) and FRIES (binning changes as a (Fibonacci-like) function of radius).

Location:
trunk/psModules/src/imcombine
Files:
6 edited

Legend:

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

    r13736 r14106  
    44 *  @author GLG, MHPCC
    55 *
    6  *  @version $Revision: 1.14 $ $Name: not supported by cvs2svn $
    7  *  @date $Date: 2007-06-09 01:06:48 $
     6 *  @version $Revision: 1.15 $ $Name: not supported by cvs2svn $
     7 *  @date $Date: 2007-07-10 23:54:26 $
    88 *
    99 *  Copyright 2004-2007 Institute for Astronomy, University of Hawaii
     
    2424
    2525#include "pmSubtraction.h"
     26
     27//#define CAN_PASS_STATIC_INLINE          // Can I pass the address of a static inline function?
    2628
    2729//////////////////////////////////////////////////////////////////////////////////////////////////////////////
     
    5355}
    5456
     57#ifndef CAN_PASS_STATIC_INLINE
    5558// Generate an image of the solved kernel
    5659// Meant to replace the following function declaration:
     
    6164//                                      double (*weightFunc)(double value) // Function for weighting
    6265//     );
    63 // because even if the weightFunc can't be "static inline", they still appear in the assembly.
     66// because even though the weightFunc is "static inline", it still appears in the assembly.
    6467// TARGET: Kernel, to return (psKernel*)
    6568// SOLUTION: Solution to the least-squares problem (psVector*)
     
    7578    \
    7679    /* Ensure the subIndex for POIS kernels is what is expected */ \
    77     assert((KERNELS)->type != PM_SUBTRACTION_KERNEL_POIS || \
     80    assert(((KERNELS)->type != PM_SUBTRACTION_KERNEL_POIS && \
     81           (KERNELS)->type != PM_SUBTRACTION_KERNEL_SPAM && \
     82           (KERNELS)->type != PM_SUBTRACTION_KERNEL_FRIES) || \
    7883           ((KERNELS)->u->data.S32[(KERNELS)->subIndex] == 0 && \
    7984            (KERNELS)->v->data.S32[(KERNELS)->subIndex] == 0 && \
     
    103108              break; \
    104109          } \
     110          /* SPAM and FRIES use the same method */ \
     111          case PM_SUBTRACTION_KERNEL_SPAM: \
     112          case PM_SUBTRACTION_KERNEL_FRIES: { \
     113            int uStart = (KERNELS)->u->data.S32[i]; \
     114            int uStop = (KERNELS)->uStop->data.S32[i]; \
     115            int vStart = (KERNELS)->v->data.S32[i]; \
     116            int vStop = (KERNELS)->vStop->data.S32[i]; \
     117            for (int v = vStart; v <= vStop; v++) { \
     118                for (int u = uStart; u <= uStop; u++) { \
     119                    (TARGET)->kernel[v][u] += value; \
     120                } \
     121            } \
     122            if ((KERNELS)->spatialOrder > 0 && i != (KERNELS)->subIndex) { \
     123                /* The (0,0) element is subtracted from most kernels to preserve photometric scaling */ \
     124                (TARGET)->kernel[0][0] += subValue; \
     125            } \
     126            break; \
     127          } \
    105128          case PM_SUBTRACTION_KERNEL_ISIS: { \
    106129              psKernel *preCalc = (KERNELS)->preCalc->data[i]; /* Precalculated values */ \
     
    122145    } \
    123146}
    124 
    125 #if 0
     147#else
    126148// Generate an image of the solved kernel
    127149static inline psKernel *solvedKernel(psKernel *kernel, // Kernel, to return
     
    139161
    140162    // Ensure the subIndex for POIS kernels is what is expected
    141     assert(kernels->type != PM_SUBTRACTION_KERNEL_POIS ||
     163    assert((kernels->type != PM_SUBTRACTION_KERNEL_POIS &&
     164            kernels->type != PM_SUBTRACTION_KERNEL_SPAM &&
     165            kernels->type != PM_SUBTRACTION_KERNEL_FRIES) ||
    142166           (kernels->u->data.S32[kernels->subIndex] == 0 && kernels->v->data.S32[kernels->subIndex] == 0 &&
    143167            kernels->xOrder->data.S32[kernels->subIndex] == 0 &&
     
    167191              break;
    168192          }
     193          /* SPAM and FRIES use the same method */
     194          case PM_SUBTRACTION_KERNEL_SPAM:
     195          case PM_SUBTRACTION_KERNEL_FRIES:
     196            int uStart = kernels->u->data.S32[i];
     197            int uStop = kernels->uStop->data.S32[i];
     198            int vStart = kernels->v->data.S32[i];
     199            int vStop = kernels->vStop->data.S32[i];
     200            for (int v = vStart; v <= vStop; v++) {
     201                for (int u = uStart; u <= uStop; u++) {
     202                    kernel->kernel[v][u] += value;
     203                }
     204            }
     205            if (kernels->spatialOrder > 0 && i != kernels->subIndex) {
     206                /* The (0,0) element is subtracted from most kernels to preserve photometric scaling */
     207                kernel->kernel[0][0] += subValue;
     208            }
     209            break;
    169210          case PM_SUBTRACTION_KERNEL_ISIS: {
    170211              psKernel *preCalc = kernels->preCalc->data[i];// Precalculated values
     
    190231#endif
    191232
     233#ifndef CAN_PASS_STATIC_INLINE
    192234// Generate the convolved pixel value
    193235// Meant to replace the following function declaration:
     
    199241//                                    double (*weightFunc)(double value) // Function for weighting
    200242//     );
    201 // because even if the weightFunc can't be "static inline", they still appear in the assembly.
     243// because even though weightFunc is "static inline", it still appears in the assembly.
    202244//
    203245// TARGET: The value to 'return' (double)
     
    225267          break; \
    226268      } \
    227       case PM_SUBTRACTION_KERNEL_ISIS: { \
     269      /* Method for SPAM and FRIES is the same */ \
     270      case PM_SUBTRACTION_KERNEL_SPAM: \
     271      case PM_SUBTRACTION_KERNEL_FRIES: { \
     272          int uStart = (KERNELS)->u->data.S32[(INDEX)]; \
     273          int uStop = (KERNELS)->uStop->data.S32[(INDEX)]; \
     274          int vStart = (KERNELS)->v->data.S32[(INDEX)]; \
     275          int vStop = (KERNELS)->vStop->data.S32[(INDEX)]; \
     276          for (int v = vStart; v <= vStop; v++) { \
     277              for (int u = uStart; u <= uStop; u++) { \
     278                  (TARGET) += FUNC(polyValue) * (IMAGE)->data.F32[(Y) + v][(X) + u]; \
     279              } \
     280          } \
     281          if ((KERNELS)->spatialOrder > 0 && (INDEX) != (KERNELS)->subIndex) { \
     282              /* The (0,0) element is subtracted from most kernels to preserve photometric scaling */ \
     283              (TARGET) += FUNC(-1.0) * (IMAGE)->data.F32[(Y)][(X)]; \
     284          } \
     285          break; \
     286      } \
     287            case PM_SUBTRACTION_KERNEL_ISIS: { \
    228288          psKernel *kernel = (KERNELS)->preCalc->data[(INDEX)]; /* The convolution kernel */ \
    229289          psKernel *subKernel = (KERNELS)->preCalc->data[(KERNELS)->subIndex]; /* Kernel to subtract */ \
     
    231291          double sum = 0.0;             /* Accumulated sum from convolution */ \
    232292          double sub = 0.0;             /* Accumulated sum to subtract */ \
    233           for (int v = -size; v <= size; v++) { \
    234               for (int u = -size; u <= size; u++) { \
    235                   sum += FUNC(kernel->kernel[v][u]) * (IMAGE)->data.F32[(Y) + v][(X) + u]; \
     293          for (int v = -size, y = (Y) - size; v <= size; v++, y++) { \
     294              for (int u = -size, x = (X) - size; u <= size; u++, x++) { \
     295                  sum += FUNC(kernel->kernel[v][u]) * (IMAGE)->data.F32[y][x]; \
    236296                  /* The (0,0) kernel is subtracted from other kernels to preserve photometric scaling */ \
    237297                  if ((KERNELS)->spatialOrder > 0 && (INDEX) != (KERNELS)->subIndex) { \
    238                       sub += FUNC(subKernel->kernel[v][u]) * (IMAGE)->data.F32[(Y) + v][(X) + u]; \
     298                      sub += FUNC(subKernel->kernel[v][u]) * (IMAGE)->data.F32[y][x]; \
    239299                  } \
    240300              } \
     
    247307    } \
    248308}
    249 
    250 #if 0
     309#else
    251310// Generate the convolved pixel value
    252311static inline double convolvePixel(const pmSubtractionKernels *kernels, // Kernel basis functions
     
    273332          }
    274333          return value;
     334      }
     335      /* Method for SPAM and FRIES is the same */
     336      case PM_SUBTRACTION_KERNEL_SPAM:
     337      case PM_SUBTRACTION_KERNEL_FRIES: {
     338          int uStart = kernels->u->data.S32[index];
     339          int uStop = kernels->uStop->data.S32[index];
     340          int vStart = kernels->v->data.S32[index];
     341          int vStop = kernels->vStop->data.S32[index];
     342          for (int v = vStart; v <= vStop; v++) {
     343              for (int u = uStart; u <= uStop; u++) {
     344                  value += weightFunc(polyValue) * image->data.F32[y + v][x + u];
     345              }
     346          }
     347          if (kernels->spatialOrder > 0 && index != kernels->subIndex) {
     348              /* The (0,0) element is subtracted from most kernels to preserve photometric scaling */
     349              value += weightFunc(-1.0) * image->data.F32[y][x];
     350          }
     351          break;
    275352      }
    276353      case PM_SUBTRACTION_KERNEL_ISIS: {
     
    333410//////////////////////////////////////////////////////////////////////////////////////////////////////////////
    334411
    335 psImage *pmSubtractionMask(const psImage *inMask, const psImage *refMask, psMaskType maskVal,
    336                            int size, int footprint)
    337 {
    338     PS_ASSERT_IMAGE_NON_NULL(inMask, NULL);
    339     PS_ASSERT_IMAGE_TYPE(inMask, PS_TYPE_MASK, NULL);
    340     PS_ASSERT_IMAGE_NON_NULL(refMask, NULL);
    341     PS_ASSERT_IMAGE_TYPE(refMask, PS_TYPE_MASK, NULL);
    342     PS_ASSERT_IMAGES_SIZE_EQUAL(inMask, refMask, NULL);
    343     PS_ASSERT_INT_NONNEGATIVE(size, NULL);
    344     PS_ASSERT_INT_NONNEGATIVE(footprint, NULL);
    345 
    346     // Size of the images
    347     int numCols = inMask->numCols;
    348     int numRows = inMask->numRows;
    349 
    350     // Worried about the masks for bad pixels and bad stamps colliding, so make our own mask
    351     psImage *mask = psImageAlloc(numCols, numRows, PS_TYPE_MASK); // The global mask
    352     psImageInit(mask, 0);
    353 
    354     // Dereference for convenience
    355     psMaskType **maskData = mask->data.PS_TYPE_MASK_DATA;
    356     psMaskType **inData = inMask->data.PS_TYPE_MASK_DATA;
    357     psMaskType **refData = refMask->data.PS_TYPE_MASK_DATA;
    358 
    359     // Block out a border around the edge of the image
    360 
    361     // Bottom stripe
    362     for (int y = 0; y < PS_MIN(size + footprint, numRows); y++) {
    363         for (int x = 0; x < numCols; x++) {
    364             maskData[y][x] |= PM_SUBTRACTION_MASK_BORDER;
    365         }
    366     }
    367     // Either side
    368     for (int y = PS_MIN(size + footprint, numRows); y < numRows - size - footprint; y++) {
    369         for (int x = 0; x < PS_MIN(size + footprint, numCols); x++) {
    370             maskData[y][x] |= PM_SUBTRACTION_MASK_BORDER;
    371         }
    372         for (int x = PS_MAX(numCols - size - footprint, 0); x < numCols; x++) {
    373             maskData[y][x] |= PM_SUBTRACTION_MASK_BORDER;
    374         }
    375     }
    376     // Top stripe
    377     for (int y = PS_MAX(numRows - size - footprint, 0); y < numRows; y++) {
    378         for (int x = 0; x < numCols; x++) {
    379             maskData[y][x] |= PM_SUBTRACTION_MASK_BORDER;
    380         }
    381     }
    382 
    383     // Mask the bad pixels, and around them
    384     for (int y = footprint + size; y < numRows - footprint - size; y++) {
    385         for (int x = 0; x < numCols; x++) {
    386             if (inData[y][x] & maskVal) {
    387                 maskData[y][x] |= PM_SUBTRACTION_MASK_INPUT;
    388                 // Block out the entire stamp footprint around this pixel
    389                 for (int v = y - footprint; v <= y + footprint; v++) {
    390                     for (int u = x - footprint; u <= x + footprint; u++) {
    391                         maskData[v][u] |= PM_SUBTRACTION_MASK_FOOTPRINT;
    392                     }
    393                 }
    394             }
    395             if (refData[y][x] & maskVal) {
    396                 maskData[y][x] |= PM_SUBTRACTION_MASK_REF;
    397 
    398                 // We want to block out with the CONVOLVE mask anything that would be bad if we convolved with
    399                 // this bad pixel (within 'size').  Then we want to block out with the FOOTPRINT mask
    400                 // everything within a footprint's distance of those (within 'footprint').
    401 
    402                 // Bottom stripe
    403                 for (int v = PS_MAX(y - footprint - size, 0); v < y - size; v++) {
    404                     for (int u = PS_MAX(x - footprint - size, 0);
    405                          u <= PS_MIN(x + footprint + size, numCols - 1); u++) {
    406                         maskData[v][u] |= PM_SUBTRACTION_MASK_FOOTPRINT;
    407                     }
    408                 }
    409                 // Middle
    410                 for (int v = PS_MAX(y - size, 0); v <= PS_MIN(y + size, numRows - 1); v++) {
    411                     // Left side
    412                     for (int u = PS_MAX(x - footprint - size, 0); u < x - size; u++) {
    413                         maskData[v][u] |= PM_SUBTRACTION_MASK_FOOTPRINT;
    414                     }
    415                     // Centre
    416                     for (int u = PS_MAX(x - size, 0); u <= PS_MIN(x + size, numCols - 1); u++) {
    417                         maskData[v][u] |= PM_SUBTRACTION_MASK_FOOTPRINT | PM_SUBTRACTION_MASK_CONVOLVE;
    418                     }
    419                     // Right side
    420                     for (int u = x + size + 1; u <= PS_MIN(x + footprint + size, numCols - 1); u++) {
    421                         maskData[v][u] |= PM_SUBTRACTION_MASK_FOOTPRINT;
    422                     }
    423                 }
    424                 // Top stripe
    425                 for (int v = y + size + 1; v <= PS_MIN(y + footprint + size, numRows - 1); v++) {
    426                     for (int u = PS_MAX(x - footprint - size, 0);
    427                          u <= PS_MIN(x + footprint + size, numCols - 1); u++) {
    428                         maskData[v][u] |= PM_SUBTRACTION_MASK_FOOTPRINT;
    429                     }
    430                 }
    431             }
    432         }
    433     }
    434 
    435     return mask;
    436 }
    437 
    438412bool pmSubtractionCalculateEquation(psArray *stamps, const psImage *reference, const psImage *input,
    439413                                    const psImage *weight, const pmSubtractionKernels *kernels, int footprint)
     
    504478                    // Generate the convolutions
    505479                    for (int i = 0; i < numKernels; i++) {
    506 #if 0
     480#ifdef CAN_PASS_STATIC_INLINE
    507481                        convolutions->data.F64[i] = convolvePixel(kernels, i, x, y, reference, polyValues,
    508482                                                                  imageWeighting);
     
    533507            psFree(polyValues);
    534508
    535             // Fill in lower diagonal of symmetric matrix, while checking for bad values
    536             bool bad = false;           // Are there bad values?
     509            // Fill in lower diagonal of symmetric matrix
    537510            for (int i = 0; i < numKernels; i++) {
    538511                for (int j = 0; j < i; j++) {
    539                     if (!isfinite(stampMatrix->data.F64[j][i])) {
    540                         bad = true;
    541                     }
    542512                    stampMatrix->data.F64[i][j] = stampMatrix->data.F64[j][i];
    543513                }
    544                 if (!isfinite(stampMatrix->data.F64[i][bgIndex]) ||
    545                     !isfinite(stampMatrix->data.F64[i][i]) ||
    546                     !isfinite(stampVector->data.F64[i])) {
    547                     bad = true;
    548                 }
    549514                stampMatrix->data.F64[bgIndex][i] = stampMatrix->data.F64[i][bgIndex];
    550515            }
    551             if (!isfinite(stampVector->data.F64[bgIndex])) {
    552                 bad = true;
    553             }
    554 
    555             if (bad) {
    556                 stamp->status = PM_SUBTRACTION_STAMP_REJECTED;
    557                 psTrace("psModules.imcombine", 3, "Rejecting stamp %d because of bad equation\n", i);
    558             } else {
    559                 stamp->status = PM_SUBTRACTION_STAMP_USED;
    560             }
     516
     517            stamp->status = PM_SUBTRACTION_STAMP_USED;
    561518
    562519            if (psTraceGetLevel("psModules.imcombine.equation") >= 10) {
     
    653610
    654611int pmSubtractionRejectStamps(psArray *stamps, const psImage *refImage, psImage *inImage,
    655                               psImage *subMask, const psVector *solution, int footprint, float sigmaRej,
    656                               const pmSubtractionKernels *kernels)
     612                              psImage *mask, psMaskType badStampMaskVal, const psVector *solution,
     613                              int footprint, float sigmaRej, const pmSubtractionKernels *kernels)
    657614{
    658615    PS_ASSERT_ARRAY_NON_NULL(stamps, -1);
     
    662619    PS_ASSERT_IMAGE_TYPE(inImage, PS_TYPE_F32, -1);
    663620    PS_ASSERT_IMAGES_SIZE_EQUAL(refImage, inImage, -1);
    664     PS_ASSERT_IMAGE_NON_EMPTY(subMask, -1);
    665     PS_ASSERT_IMAGE_TYPE(subMask, PS_TYPE_MASK, -1);
    666     PS_ASSERT_IMAGES_SIZE_EQUAL(refImage, subMask, -1);
     621    PS_ASSERT_IMAGE_NON_EMPTY(mask, -1);
     622    PS_ASSERT_IMAGE_TYPE(mask, PS_TYPE_MASK, -1);
     623    PS_ASSERT_IMAGES_SIZE_EQUAL(refImage, mask, -1);
    667624    PS_ASSERT_VECTOR_NON_NULL(solution, -1);
    668625    PS_ASSERT_VECTOR_TYPE(solution, PS_TYPE_F64, -1);
     
    707664                for (int x = footprint; x <= footprint; x++) {
    708665                    for (int k = 0; k < numKernels; k++) {
    709 #if 0
     666#ifdef CAN_PASS_STATIC_INLINE
    710667                        convolvedStamp->data.F32[y + footprint][x + footprint] +=
    711668                            convolvePixel(kernels, k, xStamp + x, yStamp + y, refImage, polyValues,
     
    753710        if (stamp->status == PM_SUBTRACTION_STAMP_USED && deviations->data.F32[i] > limit) {
    754711            // Mask out the stamp in the image so you it's not found again
    755             psTrace("psModules.imcombine", 3, "Clipping stamp %d\n", i);
     712            psTrace("psModules.imcombine", 3, "Rejecting stamp %d\n", i);
    756713            numRejected++;
    757714            for (int y = stamp->y - footprint; y <= stamp->y + footprint; y++) {
    758715                for (int x = stamp->x - footprint; x <= stamp->x + footprint; x++) {
    759                     subMask->data.PS_TYPE_MASK_DATA[y][x] |= PM_SUBTRACTION_MASK_REJ;
     716                    mask->data.PS_TYPE_MASK_DATA[y][x] |= badStampMaskVal;
    760717                }
    761718            }
     
    794751
    795752    // The appropriate kernel
    796 #if 0
     753#ifdef CAN_PASS_STATIC_INLINE
    797754    psKernel *kernel = solvedKernel(NULL, solution, kernels, polyValues, imageWeighting);
    798755#else
     
    810767
    811768bool pmSubtractionConvolve(psImage **outImage, psImage **outWeight, psImage **outMask,
    812                            const psImage *inImage, const psImage *inWeight, const psImage *subMask,
    813                            psMaskType blank, const psVector *solution, const pmSubtractionKernels *kernels)
     769                           const psImage *inImage, const psImage *inWeight, const psImage *inMask,
     770                           psMaskType maskVal, psMaskType blank,
     771                           const psVector *solution, const pmSubtractionKernels *kernels)
    814772{
    815773    PS_ASSERT_IMAGE_NON_NULL(inImage, false);
    816774    PS_ASSERT_IMAGE_TYPE(inImage, PS_TYPE_F32, false);
    817     if (subMask) {
    818         PS_ASSERT_IMAGE_NON_NULL(subMask, false);
    819         PS_ASSERT_IMAGE_TYPE(subMask, PS_TYPE_MASK, false);
    820         PS_ASSERT_IMAGES_SIZE_EQUAL(subMask, inImage, false);
     775    if (inMask) {
     776        PS_ASSERT_IMAGE_NON_NULL(inMask, false);
     777        PS_ASSERT_IMAGE_TYPE(inMask, PS_TYPE_MASK, false);
     778        PS_ASSERT_IMAGES_SIZE_EQUAL(inMask, inImage, false);
    821779    }
    822780    if (inWeight) {
     
    835793        PS_ASSERT_IMAGES_SIZE_EQUAL(*outMask, inImage, false);
    836794        PS_ASSERT_IMAGE_TYPE(*outMask, PS_TYPE_MASK, false);
    837         PS_ASSERT_IMAGE_NON_NULL(subMask, false);
     795        PS_ASSERT_IMAGE_NON_NULL(inMask, false);
    838796    }
    839797    if (outWeight && *outWeight) {
     
    865823    }
    866824    psImage *convMask = NULL;           // Convolved mask image
    867     if (outMask && subMask) {
     825    if (outMask && inMask) {
    868826        if (!*outMask) {
    869827            *outMask = psImageAlloc(numCols, numRows, PS_TYPE_MASK);
     
    896854                                           2.0 * (float)(i + size - numCols/2.0) / (float)numCols,
    897855                                           2.0 * (float)(j + size - numRows/2.0) / (float)numRows);
    898 #if 0
     856#ifdef CAN_PASS_STATIC_INLINE
    899857            kernelImage = solvedKernel(kernelImage, solution, kernels, polyValues, imageWeighting);
    900858            if (inWeight) {
     
    914872
    915873                    // Check and propagate the kernel footprint, if required
    916                     if (subMask && (subMask->data.PS_TYPE_MASK_DATA[y][x] &
    917                                     (PM_SUBTRACTION_MASK_INPUT | PM_SUBTRACTION_MASK_CONVOLVE))) {
    918                         convMask->data.PS_TYPE_MASK_DATA[y][x] |= blank;
    919                         convImage->data.F32[y][x] = NAN;
    920                         if (inWeight) {
    921                             convWeight->data.F32[y][x] = NAN;
     874                    if (inMask) {
     875                        for (int v = -size; v <= size; v++) {
     876                            for (int u = -size; u <= size; u++) {
     877                                convMask->data.PS_TYPE_MASK_DATA[y][x] |=
     878                                    inMask->data.PS_TYPE_MASK_DATA[y + v][x + u];
     879                            }
    922880                        }
    923                         continue;
     881                        if (convMask->data.PS_TYPE_MASK_DATA[y][x] & maskVal) {
     882                            convImage->data.F32[y][x] = NAN;
     883                            if (inWeight) {
     884                                convWeight->data.F32[y][x] = NAN;
     885                            }
     886                            continue;
     887                        }
    924888                    }
    925889
  • trunk/psModules/src/imcombine/pmSubtraction.h

    r13735 r14106  
    66 * @author GLG, MHPCC
    77 *
    8  * @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
    9  * @date $Date: 2007-06-09 01:04:02 $
     8 * @version $Revision: 1.3 $ $Name: not supported by cvs2svn $
     9 * @date $Date: 2007-07-10 23:54:26 $
    1010 * Copyright 2004-207 Institute for Astronomy, University of Hawaii
    1111 */
     
    1919/// @addtogroup imcombine Image Combinations
    2020/// @{
    21 
    22 typedef enum {
    23     PM_SUBTRACTION_MASK_CLEAR     = 0x00, // No masking
    24     PM_SUBTRACTION_MASK_REF       = 0x01, // Reference image is bad
    25     PM_SUBTRACTION_MASK_INPUT     = 0x02, // Input image is bad
    26     PM_SUBTRACTION_MASK_CONVOLVE  = 0x04, // If convolved, would be bad
    27     PM_SUBTRACTION_MASK_FOOTPRINT = 0x08, // Bad pixel within the stamp footprint
    28     PM_SUBTRACTION_MASK_BORDER    = 0x10, // Image border
    29     PM_SUBTRACTION_MASK_REJ       = 0x20, // Previously tried as a stamp, and rejected
    30 } pmSubtractionMasks;
    31 
    32 /// Generate a mask for use in the subtraction process
    33 psImage *pmSubtractionMask(const psImage *inMask, ///< Mask for the input image
    34                            const psImage *refMask, ///< Mask for the reference image (will be convolved)
    35                            psMaskType maskVal, ///< Value to mask out
    36                            int size, ///< Half-size of the kernel (pmSubtractionKernels.size)
    37                            int footprint ///< Half-size of the kernel footprint
    38     );
    3921
    4022/// Calculate the least-squares equation to match the image quality
     
    5638                              const psImage *refImage, ///< Reference image
    5739                              psImage *inImage, ///< Input image
    58                               psImage *subMask, ///< Subtraction mask
     40                              psImage *mask, ///< Mask image
     41                              psMaskType badStampMaskVal, ///< Value to use in mask for bad stamp
    5942                              const psVector *solution, ///< Solution vector
    6043                              int footprint, ///< Region to mask if stamp is bad
     
    7558                           const psImage *inImage, ///< Input image
    7659                           const psImage *inWeight, ///< Input weight map (or NULL)
    77                            const psImage *subMask, ///< Subtraction mask (or NULL)
     60                           const psImage *inMask, ///< Input mask (or NULL)
     61                           psMaskType maskVal, ///< Value to mask
    7862                           psMaskType blank, ///< Mask value for blank regions
    7963                           const psVector *solution, ///< The solution vector
  • trunk/psModules/src/imcombine/pmSubtractionKernels.c

    r13390 r14106  
    1515    psFree(kernels->v);
    1616    psFree(kernels->sigma);
     17    psFree(kernels->uStop);
     18    psFree(kernels->vStop);
    1719    psFree(kernels->xOrder);
    1820    psFree(kernels->yOrder);
     
    4850    kernels->u = psVectorAlloc(numBasisFunctions, PS_TYPE_S32);
    4951    kernels->v = psVectorAlloc(numBasisFunctions, PS_TYPE_S32);
     52    kernels->sigma = NULL;
     53    kernels->uStop = NULL;
     54    kernels->vStop = NULL;
    5055    kernels->xOrder = psVectorAlloc(numBasisFunctions, PS_TYPE_S32);
    5156    kernels->yOrder = psVectorAlloc(numBasisFunctions, PS_TYPE_S32);
    52     kernels->sigma = NULL;
    5357    kernels->subIndex = 0;
    5458    kernels->preCalc = NULL;
     
    187191}
    188192
     193/// Generate SPAM kernels
     194pmSubtractionKernels *pmSubtractionKernelsSPAM(int size, ///< Half-size of the kernel
     195                                               int spatialOrder, ///< Order of spatial variations
     196                                               int inner, ///< Inner radius to preserve unbinned
     197                                               int binning ///< Kernel binning factor
     198    )
     199{
     200    PS_ASSERT_INT_POSITIVE(size, NULL);
     201    PS_ASSERT_INT_NONNEGATIVE(spatialOrder, NULL);
     202    PS_ASSERT_INT_NONNEGATIVE(inner, NULL);
     203    PS_ASSERT_INT_LARGER_THAN(size, inner, NULL);
     204    PS_ASSERT_INT_POSITIVE(binning, NULL);
     205
     206    // The outer region should be divisible by the "binning"; otherwise allocate remainder to the inner region
     207    int numOuter = (size - inner) / binning; // Number of summed pixels in the outer region
     208    int numInner = inner + (size - inner) % binning; // Number of pixels in the inner region
     209    assert(numOuter * binning + numInner == size);
     210    int numTotal = numOuter + numInner; // Total number of summed pixels
     211
     212    psTrace("psModules.imcombine", 3, "Inner: %d Outer: %d\n", numInner, numOuter);
     213
     214    int num = PS_SQR(2 * numTotal + 1) *
     215        (spatialOrder + 1) * (spatialOrder + 2) / 2; // Number of basis functions
     216
     217    psTrace("psModules.imcombine", 3, "Number of basis functions: %d\n", num);
     218
     219    pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_SPAM,
     220                                                              size, spatialOrder); // The kernels
     221
     222    kernels->uStop = psVectorAlloc(num, PS_TYPE_F32);
     223    kernels->vStop = psVectorAlloc(num, PS_TYPE_F32);
     224
     225    psVector *locations = psVectorAlloc(2 * numTotal + 1, PS_TYPE_S32); // Locations for each kernel element
     226    psVector *widths = psVectorAlloc(2 * numTotal + 1, PS_TYPE_S32); // Widths for each kernel element
     227    locations->data.S32[numTotal] = 0;
     228    widths->data.S32[numTotal] = 0;
     229    for (int i = 1; i <= numInner; i++) {
     230        locations->data.S32[numTotal + i] = i;
     231        widths->data.S32[numTotal + i] = 0;
     232        locations->data.S32[numTotal - i] = - i;
     233        widths->data.S32[numTotal - i] = 0;
     234    }
     235    for (int i = numInner + 1; i <= numTotal; i++) {
     236        locations->data.S32[numTotal + i] = locations->data.S32[numTotal + i - 1] +
     237            widths->data.S32[numTotal + i - 1] + 1;
     238        widths->data.S32[numTotal + i] = binning - 1;
     239        locations->data.S32[numTotal - i] = locations->data.S32[numTotal - i + 1] -
     240            widths->data.S32[numTotal - i + 1] - binning;
     241        widths->data.S32[numTotal - i] = binning - 1;
     242    }
     243
     244    if (psTraceGetLevel("psModules.imcombine") >= 10) {
     245        for (int i = 0; i < 2 * numTotal + 1; i++) {
     246            psTrace("psModules.imcombine", 10, "%d: %d -> %d\n", i, locations->data.S32[i],
     247                    locations->data.S32[i] + widths->data.S32[i]);
     248        }
     249    }
     250
     251    // Set the kernel parameters
     252    for (int i = - numTotal, index = 0; i <= numTotal; i++) {
     253        int u = locations->data.S32[numTotal + i]; // Location of pixel
     254        int uStop = u + widths->data.S32[numTotal + i]; // Width of pixel
     255
     256        for (int j = - numTotal; j <= numTotal; j++) {
     257            int v = locations->data.S32[numTotal + j]; // Location of pixel
     258            int vStop = v + widths->data.S32[numTotal + j]; // Width of pixel
     259
     260            // Iterate over spatial order.  This loop creates the terms for
     261            // x^xOrder * y^yOrder  such that (xOrder+yOrder) <= spatialOrder.
     262            for (int xOrder = 0; xOrder <= spatialOrder; xOrder++) {
     263                for (int yOrder = 0; yOrder <= spatialOrder - xOrder; yOrder++, index++) {
     264                    kernels->u->data.S32[index] = u;
     265                    kernels->v->data.S32[index] = v;
     266                    kernels->uStop->data.S32[index] = uStop;
     267                    kernels->vStop->data.S32[index] = vStop;
     268                    kernels->xOrder->data.S32[index] = xOrder;
     269                    kernels->yOrder->data.S32[index] = yOrder;
     270
     271                    psTrace("psModules.imcombine", 7, "Kernel %d: %d %d %d %d %d %d\n", index,
     272                            u, uStop, v, vStop, xOrder, yOrder);
     273                }
     274            }
     275        }
     276    }
     277
     278    kernels->subIndex = (num - (spatialOrder + 1) * (spatialOrder + 2) / 2) / 2;
     279    assert(kernels->u->data.S32[kernels->subIndex] == 0 &&
     280           kernels->v->data.S32[kernels->subIndex] == 0 &&
     281           kernels->uStop->data.S32[kernels->subIndex] == 0 &&
     282           kernels->vStop->data.S32[kernels->subIndex] == 0 &&
     283           kernels->xOrder->data.S32[kernels->subIndex] == 0 &&
     284           kernels->yOrder->data.S32[kernels->subIndex] == 0);
     285
     286    psFree(locations);
     287    psFree(widths);
     288
     289    return kernels;
     290}
     291
     292
     293/// Generate FRIES kernels
     294pmSubtractionKernels *pmSubtractionKernelsFRIES(int size, ///< Half-size of the kernel
     295                                                int spatialOrder, ///< Order of spatial variations
     296                                                int inner ///< Inner radius to preserve unbinned
     297    )
     298{
     299    PS_ASSERT_INT_POSITIVE(size, NULL);
     300    PS_ASSERT_INT_NONNEGATIVE(spatialOrder, NULL);
     301    PS_ASSERT_INT_NONNEGATIVE(inner, NULL);
     302    PS_ASSERT_INT_LARGER_THAN(size, inner, NULL);
     303
     304    int fibNum = 0;                     // Number of Fibonacci values
     305    int fibLast = 1, fibTotal = 2;      // Fibonacci sequence
     306    while (fibTotal < size - inner) {
     307        int temp = fibTotal;
     308        fibTotal += fibLast;
     309        fibLast = temp;
     310        fibNum++;
     311    }
     312
     313    int numInner = inner;               // Number of pixels in the inner region
     314    int numOuter = fibNum;              // Number of summed pixels in the outer region
     315    int numTotal = numOuter + numInner; // Total number of summed pixels
     316
     317    psTrace("psModules.imcombine", 3, "Inner: %d Outer: %d\n", numInner, numOuter);
     318
     319    int num = PS_SQR(2 * numTotal + 1) *
     320        (spatialOrder + 1) * (spatialOrder + 2) / 2; // Number of basis functions
     321
     322    psTrace("psModules.imcombine", 3, "Number of basis functions: %d\n", num);
     323
     324    pmSubtractionKernels *kernels = pmSubtractionKernelsAlloc(num, PM_SUBTRACTION_KERNEL_SPAM,
     325                                                              size, spatialOrder); // The kernels
     326    kernels->uStop = psVectorAlloc(num, PS_TYPE_F32);
     327    kernels->vStop = psVectorAlloc(num, PS_TYPE_F32);
     328
     329    psVector *start = psVectorAlloc(2 * numTotal + 1, PS_TYPE_S32);
     330    psVector *stop = psVectorAlloc(2 * numTotal + 1, PS_TYPE_S32);
     331    start->data.S32[numTotal] = 0;
     332    stop->data.S32[numTotal] = 0;
     333    for (int i = 1; i <= numInner; i++) {
     334        start->data.S32[numTotal + i] = i;
     335        stop->data.S32[numTotal + i] = i;
     336        start->data.S32[numTotal - i] = -i;
     337        stop->data.S32[numTotal - i] = -i;
     338    }
     339    for (int i = numInner + 1, fibLast = 1, fib = 2, temp; i <= numTotal;
     340         i++, fib = (temp = fib) + fibLast, fibLast = temp) {
     341        start->data.S32[numTotal + i] = stop->data.S32[numTotal + i - 1] + 1;
     342        stop->data.S32[numTotal + i] = PS_MIN(start->data.S32[numTotal + i] + fib - 1, size);
     343        start->data.S32[numTotal - i] = - stop->data.S32[numTotal + i];
     344        stop->data.S32[numTotal - i] = - start->data.S32[numTotal + i];
     345    }
     346
     347    if (psTraceGetLevel("psModules.imcombine") >= 10) {
     348        for (int i = 0; i < 2 * numTotal + 1; i++) {
     349            psTrace("psModules.imcombine", 10, "%d: %d -> %d\n", i, start->data.S32[i], stop->data.S32[i]);
     350        }
     351    }
     352
     353    // Set the kernel parameters
     354    for (int i = - numTotal, index = 0; i <= numTotal; i++) {
     355        int u = start->data.S32[numTotal + i]; // Location of pixel
     356        int uStop = stop->data.S32[numTotal + i]; // Width of pixel
     357        for (int j = - numTotal; j <= numTotal; j++) {
     358            int v = start->data.S32[numTotal + j]; // Location of pixel
     359            int vStop = stop->data.S32[numTotal + j]; // Width of pixel
     360
     361            // Iterate over spatial order.  This loop creates the terms for
     362            // x^xOrder * y^yOrder  such that (xOrder+yOrder) <= spatialOrder.
     363            for (int xOrder = 0; xOrder <= spatialOrder; xOrder++) {
     364                for (int yOrder = 0; yOrder <= spatialOrder - xOrder; yOrder++, index++) {
     365                    kernels->u->data.S32[index] = u;
     366                    kernels->v->data.S32[index] = v;
     367                    kernels->uStop->data.S32[index] = uStop;
     368                    kernels->vStop->data.S32[index] = vStop;
     369                    kernels->xOrder->data.S32[index] = xOrder;
     370                    kernels->yOrder->data.S32[index] = yOrder;
     371
     372                    psTrace("psModules.imcombine", 7, "Kernel %d: %d %d %d %d %d %d\n", index,
     373                            u, uStop, v, vStop, xOrder, yOrder);
     374                }
     375            }
     376        }
     377    }
     378
     379    kernels->subIndex = (num - (spatialOrder + 1) * (spatialOrder + 2) / 2) / 2;
     380    assert(kernels->u->data.S32[kernels->subIndex] == 0 &&
     381           kernels->v->data.S32[kernels->subIndex] == 0 &&
     382           kernels->uStop->data.S32[kernels->subIndex] == 0 &&
     383           kernels->vStop->data.S32[kernels->subIndex] == 0 &&
     384           kernels->xOrder->data.S32[kernels->subIndex] == 0 &&
     385           kernels->yOrder->data.S32[kernels->subIndex] == 0);
     386
     387    psFree(start);
     388    psFree(stop);
     389
     390    return kernels;
     391}
     392
     393
    189394pmSubtractionKernels *pmSubtractionKernelsGenerate(pmSubtractionKernelsType type, int size, int spatialOrder,
    190                                                    const psVector *sigmas, const psVector *orders)
     395                                                   const psVector *sigmas, const psVector *orders, int inner,
     396                                                   int binning)
    191397{
    192398    switch (type) {
     
    195401      case PM_SUBTRACTION_KERNEL_ISIS:
    196402        return pmSubtractionKernelsISIS(size, spatialOrder, sigmas, orders);
     403      case PM_SUBTRACTION_KERNEL_SPAM:
     404        return pmSubtractionKernelsSPAM(size, spatialOrder, inner, binning);
     405      case PM_SUBTRACTION_KERNEL_FRIES:
     406        return pmSubtractionKernelsFRIES(size, spatialOrder, inner);
    197407      default:
    198408        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Unknown kernel type: %x", type);
  • trunk/psModules/src/imcombine/pmSubtractionKernels.h

    r13340 r14106  
    66/// Type of subtraction kernel
    77typedef enum {
    8     PM_SUBTRACTION_KERNEL_POIS,         ///< POIS kernel --- delta functions
    9     PM_SUBTRACTION_KERNEL_ISIS          ///< ISIS kernel --- gaussians modified by polynomials
     8    PM_SUBTRACTION_KERNEL_POIS,         ///< Pan-STARRS Optimal Image Subtraction --- delta functions
     9    PM_SUBTRACTION_KERNEL_ISIS,         ///< Traditional kernel --- gaussians modified by polynomials
     10    PM_SUBTRACTION_KERNEL_SPAM,         ///< Summed Pixels for Advanced Matching --- summed delta functions
     11    PM_SUBTRACTION_KERNEL_FRIES,        ///< Fibonacci Radius Increases Excellence of Subtraction
    1012} pmSubtractionKernelsType;
    1113
    1214/// Kernels specification
    1315typedef struct {
    14     pmSubtractionKernelsType type;       ///< Type of kernels --- allowing the use of multiple kernels
     16    pmSubtractionKernelsType type;      ///< Type of kernels --- allowing the use of multiple kernels
    1517    psVector *u, *v;                    ///< Offset (for POIS) or polynomial order (for ISIS)
    16     psVector *sigma;                    ///< Width of Gaussian (for ISIS)
     18    psVector *sigma;                    ///< Gaussian widths (ISIS only)
     19    psVector *uStop, *vStop;            ///< Width of kernel element (SPAM,FRIES only)
    1720    psVector *xOrder, *yOrder;          ///< Spatial Polynomial order (for all)
    1821    int subIndex;                       ///< Index of kernel to be subtracted (to maintain flux conservation)
     
    4447                                               );
    4548
     49/// Generate SPAM kernels
     50pmSubtractionKernels *pmSubtractionKernelsSPAM(int size, ///< Half-size of the kernel
     51                                               int spatialOrder, ///< Order of spatial variations
     52                                               int inner, ///< Inner radius to preserve unbinned
     53                                               int binning ///< Kernel binning factor
     54    );
     55
     56/// Generate FRIES kernels
     57pmSubtractionKernels *pmSubtractionKernelsFRIES(int size, ///< Half-size of the kernel
     58                                                int spatialOrder, ///< Order of spatial variations
     59                                                int inner ///< Inner radius to preserve unbinned
     60    );
     61
    4662/// Generate a kernel of a specified type
    4763pmSubtractionKernels *pmSubtractionKernelsGenerate(pmSubtractionKernelsType type, ///< Kernel type
     
    4965                                                   int spatialOrder, ///< Order of spatial variations
    5066                                                   const psVector *sigmas, ///< Gaussian widths
    51                                                    const psVector *orders ///< Polynomial order of gaussians
    52                                                    );
     67                                                   const psVector *orders, ///< Polynomial order of gaussians
     68                                                   int inner, ///< Inner radius to preserve unbinned
     69                                                   int binning ///< Kernel binning factor
     70    );
    5371
    5472#endif
  • trunk/psModules/src/imcombine/pmSubtractionStamps.c

    r13735 r14106  
    66#include <pslib.h>
    77
    8 #include "pmSubtraction.h"
    98#include "pmSubtractionStamps.h"
    109
     
    4039}
    4140
    42 psArray *pmSubtractionFindStamps(psArray *stamps, const psImage *image, const psImage *subMask,
    43                                  float threshold, float spacing)
     41
     42psArray *pmSubtractionFindStamps(psArray *stamps, const psImage *image, const psImage *mask,
     43                                 psMaskType maskVal, psMaskType used, float threshold,
     44                                 float spacing, int border)
    4445{
    4546    PS_ASSERT_IMAGE_NON_NULL(image, NULL);
    4647    PS_ASSERT_IMAGE_TYPE(image, PS_TYPE_F32, NULL);
    47     if (subMask) {
    48         PS_ASSERT_IMAGE_NON_NULL(subMask, NULL);
    49         PS_ASSERT_IMAGES_SIZE_EQUAL(image, subMask, NULL);
    50         PS_ASSERT_IMAGE_TYPE(subMask, PS_TYPE_MASK, NULL);
     48    if (mask) {
     49        PS_ASSERT_IMAGE_NON_NULL(mask, NULL);
     50        PS_ASSERT_IMAGES_SIZE_EQUAL(image, mask, NULL);
     51        PS_ASSERT_IMAGE_TYPE(mask, PS_TYPE_MASK, NULL);
     52    }
     53    if (used == 0) {
     54        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "The mask value for used stamps cannot be zero.");
     55        return NULL;
    5156    }
    5257    PS_ASSERT_FLOAT_LARGER_THAN(spacing, 0.0, NULL);
     58    PS_ASSERT_INT_NONNEGATIVE(border, NULL);
     59    PS_ASSERT_INT_LARGER_THAN(image->numCols, 2 * border, NULL);
     60    PS_ASSERT_INT_LARGER_THAN(image->numRows, 2 * border, NULL);
    5361
    54     // Size of image
    55     int numRows = image->numRows;
    56     int numCols = image->numCols;
    57 
    58     // Number of stamps
    59     int xNumStamps = numCols / spacing + 1;
    60     int yNumStamps = numRows / spacing + 1;
     62    maskVal |= used;                    // Make sure we don't get stamps we've already used
     63    int xNumStamps = (image->numCols - 2 * border) / spacing + 1; // Number of stamps in x
     64    int yNumStamps = (image->numRows - 2 * border) / spacing + 1; // Number of stamps in y
    6165
    6266    if (stamps) {
     
    7478        }
    7579    }
     80    // Footprint of image
     81    int numRows = image->numRows;
     82    int numCols = image->numCols;
    7683
    7784    for (int j = 0, index = 0; j < yNumStamps; j++) {
     
    8996
    9097                // Bounds of region to search for stamp
    91                 int yMin = j * numRows / (yNumStamps + 1);
    92                 int yMax = (j + 1) * numRows / (yNumStamps + 1) - 1;
    93                 int xMin = i * numCols / (xNumStamps + 1);
    94                 int xMax = (i + 1) * numCols / (xNumStamps + 1) - 1;
    95                 assert(yMax < image->numRows && xMax < image->numCols &&
    96                        yMin >= 0 && xMin >= 0);
     98                int yMin = border + j * (numRows - border) / (yNumStamps + 1);
     99                int yMax = border + (j + 1) * (numRows - border) / (yNumStamps + 1) - 1;
     100                int xMin = border + i * (numCols - border) / (xNumStamps + 1);
     101                int xMax = border + (i + 1) * (numCols - border) / (xNumStamps + 1) - 1;
     102                assert(yMax < image->numRows - border && xMax < image->numCols - border &&
     103                       yMin >= border && xMin >= border);
    97104
    98105                for (int y = yMin; y <= yMax ; y++) {
    99106                    for (int x = xMin; x <= xMax ; x++) {
    100                         if ((!subMask || !(subMask->data.PS_TYPE_MASK_DATA[y][x] &
    101                                            (PM_SUBTRACTION_MASK_BORDER | PM_SUBTRACTION_MASK_FOOTPRINT |
    102                                             PM_SUBTRACTION_MASK_REJ))) &&
    103                             image->data.F32[y][x] > fluxBest) {
    104                             fluxBest = image->data.F32[y][x];
    105                             xBest = x;
    106                             yBest = y;
     107                        if (image->data.F32[y][x] > fluxBest) {
     108                            bool ok = true;
     109                            if (mask) {
     110                                // Check kernel footprint for bad pixels
     111                                if (mask->data.PS_TYPE_MASK_DATA[y][x] & maskVal) {
     112                                    ok = false;
     113                                } else {
     114                                    for (int v = -border; v <= border && ok; v++) {
     115                                        for (int u = -border; u <= border && ok; u++) {
     116                                            if (mask->data.PS_TYPE_MASK_DATA[y + v][x + u] & maskVal) {
     117                                                ok = false;
     118#if 0
     119                                                // Mark it so we don't have to look so hard next time
     120                                                mask->data.PS_TYPE_MASK_DATA[y][x] |= maskVal;
     121#endif
     122                                            }
     123                                        }
     124                                    }
     125                                }
     126                            }
     127
     128                            if (ok) {
     129                                fluxBest = image->data.F32[y][x];
     130                                xBest = x;
     131                                yBest = y;
     132                            }
    107133                        }
    108134                    }
  • trunk/psModules/src/imcombine/pmSubtractionStamps.h

    r13735 r14106  
    33
    44#include <pslib.h>
     5
    56
    67/// Status of stamp
     
    2526                                 const psImage *image, ///< Image for which to find stamps
    2627                                 const psImage *mask, ///< Mask
     28                                 psMaskType maskVal, ///< Value for mask
     29                                 psMaskType bad, ///< Mask value for bad stamps
    2730                                 float threshold, ///< Threshold for stamps in the image
    28                                  float spacing ///< Rough spacing for stamps
     31                                 float spacing, ///< Rough spacing for stamps
     32                                 int border ///< Size of border around image; no stamps in border
    2933    );
    3034
Note: See TracChangeset for help on using the changeset viewer.