IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 19765


Ignore:
Timestamp:
Sep 26, 2008, 4:03:24 PM (18 years ago)
Author:
Paul Price
Message:

Two major changes. 1. Optimising ISIS kernels: instead of doing an FFT convolution, they're separable. 2. Trying to make the convolved weight map account for systematic errors in the convolution kernel by assuming a relative error in each kernel pixel (currently hardwired with a #define, but we can turn it into a recipe value later, or get an estimate from the data) and propagating that into the variance map. The effect is to increase the variance near the bright stars, which is hopefully sufficient to decrease the number of false sources detected in bad subtractions.

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

Legend:

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

    r19540 r19765  
    3030#define MIN_SAMPLE_STATS    7           // Minimum number to use sample statistics; otherwise use quartiles
    3131
     32#define SYS_ERROR 0.05                  // Relative error in derived convolution kernel pixels
    3233
    3334//////////////////////////////////////////////////////////////////////////////////////////////////////////////
     
    135136          }
    136137          case PM_SUBTRACTION_KERNEL_ISIS: {
    137               psKernel *preCalc = kernels->preCalc->data[i]; // Precalculated values
     138              psArray *preCalc = kernels->preCalc->data[i]; // Precalculated values
     139              psVector *xKernel = preCalc->data[0]; // Kernel in x
     140              psVector *yKernel = preCalc->data[1]; // Kernel in y
    138141              // Iterating over the kernel
    139               for (int v = -size; v <= size; v++) {
    140                   for (int u = -size; u <= size; u++) {
    141                       kernel->kernel[v][u] += preCalc->kernel[v][u] * value;
    142                       // Photometric scaling is built into the preCalc kernel --- no subtraction!
     142              for (int y = 0, v = -size; v <= size; y++, v++) {
     143                  for (int x = 0, u = -size; u <= size; x++, u++) {
     144                      kernel->kernel[v][u] +=  value * xKernel->data.F32[x] * yKernel->data.F32[y];
    143145                  }
     146              }
     147              // Photometric scaling for even kernels only
     148              if (kernels->u->data.S32[i] % 2 == 0 && kernels->v->data.S32[i] % 2 == 0) {
     149                  kernel->kernel[0][0] -= value;
    144150              }
    145151              break;
     
    200206}
    201207
     208// Take a subset of an image
     209static inline psImage *convolveSubsetAlloc(psImage *image, // Image to be convolved
     210                                           psRegion region, // Region of interest (with border)
     211                                           bool threaded // Are we running threaded?
     212                                           )
     213{
     214    if (!image) {
     215        return NULL;
     216    }
     217    if (threaded) {
     218        psMutexLock(image);
     219    }
     220    psImage *subset = psImageSubset(image, region); // Subset image, to return
     221    if (threaded) {
     222        psMutexUnlock(image);
     223    }
     224    return subset;
     225}
     226
     227// Free the subset of an image
     228static inline void convolveSubsetFree(psImage *parent, // Parent image
     229                                      psImage *child, // Child (subset) image
     230                                      bool threaded // Are we running threaded?
     231                                      )
     232{
     233    if (!child || !parent) {
     234        return;
     235    }
     236    if (threaded) {
     237        psMutexLock(parent);
     238    }
     239    psFree(child);
     240    if (threaded) {
     241        psMutexUnlock(parent);
     242    }
     243    return;
     244}
    202245
    203246// Convolve an image using FFT
     
    217260    bool threaded = pmSubtractionThreaded(); // Are we running threaded?
    218261
    219     if (threaded) {
    220         psMutexLock(image);
    221     }
    222     psImage *subImage = psImageSubset(image, border); // Subimage to convolve
    223     if (threaded) {
    224         psMutexUnlock(image);
    225     }
    226 
    227     psImage *subMask;                   // Subimage mask
    228     if (mask) {
    229         if (threaded) {
    230             psMutexLock(mask);
    231         }
    232         subMask = psImageSubset(mask, border);
    233         if (threaded) {
    234             psMutexUnlock(mask);
    235         }
    236     } else {
    237         subMask = NULL;
    238     }
     262    psImage *subImage = convolveSubsetAlloc(image, border, threaded); // Subimage to convolve
     263    psImage *subMask = convolveSubsetAlloc(mask, border, threaded); // Subimage mask
    239264
    240265    psImage *convolved = psImageConvolveFFT(NULL, subImage, subMask, maskVal, kernel); // Convolution
    241266
    242     if (threaded) {
    243         psMutexLock(image);
    244     }
    245     psFree(subImage);
    246     if (threaded) {
    247         psMutexUnlock(image);
    248     }
    249 
    250     if (mask) {
    251         if (threaded) {
    252             psMutexLock(mask);
    253         }
    254         psFree(subMask);
    255         if (threaded) {
    256             psMutexUnlock(mask);
    257         }
    258     }
     267    convolveSubsetFree(image, subImage, threaded);
     268    convolveSubsetFree(mask, subMask, threaded);
    259269
    260270    // Now, we have to stick it in where it belongs
     
    276286    return;
    277287}
     288
     289
     290// Convolve an image using FFT
     291static void convolveWeightFFT(psImage *target,// Place the result in here
     292                              psImage *weight, // Weight map to convolve
     293                              psImage *sys, // Systematic error image
     294                              psImage *mask, // Mask image
     295                              psMaskType maskVal, // Value to mask
     296                              const psKernel *kernel, // Kernel by which to convolve
     297                              psRegion region,// Region of interest
     298                              int size        // Size of (square) kernel
     299                              )
     300{
     301    psRegion border = psRegionSet(region.x0 - size, region.x1 + size,
     302                                  region.y0 - size, region.y1 + size); // Add a border
     303
     304    bool threaded = pmSubtractionThreaded(); // Are we running threaded?
     305
     306    psImage *subWeight = convolveSubsetAlloc(weight, border, threaded); // Weight map
     307    psImage *subSys = convolveSubsetAlloc(sys, border, threaded); // Systematic error image
     308    psImage *subMask = convolveSubsetAlloc(mask, border, threaded); // Mask
     309
     310    // XXX Can trim this a little by combining the convolution: only have to take the FFT of the kernel once
     311    psImage *convWeight = psImageConvolveFFT(NULL, subWeight, subMask, maskVal, kernel); // Convolved weight
     312    psImage *convSys = subSys ? psImageConvolveFFT(NULL, subSys, subMask, maskVal, kernel) : NULL; // Conv sys
     313
     314    convolveSubsetFree(weight, subWeight, threaded);
     315    convolveSubsetFree(sys, subSys, threaded);
     316    convolveSubsetFree(mask, subMask, threaded);
     317
     318    // Now, we have to stick it in where it belongs
     319    int xMin = region.x0, xMax = region.x1, yMin = region.y0, yMax = region.y1; // Bounds of region
     320    if (convSys) {
     321        for (int yTarget = yMin, ySource = size; yTarget < yMax; yTarget++, ySource++) {
     322            for (int xTarget = xMin, xSource = size; xTarget < xMax; xTarget++, xSource++) {
     323                target->data.F32[yTarget][xTarget] = convWeight->data.F32[ySource][xSource] +
     324                    convSys->data.F32[ySource][xSource];
     325            }
     326        }
     327    } else {
     328        int numBytes = (xMax - xMin) * PSELEMTYPE_SIZEOF(PS_TYPE_F32); // Number of bytes to copy
     329        for (int yTarget = yMin, ySource = size; yTarget < yMax; yTarget++, ySource++) {
     330            memcpy(&target->data.F32[yTarget][xMin], &convWeight->data.F32[ySource][size], numBytes);
     331        }
     332    }
     333
     334    psFree(convWeight);
     335    psFree(convSys);
     336
     337    return;
     338}
     339
    278340
    279341// Convolve an image directly
     
    307369                                  psImage *image, // Image to convolve
    308370                                  psImage *weight, // Weight map to convolve, or NULL
     371                                  psImage *sys, // Systematic error image, or NULL
    309372                                  psImage *subMask, // Subtraction mask
    310373                                  const pmSubtractionKernels *kernels, // Kernels
     
    343406        convolveFFT(convImage, image, subMask, subBad, *kernelImage, region, background, kernels->size);
    344407        if (weight) {
    345             convolveFFT(convWeight, weight, subMask, subBad, *kernelWeight, region, 0.0, kernels->size);
     408            convolveWeightFFT(convWeight, weight, sys, subMask, subBad, *kernelWeight, region, kernels->size);
    346409        }
    347410    } else {
     
    361424            bool threaded = pmSubtractionThreaded(); // Are we running threaded?
    362425
    363             if (threaded) {
    364                 psMutexLock(subMask);
    365             }
    366             psImage *image = psImageSubset(subMask, psRegionSet(colMin - box, colMax + box,
    367                                                                 rowMin - box, rowMax + box)); // Mask
    368             if (threaded) {
    369                 psMutexUnlock(subMask);
    370             }
     426            psRegion region = psRegionSet(colMin - box, colMax + box,
     427                                          rowMin - box, rowMax + box); // Region to convolve
     428
     429            psImage *image = convolveSubsetAlloc(subMask, region, threaded); // Mask to convolve
    371430
    372431            psImage *convolved = psImageConvolveMask(NULL, image, subBad, subConvBad,
    373432                                                     -box, box, -box, box); // Convolved subtraction mask
    374433
    375             if (threaded) {
    376                 psMutexLock(subMask);
    377             }
    378             psFree(image);
    379             if (threaded) {
    380                 psMutexUnlock(subMask);
    381             }
     434            convolveSubsetFree(subMask, image, threaded);
    382435
    383436            psAssert(convolved->numCols - 2 * box == colMax - colMin, "Bad number of columns");
     
    405458}
    406459
    407 
     460// Generate an image that can be used to track systematic errors
     461static psImage *subtractionSysErrImage(const psImage *image     // Image from which to make sys err image
     462                                       )
     463{
     464    int numCols = image->numCols, numRows = image->numRows; // Size of image
     465    psImage *sys = psImageAlloc(numCols, numRows, PS_TYPE_F32); // Systematic error image
     466
     467    for (int y = 0; y < numRows; y++) {
     468        for (int x = 0; x < numCols; x++) {
     469            sys->data.F32[y][x] = PS_SQR(image->data.F32[y][x]) * PS_SQR(SYS_ERROR);
     470        }
     471    }
     472
     473    return sys;
     474}
    408475
    409476//////////////////////////////////////////////////////////////////////////////////////////////////////////////
     
    575642      }
    576643      case PM_SUBTRACTION_KERNEL_ISIS: {
     644          psArray *preCalc = kernels->preCalc->data[index]; // Precalculated values
     645          psVector *xKernel = preCalc->data[0]; // Kernel in x
     646          psVector *yKernel = preCalc->data[1]; // Kernel in y
     647          int size = kernels->size;     // Size of kernel
     648
     649          // Convolve in x
     650          // Need to convolve a bit more than the footprint, for the y convolution
     651          int yMin = -size - footprint, yMax = size + footprint; // Range for y
     652          psKernel *temp = psKernelAlloc(yMin, yMax,
     653                                         -footprint, footprint); // Temporary convolution; NOTE: wrong way!
     654          for (int y = yMin; y <= yMax; y++) {
     655              for (int x = -footprint; x <= footprint; x++) {
     656                  float value = 0.0;    // Value of convolved pixel
     657                  int uMin = x - size, uMax = x + size; // Range for u
     658                  psF32 *xKernelData = xKernel->data.F32; // Kernel values
     659                  psF32 *imageData = &image->kernel[y][uMin]; // Image values
     660                  for (int u = uMin; u <= uMax; u++, xKernelData++, imageData++) {
     661                      value += *xKernelData * *imageData;
     662                  }
     663                  temp->kernel[x][y] = value; // NOTE: putting in wrong way!
     664              }
     665          }
     666
     667          // Convolve in y
     668          psKernel *convolved = psKernelAlloc(-footprint, footprint, -footprint, footprint);// Convolved image
     669          for (int x = -footprint; x <= footprint; x++) {
     670              for (int y = -footprint; y <= footprint; y++) {
     671                  float value = 0.0;    // Value of convolved pixel
     672                  int vMin = y - size, vMax = y + size; // Range for v
     673                  psF32 *yKernelData = yKernel->data.F32; // Kernel values
     674                  psF32 *imageData = &temp->kernel[x][vMin]; // Image values; NOTE: wrong way!
     675                  for (int v = vMin; v <= vMax; v++, yKernelData++, imageData++) {
     676                      value += *yKernelData * *imageData;
     677                  }
     678                  convolved->kernel[y][x] = value;
     679              }
     680          }
     681          psFree(temp);
     682
     683          // Photometric scaling for even kernels only
     684          if (kernels->u->data.S32[index] % 2 == 0 && kernels->v->data.S32[index] % 2 == 0) {
     685              convolveSub(convolved, image, footprint);
     686          }
     687          return convolved;
     688#if 0
    577689          // Photometric scaling is already built in to the precalculated kernel
    578690          return p_pmSubtractionConvolveStampPrecalc(image, kernels->preCalc->data[index]);
     691#endif
    579692      }
    580693      case PM_SUBTRACTION_KERNEL_RINGS: {
     
    8891002                                     psImage *convMask, // Output convolved mask
    8901003                                     const pmReadout *ro1, const pmReadout *ro2, // Input readouts
     1004                                     psImage *sys1, psImage *sys2, // Systematic error images
    8911005                                     psImage *subMask, // Input subtraction mask
    8921006                                     psMaskType maskBad, // Mask value to give bad pixels
     
    9141028    if (kernels->mode == PM_SUBTRACTION_MODE_1 || kernels->mode == PM_SUBTRACTION_MODE_DUAL) {
    9151029        convolveRegion(out1->image, out1->weight, convMask, &kernelImage, &kernelWeight,
    916                        ro1->image, ro1->weight, subMask, kernels, polyValues, background, *region,
     1030                       ro1->image, ro1->weight, sys1, subMask, kernels, polyValues, background, *region,
    9171031                       maskBad, maskPoor, poorFrac, useFFT, false);
    9181032    }
    9191033    if (kernels->mode == PM_SUBTRACTION_MODE_2 || kernels->mode == PM_SUBTRACTION_MODE_DUAL) {
    9201034        convolveRegion(out2->image, out2->weight, convMask, &kernelImage, &kernelWeight,
    921                        ro2->image, ro2->weight, subMask, kernels, polyValues, background, *region,
     1035                       ro2->image, ro2->weight, sys2, subMask, kernels, polyValues, background, *region,
    9221036                       maskBad, maskPoor, poorFrac, useFFT, kernels->mode == PM_SUBTRACTION_MODE_DUAL);
    9231037    }
     
    9651079    const pmReadout *ro1 = args->data[7]; // Input readout 1
    9661080    const pmReadout *ro2 = args->data[8]; // Input readout 2
    967     psImage *subMask = args->data[9]; // Subtraction mask
    968     psMaskType maskBad = PS_SCALAR_VALUE(args->data[10], U8); // Output mask value for bad pixels
    969     psMaskType maskPoor = PS_SCALAR_VALUE(args->data[11], U8); // Output mask value for poor pixels
    970     float poorFrac = PS_SCALAR_VALUE(args->data[12], F32); // Fraction for "poor"
    971     const psRegion *region = args->data[13]; // Region to convolve
    972     const pmSubtractionKernels *kernels = args->data[14]; // Kernels
    973     bool doBG = PS_SCALAR_VALUE(args->data[15], U8); // Do background subtraction?
    974     bool useFFT = PS_SCALAR_VALUE(args->data[16], U8); // Use FFT for convolution?
    975 
    976     return subtractionConvolvePatch(numCols, numRows, x0, y0, out1, out2, convMask, ro1, ro2, subMask,
    977                                     maskBad, maskPoor, poorFrac, region, kernels, doBG, useFFT);
     1081    psImage *sys1 = args->data[9]; // Systematic error image 1
     1082    psImage *sys2 = args->data[10]; // Systematic error image 2
     1083    psImage *subMask = args->data[11]; // Subtraction mask
     1084    psMaskType maskBad = PS_SCALAR_VALUE(args->data[12], U8); // Output mask value for bad pixels
     1085    psMaskType maskPoor = PS_SCALAR_VALUE(args->data[13], U8); // Output mask value for poor pixels
     1086    float poorFrac = PS_SCALAR_VALUE(args->data[14], F32); // Fraction for "poor"
     1087    const psRegion *region = args->data[15]; // Region to convolve
     1088    const pmSubtractionKernels *kernels = args->data[16]; // Kernels
     1089    bool doBG = PS_SCALAR_VALUE(args->data[17], U8); // Do background subtraction?
     1090    bool useFFT = PS_SCALAR_VALUE(args->data[18], U8); // Use FFT for convolution?
     1091
     1092    return subtractionConvolvePatch(numCols, numRows, x0, y0, out1, out2, convMask, ro1, ro2, sys1, sys2,
     1093                                    subMask, maskBad, maskPoor, poorFrac, region, kernels, doBG, useFFT);
    9781094}
    9791095
     
    10221138    }
    10231139
    1024     // Inputs
    1025     psImage *image1 = NULL, *weight1 = NULL; // Image and weight map from input 1
    1026     if (ro1) {
    1027         image1 = ro1->image;
    1028         weight1 = ro1->weight;
    1029     }
    1030     psImage *image2 = NULL, *weight2 = NULL; // Image and weight map from input 2
    1031     if (ro2) {
    1032         image2 = ro2->image;
    1033         weight2 = ro2->weight;
    1034     }
    1035 
    10361140    bool threaded = pmSubtractionThreaded(); // Running threaded?
    10371141
    10381142    // Outputs
    1039     psImage *convImage1 = NULL, *convWeight1 = NULL; // Convolved image and weight from input 1
    10401143    if (kernels->mode == PM_SUBTRACTION_MODE_1 || kernels->mode == PM_SUBTRACTION_MODE_DUAL) {
    1041         convImage1 = out1->image;
    1042         if (!convImage1) {
    1043             convImage1 = out1->image = psImageAlloc(numCols, numRows, PS_TYPE_F32);
     1144        if (!out1->image) {
     1145            out1->image = psImageAlloc(numCols, numRows, PS_TYPE_F32);
    10441146            if (threaded) {
    1045                 psMutexInit(convImage1);
     1147                psMutexInit(out1->image);
    10461148            }
    10471149        }
    1048         if (weight1) {
     1150        if (ro1->weight) {
    10491151            if (!out1->weight) {
    10501152                out1->weight = psImageAlloc(numCols, numRows, PS_TYPE_F32);
     
    10531155                }
    10541156            }
    1055             convWeight1 = out1->weight;
    1056             psImageInit(convWeight1, 0.0);
    1057         }
    1058     }
    1059     psImage *convImage2 = NULL, *convWeight2 = NULL; // Convolved image and weight from input 2
     1157            psImageInit(out1->weight, 0.0);
     1158        }
     1159    }
    10601160    if (kernels->mode == PM_SUBTRACTION_MODE_2 || kernels->mode == PM_SUBTRACTION_MODE_DUAL) {
    1061         convImage2 = out2->image;
    1062         if (!convImage2) {
    1063             convImage2 = out2->image = psImageAlloc(numCols, numRows, PS_TYPE_F32);
     1161        if (!out2->image) {
     1162            out2->image = psImageAlloc(numCols, numRows, PS_TYPE_F32);
    10641163            if (threaded) {
    1065                 psMutexInit(convImage2);
     1164                psMutexInit(out2->image);
    10661165            }
    10671166        }
    1068         if (weight2) {
     1167        if (ro2->weight) {
    10691168            if (!out2->weight) {
    10701169                out2->weight = psImageAlloc(numCols, numRows, PS_TYPE_F32);
     
    10731172                }
    10741173            }
    1075             convWeight2 = out2->weight;
    1076             psImageInit(convWeight2, 0.0);
     1174            psImageInit(out2->weight, 0.0);
    10771175        }
    10781176    }
     
    11041202    }
    11051203
     1204    psImage *sys1 = NULL, *sys2 = NULL; // Systematic error images
     1205    if (kernels->mode == PM_SUBTRACTION_MODE_1 || kernels->mode == PM_SUBTRACTION_MODE_DUAL) {
     1206        sys1 = subtractionSysErrImage(ro1->image);
     1207        if (threaded) {
     1208            psMutexInit(sys1);
     1209        }
     1210    }
     1211    if (kernels->mode == PM_SUBTRACTION_MODE_2 || kernels->mode == PM_SUBTRACTION_MODE_DUAL) {
     1212        sys2 = subtractionSysErrImage(ro2->image);
     1213        if (threaded) {
     1214            psMutexInit(sys2);
     1215        }
     1216    }
    11061217
    11071218    int size = kernels->size;           // Half-size of kernel
     
    11441255                psArrayAdd(args, 1, (pmReadout*)ro2); // Casting away const
    11451256                // Since adding to the array can impact the reference count, we need to lock
     1257                if (sys1) {
     1258                    psMutexLock(sys1);
     1259                }
     1260                psArrayAdd(args, 1, sys1);
     1261                if (sys1) {
     1262                    psMutexUnlock(sys1);
     1263                }
     1264                if (sys2) {
     1265                    psMutexLock(sys2);
     1266                }
     1267                psArrayAdd(args, 1, sys2);
     1268                if (sys2) {
     1269                    psMutexUnlock(sys2);
     1270                }
    11461271                if (subMask) {
    11471272                    psMutexLock(subMask);
     
    11651290                psFree(job);
    11661291            } else {
    1167                 subtractionConvolvePatch(numCols, numRows, x0, y0, out1, out2, convMask, ro1, ro2, subMask,
    1168                                          maskBad, maskPoor, poorFrac, subRegion, kernels, doBG, useFFT);
     1292                subtractionConvolvePatch(numCols, numRows, x0, y0, out1, out2, convMask, ro1, ro2,
     1293                                         sys1, sys2, subMask, maskBad, maskPoor, poorFrac, subRegion,
     1294                                         kernels, doBG, useFFT);
    11691295            }
    11701296            psFree(subRegion);
     
    11901316            psMutexDestroy(subMask);
    11911317        }
     1318        if (sys1) {
     1319            psMutexDestroy(sys1);
     1320        }
     1321        if (sys2) {
     1322            psMutexDestroy(sys2);
     1323        }
    11921324    }
    11931325
  • trunk/psModules/src/imcombine/pmSubtractionEquation.c

    r19532 r19765  
    758758        calculatePenalty(sumVector, kernels);
    759759
     760#ifdef TESTING
     761        {
     762            psImage *inverse = psMatrixInvert(NULL, sumMatrix, NULL);
     763            psFits *fits = psFitsOpen("matrixInv.fits", "w");
     764            psFitsWriteImage(fits, NULL, inverse, 0, NULL);
     765            psFitsClose(fits);
     766            psFree(inverse);
     767        }
     768        {
     769            psImage *X = psMatrixInvert(NULL, sumMatrix, NULL);
     770            psImage *Xt = psMatrixTranspose(NULL, X);
     771            psImage *XtX = psMatrixMultiply(NULL, Xt, X);
     772            psFits *fits = psFitsOpen("matrixErr.fits", "w");
     773            psFitsWriteImage(fits, NULL, XtX, 0, NULL);
     774            psFitsClose(fits);
     775            psFree(X);
     776            psFree(Xt);
     777            psFree(XtX);
     778        }
     779#endif
     780
    760781        psVector *permutation = NULL;       // Permutation vector, required for LU decomposition
    761782        psImage *luMatrix = psMatrixLUD(NULL, &permutation, sumMatrix);
     
    769790        }
    770791        kernels->solution1 = psMatrixLUSolve(kernels->solution1, luMatrix, sumVector, permutation);
     792
    771793        psFree(sumVector);
    772794        psFree(luMatrix);
     
    806828        calculatePenalty(sumVector2, kernels);
    807829
    808 #if 0
    809         // Apply weighting to maximise the difference between solution coefficients for the same functions
    810         double fudge = PS_SQR(2 * stamps->footprint + 1); // Fudge factor
    811         for (int i = 0; i < kernels->num; i++) {
    812             sumMatrix1->data.F64[i][i] -= fudge;
    813             sumMatrix2->data.F64[i][i] += fudge;
    814         }
    815 #endif
    816 
    817830        // Pure matrix operations
    818831
     
    941954#endif
    942955
     956#ifdef TESTING
    943957        {
    944958            psFits *fits = psFitsOpen("sumMatrix1.fits", "w");
     
    961975            psFitsClose(fits);
    962976        }
    963 
     977#endif
    964978
    965979        kernels->solution1 = a;
  • trunk/psModules/src/imcombine/pmSubtractionKernels.c

    r19209 r19765  
    4242    }
    4343    return result;
     44}
     45
     46// Generate 1D convolution kernel for ISIS
     47static psVector *subtractionKernelISIS(float sigma, // Gaussian width
     48                                       int order, // Polynomial order
     49                                       int size // Kernel half-size
     50    )
     51{
     52    int fullSize = 2 * size + 1;        // Full size of kernel
     53    psVector *kernel = psVectorAlloc(fullSize, PS_TYPE_F32); // Kernel to return
     54
     55    float expNorm = -0.5 / PS_SQR(sigma); // Normalisation for exponential
     56    float norm = 1.0 / (M_2_PI * sqrtf(sigma)); // Normalisation for Gaussian
     57    for (int i = 0, x = -size; x <= size; i++, x++) {
     58        kernel->data.F32[i] = norm * power(x, order) * expf(expNorm * PS_SQR(x));
     59    }
     60
     61    return kernel;
    4462}
    4563
     
    116134
    117135    // Set the kernel parameters
     136    int fullSize = 2 * size + 1;        // Full size of kernels
    118137    for (int i = 0, index = 0; i < numGaussians; i++) {
    119138        float sigma = fwhms->data.F32[i] / (2.0 * sqrtf(2.0 * logf(2.0))); // Gaussian sigma
    120         float norm = 1.0 / (M_2_PI * sqrtf(sigma)); // Normalisation for Gaussian
    121139        // Iterate over (u,v) order
    122140        for (int uOrder = 0; uOrder <= orders->data.S32[i]; uOrder++) {
    123141            for (int vOrder = 0; vOrder <= orders->data.S32[i] - uOrder; vOrder++, index++) {
    124                 // Set the pre-calculated kernel
    125                 psKernel *preCalc = psKernelAlloc(-size, size, -size, size);
    126                 double sum = 0.0;       // Normalisation
     142                psArray *preCalc = psArrayAlloc(2); // Array to hold precalculated values
     143                psVector *xKernel = preCalc->data[0] = subtractionKernelISIS(sigma, uOrder, size); // x Kernel
     144                psVector *yKernel = preCalc->data[1] = subtractionKernelISIS(sigma, vOrder, size); // y Kernel
     145
     146                // Calculate moments
     147                double sum = 0.0;       // Sum of kernel component, for normalisation
    127148                double moment = 0.0;    // Moment, for penalty
    128                 for (int v = -size; v <= size; v++) {
    129                     for (int u = -size; u <= size; u++) {
    130                         sum += preCalc->kernel[v][u] = norm * power(u, uOrder) * power(v, vOrder) *
    131                             expf(-0.5 * (PS_SQR(u) + PS_SQR(v)) / PS_SQR(sigma));
    132                         moment += preCalc->kernel[v][u] * (PS_SQR(u) + PS_SQR(v));
     149                for (int v = -size, y = 0; v <= size; v++, y++) {
     150                    for (int u = -size, x = 0; u <= size; u++, x++) {
     151                        double value = xKernel->data.F32[x] * yKernel->data.F32[y]; // Value of kernel
     152                        sum += value;
     153                        moment += value * (PS_SQR(u) + PS_SQR(v));
    133154                    }
    134155                }
     156                moment = 0.0;
    135157
    136158                // Normalise sum of kernel component to unity for even functions
    137159                if (uOrder % 2 == 0 && vOrder % 2 == 0) {
    138                     for (int v = -size; v <= size; v++) {
    139                         for (int u = -size; u <= size; u++) {
    140                             preCalc->kernel[v][u] = preCalc->kernel[v][u] / sum;
     160                    double sum = 0.0;   // Sum of kernel component
     161                    for (int v = 0; v < fullSize; v++) {
     162                        for (int u = 0; u < fullSize; u++) {
     163                            sum += xKernel->data.F32[u] * yKernel->data.F32[v];
    141164                        }
    142165                    }
    143                     preCalc->kernel[0][0] -= 1.0;
     166                    sum = 1.0 / sum;
     167                    psBinaryOp(xKernel, xKernel, "*", psScalarAlloc(sum, PS_TYPE_F32));
     168                    psBinaryOp(yKernel, yKernel, "*", psScalarAlloc(sum, PS_TYPE_F32));
     169                    moment *= sum;
    144170                }
    145171
     
    702728            // Count the number of Gaussians
    703729            int numGauss = 0;
    704             for (char *string = ptr; string; string = strchr(string, '(')) {
     730            for (char *string = ptr; string; string = strchr(string + 1, '(')) {
    705731                numGauss++;
    706732            }
  • trunk/psModules/src/imcombine/pmSubtractionThreads.c

    r19340 r19765  
    7676
    7777    {
    78         psThreadTask *task = psThreadTaskAlloc("PSMODULES_SUBTRACTION_CONVOLVE", 17);
     78        psThreadTask *task = psThreadTaskAlloc("PSMODULES_SUBTRACTION_CONVOLVE", 19);
    7979        task->function = &pmSubtractionConvolveThread;
    8080        psThreadTaskAdd(task);
Note: See TracChangeset for help on using the changeset viewer.