IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 17295


Ignore:
Timestamp:
Apr 2, 2008, 2:26:17 PM (18 years ago)
Author:
Paul Price
Message:

The method of calculating the moments and then dividing wasn't working
well. I believe this was due to the fact that the moments suffered
due to poor S/N at large radius, where there is no star flux.
Instead, now fitting a range of Gaussians (integer widths; could be
improved to take a list of floating-point widths, or some recipe to
determine a list of widths) to stamps, and selecting the best fit as a
rough measure of the width. The mean ratio of the widths then
provides the guess as to which image as better seeing.

File:
1 edited

Legend:

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

    r16630 r17295  
    1919
    2020#define KERNEL_MOSAIC 2                 // Half-number of kernel instances in the mosaic image
     21#define BG_STAT PS_STAT_ROBUST_MEDIAN   // Statistic to use for background
    2122
    2223static bool useFFT = true;              // Do convolutions using FFT
     
    272273
    273274            if (mode == PM_SUBTRACTION_MODE_UNSURE || mode == PM_SUBTRACTION_MODE_TARGET) {
    274                 pmSubtractionMode newMode = pmSubtractionOrder(stamps, footprint); // Subtraction mode
     275                // Get backgrounds
     276                psStats *bgStats = psStatsAlloc(BG_STAT); // Statistics for background
     277                psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS, 0); // Random number generator
     278                psVector *buffer = NULL;// Buffer for stats
     279                if (!psImageBackground(bgStats, &buffer, ro1->image, ro1->mask, maskBad, rng)) {
     280                    psError(PS_ERR_UNKNOWN, false, "Unable to measure background of image 1.");
     281                    psFree(bgStats);
     282                    psFree(rng);
     283                    psFree(buffer);
     284                    goto MATCH_ERROR;
     285                }
     286                float bg1 = psStatsGetValue(bgStats, BG_STAT); // Background for image 1
     287                if (!psImageBackground(bgStats, &buffer, ro2->image, ro2->mask, maskBad, rng)) {
     288                    psError(PS_ERR_UNKNOWN, false, "Unable to measure background of image 2.");
     289                    psFree(bgStats);
     290                    psFree(rng);
     291                    psFree(buffer);
     292                    goto MATCH_ERROR;
     293                }
     294                float bg2 = psStatsGetValue(bgStats, BG_STAT); // Background for image 2
     295                psFree(bgStats);
     296                psFree(rng);
     297                psFree(buffer);
     298
     299                pmSubtractionMode newMode = pmSubtractionOrder(stamps, bg1, bg2); // Subtraction mode to use
    275300                switch (newMode) {
    276301                  case PM_SUBTRACTION_MODE_1:
     
    529554}
    530555
    531 // Calculate the second order moments for an image
    532 static float subtractionOrderMoment(const psKernel *kernel, // Image for which to measure moments
    533                                     int radius   // Maximum radius
    534                                     )
     556
     557// Determine a rough width (integer value) of the star in the image
     558// XXX Could improve this by using a user-provided list of floating-point widths (or an end point and
     559// increment).
     560static int subtractionOrderWidth(const psKernel *kernel, // Image
     561                                 float bg, // Background in image
     562                                 int size, // Maximum size
     563                                 psArray **models, // Buffer of models
     564                                 psVector **modelSums // Buffer of model sums
     565    )
    535566{
    536     assert(kernel && kernel->kernel);
    537 
    538     int xMin = PS_MAX(kernel->xMin, -radius), xMax = PS_MIN(kernel->xMax, radius); // Bounds in x
    539     int yMin = PS_MAX(kernel->yMin, -radius), yMax = PS_MIN(kernel->yMax, radius); // Bounds in y
    540 
    541     float xCentroid = 0.0, yCentroid = 0.0; // Centroid (first moment)
    542     float sum = 0.0;       // Sum (zero-th moment)
    543     for (int y = yMin; y <= yMax; y++) {
    544         for (int x = xMin; x <= xMax; x++) {
    545             xCentroid += kernel->kernel[y][x] * x;
    546             yCentroid += kernel->kernel[y][x] * y;
    547             sum += kernel->kernel[y][x];
    548         }
    549     }
    550     xCentroid /= sum;
    551     yCentroid /= sum;
    552 
    553     float eta20 = 0.0, eta02 = 0.0;     // Second moments
    554     for (int y = yMin; y <= yMax; y++) {
    555         float yDiff = y - yCentroid;
    556         for (int x = xMin; x <= xMax; x++) {
    557             float xDiff = x - xCentroid;
    558             eta20 += PS_SQR(xDiff) * kernel->kernel[y][x];
    559             eta02 += PS_SQR(yDiff) * kernel->kernel[y][x];
    560         }
    561     }
    562 
    563     // Normalise to calculate the scale-invariant
    564     float sum2 = PS_SQR(sum);
    565     eta20 /= sum2;
    566     eta02 /= sum2;
    567     // eta11 /= sum2;
    568 
    569     return eta20 + eta02;
     567    assert(kernel);
     568    assert(models);
     569    assert(modelSums);
     570
     571    int xMin = kernel->xMin, xMax = kernel->xMax; // Bounds in x
     572    int yMin = kernel->yMin, yMax = kernel->yMax; // Bounds in y
     573
     574    // Generate models
     575    if (!*models) {
     576        assert(!*modelSums);
     577        *models = psArrayAlloc(size);
     578        *modelSums = psVectorAlloc(size, PS_TYPE_F64);
     579        for (int sigma = 0; sigma < size; sigma++) {
     580            psKernel *model = psKernelAlloc(xMin, xMax, yMin, yMax); // Gaussian model
     581            float invSigma2 = 1.0 / (float)PS_SQR(1 + sigma); // Inverse sigma squared
     582            double sumGG = 0.0;         // Sum of square of Gaussian
     583            for (int y = yMin; y <= yMax; y++) {
     584                int y2 = PS_SQR(y);     // y squared
     585                for (int x = xMin; x <= xMax; x++) {
     586                    float rad2 = PS_SQR(x) + y2; // Radius squared
     587                    float value = expf(-rad2 * invSigma2); // Model value
     588                    model->kernel[y][x] = value;
     589                    sumGG += PS_SQR(value);
     590                }
     591            }
     592            (*models)->data[sigma] = model;
     593            (*modelSums)->data.F64[sigma] = sumGG;
     594        }
     595    }
     596
     597    // Fit gaussians of varying widths to the image, record the chi^2
     598    psVector *chi2 = psVectorAlloc(size, PS_TYPE_F32); // chi^2 as a function of radius
     599    for (int sigma = 0; sigma < size; sigma++) {
     600        double sumFG = 0.0; // Sum for calculating the normalisation of the Gaussian
     601        psKernel *model = (*models)->data[sigma]; // Model of interest
     602        for (int y = yMin; y <= yMax; y++) {
     603            for (int x = xMin; x <= xMax; x++) {
     604                sumFG += model->kernel[y][x] * (kernel->kernel[y][x] - bg);
     605            }
     606        }
     607        float norm = sumFG / (*modelSums)->data.F64[sigma]; // Normalisation for Gaussian
     608        double sumDev2 = 0.0;           // Sum of square deviations
     609        for (int y = yMin; y <= yMax; y++) {
     610            for (int x = xMin; x <= xMax; x++) {
     611                float dev = kernel->kernel[y][x] - bg - norm * model->kernel[y][x]; // Deviation
     612                sumDev2 += PS_SQR(dev);
     613            }
     614        }
     615        chi2->data.F32[sigma] = sumDev2;
     616    }
     617
     618    // Find the minimum chi^2
     619    int bestIndex = -1;                 // Index of best chi^2
     620    float bestChi2 = INFINITY;          // Best chi^2
     621    for (int i = 0; i < size; i++) {
     622        if (chi2->data.F32[i] < bestChi2) {
     623            bestChi2 = chi2->data.F32[i];
     624            bestIndex = i;
     625        }
     626    }
     627    psFree(chi2);
     628
     629    return bestIndex + 1;
    570630}
    571631
    572 #if 0
    573 // Calculate the deviations for a particular subtraction order
    574 static psVector *subtractionOrderDeviation(float *sumKernel, // Sum of the kernel
    575                                            pmSubtractionStampList *stamps, // Stamps to convolve
    576                                            const pmSubtractionKernels *kernels, // Kernel basis functions
    577                                            int footprint, // Stamp footprint
    578                                            pmSubtractionMode mode // Mode of subtraction
    579                                            )
     632pmSubtractionMode pmSubtractionOrder(pmSubtractionStampList *stamps, float bg1, float bg2)
    580633{
    581     assert(stamps);
    582     assert(footprint >= 0);
    583     assert(mode == PM_SUBTRACTION_MODE_1 || mode == PM_SUBTRACTION_MODE_2);
    584 
    585     if (!pmSubtractionCalculateEquation(stamps, kernels, footprint, mode)) {
    586         psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation.");
    587         return NULL;
    588     }
    589 
    590     psVector *solution = pmSubtractionSolveEquation(NULL, stamps);
    591     if (!solution) {
    592         psError(PS_ERR_UNKNOWN, false, "Unable to calculate least-squares equation.");
    593         return NULL;
    594     }
    595 
    596     if (sumKernel) {
    597         float sum = 0.0;                // Sum of the kernel
    598         psImage *image = pmSubtractionKernelImage(solution, kernels, 0.0, 0.0); // Image of kernel
    599         for (int y = 0; y < image->numRows; y++) {
    600             for (int x = 0; x < image->numCols; x++) {
    601                 sum += image->data.F32[y][x];
    602             }
    603         }
    604         psFree(image);
    605         *sumKernel = sum;
    606     }
    607 
    608     psVector *deviations = pmSubtractionCalculateDeviations(stamps, solution, footprint, kernels, mode);
    609     psFree(solution);
    610     if (!deviations) {
    611         psError(PS_ERR_UNKNOWN, false, "Unable to calculate deviations.");
    612         return NULL;
    613     }
    614 
    615     return deviations;
    616 }
    617 #endif
    618 
    619 pmSubtractionMode pmSubtractionOrder(pmSubtractionStampList *stamps, int radius)
    620 {
    621     PS_ASSERT_INT_POSITIVE(radius, PM_SUBTRACTION_MODE_ERR);
     634    PM_ASSERT_SUBTRACTION_STAMP_LIST_NON_NULL(stamps, PM_SUBTRACTION_MODE_ERR);
    622635
    623636    psVector *mask = psVectorAlloc(stamps->num, PS_TYPE_MASK); // Mask for stamps
    624     psVector *moments = psVectorAlloc(stamps->num, PS_TYPE_F32); // Moments
     637    psVector *ratios = psVectorAlloc(stamps->num, PS_TYPE_F32); // Ratios of widths
     638    psArray *models = NULL;             // Gaussian models
     639    psVector *modelSums = NULL;         // Gaussian model sums
    625640    for (int i = 0; i < stamps->num; i++) {
    626641        pmSubtractionStamp *stamp = stamps->stamps->data[i]; // Stamp of interest
     
    630645        }
    631646        mask->data.PS_TYPE_MASK_DATA[i] = 0;
    632         moments->data.F32[i] = subtractionOrderMoment(stamp->image1, radius) /
    633             subtractionOrderMoment(stamp->image2, radius);
    634     }
     647
     648        // Widths of stars
     649        int width1 = subtractionOrderWidth(stamp->image1, bg1, stamps->footprint, &models, &modelSums);
     650        int width2 = subtractionOrderWidth(stamp->image2, bg2, stamps->footprint, &models, &modelSums);
     651
     652        if (width1 == -1 || width2 == -2) {
     653            ratios->data.F32[i] = NAN;
     654            mask->data.PS_TYPE_MASK_DATA[i] = 0xff;
     655        } else {
     656            ratios->data.F32[i] = (float)width1 / (float)width2;
     657        }
     658    }
     659    psFree(models);
     660    psFree(modelSums);
    635661
    636662    psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN);
    637     if (!psVectorStats(stats, moments, NULL, mask, 0xff)) {
     663    if (!psVectorStats(stats, ratios, NULL, mask, 0xff)) {
    638664        psError(PS_ERR_UNKNOWN, false, "Unable to calculate statistics for moments ratio.");
    639665        psFree(mask);
    640         psFree(moments);
     666        psFree(ratios);
    641667        psFree(stats);
    642668        return PM_SUBTRACTION_MODE_ERR;
    643669    }
    644     psFree(moments);
     670    psFree(ratios);
    645671    psFree(mask);
    646672
    647     psLogMsg("psModules.imcombine", PS_LOG_INFO, "Median ratio of second moments: %lf", stats->robustMedian);
     673    psLogMsg("psModules.imcombine", PS_LOG_INFO, "Median moment: %lf", stats->robustMedian);
    648674    pmSubtractionMode mode = (stats->robustMedian <= 1.0 ? PM_SUBTRACTION_MODE_1 : PM_SUBTRACTION_MODE_2);
    649675    psFree(stats);
Note: See TracChangeset for help on using the changeset viewer.