IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
May 3, 2010, 8:50:52 AM (16 years ago)
Author:
eugene
Message:

updates from trunk

Location:
branches/simtest_nebulous_branches
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • branches/simtest_nebulous_branches

  • branches/simtest_nebulous_branches/psModules

  • branches/simtest_nebulous_branches/psModules/src/objects/pmFootprintFindAtPoint.c

    r21183 r27840  
    2121#include "pmFootprint.h"
    2222#include "pmPeaks.h"
    23 
    24 /*
    25  * A data structure to hold the starting point for a search for pixels above threshold,
    26  * used by pmFootprintsFindAtPoint
    27  *
    28  * We don't want to find this span again --- it's already part of the footprint ---
    29  * so we set appropriate mask bits
    30  *
    31  * EAM : these function were confusingly using "startspan" and "spartspan" 
    32  * I've rationalized them all to 'startspan'
    33  */
    34 
    35 //
    36 // An enum for what we should do with a Startspan
    37 //
    38 typedef enum {PM_SSPAN_DOWN = 0,        // scan down from this span
    39               PM_SSPAN_UP,              // scan up from this span
    40               PM_SSPAN_RESTART,         // restart scanning from this span
    41               PM_SSPAN_DONE             // this span is processed
    42 } PM_SSPAN_DIR;                         // How to continue searching
    43 //
    44 // An enum for mask's pixel values.  We're looking for pixels that are above threshold, and
    45 // we keep extra book-keeping information in the PM_SSPAN_STOP plane.  It's simpler to be
    46 // able to check for
    47 //
    48 enum {
    49     PM_SSPAN_INITIAL = 0x0,             // initial state of pixels.
    50     PM_SSPAN_DETECTED = 0x1,            // we've seen this pixel
    51     PM_SSPAN_STOP = 0x2                 // you may stop searching when you see this pixel
    52 };
    53 //
    54 // The struct that remembers how to [re-]start scanning the image for pixels
    55 //
    56 typedef struct {
    57     const pmSpan *span;                 // save the pixel range
    58     PM_SSPAN_DIR direction;             // How to continue searching
    59     bool stop;                          // should we stop searching?
    60 } Startspan;
    61 
    62 static void startspanFree(Startspan *sspan) {
    63     psFree((void *)sspan->span);
    64 }
    65 
    66 static Startspan *
    67 StartspanAlloc(const pmSpan *span,      // The span in question
    68                psImage *mask,           // Pixels that we've already detected
    69                const PM_SSPAN_DIR dir   // Should we continue searching towards the top of the image?
    70     ) {
    71     Startspan *sspan = psAlloc(sizeof(Startspan));
    72     psMemSetDeallocator(sspan, (psFreeFunc)startspanFree);
    73 
    74     sspan->span = psMemIncrRefCounter((void *)span);
    75     sspan->direction = dir;
    76     sspan->stop = false;
    77    
    78     if (mask != NULL) {                 // remember that we've detected these pixels
    79         psImageMaskType *mpix = &mask->data.PS_TYPE_IMAGE_MASK_DATA[span->y - mask->row0][span->x0 - mask->col0];
    80 
    81         for (int i = 0; i <= span->x1 - span->x0; i++) {
    82             mpix[i] |= PM_SSPAN_DETECTED;
    83             if (mpix[i] & PM_SSPAN_STOP) {
    84                 sspan->stop = true;
    85             }
    86         }
    87     }
    88    
    89     return sspan;
    90 }
    91 
    92 //
    93 // Add a new Startspan to an array of Startspans.  Iff we see a stop bit, return true
    94 //
    95 static bool add_startspan(psArray *startspans, // the saved Startspans
    96                           const pmSpan *sp, // the span in question
    97                           psImage *mask, // mask of detected/stop pixels
    98                           const PM_SSPAN_DIR dir) { // the desired direction to search
    99     if (dir == PM_SSPAN_RESTART) {
    100         if (add_startspan(startspans, sp, mask,  PM_SSPAN_UP) ||
    101             add_startspan(startspans, sp, NULL, PM_SSPAN_DOWN)) {
    102             return true;
    103         }
    104     } else {
    105         Startspan *sspan = StartspanAlloc(sp, mask, dir);
    106         if (sspan->stop) {              // we detected a stop bit
    107             psFree(sspan);              // don't allocate new span
    108 
    109             return true;
    110         } else {
    111             psArrayAdd(startspans, 1, sspan);
    112             psFree(sspan);              // as it's now owned by startspans
    113         }
    114     }
    115 
    116     return false;
    117 }
     23#include "pmFootprintSpans.h"
    11824
    11925/************************************************************************************************************/
    12026/*
    121  * Search the image for pixels above threshold, starting at a single Startspan.
     27 * Search the image for pixels above threshold, starting at a single pmStartSpan.
    12228 * We search the array looking for one to process; it'd be better to move the
    12329 * ones that we're done with to the end, but it probably isn't worth it for
     
    12632 * This is the guts of pmFootprintsFindAtPoint
    12733 */
    128 static bool do_startspan(pmFootprint *fp, // the footprint that we're building
    129                          const psImage *img, // the psImage we're working on
    130                          psImage *mask, // the associated masks
    131                          const float threshold, // Threshold
    132                          psArray *startspans) { // specify which span to process next
    133     bool F32 = false;                   // is this an F32 image?
     34bool pmFootprintSpansBuild(pmFootprint *fp, // the footprint that we're building
     35                           pmFootprintSpans *fpSpans,
     36                           const psImage *img, // the psImage we're working on
     37                           psImage *mask, // the associated masks
     38                           const float threshold // Threshold
     39    ) {
     40    bool F32 = false;                   // is this an F32 image?
     41    if (img->type.type == PS_TYPE_F32) {
     42        F32 = true;
     43    } else if (img->type.type == PS_TYPE_S32) {
     44        F32 = false;
     45    } else {                            // N.b. You can't trivially add more cases here; F32 is just a bool
     46        psError(PS_ERR_UNKNOWN, true, "Unsupported psImage type: %d", img->type.type);
     47        return NULL;
     48    }
     49
     50    psF32 *imgRowF32 = NULL;            // row pointer if F32
     51    psS32 *imgRowS32 = NULL;            //  "   "   "  "  !F32
     52    psImageMaskType *maskRow = NULL;            //  masks's row pointer
     53
     54    const int row0 = img->row0;
     55    const int col0 = img->col0;
     56    const int numRows = img->numRows;
     57    const int numCols = img->numCols;
     58
     59    /********************************************************************************************************/
     60
     61    pmStartSpan *startspan = NULL;
     62    for (int i = 0; i < fpSpans->nStartSpans; i++) {
     63        startspan = fpSpans->startspans->data[i];
     64        if (startspan->direction != PM_STARTSPAN_DONE) {
     65            break;
     66        }
     67        if (startspan->stop) {
     68            break;
     69        }
     70    }
     71    if (startspan == NULL || startspan->direction == PM_STARTSPAN_DONE) { // no more pmStartSpans to process
     72        return false;
     73    }
     74    if (startspan->stop) {                  // they don't want any more spans processed
     75        return false;
     76    }
     77
     78    /*
     79     * Work
     80     */
     81    const PM_STARTSPAN_DIR dir = startspan->direction;
     82    /*
     83     * Set initial span to the startspan
     84     */
     85    int x0 = startspan->span->x0 - col0, x1 = startspan->span->x1 - col0;
     86    /*
     87     * Go through image identifying objects
     88     */
     89    int nx0, nx1 = -1;                  // new values of x0, x1
     90    const int di = (dir == PM_STARTSPAN_UP) ? 1 : -1; // how much i changes to get to the next row
     91    bool stop = false;                  // should I stop searching for spans?
     92
     93    for (int i = startspan->span->y - row0 + di; i < numRows && i >= 0; i += di) {
     94        imgRowF32 = img->data.F32[i];   // only one of
     95        imgRowS32 = img->data.S32[i];   //      these is valid!
     96        maskRow = mask->data.PS_TYPE_IMAGE_MASK_DATA[i];
     97        //
     98        // Search left from the pixel diagonally to the left of (i - di, x0). If there's
     99        // a connected span there it may need to grow up and/or down, so push it onto
     100        // the stack for later consideration
     101        //
     102        nx0 = -1;
     103        for (int j = x0 - 1; j >= -1; j--) {
     104            double pixVal = (j < 0) ? threshold - 100 : (F32 ? imgRowF32[j] : imgRowS32[j]);
     105            if ((maskRow[j] & PM_STARTSPAN_DETECTED) || pixVal < threshold) {
     106                if (j < x0 - 1) {       // we found some pixels above threshold
     107                    nx0 = j + 1;
     108                }
     109                break;
     110            }
     111        }
     112
     113        if (nx0 < 0) {                  // no span to the left
     114            nx1 = x0 - 1;               // we're going to resume searching at nx1 + 1
     115        } else {
     116            //
     117            // Search right in leftmost span
     118            //
     119            for (int j = nx0 + 1; j <= numCols; j++) {
     120                double pixVal = (j >= numCols) ? threshold - 100 : (F32 ? imgRowF32[j] : imgRowS32[j]);
     121                if ((maskRow[j] & PM_STARTSPAN_DETECTED) || pixVal < threshold) {
     122                    nx1 = j - 1;
     123                    break;
     124                }
     125            }
     126
     127            pmSpan *sp = pmFootprintSetSpan(fp, i + row0, nx0 + col0, nx1 + col0);
     128            bool status = pmFootprintSpansSet(fpSpans, sp, mask, PM_STARTSPAN_RESTART);
     129            // fprintf (stderr, "set 1: %d vs %d\n", fp->nspans, fpSpans->nStartSpans);
     130            if (status) {
     131                stop = true;
     132                break;
     133            }
     134        }
     135        //
     136        // Now look for spans connected to the old span.  The first of these we'll
     137        // simply process, but others will have to be deferred for later consideration.
     138        //
     139        // In fact, if the span overhangs to the right we'll have to defer the overhang
     140        // until later too, as it too can grow in both directions
     141        //
     142        // Note that column numCols exists virtually, and always ends the last span; this
     143        // is why we claim below that sx1 is always set
     144        //
     145        bool first = false;             // is this the first new span detected?
     146        for (int j = nx1 + 1; j <= x1 + 1; j++) {
     147            double pixVal = (j >= numCols) ? threshold - 100 : (F32 ? imgRowF32[j] : imgRowS32[j]);
     148            if (!(maskRow[j] & PM_STARTSPAN_DETECTED) && pixVal >= threshold) {
     149                int sx0 = j++;          // span that we're working on is sx0:sx1
     150                int sx1 = -1;           // We know that if we got here, we'll also set sx1
     151                for (; j <= numCols; j++) {
     152                    double pixVal = (j >= numCols) ? threshold - 100 : (F32 ? imgRowF32[j] : imgRowS32[j]);
     153                    if ((maskRow[j] & PM_STARTSPAN_DETECTED) || pixVal < threshold) { // end of span
     154                        sx1 = j;
     155                        break;
     156                    }
     157                }
     158                assert (sx1 >= 0);
     159
     160                pmSpan *sp;
     161                if (first) {
     162                    if (sx1 <= x1) {
     163                        sp = pmFootprintSetSpan(fp, i + row0, sx0 + col0, sx1 + col0 - 1);
     164                        bool status = pmFootprintSpansSet(fpSpans, sp, mask, PM_STARTSPAN_DONE);
     165                        // fprintf (stderr, "set 2: %d vs %d\n", fp->nspans, fpSpans->nStartSpans);
     166                        if (status) {
     167                            stop = true;
     168                            break;
     169                        }
     170                    } else {            // overhangs to right
     171                        sp = pmFootprintSetSpan(fp, i + row0, sx0 + col0, x1 + col0);
     172                        bool status = pmFootprintSpansSet(fpSpans, sp, mask, PM_STARTSPAN_DONE);
     173                        // fprintf (stderr, "set 3: %d vs %d\n", fp->nspans, fpSpans->nStartSpans);
     174                        if (status) {
     175                            stop = true;
     176                            break;
     177                        }
     178                        sp = pmFootprintSetSpan(fp, i + row0, x1 + 1 + col0, sx1 + col0 - 1);
     179                        status = pmFootprintSpansSet(fpSpans, sp, mask, PM_STARTSPAN_RESTART);
     180                        // fprintf (stderr, "set 4: %d vs %d\n", fp->nspans, fpSpans->nStartSpans);
     181                        if (status) {
     182                            stop = true;
     183                            break;
     184                        }
     185                    }
     186                    first = false;
     187                } else {
     188                    sp = pmFootprintSetSpan(fp, i + row0, sx0 + col0, sx1 + col0 - 1);
     189                    bool status = pmFootprintSpansSet(fpSpans, sp, mask, PM_STARTSPAN_RESTART);
     190                    // fprintf (stderr, "set 5: %d vs %d\n", fp->nspans, fpSpans->nStartSpans);
     191                    if (status) {
     192                        stop = true;
     193                        break;
     194                    }
     195                }
     196            }
     197        }
     198
     199        if (stop || first == false) {   // we're done
     200            break;
     201        }
     202
     203        x0 = nx0; x1 = nx1;
     204    }
     205    /*
     206     * Cleanup
     207     */
     208
     209    startspan->direction = PM_STARTSPAN_DONE;
     210    return stop ? false : true;
     211}
     212
     213/*
     214 * Go through an image, starting at (row, col) and assembling all the pixels
     215 * that are connected to that point (in a chess kings-move sort of way) into
     216 * a pmFootprint.
     217 *
     218 * This is much slower than pmFootprintsFind if you want to find lots of
     219 * footprints, but if you only want a small region about a given point it
     220 * can be much faster
     221 *
     222 * N.b. The returned pmFootprint is not in "normal form"; that is the pmSpans
     223 * are not sorted by increasing y, x0, x1.  If this matters to you, call
     224 * pmFootprintNormalize()
     225 *
     226 * The calling function must supply a footprint allocated with a reasonable amount of space
     227 *
     228 */
     229
     230bool pmFootprintsFindAtPoint(pmFootprint *fp,
     231                             pmFootprintSpans *fpSpans,
     232                             const psImage *img,     // image to search
     233                             psImage *mask,
     234                             const float threshold,   // Threshold
     235                             const psArray *peaks, // array of peaks; finding one terminates search for footprint
     236                             int row, int col) { // starting position (in img's parent's coordinate system)
     237    psAssert(img, "image must be supplied");
     238    psAssert(fp, "footprint must be supplied");
     239    psAssert(fpSpans, "footprint spans must be supplied");
     240
     241    bool F32 = false;                    // is this an F32 image?
    134242    if (img->type.type == PS_TYPE_F32) {
    135243        F32 = true;
    136244    } else if (img->type.type == PS_TYPE_S32) {
    137245        F32 = false;
    138     } else {                            // N.b. You can't trivially add more cases here; F32 is just a bool
     246    } else {                             // N.b. You can't trivially add more cases here; F32 is just a bool
    139247        psError(PS_ERR_UNKNOWN, true, "Unsupported psImage type: %d", img->type.type);
    140         return NULL;
    141     }
    142 
    143     psF32 *imgRowF32 = NULL;            // row pointer if F32
    144     psS32 *imgRowS32 = NULL;            //  "   "   "  "  !F32
    145     psImageMaskType *maskRow = NULL;            //  masks's row pointer
    146    
     248        return false;
     249    }
     250    psF32 *imgRowF32 = NULL;             // row pointer if F32
     251    psS32 *imgRowS32 = NULL;             //  "   "   "  "  !F32
     252
    147253    const int row0 = img->row0;
    148254    const int col0 = img->col0;
    149255    const int numRows = img->numRows;
    150256    const int numCols = img->numCols;
    151    
    152     /********************************************************************************************************/
    153    
    154     Startspan *sspan = NULL;
    155     for (int i = 0; i < startspans->n; i++) {
    156         sspan = startspans->data[i];
    157         if (sspan->direction != PM_SSPAN_DONE) {
    158             break;
     257
     258    /*
     259     * Is point in image, and above threshold?
     260     */
     261    row -= row0; col -= col0;
     262    if (row < 0 || row >= numRows ||
     263        col < 0 || col >= numCols) {
     264        psError(PS_ERR_BAD_PARAMETER_VALUE, true,
     265                "row/col == (%d, %d) are out of bounds [%d--%d, %d--%d]",
     266                row + row0, col + col0, row0, row0 + numRows - 1, col0, col0 + numCols - 1);
     267        return false;
     268    }
     269
     270    double pixVal = F32 ? img->data.F32[row][col] : img->data.S32[row][col];
     271    if (pixVal < threshold) {
     272        return true;
     273    }
     274
     275    /*
     276     * We need a mask for two purposes; to indicate which pixels are already detected,
     277     * and to store the "stop" pixels --- those that, once reached, should stop us
     278     * looking for the rest of the pmFootprint.  These are generally set from peaks.
     279     */
     280
     281    pmFootprintInit(fp);
     282    pmFootprintSpansInit(fpSpans);
     283    psImageInit(mask, PM_STARTSPAN_INITIAL);
     284
     285    // fprintf (stderr, "init: %d vs %d\n", fp->nspans, fpSpans->nStartSpans);
     286
     287    //
     288    // Set stop bits from peaks list
     289    //
     290    assert (peaks == NULL || peaks->n == 0 || psMemCheckPeak(peaks->data[0]));
     291    if (peaks != NULL) {
     292        for (int i = 0; i < peaks->n; i++) {
     293            pmPeak *peak = peaks->data[i];
     294            mask->data.PS_TYPE_IMAGE_MASK_DATA[peak->y - mask->row0][peak->x - mask->col0] |= PM_STARTSPAN_STOP;
    159295        }
    160         if (sspan->stop) {
    161             break;
    162         }
    163     }
    164     if (sspan == NULL || sspan->direction == PM_SSPAN_DONE) { // no more Startspans to process
    165         return false;
    166     }
    167     if (sspan->stop) {                  // they don't want any more spans processed
    168         return false;
    169     }
    170     /*
    171      * Work
    172      */
    173     const PM_SSPAN_DIR dir = sspan->direction;
    174     /*
    175      * Set initial span to the startspan
    176      */
    177     int x0 = sspan->span->x0 - col0, x1 = sspan->span->x1 - col0;
    178     /*
    179      * Go through image identifying objects
    180      */
    181     int nx0, nx1 = -1;                  // new values of x0, x1
    182     const int di = (dir == PM_SSPAN_UP) ? 1 : -1; // how much i changes to get to the next row
    183     bool stop = false;                  // should I stop searching for spans?
    184 
    185     for (int i = sspan->span->y -row0 + di; i < numRows && i >= 0; i += di) {
    186         imgRowF32 = img->data.F32[i];   // only one of
    187         imgRowS32 = img->data.S32[i];   //      these is valid!
    188         maskRow = mask->data.PS_TYPE_IMAGE_MASK_DATA[i];
    189         //
    190         // Search left from the pixel diagonally to the left of (i - di, x0). If there's
    191         // a connected span there it may need to grow up and/or down, so push it onto
    192         // the stack for later consideration
    193         //
    194         nx0 = -1;
    195         for (int j = x0 - 1; j >= -1; j--) {
    196             double pixVal = (j < 0) ? threshold - 100 : (F32 ? imgRowF32[j] : imgRowS32[j]);
    197             if ((maskRow[j] & PM_SSPAN_DETECTED) || pixVal < threshold) {
    198                 if (j < x0 - 1) {       // we found some pixels above threshold
    199                     nx0 = j + 1;
    200                 }
     296    }
     297
     298    /*
     299     * Find starting span passing through (row, col)
     300     */
     301    imgRowF32 = img->data.F32[row];      // only one of
     302    imgRowS32 = img->data.S32[row];      //      these is valid!
     303    psImageMaskType *maskRow = mask->data.PS_TYPE_IMAGE_MASK_DATA[row];
     304    {
     305        int i;
     306        for (i = col; i >= 0; i--) {
     307            pixVal = F32 ? imgRowF32[i] : imgRowS32[i];
     308            if ((maskRow[i] & PM_STARTSPAN_DETECTED) || pixVal < threshold) {
    201309                break;
    202310            }
    203311        }
    204 
    205         if (nx0 < 0) {                  // no span to the left
    206             nx1 = x0 - 1;               // we're going to resume searching at nx1 + 1
    207         } else {
    208             //
    209             // Search right in leftmost span
    210             //
    211             //nx1 = 0;                  // make gcc happy
    212             for (int j = nx0 + 1; j <= numCols; j++) {
    213                 double pixVal = (j >= numCols) ? threshold - 100 : (F32 ? imgRowF32[j] : imgRowS32[j]);
    214                 if ((maskRow[j] & PM_SSPAN_DETECTED) || pixVal < threshold) {
    215                     nx1 = j - 1;
    216                     break;
    217                 }
    218             }
    219            
    220             const pmSpan *sp = pmFootprintAddSpan(fp, i + row0, nx0 + col0, nx1 + col0);
    221            
    222             if (add_startspan(startspans, sp, mask, PM_SSPAN_RESTART)) {
    223                 stop = true;
     312        int i0 = i;
     313        for (i = col; i < numCols; i++) {
     314            pixVal = F32 ? imgRowF32[i] : imgRowS32[i];
     315            if ((maskRow[i] & PM_STARTSPAN_DETECTED) || pixVal < threshold) {
    224316                break;
    225317            }
    226318        }
    227         //
    228         // Now look for spans connected to the old span.  The first of these we'll
    229         // simply process, but others will have to be deferred for later consideration.
    230         //
    231         // In fact, if the span overhangs to the right we'll have to defer the overhang
    232         // until later too, as it too can grow in both directions
    233         //
    234         // Note that column numCols exists virtually, and always ends the last span; this
    235         // is why we claim below that sx1 is always set
    236         //
    237         bool first = false;             // is this the first new span detected?
    238         for (int j = nx1 + 1; j <= x1 + 1; j++) {
    239             double pixVal = (j >= numCols) ? threshold - 100 : (F32 ? imgRowF32[j] : imgRowS32[j]);
    240             if (!(maskRow[j] & PM_SSPAN_DETECTED) && pixVal >= threshold) {
    241                 int sx0 = j++;          // span that we're working on is sx0:sx1
    242                 int sx1 = -1;           // We know that if we got here, we'll also set sx1
    243                 for (; j <= numCols; j++) {
    244                     double pixVal = (j >= numCols) ? threshold - 100 : (F32 ? imgRowF32[j] : imgRowS32[j]);
    245                     if ((maskRow[j] & PM_SSPAN_DETECTED) || pixVal < threshold) { // end of span
    246                         sx1 = j;
    247                         break;
    248                     }
    249                 }
    250                 assert (sx1 >= 0);
    251 
    252                 const pmSpan *sp;
    253                 if (first) {
    254                     if (sx1 <= x1) {
    255                         sp = pmFootprintAddSpan(fp, i + row0, sx0 + col0, sx1 + col0 - 1);
    256                         if (add_startspan(startspans, sp, mask, PM_SSPAN_DONE)) {
    257                             stop = true;
    258                             break;
    259                         }
    260                     } else {            // overhangs to right
    261                         sp = pmFootprintAddSpan(fp, i + row0, sx0 + col0, x1 + col0);
    262                         if (add_startspan(startspans, sp, mask, PM_SSPAN_DONE)) {
    263                             stop = true;
    264                             break;
    265                         }
    266                         sp = pmFootprintAddSpan(fp, i + row0, x1 + 1 + col0, sx1 + col0 - 1);
    267                         if (add_startspan(startspans, sp, mask, PM_SSPAN_RESTART)) {
    268                             stop = true;
    269                             break;
    270                         }
    271                     }
    272                     first = false;
    273                 } else {
    274                     sp = pmFootprintAddSpan(fp, i + row0, sx0 + col0, sx1 + col0 - 1);
    275                     if (add_startspan(startspans, sp, mask, PM_SSPAN_RESTART)) {
    276                         stop = true;
    277                         break;
    278                     }
    279                 }
    280             }
    281         }
    282 
    283         if (stop || first == false) {   // we're done
    284             break;
    285         }
    286 
    287         x0 = nx0; x1 = nx1;
    288     }
     319        int i1 = i;
     320        pmSpan *sp = pmFootprintSetSpan(fp, row + row0, i0 + col0 + 1, i1 + col0 - 1);
     321        pmFootprintSpansSet(fpSpans, sp, mask, PM_STARTSPAN_RESTART);
     322        // fprintf (stderr, "first: %d vs %d\n", fp->nspans, fpSpans->nStartSpans);
     323    }
     324    /*
     325     * Now workout from those pmStartSpans, searching for pixels above threshold
     326     */
     327    while (pmFootprintSpansBuild(fp, fpSpans, img, mask, threshold)) continue;
    289328    /*
    290329     * Cleanup
    291330     */
    292 
    293     sspan->direction = PM_SSPAN_DONE;
    294     return stop ? false : true;
     331    // psFree(mask);
     332    // psFree(startspans);                  // restores the image pixel
     333
     334    return fp;                           // pmFootprint really
    295335}
    296 
    297 /*
    298  * Go through an image, starting at (row, col) and assembling all the pixels
    299  * that are connected to that point (in a chess kings-move sort of way) into
    300  * a pmFootprint.
    301  *
    302  * This is much slower than pmFootprintsFind if you want to find lots of
    303  * footprints, but if you only want a small region about a given point it
    304  * can be much faster
    305  *
    306  * N.b. The returned pmFootprint is not in "normal form"; that is the pmSpans
    307  * are not sorted by increasing y, x0, x1.  If this matters to you, call
    308  * pmFootprintNormalize()
    309  */
    310 pmFootprint *
    311 pmFootprintsFindAtPoint(const psImage *img,     // image to search
    312                        const float threshold,   // Threshold
    313                        const psArray *peaks, // array of peaks; finding one terminates search for footprint
    314                        int row, int col) { // starting position (in img's parent's coordinate system)
    315    assert(img != NULL);
    316 
    317    bool F32 = false;                    // is this an F32 image?
    318    if (img->type.type == PS_TYPE_F32) {
    319        F32 = true;
    320    } else if (img->type.type == PS_TYPE_S32) {
    321        F32 = false;
    322    } else {                             // N.b. You can't trivially add more cases here; F32 is just a bool
    323        psError(PS_ERR_UNKNOWN, true, "Unsupported psImage type: %d", img->type.type);
    324        return NULL;
    325    }
    326    psF32 *imgRowF32 = NULL;             // row pointer if F32
    327    psS32 *imgRowS32 = NULL;             //  "   "   "  "  !F32
    328    
    329    const int row0 = img->row0;
    330    const int col0 = img->col0;
    331    const int numRows = img->numRows;
    332    const int numCols = img->numCols;
    333 /*
    334  * Is point in image, and above threshold?
    335  */
    336    row -= row0; col -= col0;
    337    if (row < 0 || row >= numRows ||
    338        col < 0 || col >= numCols) {
    339         psError(PS_ERR_BAD_PARAMETER_VALUE, true,
    340                 "row/col == (%d, %d) are out of bounds [%d--%d, %d--%d]",
    341                 row + row0, col + col0, row0, row0 + numRows - 1, col0, col0 + numCols - 1);
    342        return NULL;
    343    }
    344 
    345    double pixVal = F32 ? img->data.F32[row][col] : img->data.S32[row][col];
    346    if (pixVal < threshold) {
    347        return pmFootprintAlloc(0, img);
    348    }
    349    
    350    pmFootprint *fp = pmFootprintAlloc(1 + img->numRows/10, img);
    351 /*
    352  * We need a mask for two purposes; to indicate which pixels are already detected,
    353  * and to store the "stop" pixels --- those that, once reached, should stop us
    354  * looking for the rest of the pmFootprint.  These are generally set from peaks.
    355  */
    356    psImage *mask = psImageAlloc(numCols, numRows, PS_TYPE_IMAGE_MASK);
    357    P_PSIMAGE_SET_ROW0(mask, row0);
    358    P_PSIMAGE_SET_COL0(mask, col0);
    359    psImageInit(mask, PM_SSPAN_INITIAL);
    360    //
    361    // Set stop bits from peaks list
    362    //
    363    assert (peaks == NULL || peaks->n == 0 || psMemCheckPeak(peaks->data[0]));
    364    if (peaks != NULL) {
    365        for (int i = 0; i < peaks->n; i++) {
    366            pmPeak *peak = peaks->data[i];
    367            mask->data.PS_TYPE_IMAGE_MASK_DATA[peak->y - mask->row0][peak->x - mask->col0] |= PM_SSPAN_STOP;
    368        }
    369    }
    370 /*
    371  * Find starting span passing through (row, col)
    372  */
    373    psArray *startspans = psArrayAllocEmpty(1); // spans where we have to restart the search
    374    
    375    imgRowF32 = img->data.F32[row];      // only one of
    376    imgRowS32 = img->data.S32[row];      //      these is valid!
    377    psImageMaskType *maskRow = mask->data.PS_TYPE_IMAGE_MASK_DATA[row];
    378    {
    379        int i;
    380        for (i = col; i >= 0; i--) {
    381            pixVal = F32 ? imgRowF32[i] : imgRowS32[i];
    382            if ((maskRow[i] & PM_SSPAN_DETECTED) || pixVal < threshold) {
    383                break;
    384            }
    385        }
    386        int i0 = i;
    387        for (i = col; i < numCols; i++) {
    388            pixVal = F32 ? imgRowF32[i] : imgRowS32[i];
    389            if ((maskRow[i] & PM_SSPAN_DETECTED) || pixVal < threshold) {
    390                break;
    391            }
    392        }
    393        int i1 = i;
    394        const pmSpan *sp = pmFootprintAddSpan(fp, row + row0, i0 + col0 + 1, i1 + col0 - 1);
    395 
    396        (void)add_startspan(startspans, sp, mask, PM_SSPAN_RESTART);
    397    }
    398    /*
    399     * Now workout from those Startspans, searching for pixels above threshold
    400     */
    401    while (do_startspan(fp, img, mask, threshold, startspans)) continue;
    402    /*
    403     * Cleanup
    404     */
    405    psFree(mask);
    406    psFree(startspans);                  // restores the image pixel
    407 
    408    return fp;                           // pmFootprint really
    409 }
Note: See TracChangeset for help on using the changeset viewer.