IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 30973


Ignore:
Timestamp:
Mar 18, 2011, 2:05:06 PM (15 years ago)
Author:
eugene
Message:

add alternative method of culling peaks from footprints by using quantized threshold levels: if a footprint has many peaks, we can save a lot of time by generating a single footprint for many peaks at once, rather than generating a full, large footprint for each peak

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/eam_branches/ipp-20110213/psModules/src/objects/pmFootprintCullPeaks.c

    r30902 r30973  
    4040                                 const float min_threshold, // minimum permitted coll height
    4141                                 const float max_threshold,
    42                                  const bool isWeightVar
     42                                 const bool useSmoothedImage
    4343    ) { // maximum permitted coll height
    4444    assert (img != NULL); assert (img->type.type == PS_TYPE_F32);
     
    4747    assert (fp != NULL);
    4848
    49     if (fp->peaks == NULL || fp->peaks->n == 0) { // nothing to do
     49    if (fp->peaks == NULL || fp->peaks->n < 2) { // nothing to do
    5050        return PS_ERR_NONE;
    5151    }
     
    5656
    5757    psImage *subImg = psImageSubset((psImage *)img, subRegion);
    58     psImage *subWt = psImageSubset((psImage *)weight, subRegion);
    59     assert (subImg != NULL && subWt != NULL);
     58    psAssert (subImg, "trouble making local subimage");
    6059
    6160    psImage *idImg = psImageAlloc(subImg->numCols, subImg->numRows, PS_TYPE_S32);
     
    8685    psImage *subMask = psImageCopy(NULL, subImg, PS_TYPE_IMAGE_MASK);
    8786
    88     // The brightest peak is always safe; go through other peaks trying to cull them
    89     for (int i = 1; i < fp->peaks->n; i++) { // n.b. fp->peaks->n can change within the loop
    90         const pmPeak *peak = fp->peaks->data[i];
    91         int x = peak->x - subImg->col0;
    92         int y = peak->y - subImg->row0;
    93         //
    94         // Find the level nsigma below the peak that must separate the peak
    95         // from any of its friends
    96         //
    97         assert (x >= 0 && x < subImg->numCols && y >= 0 && y < subImg->numRows);
    98 
    99         // const float stdev = sqrt(subWt->data.F32[y][x]);
    100         // float threshold = subImg->data.F32[y][x] - nsigma_delta*stdev;
    101 
    102         float stdev = 0.0;
    103         float flux = 0.0;
    104         if (isWeightVar) {
    105             flux = subImg->data.F32[y][x];
    106             stdev = sqrt(subWt->data.F32[y][x]);
    107         } else {
    108             flux = subImg->data.F32[y][x];
    109             stdev = flux / sqrt(subWt->data.F32[y][x]); // should be 1/sqrt(subWT)
    110         }
    111         const float fStdev = fabs(stdev/flux);
    112         const float stdev_pad = fabs(flux * hypot(fStdev, fPadding));
    113 
    114         // if flux is negative, careful with fStdev
    115 
    116         float threshold = flux - nsigma_delta*stdev_pad;
    117 
    118         if (isnan(threshold)) {
    119             // min_threshold is assumed to be below the detection threshold,
    120             // so all the peaks are pmFootprint, and this isn't the brightest
    121             continue;
    122         }
    123 
    124         // XXX EAM : if stdev >= 0, i'm not sure how this can ever be true?
    125         if (threshold > subImg->data.F32[y][x]) {
    126             threshold = subImg->data.F32[y][x] - 10*FLT_EPSILON;
    127         }
    128 
    129         if (threshold < min_threshold) {
    130             threshold = min_threshold;
    131         }
    132         if (threshold > max_threshold) {
    133             threshold = max_threshold;
    134         }
    135 
    136         // XXX can we / should we use pmFootprintsFind() if the starting footprint is too large?
    137         // init peakFootprint here?
    138         pmFootprintsFindAtPoint(peakFootprint, peakFPSpans, subImg, subMask, threshold, brightPeaks, peak->y, peak->x);
    139         if (peakFPSpans->nStartSpans > 2000) {
    140             // dumpfootprints(peakFootprint, peakFPSpans);
    141             // fprintf (stderr, "big footprint %d : %d\n", peakFootprint->nspans, peakFPSpans->nStartSpans);
    142             fprintf (stderr, "big test footprint: %f %f to %f %f (%d pix)\n", peakFootprint->bbox.x0, peakFootprint->bbox.y0, peakFootprint->bbox.x1, peakFootprint->bbox.y1, peakFootprint->npix);
    143         }
    144 
    145         // at this point brightPeaks only has the peaks brighter than the current
    146 
    147         // we set the IDs to either 1 (in peak) or 0 (not in peak)
    148         pmSetFootprintID (idImg, peakFootprint, IN_PEAK);
    149 
    150         // If this peak has not already been assigned to a source, then we can look for any
    151         // brighter peaks within its footprint. Check if any of the previous (brighter) peaks
    152         // are within the footprint of this peak If so, the current peak is bogus; drop it.
    153         bool keep = true;
    154         for (int j = 0; keep && !peak->assigned && (j < brightPeaks->n); j++) {
    155             // const pmPeak *peak2 = fp->peaks->data[j]; XXX isn't this an error?  we only care about the kept brighter peak, right?
    156             const pmPeak *peak2 = brightPeaks->data[j];
    157             int x2 = peak2->x - subImg->col0;
    158             int y2 = peak2->y - subImg->row0;
    159             if (idImg->data.S32[y2][x2] == IN_PEAK) {
    160                 // There's a brighter peak within the footprint above threshold; so cull our initial peak
    161                 keep = false;
    162             }
    163         }
    164         if (!keep) {
    165             psAssert (!peak->assigned, "logic error: trying to drop a previously-assigned peak");  // we should not drop any already assigned peaks.
    166             continue;
    167         }
    168         psArrayAdd (brightPeaks, 128, fp->peaks->data[i]);
     87    // if we have many peaks in a large footprint, we waste a lot of time generating nearly identical footprints
     88    // here we attempt to cull peaks drawing a single footprint for all peaks in some threshold range
     89    fprintf (stderr, "footprint: %d x %d : %d pix, %d peaks\n", subImg->numCols, subImg->numRows, fp->npix, (int) fp->peaks->n);
     90    if ((fp->npix > 30000) && (fp->peaks->n > 10)) {
     91
     92        // max flux is above threshold for brightest peak
     93        pmPeak *maxPeak = fp->peaks->data[0];
     94        float maxFlux = useSmoothedImage ? maxPeak->smoothFlux : maxPeak->rawFlux;
     95
     96        // we have a relationship between the bin and the threshold of:
     97        // threshold = 0.25 beta^2 bin^2 + minThreshold
     98        // thus, the max bin is: sqrt(4.0*(maxThreshold - minThreshold)/ALPHA^2)
     99
     100# define ALPHA 0.1
     101       
     102        float beta = nsigma_delta * ALPHA;
     103        float beta2 = PS_SQR(beta);
     104        int nBins = sqrt(4.0*(maxFlux - min_threshold)/beta2) + 10; // let's be extra generous
     105
     106        // create a vector to store the threshold bins used for each peak
     107        psVector *threshbins = psVectorAlloc(fp->peaks->n, PS_TYPE_S32);
     108        threshbins->data.S32[0] = -1; // we skip the first peak
     109
     110        /// create a vector to track if a peak has been tried or not:
     111        psVector *peaktried = psVectorAlloc(fp->peaks->n, PS_TYPE_U8);
     112        psVectorInit(peaktried, 0);
     113        peaktried->data.U8[0] = true; // we skip the first peak
     114
     115        psVector *threshbounds = psVectorAlloc(nBins, PS_TYPE_F32);
     116        for (int i = 0; i < nBins; i++) {
     117            threshbounds->data.F32[i] = 0.25*beta2*PS_SQR(i) + min_threshold;       
     118        }
     119        psAssert(threshbounds->data.F32[threshbounds->n-1] > maxFlux, "upper limit does not include max flux");
     120
     121        psHistogram *threshist = psHistogramAllocGeneric(threshbounds);
     122
     123        // assign the peaks to the histogram bins based on their nominal thresholsd
     124        for (int i = 1; i < fp->peaks->n; i++) {
     125            const pmPeak *peak = fp->peaks->data[i];
     126            float flux = useSmoothedImage ? peak->smoothFlux : peak->rawFlux;
     127            float stdev = useSmoothedImage ? peak->smoothFluxStdev : peak->rawFluxStdev;
     128
     129            // if flux is negative, careful with fStdev
     130            const float fStdev = fabs(stdev/flux);
     131            const float stdev_pad = fabs(flux * hypot(fStdev, fPadding));
     132
     133            float threshold = flux - nsigma_delta*stdev_pad;
     134            psAssert(!isnan(threshold), "impossible");
     135
     136            if (threshold <= min_threshold) {
     137                threshist->nums->data.F32[0] += 1.0;
     138                threshbins->data.S32[i] = 0;
     139                continue;
     140            }
     141            int bin = sqrt(4.0*(threshold - min_threshold)/beta2);
     142            psAssert(bin >= 0, "impossible bin");
     143
     144            bin = PS_MIN(bin, threshist->nums->n - 1);
     145            threshist->nums->data.F32[bin] += 1.0;
     146           
     147            // record the bin selected for this peak
     148            threshbins->data.S32[i] = bin;
     149        }
     150
     151        // XXX TEST: did we assign correctly
     152# if (0)
     153        int nPeaks = 1; // we don't put the brightest in the histogram
     154        for (int i = 0; i < threshist->nums->n; i++) {
     155            if (threshist->nums->data.F32[i] > 0) {
     156                fprintf (stderr, "%f : %f : %d\n", threshist->bounds->data.F32[i], threshist->bounds->data.F32[i+1], (int)threshist->nums->data.F32[i]);
     157                nPeaks += threshist->nums->data.F32[i];
     158            }
     159        }
     160        fprintf (stderr, "%d peaks vs %d in histogram\n", (int) fp->peaks->n, nPeaks);
     161# endif
     162
     163        // XXX for the moment, we will use the alternate cull for all peaks -- it might be
     164        // faster to use the standard process for the peaks for which the threshold bin
     165        // contains < N sources (N ~ 5-10?)
     166
     167        // loop over the threshold bins from brightest to faintest
     168        for (int i = threshist->nums->n - 1; i >= 0; i--) {
     169            if (threshist->nums->data.F32[i] == 0) continue;
     170
     171            // we are going to examine the footprints at this threshold
     172            float threshold = 0.5*(threshist->bounds->data.F32[i] + threshist->bounds->data.F32[i+1]);
     173                   
     174            // generate all footprints corresponding to this threshold
     175            psArray *myFP = pmFootprintsFind(subImg, threshold, 5);
     176            if (!myFP) {
     177                psWarning ("missing footprint?");
     178                continue;
     179            }
     180            if (!myFP->n) {
     181                psWarning ("empty footprint?");
     182                continue;
     183            }
     184
     185            // an array to track if the footprint has a brighter peak or not
     186            psVector *found = psVectorAlloc(myFP->n + 1, PS_TYPE_U8);
     187            psVectorInit(found, 0);
     188            int nFound = 0;
     189
     190            // set IDs to distinguish the footprints
     191            psImageInit(idImg, 0);
     192            pmSetFootprintArrayIDsForImage(idImg, myFP, true);
     193       
     194            // check which footprints contain already-accepted (brighter) peaks
     195            // (we can give up if/when we found a peak for all footprints)
     196            for (int j = 0; (j < brightPeaks->n) && (nFound < found->n); j++) {
     197                const pmPeak *peak = brightPeaks->data[j];
     198                int x = peak->x - subImg->col0;
     199                int y = peak->y - subImg->row0;
     200                int myID = idImg->data.S32[y][x];
     201                psAssert(myID >= 0, "impossible");
     202                psAssert(myID < found->n, "impossible");
     203
     204                if (myID == 0) continue; // bright peak is not in a footprint
     205                if (found->data.U8[myID]) continue; // we already know this footprint contains a peak
     206                found->data.U8[myID] = true;
     207                nFound ++;
     208            }
     209       
     210            // check the peaks from this threshold bin: if they land in a footprint which has
     211            // been found, we should drop that peak.  otherwise, keep it
     212            for (int j = 0; j < fp->peaks->n; j++) {
     213                pmPeak *peak = fp->peaks->data[j];
     214                if (peak->assigned) continue; // peak is already claimed by a source -- don't cull
     215
     216                // skip peaks if we've already tried them
     217                if (peaktried->data.U8[j]) continue;
     218
     219                // is this peak in the threshold bin of interest?
     220                if (threshbins->data.S32[j] != i) continue;
     221               
     222                // do not try this peak again
     223                peaktried->data.U8[j] = true;
     224
     225                int x = peak->x - subImg->col0;
     226                int y = peak->y - subImg->row0;
     227                int myID = idImg->data.S32[y][x];
     228
     229                // a peak in this threshold bin must be in a valid footprint, right?
     230                psAssert(myID > 0, "impossible");
     231                psAssert(myID < found->n, "impossible");
     232
     233                // keep this peak if found->data.U8[myID] == false (no brighter peak in the footprint)
     234                if (!found->data.U8[myID]) {
     235                    // fprintf (stderr, "keeping %d: %d,%d\n", j, peak->x, peak->y);
     236                    psArrayAdd (brightPeaks, 128, peak);
     237                    continue;
     238                }
     239                // fprintf (stderr, "skipping %d: %d,%d\n", j, peak->x, peak->y);
     240            }
     241            psFree (myFP);
     242            psFree (found);
     243        }
     244        psFree (threshist);
     245        psFree (threshbounds);
     246        psFree (threshbins);
     247        psFree (peaktried);
     248
     249    } else {
     250
     251        // The brightest peak is always safe; go through other peaks trying to cull them
     252        for (int i = 1; i < fp->peaks->n; i++) { // n.b. fp->peaks->n can change within the loop
     253            const pmPeak *peak = fp->peaks->data[i];
     254
     255            float flux  = useSmoothedImage ? peak->smoothFlux      : peak->rawFlux;
     256            float stdev = useSmoothedImage ? peak->smoothFluxStdev : peak->rawFluxStdev;
     257
     258            // if flux is negative, careful with fStdev
     259            const float fStdev = fabs(stdev/flux);
     260            const float stdev_pad = fabs(flux * hypot(fStdev, fPadding));
     261
     262            float threshold = flux - nsigma_delta*stdev_pad;
     263
     264            if (isnan(threshold)) {
     265                // min_threshold is assumed to be below the detection threshold,
     266                // so all the peaks are pmFootprint, and this isn't the brightest
     267                continue;
     268            }
     269
     270            // just in case, force the threshold below the peak source flux
     271            if (threshold > flux) {
     272                threshold = flux - 10*FLT_EPSILON;
     273            }
     274
     275            if (threshold < min_threshold) {
     276                threshold = min_threshold;
     277            }
     278            if (threshold > max_threshold) {
     279                threshold = max_threshold;
     280            }
     281
     282            pmFootprintsFindAtPoint(peakFootprint, peakFPSpans, subImg, subMask, threshold, brightPeaks, peak->y, peak->x);
     283            if (peakFPSpans->nStartSpans > 2000) {
     284                // dumpfootprints(peakFootprint, peakFPSpans);
     285                // fprintf (stderr, "big footprint %d : %d\n", peakFootprint->nspans, peakFPSpans->nStartSpans);
     286                fprintf (stderr, "big test footprint: %f %f to %f %f (%d pix)\n", peakFootprint->bbox.x0, peakFootprint->bbox.y0, peakFootprint->bbox.x1, peakFootprint->bbox.y1, peakFootprint->npix);
     287            }
     288
     289            // at this point brightPeaks only has the peaks brighter than the current
     290
     291            // we set the IDs to either 1 (in peak) or 0 (not in peak)
     292            pmSetFootprintID (idImg, peakFootprint, IN_PEAK);
     293
     294            // If this peak has not already been assigned to a source, then we can look for any
     295            // brighter peaks within its footprint. Check if any of the previous (brighter) peaks
     296            // are within the footprint of this peak If so, the current peak is bogus; drop it.
     297            bool keep = true;
     298            for (int j = 0; keep && !peak->assigned && (j < brightPeaks->n); j++) {
     299                // const pmPeak *peak2 = fp->peaks->data[j]; XXX isn't this an error?  we only care about the kept brighter peak, right?
     300                const pmPeak *peak2 = brightPeaks->data[j];
     301                int x2 = peak2->x - subImg->col0;
     302                int y2 = peak2->y - subImg->row0;
     303                if (idImg->data.S32[y2][x2] == IN_PEAK) {
     304                    // There's a brighter peak within the footprint above threshold; so cull our initial peak
     305                    keep = false;
     306                }
     307            }
     308            if (!keep) {
     309                psAssert (!peak->assigned, "logic error: trying to drop a previously-assigned peak");  // we should not drop any already assigned peaks.
     310                continue;
     311            }
     312            psArrayAdd (brightPeaks, 128, fp->peaks->data[i]);
     313        }
    169314    }
    170315
     
    174319    psFree(idImg);
    175320    psFree(subImg);
    176     psFree(subWt);
    177321    psFree(subMask);
    178322    psFree(peakFootprint);
Note: See TracChangeset for help on using the changeset viewer.