IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 17443


Ignore:
Timestamp:
Apr 12, 2008, 10:06:01 PM (18 years ago)
Author:
eugene
Message:

split out functions from pmFootprints into more concise files for clarity

Location:
trunk/psphot/src
Files:
11 added
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/psphot/src/Makefile.am

    r17396 r17443  
    2020        psphotErrorCodes.c             \
    2121        pmFootprint.c                  \
     22        pmFootprintArrayGrow.c         \
     23        pmFootprintArraysMerge.c       \
     24        pmFootprintIDs.c               \
     25        pmFootprintsFind.c             \
     26        pmFootprintsFindAtPoint.c      \
     27        pmFootprintsAssignPeaks.c      \
     28        pmDetections.c                 \
     29        pmSpan.c                       \
     30        psphotCullPeaks.c              \
    2231        psphotVersion.c                \
    2332        psphotModelGroupInit.c         \
     
    2938        psphotFindDetections.c         \
    3039        psphotFindPeaks.c              \
     40        psphotFindFootprints.c         \
     41        psphotSignificanceImage.c      \
    3142        psphotSourceStats.c            \
    3243        psphotRoughClass.c             \
  • trunk/psphot/src/pmFootprint.c

    r16820 r17443  
    1 /*****************************************************************************/
    2 /*
    3  * Handle pmFootprints
    4  */
    5 #include <assert.h>
    6 #include <string.h>
    7 #include <pslib.h>
    8 #include <psmodules.h>
    9 #include "psphot.h"
    10 #include "pmFootprint.h"
     1# include "psphotInternal.h"
    112
    12 static void spanFree(pmSpan *tmp) {
    13    ;
    14 }
    15 
    16 /*
    17  * pmSpanAlloc()
    18  */
    19 pmSpan *pmSpanAlloc(int y, int x0, int x1)
    20 {
    21     pmSpan *span = (pmSpan *)psAlloc(sizeof(pmSpan));
    22     psMemSetDeallocator(span, (psFreeFunc) spanFree);
    23 
    24     span->y = y;
    25     span->x0 = x0;
    26     span->x1 = x1;
    27 
    28     return(span);
    29 }
    30 
    31 bool pmSpanTest(const psPtr ptr)
    32 {
    33     return (psMemGetDeallocator(ptr) == (psFreeFunc)spanFree);
    34 }
    35 
    36 //
    37 // Sort pmSpans by y, then x0, then x1
    38 //
    39 int pmSpanSortByYX(const void **a, const void **b) {
    40     const pmSpan *sa = *(const pmSpan **)a;
    41     const pmSpan *sb = *(const pmSpan **)b;
    42 
    43     if (sa->y < sb->y) {
    44         return -1;
    45     } else if (sa->y == sb->y) {
    46         if (sa->x0 < sb->x0) {
    47             return -1;
    48         } else if (sa->x0 == sb->x0) {
    49             if (sa->x1 < sb->x1) {
    50                 return -1;
    51             } else if (sa->x1 == sb->x1) {
    52                 return 0;
    53             } else {
    54                 return 1;
    55             }
    56         } else {
    57             return 1;
    58         }
    59     } else {
    60         return 1;
    61     }
    62 }
    63 
    64 /************************************************************************************************************/
     3/**** low-level pmFootprint functions ****/
    654
    665static void footprintFree(pmFootprint *tmp)
     
    13170// Add a span to a footprint, returning the new span
    13271//
    133 static pmSpan *pmFootprintAddSpan(pmFootprint *fp,      // the footprint to add to
    134                                   const int y, // row to add
    135                                   int x0,      // range of
    136                                   int x1) {    //          columns
     72pmSpan *pmFootprintAddSpan(pmFootprint *fp,     // the footprint to add to
     73                           const int y, // row to add
     74                           int x0,      // range of
     75                           int x1) {    //          columns
    13776
    13877    if (x1 < x0) {
     
    201140}
    202141
    203 /************************************************************************************************************/
    204 
    205 typedef struct {                        /* run-length code for part of object*/
    206    int id;                              /* ID for object */
    207    int y;                               /* Row wherein WSPAN dwells */
    208    int x0, x1;                          /* inclusive range of columns */
    209 } WSPAN;
    210 
    211 /*
    212  * comparison function for qsort; sort by ID then row
    213  */
    214 static int
    215 compar(const void *va, const void *vb)
    216 {
    217    const WSPAN *a = va;
    218    const WSPAN *b = vb;
    219 
    220    if(a->id < b->id) {
    221       return(-1);
    222    } else if(a->id > b->id) {
    223       return(1);
    224    } else {
    225       return(a->y - b->y);
    226    }
    227 }
    228 
    229 /*
    230  * Follow a chain of aliases, returning the final resolved value.
    231  */
    232 static int
    233 resolve_alias(const int *aliases,       /* list of aliases */
    234               int id)                   /* alias to look up */
    235 {
    236    int resolved = id;                   /* resolved alias */
    237 
    238    while(id != aliases[id]) {
    239       resolved = id = aliases[id];
    240    }
    241 
    242    return(resolved);
    243 }
    244 
    245 /*
    246  * Go through an image, finding sets of connected pixels above threshold
    247  * and assembling them into pmFootprints;  the resulting set of objects
    248  * is returned as a psArray
    249  */
    250 psArray *
    251 pmFindFootprints(const psImage *img,    // image to search
    252                  const float threshold, // Threshold
    253                  const int npixMin)     // minimum number of pixels in an acceptable pmFootprint
    254 {
    255    int i0;                              /* initial value of i */
    256    int id;                              /* object ID */
    257    int in_span;                         /* object ID of current WSPAN */
    258    int nspan = 0;                       /* number of spans */
    259    int nobj = 0;                        /* number of objects found */
    260    int x0 = 0;                          /* unpacked from a WSPAN */
    261    int *tmp;                            /* used in swapping idc/idp */
    262 
    263    assert(img != NULL);
    264 
    265    bool F32 = false;                    // is this an F32 image?
    266    if (img->type.type == PS_TYPE_F32) {
    267        F32 = true;
    268    } else if (img->type.type == PS_TYPE_S32) {
    269        F32 = false;
    270    } else {                             // N.b. You can't trivially add more cases here; F32 is just a bool
    271        psError(PS_ERR_UNKNOWN, true, "Unsupported psImage type: %d", img->type.type);
    272        return NULL;
    273    }
    274    psF32 *imgRowF32 = NULL;             // row pointer if F32
    275    psS32 *imgRowS32 = NULL;             //  "   "   "  "  !F32
    276    
    277    const int row0 = img->row0;
    278    const int col0 = img->col0;
    279    const int numRows = img->numRows;
    280    const int numCols = img->numCols;
    281 /*
    282  * Storage for arrays that identify objects by ID. We want to be able to
    283  * refer to idp[-1] and idp[numCols], hence the (numCols + 2)
    284  */
    285    int *id_s = psAlloc(2*(numCols + 2)*sizeof(int));
    286    memset(id_s, '\0', 2*(numCols + 2)*sizeof(int)); assert(id_s[0] == 0);
    287    int *idc = id_s + 1;                 // object IDs in current/
    288    int *idp = idc + (numCols + 2);      //                       previous row
    289 
    290    int size_aliases = 1 + numRows/20;   // size of aliases[] array
    291    int *aliases = psAlloc(size_aliases*sizeof(int)); // aliases for object IDs
    292 
    293    int size_spans = 1 + numRows/20;     // size of spans[] array
    294    WSPAN *spans = psAlloc(size_spans*sizeof(WSPAN)); // row:x0,x1 for objects
    295 /*
    296  * Go through image identifying objects
    297  */
    298    for (int i = 0; i < numRows; i++) {
    299       int j;
    300       tmp = idc; idc = idp; idp = tmp;  /* swap ID pointers */
    301       memset(idc, '\0', numCols*sizeof(int));
    302      
    303       imgRowF32 = img->data.F32[i];     // only one of
    304       imgRowS32 = img->data.S32[i];     //      these is valid!
    305 
    306       in_span = 0;                      /* not in a span */
    307       for (j = 0; j < numCols; j++) {
    308          double pixVal = F32 ? imgRowF32[j] : imgRowS32[j];
    309          if (pixVal < threshold) {
    310             if (in_span) {
    311                if(nspan >= size_spans) {
    312                   size_spans *= 2;
    313                   spans = psRealloc(spans, size_spans*sizeof(WSPAN));
    314                }
    315                spans[nspan].id = in_span;
    316                spans[nspan].y = i;
    317                spans[nspan].x0 = x0;
    318                spans[nspan].x1 = j - 1;
    319                
    320                nspan++;
    321 
    322                in_span = 0;
    323             }
    324          } else {                       /* a pixel to fix */
    325             if(idc[j - 1] != 0) {
    326                id = idc[j - 1];
    327             } else if(idp[j - 1] != 0) {
    328                id = idp[j - 1];
    329             } else if(idp[j] != 0) {
    330                id = idp[j];
    331             } else if(idp[j + 1] != 0) {
    332                id = idp[j + 1];
    333             } else {
    334                id = ++nobj;
    335 
    336                if(id >= size_aliases) {
    337                   size_aliases *= 2;
    338                   aliases = psRealloc(aliases, size_aliases*sizeof(int));
    339                }
    340                aliases[id] = id;
    341             }
    342 
    343             idc[j] = id;
    344             if(!in_span) {
    345                x0 = j; in_span = id;
    346             }
    347 /*
    348  * Do we need to merge ID numbers? If so, make suitable entries in aliases[]
    349  */
    350             if(idp[j + 1] != 0 && idp[j + 1] != id) {
    351                aliases[resolve_alias(aliases, idp[j + 1])] =
    352                                                     resolve_alias(aliases, id);
    353                
    354                idc[j] = id = idp[j + 1];
    355             }
    356          }
    357       }
    358 
    359       if(in_span) {
    360          if(nspan >= size_spans) {
    361             size_spans *= 2;
    362             spans = psRealloc(spans, size_spans*sizeof(WSPAN));
    363          }
    364 
    365          assert(nspan < size_spans);    /* we checked for space above */
    366          spans[nspan].id = in_span;
    367          spans[nspan].y = i;
    368          spans[nspan].x0 = x0;
    369          spans[nspan].x1 = j - 1;
    370          
    371          nspan++;
    372       }
    373    }
    374 
    375    psFree(id_s);
    376 /*
    377  * Resolve aliases; first alias chains, then the IDs in the spans
    378  */
    379    for (int i = 0; i < nspan; i++) {
    380       spans[i].id = resolve_alias(aliases, spans[i].id);
    381    }
    382 
    383    psFree(aliases);
    384 /*
    385  * Sort spans by ID, so we can sweep through them once
    386  */
    387    if(nspan > 0) {
    388       qsort(spans, nspan, sizeof(WSPAN), compar);
    389    }
    390 /*
    391  * Build pmFootprints from the spans
    392  */
    393    psArray *footprints = psArrayAlloc(nobj);
    394    int n = 0;                   // number of pmFootprints
    395 
    396    if(nspan > 0) {
    397       id = spans[0].id;
    398       i0 = 0;
    399       for (int i = 0; i <= nspan; i++) {        /* nspan + 1 to catch last object */
    400          if(i == nspan || spans[i].id != id) {
    401             pmFootprint *fp = pmFootprintAlloc(i - i0, img);
    402            
    403             for(; i0 < i; i0++) {
    404                 pmFootprintAddSpan(fp, spans[i0].y + row0,
    405                                    spans[i0].x0 + col0, spans[i0].x1 + col0);
    406             }
    407 
    408             if (fp->npix < npixMin) {
    409                psFree(fp);
    410             } else {
    411                footprints->data[n++] = fp;
    412             }
    413          }
    414          
    415          id = spans[i].id;
    416       }
    417    }
    418 
    419    footprints = psArrayRealloc(footprints, n);
    420 /*
    421  * clean up
    422  */
    423    psFree(spans);
    424 
    425    return footprints;
    426 }
    427 
    428 /************************************************************************************************************/
    429 /*
    430  * A data structure to hold the starting point for a search for pixels above threshold,
    431  * used by pmFindFootprintAtPoint
    432  *
    433  * We don't want to find this span again --- it's already part of the footprint ---
    434  * so we set appropriate mask bits
    435  */
    436 //
    437 // An enum for what we should do with a Startspan
    438 //
    439 typedef enum {PM_SSPAN_DOWN = 0,        // scan down from this span
    440               PM_SSPAN_UP,              // scan up from this span
    441               PM_SSPAN_RESTART,         // restart scanning from this span
    442               PM_SSPAN_DONE             // this span is processed
    443 } PM_SSPAN_DIR;                         // How to continue searching
    444 //
    445 // An enum for mask's pixel values.  We're looking for pixels that are above threshold, and
    446 // we keep extra book-keeping information in the PM_SSPAN_STOP plane.  It's simpler to be
    447 // able to check for
    448 //
    449 enum {
    450     PM_SSPAN_INITIAL = 0x0,             // initial state of pixels.
    451     PM_SSPAN_DETECTED = 0x1,            // we've seen this pixel
    452     PM_SSPAN_STOP = 0x2                 // you may stop searching when you see this pixel
    453 };
    454 //
    455 // The struct that remembers how to [re-]start scanning the image for pixels
    456 //
    457 typedef struct {
    458     const pmSpan *span;                 // save the pixel range
    459     PM_SSPAN_DIR direction;             // How to continue searching
    460     bool stop;                          // should we stop searching?
    461 } Spartspan;
    462 
    463 static void startspanFree(Spartspan *sspan) {
    464     psFree((void *)sspan->span);
    465 }
    466 
    467 static Spartspan *
    468 SpartspanAlloc(const pmSpan *span,      // The span in question
    469                psImage *mask,           // Pixels that we've already detected
    470                const PM_SSPAN_DIR dir   // Should we continue searching towards the top of the image?
    471     ) {
    472     Spartspan *sspan = psAlloc(sizeof(Spartspan));
    473     psMemSetDeallocator(sspan, (psFreeFunc)startspanFree);
    474 
    475     sspan->span = psMemIncrRefCounter((void *)span);
    476     sspan->direction = dir;
    477     sspan->stop = false;
    478    
    479     if (mask != NULL) {                 // remember that we've detected these pixels
    480         psMaskType *mpix = &mask->data.PS_TYPE_MASK_DATA[span->y - mask->row0][span->x0 - mask->col0];
    481 
    482         for (int i = 0; i <= span->x1 - span->x0; i++) {
    483             mpix[i] |= PM_SSPAN_DETECTED;
    484             if (mpix[i] & PM_SSPAN_STOP) {
    485                 sspan->stop = true;
    486             }
    487         }
    488     }
    489    
    490     return sspan;
    491 }
    492 
    493 //
    494 // Add a new Spartspan to an array of Spartspans.  Iff we see a stop bit, return true
    495 //
    496 static bool add_startspan(psArray *startspans, // the saved Spartspans
    497                           const pmSpan *sp, // the span in question
    498                           psImage *mask, // mask of detected/stop pixels
    499                           const PM_SSPAN_DIR dir) { // the desired direction to search
    500     if (dir == PM_SSPAN_RESTART) {
    501         if (add_startspan(startspans, sp, mask,  PM_SSPAN_UP) ||
    502             add_startspan(startspans, sp, NULL, PM_SSPAN_DOWN)) {
    503             return true;
    504         }
    505     } else {
    506         Spartspan *sspan = SpartspanAlloc(sp, mask, dir);
    507         if (sspan->stop) {              // we detected a stop bit
    508             psFree(sspan);              // don't allocate new span
    509 
    510             return true;
    511         } else {
    512             psArrayAdd(startspans, 1, sspan);
    513             psFree(sspan);              // as it's now owned by startspans
    514         }
    515     }
    516 
    517     return false;
    518 }
    519 
    520 /************************************************************************************************************/
    521 /*
    522  * Search the image for pixels above threshold, starting at a single Spartspan.
    523  * We search the array looking for one to process; it'd be better to move the
    524  * ones that we're done with to the end, but it probably isn't worth it for
    525  * the anticipated uses of this routine.
    526  *
    527  * This is the guts of pmFindFootprintAtPoint
    528  */
    529 static bool do_startspan(pmFootprint *fp, // the footprint that we're building
    530                          const psImage *img, // the psImage we're working on
    531                          psImage *mask, // the associated masks
    532                          const float threshold, // Threshold
    533                          psArray *startspans) { // specify which span to process next
    534     bool F32 = false;                   // is this an F32 image?
    535     if (img->type.type == PS_TYPE_F32) {
    536         F32 = true;
    537     } else if (img->type.type == PS_TYPE_S32) {
    538         F32 = false;
    539     } else {                            // N.b. You can't trivially add more cases here; F32 is just a bool
    540         psError(PS_ERR_UNKNOWN, true, "Unsupported psImage type: %d", img->type.type);
    541         return NULL;
    542     }
    543 
    544     psF32 *imgRowF32 = NULL;            // row pointer if F32
    545     psS32 *imgRowS32 = NULL;            //  "   "   "  "  !F32
    546     psMaskType *maskRow = NULL;         //  masks's row pointer
    547    
    548     const int row0 = img->row0;
    549     const int col0 = img->col0;
    550     const int numRows = img->numRows;
    551     const int numCols = img->numCols;
    552    
    553     /********************************************************************************************************/
    554    
    555     Spartspan *sspan = NULL;
    556     for (int i = 0; i < startspans->n; i++) {
    557         sspan = startspans->data[i];
    558         if (sspan->direction != PM_SSPAN_DONE) {
    559             break;
    560         }
    561         if (sspan->stop) {
    562             break;
    563         }
    564     }
    565     if (sspan == NULL || sspan->direction == PM_SSPAN_DONE) { // no more Spartspans to process
    566         return false;
    567     }
    568     if (sspan->stop) {                  // they don't want any more spans processed
    569         return false;
    570     }
    571     /*
    572      * Work
    573      */
    574     const PM_SSPAN_DIR dir = sspan->direction;
    575     /*
    576      * Set initial span to the startspan
    577      */
    578     int x0 = sspan->span->x0 - col0, x1 = sspan->span->x1 - col0;
    579     /*
    580      * Go through image identifying objects
    581      */
    582     int nx0, nx1 = -1;                  // new values of x0, x1
    583     const int di = (dir == PM_SSPAN_UP) ? 1 : -1; // how much i changes to get to the next row
    584     bool stop = false;                  // should I stop searching for spans?
    585 
    586     for (int i = sspan->span->y -row0 + di; i < numRows && i >= 0; i += di) {
    587         imgRowF32 = img->data.F32[i];   // only one of
    588         imgRowS32 = img->data.S32[i];   //      these is valid!
    589         maskRow = mask->data.PS_TYPE_MASK_DATA[i];
    590         //
    591         // Search left from the pixel diagonally to the left of (i - di, x0). If there's
    592         // a connected span there it may need to grow up and/or down, so push it onto
    593         // the stack for later consideration
    594         //
    595         nx0 = -1;
    596         for (int j = x0 - 1; j >= -1; j--) {
    597             double pixVal = (j < 0) ? threshold - 100 : (F32 ? imgRowF32[j] : imgRowS32[j]);
    598             if ((maskRow[j] & PM_SSPAN_DETECTED) || pixVal < threshold) {
    599                 if (j < x0 - 1) {       // we found some pixels above threshold
    600                     nx0 = j + 1;
    601                 }
    602                 break;
    603             }
    604         }
    605 
    606         if (nx0 < 0) {                  // no span to the left
    607             nx1 = x0 - 1;               // we're going to resume searching at nx1 + 1
    608         } else {
    609             //
    610             // Search right in leftmost span
    611             //
    612             //nx1 = 0;                  // make gcc happy
    613             for (int j = nx0 + 1; j <= numCols; j++) {
    614                 double pixVal = (j >= numCols) ? threshold - 100 : (F32 ? imgRowF32[j] : imgRowS32[j]);
    615                 if ((maskRow[j] & PM_SSPAN_DETECTED) || pixVal < threshold) {
    616                     nx1 = j - 1;
    617                     break;
    618                 }
    619             }
    620            
    621             const pmSpan *sp = pmFootprintAddSpan(fp, i + row0, nx0 + col0, nx1 + col0);
    622            
    623             if (add_startspan(startspans, sp, mask, PM_SSPAN_RESTART)) {
    624                 stop = true;
    625                 break;
    626             }
    627         }
    628         //
    629         // Now look for spans connected to the old span.  The first of these we'll
    630         // simply process, but others will have to be deferred for later consideration.
    631         //
    632         // In fact, if the span overhangs to the right we'll have to defer the overhang
    633         // until later too, as it too can grow in both directions
    634         //
    635         // Note that column numCols exists virtually, and always ends the last span; this
    636         // is why we claim below that sx1 is always set
    637         //
    638         bool first = false;             // is this the first new span detected?
    639         for (int j = nx1 + 1; j <= x1 + 1; j++) {
    640             double pixVal = (j >= numCols) ? threshold - 100 : (F32 ? imgRowF32[j] : imgRowS32[j]);
    641             if (!(maskRow[j] & PM_SSPAN_DETECTED) && pixVal >= threshold) {
    642                 int sx0 = j++;          // span that we're working on is sx0:sx1
    643                 int sx1 = -1;           // We know that if we got here, we'll also set sx1
    644                 for (; j <= numCols; j++) {
    645                     double pixVal = (j >= numCols) ? threshold - 100 : (F32 ? imgRowF32[j] : imgRowS32[j]);
    646                     if ((maskRow[j] & PM_SSPAN_DETECTED) || pixVal < threshold) { // end of span
    647                         sx1 = j;
    648                         break;
    649                     }
    650                 }
    651                 assert (sx1 >= 0);
    652 
    653                 const pmSpan *sp;
    654                 if (first) {
    655                     if (sx1 <= x1) {
    656                         sp = pmFootprintAddSpan(fp, i + row0, sx0 + col0, sx1 + col0 - 1);
    657                         if (add_startspan(startspans, sp, mask, PM_SSPAN_DONE)) {
    658                             stop = true;
    659                             break;
    660                         }
    661                     } else {            // overhangs to right
    662                         sp = pmFootprintAddSpan(fp, i + row0, sx0 + col0, x1 + col0);
    663                         if (add_startspan(startspans, sp, mask, PM_SSPAN_DONE)) {
    664                             stop = true;
    665                             break;
    666                         }
    667                         sp = pmFootprintAddSpan(fp, i + row0, x1 + 1 + col0, sx1 + col0 - 1);
    668                         if (add_startspan(startspans, sp, mask, PM_SSPAN_RESTART)) {
    669                             stop = true;
    670                             break;
    671                         }
    672                     }
    673                     first = false;
    674                 } else {
    675                     sp = pmFootprintAddSpan(fp, i + row0, sx0 + col0, sx1 + col0 - 1);
    676                     if (add_startspan(startspans, sp, mask, PM_SSPAN_RESTART)) {
    677                         stop = true;
    678                         break;
    679                     }
    680                 }
    681             }
    682         }
    683 
    684         if (stop || first == false) {   // we're done
    685             break;
    686         }
    687 
    688         x0 = nx0; x1 = nx1;
    689     }
    690     /*
    691      * Cleanup
    692      */
    693 
    694     sspan->direction = PM_SSPAN_DONE;
    695     return stop ? false : true;
    696 }
    697 
    698 /*
    699  * Go through an image, starting at (row, col) and assembling all the pixels
    700  * that are connected to that point (in a chess kings-move sort of way) into
    701  * a pmFootprint.
    702  *
    703  * This is much slower than pmFindFootprints if you want to find lots of
    704  * footprints, but if you only want a small region about a given point it
    705  * can be much faster
    706  *
    707  * N.b. The returned pmFootprint is not in "normal form"; that is the pmSpans
    708  * are not sorted by increasing y, x0, x1.  If this matters to you, call
    709  * pmFootprintNormalize()
    710  */
    711 pmFootprint *
    712 pmFindFootprintAtPoint(const psImage *img,      // image to search
    713                        const float threshold,   // Threshold
    714                        const psArray *peaks, // array of peaks; finding one terminates search for footprint
    715                        int row, int col) { // starting position (in img's parent's coordinate system)
    716    assert(img != NULL);
    717 
    718    bool F32 = false;                    // is this an F32 image?
    719    if (img->type.type == PS_TYPE_F32) {
    720        F32 = true;
    721    } else if (img->type.type == PS_TYPE_S32) {
    722        F32 = false;
    723    } else {                             // N.b. You can't trivially add more cases here; F32 is just a bool
    724        psError(PS_ERR_UNKNOWN, true, "Unsupported psImage type: %d", img->type.type);
    725        return NULL;
    726    }
    727    psF32 *imgRowF32 = NULL;             // row pointer if F32
    728    psS32 *imgRowS32 = NULL;             //  "   "   "  "  !F32
    729    
    730    const int row0 = img->row0;
    731    const int col0 = img->col0;
    732    const int numRows = img->numRows;
    733    const int numCols = img->numCols;
    734 /*
    735  * Is point in image, and above threshold?
    736  */
    737    row -= row0; col -= col0;
    738    if (row < 0 || row >= numRows ||
    739        col < 0 || col >= numCols) {
    740         psError(PS_ERR_BAD_PARAMETER_VALUE, true,
    741                 "row/col == (%d, %d) are out of bounds [%d--%d, %d--%d]",
    742                 row + row0, col + col0, row0, row0 + numRows - 1, col0, col0 + numCols - 1);
    743        return NULL;
    744    }
    745 
    746    double pixVal = F32 ? img->data.F32[row][col] : img->data.S32[row][col];
    747    if (pixVal < threshold) {
    748        return pmFootprintAlloc(0, img);
    749    }
    750    
    751    pmFootprint *fp = pmFootprintAlloc(1 + img->numRows/10, img);
    752 /*
    753  * We need a mask for two purposes; to indicate which pixels are already detected,
    754  * and to store the "stop" pixels --- those that, once reached, should stop us
    755  * looking for the rest of the pmFootprint.  These are generally set from peaks.
    756  */
    757    psImage *mask = psImageAlloc(numCols, numRows, PS_TYPE_MASK);
    758    P_PSIMAGE_SET_ROW0(mask, row0);
    759    P_PSIMAGE_SET_COL0(mask, col0);
    760    psImageInit(mask, PM_SSPAN_INITIAL);
    761    //
    762    // Set stop bits from peaks list
    763    //
    764    assert (peaks == NULL || peaks->n == 0 || psMemCheckPeak(peaks->data[0]));
    765    if (peaks != NULL) {
    766        for (int i = 0; i < peaks->n; i++) {
    767            pmPeak *peak = peaks->data[i];
    768            mask->data.PS_TYPE_MASK_DATA[peak->y - mask->row0][peak->x - mask->col0] |= PM_SSPAN_STOP;
    769        }
    770    }
    771 /*
    772  * Find starting span passing through (row, col)
    773  */
    774    psArray *startspans = psArrayAllocEmpty(1); // spans where we have to restart the search
    775    
    776    imgRowF32 = img->data.F32[row];      // only one of
    777    imgRowS32 = img->data.S32[row];      //      these is valid!
    778    psMaskType *maskRow = mask->data.PS_TYPE_MASK_DATA[row];
    779    {
    780        int i;
    781        for (i = col; i >= 0; i--) {
    782            pixVal = F32 ? imgRowF32[i] : imgRowS32[i];
    783            if ((maskRow[i] & PM_SSPAN_DETECTED) || pixVal < threshold) {
    784                break;
    785            }
    786        }
    787        int i0 = i;
    788        for (i = col; i < numCols; i++) {
    789            pixVal = F32 ? imgRowF32[i] : imgRowS32[i];
    790            if ((maskRow[i] & PM_SSPAN_DETECTED) || pixVal < threshold) {
    791                break;
    792            }
    793        }
    794        int i1 = i;
    795        const pmSpan *sp = pmFootprintAddSpan(fp, row + row0, i0 + col0 + 1, i1 + col0 - 1);
    796 
    797        (void)add_startspan(startspans, sp, mask, PM_SSPAN_RESTART);
    798    }
    799    /*
    800     * Now workout from those Spartspans, searching for pixels above threshold
    801     */
    802    while (do_startspan(fp, img, mask, threshold, startspans)) continue;
    803    /*
    804     * Cleanup
    805     */
    806    psFree(mask);
    807    psFree(startspans);                  // restores the image pixel
    808 
    809    return fp;                           // pmFootprint really
    810 }
    811 
    812 /************************************************************************************************************/
    813 /*
    814  * Worker routine for the pmSetFootprintArrayIDs/pmSetFootprintID (and pmMergeFootprintArrays)
    815  */
    816 static void
    817 set_footprint_id(psImage *idImage,      // the image to set
    818                  const pmFootprint *fp, // the footprint to insert
    819                  const int id) {        // the desired ID
    820    const int col0 = fp->region.x0;
    821    const int row0 = fp->region.y0;
    822 
    823    for (int j = 0; j < fp->spans->n; j++) {
    824        const pmSpan *span = fp->spans->data[j];
    825        psS32 *imgRow = idImage->data.S32[span->y - row0];
    826        for(int k = span->x0 - col0; k <= span->x1 - col0; k++) {
    827            imgRow[k] += id;
    828        }
    829    }
    830 }
    831 
    832 static void
    833 set_footprint_array_ids(psImage *idImage,
    834                         const psArray *footprints, // the footprints to insert
    835                         const bool relativeIDs) { // show IDs starting at 0, not pmFootprint->id
    836    int id = 0;                          // first index will be 1
    837    for (int i = 0; i < footprints->n; i++) {
    838        const pmFootprint *fp = footprints->data[i];
    839        if (relativeIDs) {
    840            id++;
    841        } else {
    842            id = fp->id;
    843        }
    844        
    845        set_footprint_id(idImage, fp, id);
    846    }
    847 }
    848 
    849 /*
    850  * Set an image to the value of footprint's ID whever they may fall
    851  */
    852 psImage *pmSetFootprintArrayIDs(const psArray *footprints, // the footprints to insert
    853                                 const bool relativeIDs) { // show IDs starting at 1, not pmFootprint->id
    854    assert (footprints != NULL);
    855 
    856    if (footprints->n == 0) {
    857        psError(PS_ERR_BAD_PARAMETER_SIZE, true, "You didn't provide any footprints");
    858        return NULL;
    859    }
    860    const pmFootprint *fp = footprints->data[0];
    861    assert(pmFootprintTest((const psPtr)fp));
    862    const int numCols = fp->region.x1 - fp->region.x0 + 1;
    863    const int numRows = fp->region.y1 - fp->region.y0 + 1;
    864    const int col0 = fp->region.x0;
    865    const int row0 = fp->region.y0;
    866    assert (numCols >= 0 && numRows >= 0);
    867    
    868    psImage *idImage = psImageAlloc(numCols, numRows, PS_TYPE_S32);
    869    P_PSIMAGE_SET_ROW0(idImage, row0);
    870    P_PSIMAGE_SET_COL0(idImage, col0);
    871    psImageInit(idImage, 0);
    872    /*
    873     * do the work
    874     */
    875    set_footprint_array_ids(idImage, footprints, relativeIDs);
    876 
    877    return idImage;
    878    
    879 }
    880 
    881 /*
    882  * Set an image to the value of footprint's ID whever they may fall
    883  */
    884 psImage *pmSetFootprintID(const pmFootprint *fp, // the footprint to insert
    885                           const int id) {       // the desired ID
    886    assert(fp != NULL && pmFootprintTest((const psPtr)fp));
    887    const int numCols = fp->region.x1 - fp->region.x0 + 1;
    888    const int numRows = fp->region.y1 - fp->region.y0 + 1;
    889    const int col0 = fp->region.x0;
    890    const int row0 = fp->region.y0;
    891    assert (numCols >= 0 && numRows >= 0);
    892    
    893    psImage *idImage = psImageAlloc(numCols, numRows, PS_TYPE_S32);
    894    P_PSIMAGE_SET_ROW0(idImage, row0);
    895    P_PSIMAGE_SET_COL0(idImage, col0);
    896    psImageInit(idImage, 0);
    897    /*
    898     * do the work
    899     */
    900    set_footprint_id(idImage, fp, id);
    901 
    902    return idImage;
    903    
    904 }
    905 
    906 /************************************************************************************************************/
    907 /*
    908  * Grow a psArray of pmFootprints isotropically by r pixels, returning a new psArray of new pmFootprints
    909  */
    910 psArray *pmGrowFootprintArray(const psArray *footprints, // footprints to grow
    911                               int r) {  // how much to grow each footprint
    912     assert (footprints->n == 0 || pmFootprintTest(footprints->data[0]));
    913 
    914     if (footprints->n == 0) {           // we don't know the size of the footprint's region
    915         return psArrayAlloc(0);
    916     }
    917     /*
    918      * We'll insert the footprints into an image, then convolve with a disk,
    919      * then extract a footprint from the result --- this is magically what we want.
    920      */
    921     psImage *idImage = pmSetFootprintArrayIDs(footprints, true);
    922     if (r <= 0) {
    923         r = 1;                          // r == 1 => no grow
    924     }
    925     psKernel *circle = psKernelAlloc(-r, r, -r, r);
    926     assert (circle->image->numRows == 2*r + 1 && circle->image->numCols == circle->image->numRows);
    927     for (int i = 0; i <= r; i++) {
    928         for (int j = 0; j <= r; j++) {
    929             if (i*i + j*j <= r*r) {
    930                 circle->kernel[i][j] =
    931                     circle->kernel[i][-j] =
    932                     circle->kernel[-i][j] =
    933                     circle->kernel[-i][-j] = 1;
    934             }
    935         }
    936     }
    937 
    938     psImage *grownIdImage = psImageConvolveDirect(NULL, idImage, circle); // Here's the actual grow step
    939     psFree(circle);     
    940 
    941     psArray *grown = pmFindFootprints(grownIdImage, 0.5, 1); // and here we rebuild the grown footprints
    942     assert (grown != NULL);
    943     psFree(idImage); psFree(grownIdImage);
    944     /*
    945      * Now assign the peaks appropriately.  We could do this more efficiently
    946      * using grownIdImage (which we just freed), but this is easy and probably fast enough
    947      */
    948     const psArray *peaks = pmFootprintArrayToPeaks(footprints);
    949     pmPeaksAssignToFootprints(grown, peaks);
    950     psFree((psArray *)peaks);
    951 
    952     return grown;
    953    
    954 }
    955 
    956 /************************************************************************************************************/
    957 /*
    958  * Merge together two psArrays of pmFootprints neither of which is damaged.
    959  *
    960  * The returned psArray may contain elements of the inital psArrays (with
    961  * their reference counters suitable incremented)
    962  */
    963 psArray *pmMergeFootprintArrays(const psArray *footprints1, // one set of footprints
    964                                 const psArray *footprints2, // the other set
    965                                 const int includePeaks) { // which peaks to set? 0x1 => footprints1, 0x2 => 2
    966     assert (footprints1->n == 0 || pmFootprintTest(footprints1->data[0]));
    967     assert (footprints2->n == 0 || pmFootprintTest(footprints2->data[0]));
    968 
    969     if (footprints1->n == 0 || footprints2->n == 0) {           // nothing to do but put copies on merged
    970         const psArray *old = (footprints1->n == 0) ? footprints2 : footprints1;
    971 
    972         psArray *merged = psArrayAllocEmpty(old->n);
    973         for (int i = 0; i < old->n; i++) {
    974             psArrayAdd(merged, 1, old->data[i]);
    975         }
    976        
    977         return merged;
    978     }
    979     /*
    980      * We have real work to do as some pmFootprints in footprints2 may overlap
    981      * with footprints1
    982      */
    983     {
    984         pmFootprint *fp1 = footprints1->data[0];
    985         pmFootprint *fp2 = footprints2->data[0];
    986         if (fp1->region.x0 != fp2->region.x0 ||
    987             fp1->region.x1 != fp2->region.x1 ||
    988             fp1->region.y0 != fp2->region.y0 ||
    989             fp1->region.y1 != fp2->region.y1) {
    990             psError(PS_ERR_BAD_PARAMETER_SIZE, true,
    991                     "The two pmFootprint arrays correspnond to different-sized regions");
    992             return NULL;
    993         }
    994     }
    995     /*
    996      * We'll insert first one set of footprints then the other into an image, then
    997      * extract a footprint from the result --- this is magically what we want.
    998      */
    999     psImage *idImage = pmSetFootprintArrayIDs(footprints1, true);
    1000     set_footprint_array_ids(idImage, footprints2, true);
    1001 
    1002     psArray *merged = pmFindFootprints(idImage, 0.5, 1);
    1003     assert (merged != NULL);
    1004     psFree(idImage);
    1005     /*
    1006      * Now assign the peaks appropriately.  We could do this more efficiently
    1007      * using idImage (which we just freed), but this is easy and probably fast enough
    1008      */
    1009     if (includePeaks & 0x1) {
    1010         const psArray *peaks = pmFootprintArrayToPeaks(footprints1);
    1011         pmPeaksAssignToFootprints(merged, peaks);
    1012         psFree((psArray *)peaks);
    1013     }
    1014 
    1015     if (includePeaks & 0x2) {
    1016         const psArray *peaks = pmFootprintArrayToPeaks(footprints2);
    1017         pmPeaksAssignToFootprints(merged, peaks);
    1018         psFree((psArray *)peaks);
    1019     }
    1020    
    1021     return merged;
    1022 }
    1023 
    1024 /************************************************************************************************************/
    1025 /*
    1026  * Given a psArray of pmFootprints and another of pmPeaks, assign the peaks to the
    1027  * footprints in which that fall; if they _don't_ fall in a footprint, add a suitable
    1028  * one to the list.
    1029  */
    1030 psErrorCode
    1031 pmPeaksAssignToFootprints(psArray *footprints,  // the pmFootprints
    1032                           const psArray *peaks) { // the pmPeaks
    1033     assert (footprints != NULL);
    1034     assert (footprints->n == 0 || pmFootprintTest(footprints->data[0]));
    1035     assert (peaks != NULL);
    1036     assert (peaks->n == 0 || psMemCheckPeak(peaks->data[0]));
    1037    
    1038     if (footprints->n == 0) {
    1039         if (peaks->n > 0) {
    1040             return psError(PS_ERR_BAD_PARAMETER_SIZE, true, "Your list of footprints is empty");
    1041         }
    1042         return PS_ERR_NONE;
    1043     }
    1044     /*
    1045      * Create an image filled with the object IDs, and use it to assign pmPeaks to the
    1046      * objects
    1047      */
    1048     psImage *ids = pmSetFootprintArrayIDs(footprints, true);
    1049     assert (ids != NULL);
    1050     assert (ids->type.type == PS_TYPE_S32);
    1051     const int row0 = ids->row0;
    1052     const int col0 = ids->col0;
    1053     const int numRows = ids->numRows;
    1054     const int numCols = ids->numCols;
    1055 
    1056     for (int i = 0; i < peaks->n; i++) {
    1057         pmPeak *peak = peaks->data[i];
    1058         const int x = peak->x - col0;
    1059         const int y = peak->y - row0;
    1060        
    1061         assert (x >= 0 && x < numCols && y >= 0 && y < numRows);
    1062         int id = ids->data.S32[y][x - col0];
    1063 
    1064         if (id == 0) {                  // peak isn't in a footprint, so make one for it
    1065             pmFootprint *nfp = pmFootprintAlloc(1, ids);
    1066             pmFootprintAddSpan(nfp, y, x, x);
    1067             psArrayAdd(footprints, 1, nfp);
    1068             psFree(nfp);
    1069             id = footprints->n;
    1070         }
    1071 
    1072         assert (id >= 1 && id <= footprints->n);
    1073         pmFootprint *fp = footprints->data[id - 1];
    1074         psArrayAdd(fp->peaks, 5, peak);
    1075     }
    1076    
    1077     psFree(ids);
    1078     //
    1079     // Make sure that peaks within each footprint are sorted and unique
    1080     //
    1081     for (int i = 0; i < footprints->n; i++) {
    1082         pmFootprint *fp = footprints->data[i];
    1083         fp->peaks = psArraySort(fp->peaks, pmPeakSortBySN);
    1084 
    1085         for (int j = 1; j < fp->peaks->n; j++) { // check for duplicates
    1086             if (fp->peaks->data[j] == fp->peaks->data[j-1]) {
    1087                 (void)psArrayRemoveIndex(fp->peaks, j);
    1088                 j--;                    // we moved everything down one
    1089             }
    1090         }
    1091     }
    1092 
    1093     return PS_ERR_NONE;
    1094 }
    1095 
    1096 /************************************************************************************************************/
    1097  /*
    1098   * Examine the peaks in a pmFootprint, and throw away the ones that are not sufficiently
    1099   * isolated.  More precisely, for each peak find the highest coll that you'd have to traverse
    1100   * to reach a still higher peak --- and if that coll's more than nsigma DN below your
    1101   * starting point, discard the peak.
    1102   */
    1103 psErrorCode pmFootprintCullPeaks(const psImage *img, // the image wherein lives the footprint
    1104                                  const psImage *weight, // corresponding variance image
    1105                                  pmFootprint *fp, // Footprint containing mortal peaks
    1106                                  const float nsigma_delta, // how many sigma above local background a peak
    1107                                         // needs to be to survive
    1108                                  const float min_threshold) { // minimum permitted coll height
    1109     assert (img != NULL); assert (img->type.type == PS_TYPE_F32);
    1110     assert (weight != NULL); assert (weight->type.type == PS_TYPE_F32);
    1111     assert (img->row0 == weight->row0 && img->col0 == weight->col0);
    1112     assert (fp != NULL);
    1113 
    1114     if (fp->peaks == NULL || fp->peaks->n == 0) { // nothing to do
    1115         return PS_ERR_NONE;
    1116     }
    1117 
    1118     psRegion subRegion;                 // desired subregion; 1 larger than bounding box (grr)
    1119     subRegion.x0 = fp->bbox.x0; subRegion.x1 = fp->bbox.x1 + 1;
    1120     subRegion.y0 = fp->bbox.y0; subRegion.y1 = fp->bbox.y1 + 1;
    1121     const psImage *subImg = psImageSubset((psImage *)img, subRegion);
    1122     const psImage *subWt = psImageSubset((psImage *)weight, subRegion);
    1123     assert (subImg != NULL && subWt != NULL);
    1124     //
    1125     // We need a psArray of peaks brighter than the current peak.  We'll fake this
    1126     // by reusing the fp->peaks but lying about n.
    1127     //
    1128     // We do this for efficiency (otherwise I'd need two peaks lists), and we are
    1129     // rather too chummy with psArray in consequence.  But it works.
    1130     //
    1131     psArray *brightPeaks = psArrayAlloc(0);
    1132     psFree(brightPeaks->data);
    1133     brightPeaks->data = psMemIncrRefCounter(fp->peaks->data);// use the data from fp->peaks
    1134     //
    1135     // The brightest peak is always safe; go through other peaks trying to cull them
    1136     //
    1137     for (int i = 1; i < fp->peaks->n; i++) { // n.b. fp->peaks->n can change within the loop
    1138         const pmPeak *peak = fp->peaks->data[i];
    1139         int x = peak->x - subImg->col0;
    1140         int y = peak->y - subImg->row0;
    1141         //
    1142         // Find the level nsigma below the peak that must separate the peak
    1143         // from any of its friends
    1144         //
    1145         assert (x >= 0 && x < subImg->numCols && y >= 0 && y < subImg->numRows);
    1146         const float stdev = sqrt(subWt->data.F32[y][x]);
    1147         float threshold = subImg->data.F32[y][x] - nsigma_delta*stdev;
    1148         if (isnan(threshold) || threshold < min_threshold) {
    1149 #if 1                                   // min_threshold is assumed to be below the detection threshold,
    1150                                         // so all the peaks are pmFootprint, and this isn't the brightest
    1151             (void)psArrayRemoveIndex(fp->peaks, i);
    1152             i--;                        // we moved everything down one
    1153             continue;
    1154 #else
    1155 #error n.b. We will be running LOTS of checks at this threshold, so only find the footprint once
    1156             threshold = min_threshold;
    1157 #endif
    1158         }
    1159         if (threshold > subImg->data.F32[y][x]) {
    1160             threshold = subImg->data.F32[y][x] - 10*FLT_EPSILON;
    1161         }
    1162 
    1163         const int peak_id = 1;          // the ID for the peak of interest
    1164         brightPeaks->n = i;             // only stop at a peak brighter than we are
    1165         pmFootprint *peakFootprint = pmFindFootprintAtPoint(subImg, threshold, brightPeaks, peak->y, peak->x);
    1166         brightPeaks->n = 0;             // don't double free
    1167         psImage *idImg = pmSetFootprintID(peakFootprint, peak_id);
    1168         psFree(peakFootprint);
    1169 
    1170         int j;
    1171         for (j = 0; j < i; j++) {
    1172             const pmPeak *peak2 = fp->peaks->data[j];
    1173             int x2 = peak2->x - subImg->col0;
    1174             int y2 = peak2->y - subImg->row0;
    1175             const int peak2_id = idImg->data.S32[y2][x2]; // the ID for some other peak
    1176 
    1177             if (peak2_id == peak_id) {  // There's a brighter peak within the footprint above
    1178                 ;                       // threshold; so cull our initial peak
    1179                 (void)psArrayRemoveIndex(fp->peaks, i);
    1180                 i--;                    // we moved everything down one
    1181                 break;
    1182             }
    1183         }
    1184         if (j == i) {
    1185             j++;
    1186         }
    1187 
    1188         psFree(idImg);
    1189     }
    1190 
    1191     brightPeaks->n = 0; psFree(brightPeaks);
    1192     psFree((psImage *)subImg);
    1193     psFree((psImage *)subWt);
    1194 
    1195     return PS_ERR_NONE;
    1196 }
    1197 
    1198 /*
    1199  * Cull an entire psArray of pmFootprints
    1200  */
    1201 psErrorCode
    1202 pmFootprintArrayCullPeaks(const psImage *img, // the image wherein lives the footprint
    1203                           const psImage *weight,        // corresponding variance image
    1204                           psArray *footprints, // array of pmFootprints
    1205                           const float nsigma_delta, // how many sigma above local background a peak
    1206                                         // needs to be to survive
    1207                           const float min_threshold) { // minimum permitted coll height
    1208     for (int i = 0; i < footprints->n; i++) {
    1209         pmFootprint *fp = footprints->data[i];
    1210         if (pmFootprintCullPeaks(img, weight, fp, nsigma_delta, min_threshold) != PS_ERR_NONE) {
    1211             return psError(PS_ERR_UNKNOWN, false, "Culling pmFootprint %d", fp->id);
    1212         }
    1213     }
    1214    
    1215     return PS_ERR_NONE;
    1216 }
    1217 
    1218 /************************************************************************************************************/
    1219142/*
    1220143 * Extract the peaks in a psArray of pmFootprints, returning a psArray of pmPeaks
     
    1242165}
    1243166
    1244 void pmDetectionsFree (pmDetections *detections) {
    1245 
    1246   if (!detections) return;
    1247 
    1248   psFree (detections->footprints);
    1249   psFree (detections->peaks);
    1250   psFree (detections->oldPeaks);
    1251   return;
    1252 }
    1253 
    1254 // generate a pmDetections container with empty (allocated) footprints and peaks containers
    1255 pmDetections *pmDetectionsAlloc() {
    1256 
    1257     pmDetections *detections = (pmDetections *)psAlloc(sizeof(pmDetections));
    1258     psMemSetDeallocator(detections, (psFreeFunc) pmDetectionsFree);
    1259 
    1260     detections->footprints = NULL;
    1261     detections->peaks      = NULL;
    1262     detections->oldPeaks   = NULL;
    1263     detections->last       = 0;
    1264 
    1265     return (detections);
    1266 }
    1267 
    1268167/************************************************************************************************************/
    1269 /*
    1270  * Cull a set of peaks contained in a psArray of pmFootprints
    1271  */
    1272 psErrorCode
    1273 psphotCullPeaks(const psImage *image,   // the image wherein lives the footprint
    1274                 const psImage *weight,  // corresponding variance image
    1275                 const psMetadata *recipe,
    1276                 psArray *footprints) {  // array of pmFootprints
    1277     bool status = false;
    1278     float nsigma_delta = psMetadataLookupF32(&status, recipe, "FOOTPRINT_CULL_NSIGMA_DELTA");
    1279     if (!status) {
    1280         nsigma_delta = 0; // min.
    1281     }
    1282     float nsigma_min = psMetadataLookupF32(&status, recipe, "FOOTPRINT_CULL_NSIGMA_MIN");
    1283     if (!status) {
    1284         nsigma_min = 0;
    1285     }
    1286     const float skyStdev = psMetadataLookupF32(NULL, recipe, "SKY_STDEV");
    1287 
    1288     return pmFootprintArrayCullPeaks(image, weight, footprints,
    1289                                      nsigma_delta, nsigma_min*skyStdev);
    1290 }
    1291 
  • trunk/psphot/src/pmFootprint.h

    r16820 r17443  
    3030int pmFootprintSetNpix(pmFootprint *fp);
    3131void pmFootprintSetBBox(pmFootprint *fp);
    32 psArray *pmFindFootprints(const psImage *img, const float threshold, const int npixMin);
    33 pmFootprint *pmFindFootprintAtPoint(const psImage *img,
     32
     33pmSpan *pmFootprintAddSpan(pmFootprint *fp,     // the footprint to add to
     34                           const int y, // row to add
     35                           int x0,      // range of
     36                           int x1);    //          columns
     37
     38psArray *pmFootprintsFind(const psImage *img, const float threshold, const int npixMin);
     39pmFootprint *pmFootprintsFindAtPoint(const psImage *img,
    3440                                    const float threshold,
    3541                                    const psArray *peaks,
    3642                                    int row, int col);
    3743
    38 psArray *pmGrowFootprintArray(const psArray *footprints, int r);
    39 psArray *pmMergeFootprintArrays(const psArray *footprints1, const psArray *footprints2,
     44psArray *pmFootprintArrayGrow(const psArray *footprints, int r);
     45psArray *pmFootprintArraysMerge(const psArray *footprints1, const psArray *footprints2,
    4046                                const int includePeaks);
    4147
    4248psImage *pmSetFootprintArrayIDs(const psArray *footprints, const bool relativeIDs);
    4349psImage *pmSetFootprintID(const pmFootprint *fp, const int id);
     50void pmSetFootprintArrayIDsForImage(psImage *idImage,
     51                                    const psArray *footprints, // the footprints to insert
     52                                    const bool relativeIDs); // show IDs starting at 0, not pmFootprint->id
    4453
    45 psErrorCode pmPeaksAssignToFootprints(psArray *footprints, const psArray *peaks);
     54psErrorCode pmFootprintsAssignPeaks(psArray *footprints, const psArray *peaks);
    4655
    4756psErrorCode pmFootprintArrayCullPeaks(const psImage *img, const psImage *weight, psArray *footprints,
  • trunk/psphot/src/psphot.h

    r17396 r17443  
    4949
    5050// used by psphotFindDetections
    51 psArray        *psphotFindPeaks (pmReadout *readout, psMetadata *recipe, const bool returnFootprints, const int pass, psMaskType maskVal);
     51psImage        *psphotSignificanceImage (pmReadout *readout, psMetadata *recipe, const int pass, psMaskType maskVal);
     52psArray        *psphotFindPeaks (psImage *significance, pmReadout *readout, psMetadata *recipe, const int pass, psMaskType maskVal);
     53bool            psphotFindFootprints (pmDetections *detections, psImage *significance, pmReadout *readout, psMetadata *recipe, const int pass, psMaskType maskVal);
    5254psErrorCode     psphotCullPeaks(const psImage *img, const psImage *weight, const psMetadata *recipe, psArray *footprints);
    5355
Note: See TracChangeset for help on using the changeset viewer.