IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 12589


Ignore:
Timestamp:
Mar 26, 2007, 4:44:42 PM (19 years ago)
Author:
magnier
Message:

converted binning operations to use the common pmImageBinning methods

Location:
trunk/psModules/src
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/psModules/src/camera/pmFPACopy.c

    r12564 r12589  
    1717
    1818//////////////////////////////////////////////////////////////////////////////////////////////////////////////
    19 // File-static functions
    20 //////////////////////////////////////////////////////////////////////////////////////////////////////////////
    21 
    22 // Bin a region down by specified factors in x and y
    23 static void binRegion(psRegion *region, // Region to be binned
    24                       int xBin, int yBin // Binning in x and y
    25                      )
    26 {
    27     assert(region);
    28     assert(xBin > 0);
    29     assert(yBin > 0);
    30 
    31     // Want to include the lower bound: 1 binned by 4 --> 0; 3 binned by 4 --> 0; 4 binned by 4 --> 1
    32     region->x0 = (int)(region->x0 / xBin);
    33     region->y0 = (int)(region->y0 / yBin);
    34     // Want to exclude the upper bound: 4 binned by 4 --> 1; 5 binned by 4 --> 2; 7 binned by 4 --> 2
    35     region->x1 = (int)((region->x1 + xBin - 1) / xBin);
    36     region->y1 = (int)((region->y1 + yBin - 1) / yBin);
    37 }
    38 
    39 #if 1
     19// File-static functions and macros
     20//////////////////////////////////////////////////////////////////////////////////////////////////////////////
     21
     22// Copy the value for a concept
     23#define COPY_CONCEPT(TARGET, SOURCE, NAME, TYPE) { \
     24    psMetadataItem *targetItem = psMetadataLookup(TARGET, NAME); \
     25    psMetadataItem *sourceItem = psMetadataLookup(SOURCE, NAME); \
     26    targetItem->data.TYPE = sourceItem->data.TYPE; }
     27
    4028// Find the blank (image-less) PHU, given a cell.
    4129static pmHDU *findBlankPHU(const pmCell *cell // The cell for which to find the PHU
     
    5846    return NULL;
    5947}
    60 #endif
     48
     49// copy one of the psImage components of the readout
     50static void readoutCopyComponent (psImage **target, psImage *source, psImageBinning *binning, bool xFlip, bool yFlip, bool pixels) {
     51
     52    if (!source) return;
     53
     54    if (*target) {
     55        psFree(*target);
     56    }
     57    if (pixels) {
     58        *target = psImageFlip(NULL, source, xFlip, yFlip);
     59        return;
     60    }
     61
     62    // I have the fine image size, I know the binning factor, determine the ruff image size
     63    binning->nXfine = source->numCols;
     64    binning->nYfine = source->numRows;
     65    psImageBinningSetRuffSize(binning, PS_IMAGE_BINNING_CENTER);
     66    *target = psImageAlloc(binning->nXruff, binning->nYruff, source->type.type);
     67    return;
     68}
    6169
    6270//////////////////////////////////////////////////////////////////////////////////////////////////////////////
     
    7785    assert(xBin > 0 && yBin > 0);
    7886
     87    // XXX this is a programming / config error
     88    if (pixels && (xBin != 1 || yBin != 1)) {
     89        psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Unable to copy pixels if binning is set\n");
     90        return false;
     91    }
     92
     93    // the binning structure carries the information no how to rebin the images if needed
     94    psImageBinning *binning = psImageBinningAlloc();
     95    binning->nXbin = xBin;
     96    binning->nYbin = yBin;
     97
    7998    psArray *sourceReadouts = source->readouts; // The source readouts
    8099    int numReadouts = sourceReadouts->n; // Number of readouts copied
    81100
    82     // Copy the value for a concept
    83     #define COPY_CONCEPT(TARGET, SOURCE, NAME, TYPE) \
    84     psMetadataItem *targetItem = psMetadataLookup(TARGET, NAME); \
    85     psMetadataItem *sourceItem = psMetadataLookup(SOURCE, NAME); \
    86     targetItem->data.TYPE = sourceItem->data.TYPE;
    87 
    88101    // Need to check/change CELL.XPARITY and CELL.YPARITY
    89     bool mdok = true;                   // Status of MD lookup
     102    bool mdokS = true;                   // Status of MD lookup
     103    bool mdokT = true;                   // Status of MD lookup
    90104    bool xFlip = false;                 // Switch parity in x?
    91105    bool yFlip = false;                 // Switch parity in y?
    92     {
    93         int xParityTarget = psMetadataLookupS32(&mdok, target->concepts, "CELL.XPARITY"); // Target x parity
    94         if (mdok && (xParityTarget == 1 || xParityTarget == -1))
    95         {
    96             int xParitySource = psMetadataLookupS32(&mdok, source->concepts, "CELL.XPARITY"); // Source parity
    97             if (mdok && (xParitySource == 1 || xParitySource == -1) && xParityTarget != xParitySource) {
    98                 xFlip = true;
    99             }
    100         } else
    101         {
    102             // Use the source parity
    103             COPY_CONCEPT(target->concepts, source->concepts, "CELL.XPARITY", S32);
    104         }
    105         int yParityTarget = psMetadataLookupS32(&mdok, target->concepts, "CELL.YPARITY"); // Target y parity
    106         if (mdok && (yParityTarget == 1 || yParityTarget == -1))
    107         {
    108             int yParitySource = psMetadataLookupS32(&mdok, source->concepts, "CELL.YPARITY"); // Source parity
    109             if (mdok && (yParitySource == 1 || yParitySource == -1) && yParityTarget != yParitySource) {
    110                 yFlip = true;
    111             }
    112         } else
    113         {
    114             // Use the source parity
    115             COPY_CONCEPT(target->concepts, source->concepts, "CELL.YPARITY", S32);
    116         }
    117         psTrace("psModules.camera", 3, "xFlip: %d; yFlip: %d\n", xFlip, yFlip);
    118     }
    119 
    120     if (pixels && (xBin != 1 || yBin != 1)) {
    121         psLogMsg(__func__, PS_LOG_WARN, "Unable to copy pixels if binning is set --- copy turned off.\n");
    122         pixels = false;
    123     }
     106
     107    // enforce the following conditions:
     108    // CELL.XPARITY is required
     109    // CELL.XPARITY must be +/- 1
     110    int xParitySource = psMetadataLookupS32(&mdokS, source->concepts, "CELL.XPARITY"); // Source parity
     111    int xParityTarget = psMetadataLookupS32(&mdokT, target->concepts, "CELL.XPARITY"); // Target x parity
     112    assert (mdokS && mdokT);
     113    assert (abs(xParitySource) == 1);
     114    assert (abs(xParityTarget) == 1);
     115    if (xParityTarget != xParitySource) {
     116        xFlip = true;
     117    } else {
     118        // Use the source parity
     119        COPY_CONCEPT(target->concepts, source->concepts, "CELL.XPARITY", S32);
     120    }
     121
     122    int yParityTarget = psMetadataLookupS32(&mdokT, target->concepts, "CELL.YPARITY"); // Target y parity
     123    int yParitySource = psMetadataLookupS32(&mdokS, source->concepts, "CELL.YPARITY"); // Source parity
     124    assert (mdokS && mdokT);
     125    assert (abs(yParitySource) == 1);
     126    assert (abs(yParityTarget) == 1);
     127    if (yParityTarget != yParitySource) {
     128        yFlip = true;
     129    } else {
     130        // Use the source parity
     131        COPY_CONCEPT(target->concepts, source->concepts, "CELL.YPARITY", S32);
     132    }
     133    psTrace("psModules.camera", 3, "xFlip: %d; yFlip: %d\n", xFlip, yFlip);
    124134
    125135    // Perform deep copy of the images.  I would prefer *not* to do a deep copy, in the interests of speed (we
     
    132142
    133143        // Copy attributes
     144        // XXX is this correct under binning?
    134145        targetReadout->col0 = sourceReadout->col0;
    135146        targetReadout->row0 = sourceReadout->row0;
     
    138149        targetReadout->data_exists = sourceReadout->data_exists;
    139150
    140         // Copy image
    141         if (sourceReadout->image) {
    142             if (targetReadout->image) {
    143                 psFree(targetReadout->image);
    144             }
    145             if (pixels) {
    146                 targetReadout->image = psImageFlip(NULL, sourceReadout->image, xFlip, yFlip);
    147             } else {
    148                 psImage *image = sourceReadout->image; // The source image
    149                 long binnedCols = (image->numCols + xBin - 1) / xBin;
    150                 long binnedRows = (image->numRows + yBin - 1) / yBin;
    151                 targetReadout->image = psImageAlloc(binnedCols, binnedRows, image->type.type);
    152             }
    153         }
    154 
    155         // Copy mask
    156         if (sourceReadout->mask) {
    157             if (targetReadout->mask) {
    158                 psFree(targetReadout->mask);
    159             }
    160             if (pixels) {
    161                 targetReadout->mask = psImageFlip(NULL, sourceReadout->mask, xFlip, yFlip);
    162             } else {
    163                 psImage *mask = sourceReadout->mask; // The source mask image
    164                 long binnedCols = (mask->numCols + xBin - 1) / xBin;
    165                 long binnedRows = (mask->numRows + yBin - 1) / yBin;
    166                 targetReadout->mask = psImageAlloc(binnedCols, binnedRows, mask->type.type);
    167             }
    168         }
    169 
    170         // Copy weight
    171         if (sourceReadout->weight) {
    172             if (targetReadout->weight) {
    173                 psFree(targetReadout->weight);
    174             }
    175             if (pixels) {
    176                 targetReadout->weight = psImageFlip(NULL, sourceReadout->weight, xFlip, yFlip);
    177             } else {
    178                 psImage *weight = sourceReadout->weight; // The source weight image
    179                 long binnedCols = (weight->numCols + xBin - 1) / xBin;
    180                 long binnedRows = (weight->numRows + yBin - 1) / yBin;
    181                 targetReadout->weight = psImageAlloc(binnedCols, binnedRows, weight->type.type);
    182             }
    183         }
     151        // Copy all three image components (image, mask, weight)
     152        readoutCopyComponent (&targetReadout->image,  sourceReadout->image,  binning, xFlip, yFlip, pixels);
     153        readoutCopyComponent (&targetReadout->mask,   sourceReadout->mask,   binning, xFlip, yFlip, pixels);
     154        readoutCopyComponent (&targetReadout->weight, sourceReadout->weight, binning, xFlip, yFlip, pixels);
    184155
    185156        // Copy bias
     
    187158            psListRemove(targetReadout->bias, PS_LIST_HEAD);
    188159        }
     160
    189161        // Iterate over the biases
    190162        psListIterator *biasIter = psListIteratorAlloc(sourceReadout->bias, PS_LIST_HEAD, false);
    191163        psImage *bias = NULL;           // Bias image from iteration
    192164        while ((bias = psListGetAndIncrement(biasIter))) {
    193             psImage *biasCopy;          // Copy of the bias
    194             if (pixels) {
    195                 biasCopy = psImageFlip(NULL, bias, xFlip, yFlip);
    196             } else {
    197                 long binnedCols = (bias->numCols + xBin - 1) / xBin;
    198                 long binnedRows = (bias->numRows + yBin - 1) / yBin;
    199                 biasCopy = psImageAlloc(binnedCols, binnedRows, bias->type.type);
    200             }
     165            psImage *biasCopy = NULL;          // Copy of the bias
     166            readoutCopyComponent (&biasCopy, bias, binning, xFlip, yFlip, pixels);
    201167            psListAdd(targetReadout->bias, PS_LIST_TAIL, biasCopy);
    202168            psFree(biasCopy);           // Drop reference
     
    216182    while ((conceptItem = psMetadataGetAndIncrement(conceptsIter))) {
    217183        psString name = conceptItem->name; // Name of concept
    218         if (strcmp(name, "CELL.TRIMSEC") != 0 && strcmp(name, "CELL.BIASSEC") != 0 &&
    219                 strcmp(name, "CELL.XPARITY") != 0 && strcmp(name, "CELL.YPARITY") != 0 &&
    220                 strcmp(name, "CELL.X0") != 0 && strcmp(name, "CELL.Y0") != 0) {
    221             psMetadataItem *copy = psMetadataItemCopy(conceptItem); // Copy of the concept
    222             psMetadataAddItem(target->concepts, copy, PS_LIST_TAIL, PS_META_REPLACE);
    223             psFree(copy);               // Drop reference
    224         }
     184        if (!strcmp(name, "CELL.TRIMSEC")) continue;
     185        if (!strcmp(name, "CELL.BIASSEC")) continue;
     186        if (!strcmp(name, "CELL.XPARITY")) continue;
     187        if (!strcmp(name, "CELL.YPARITY")) continue;
     188        if (!strcmp(name, "CELL.X0")) continue;
     189        if (!strcmp(name, "CELL.Y0")) continue;
     190
     191        psMetadataItem *copy = psMetadataItemCopy(conceptItem); // Copy of the concept
     192        psMetadataAddItem(target->concepts, copy, PS_LIST_TAIL, PS_META_REPLACE);
     193        psFree(copy);               // Drop reference
    225194    }
    226195    psFree(conceptsIter);
    227196
    228197    // Need to update CELL.TRIMSEC and CELL.BIASSEC if we changed the binning and they exist already.
    229     if (xBin != 1 || yBin != 1) {
     198    // XXX this code seems to be very similar to pmConceptsUpdate
     199    if ((binning->nXbin != 1) || (binning->nYbin != 1)) {
     200        bool mdok = false;
    230201        psRegion *trimsec = psMetadataLookupPtr(&mdok, target->concepts, "CELL.TRIMSEC"); // The trim section
    231202        if (mdok && trimsec && !psRegionIsNaN(*trimsec)) {
    232             binRegion(trimsec, xBin, yBin);
     203            *trimsec = psImageBinningSetRuffRegion(binning, *trimsec);
    233204        }
    234205        psList *biassecs = psMetadataLookupPtr(&mdok, target->concepts, "CELL.BIASSEC"); // The bias sections
     
    238209            while ((biassec = psListGetAndIncrement(biassecsIter))) {
    239210                if (!psRegionIsNaN(*biassec)) {
    240                     binRegion(biassec, xBin, yBin);
     211                    *biassec = psImageBinningSetRuffRegion(binning, *biassec);
    241212                }
    242213            }
     
    246217
    247218    // Need to update CELL.X0 and CELL.Y0 if we flipped
     219    // XXX this section should probably use a common function consistent with psImageBinning
    248220    if (xFlip) {
    249221        int xZero = psMetadataLookupS32(NULL, source->concepts, "CELL.X0"); // CELL.X0 from source
     
    254226        if (sourceBin == 0) {
    255227            // Don't know the binning; assume it is unity
    256             sourceBin = xBin;
    257         }
    258 
    259         psTrace("psModules.camera", 3, "CELL.X0: Before: %d After: %d\n", xZero,
    260                 xZero + (xSize - 1) * xParity * sourceBin);
     228            sourceBin = binning->nXbin;
     229        }
     230
     231        // XXX make sure this is consistent with the psImageBinning
     232        psTrace("psModules.camera", 3, "CELL.X0: Before: %d After: %d\n", xZero, xZero + (xSize - 1) * xParity * sourceBin);
    261233        psTrace("psModules.camera", 9, "(xParity: %d xBin: %d numCols: %d)\n", xParity, sourceBin, xSize);
    262234
     
    277249        if (sourceBin == 0) {
    278250            // Don't know the binning; assume it is unity
    279             sourceBin = yBin;
    280         }
    281 
    282         psTrace("psModules.camera", 3, "CELL.Y0: Before: %d After: %d\n", yZero,
    283                 yZero + (ySize - 1) * yParity * sourceBin);
     251            sourceBin = binning->nYbin;
     252        }
     253
     254        psTrace("psModules.camera", 3, "CELL.Y0: Before: %d After: %d\n", yZero, yZero + (ySize - 1) * yParity * sourceBin);
    284255        psTrace("psModules.camera", 9, "(yParity: %d yBin: %d numRows: %d)\n", yParity, sourceBin, ySize);
    285256
     
    295266
    296267    // Update the binning concepts
     268    // XXX this should probably be done with a common function using psImageBinning
    297269    psMetadataItem *binItem = psMetadataLookup(target->concepts, "CELL.XBIN");
    298270    binItem->data.S32 *= xBin;
     
    314286    pmHDU *targetPHU = findBlankPHU(target); // The target PHU
    315287    if (targetPHU && targetPHU != targetHDU) {
    316 //        pmHDU *sourcePHU = pmHDUGetHighest(source->parent->parent, source->parent, source); // A source HDU
     288        // pmHDU *sourcePHU = pmHDUGetHighest(source->parent->parent, source->parent, source); // A source HDU
    317289        pmHDU *sourcePHU = findBlankPHU(source); // The target PHU
    318290        if (sourcePHU && sourcePHU->header) {
     
    321293    }
    322294
     295    psFree (binning);
    323296    target->data_exists = true;
    324297    return true;
  • trunk/psModules/src/camera/pmFPAMosaic.c

    r11786 r12589  
    382382}
    383383
    384 // Mosaic multiple images, with flips, binning and offsets
    385 static psImage *imageMosaic(const psArray *source, // Images to splice in
    386                             const psVector *xFlip, const psVector *yFlip, // Need to flip x and y?
    387                             const psVector *xBinSource, // Binning in x of source images
    388                             const psVector *yBinSource, // Binning in y of source images
    389                             int xBinTarget, int yBinTarget, // Binning in x and y of target images
    390                             const psVector *x0, const psVector *y0 // Offsets for source images on target
    391                            )
    392 {
    393     assert(source);
    394     assert(xFlip && xFlip->type.type == PS_TYPE_U8);
    395     assert(yFlip && yFlip->type.type == PS_TYPE_U8);
    396     assert(xBinSource && xBinSource->type.type == PS_TYPE_S32);
    397     assert(yBinSource && yBinSource->type.type == PS_TYPE_S32);
    398     assert(x0 && x0->type.type == PS_TYPE_S32);
    399     assert(y0 && y0->type.type == PS_TYPE_S32);
    400     assert(xFlip->n == source->n);
    401     assert(yFlip->n == source->n);
    402     assert(xBinSource->n == source->n);
    403     assert(yBinSource->n == source->n);
    404     assert(x0->n == source->n);
    405     assert(y0->n == source->n);
    406 
    407     if (source->n == 0) {
    408         return NULL;
    409     }
    410 
    411     // Get the maximum extent of the mosaic image
    412     int xMin = INT_MAX;
    413     int xMax = - INT_MAX;
    414     int yMin = INT_MAX;
    415     int yMax = - INT_MAX;
    416     psElemType type = 0;
    417     int numImages = 0;                  // Number of images
    418     psTrace("psModules.camera", 3, "Mosaicking %ld cells.\n", source->n);
    419     for (int i = 0; i < source->n; i++) {
    420         psImage *image = source->data[i]; // The image of interest
    421         if (!image) {
    422             continue;
    423         }
    424         numImages++;
    425 
    426         // Only implemented for F32 and U8 images so far.
    427         assert(image->type.type == PS_TYPE_F32 || image->type.type == PS_TYPE_U8);
    428         // All input types must be the same
    429         if (type == 0) {
    430             type = image->type.type;
    431         }
    432         assert(type == image->type.type);
    433 
    434         // Size of cell in x and y
    435         int xParity = xFlip->data.U8[i] ? -1 : 1;
    436         int yParity = yFlip->data.U8[i] ? -1 : 1;
    437         psTrace("psModules.camera", 5, "Extent of cell %d: %d -> %d , %d -> %d\n", i, x0->data.S32[i],
    438                 x0->data.S32[i] + xParity * xBinSource->data.S32[i] * image->numCols, y0->data.S32[i],
    439                 y0->data.S32[i] + yParity * yBinSource->data.S32[i] * image->numRows);
    440 
    441         COMPARE(x0->data.S32[i], xMin, xMax);
    442         COMPARE(y0->data.S32[i], yMin, yMax);
    443         // Subtract the parity to get the inclusive limit (not exclusive)
    444         COMPARE(x0->data.S32[i] + xParity * xBinSource->data.S32[i] * image->numCols - xParity, xMin, xMax);
    445         COMPARE(y0->data.S32[i] + yParity * yBinSource->data.S32[i] * image->numRows - yParity, yMin, yMax);
    446     }
    447     if (numImages == 0) {
    448         return NULL;
    449     }
    450 
    451     // Set up the image
    452     // Since both upper and lower values are inclusive, we need to add one to the size
    453     float xSize = (float)(xMax - xMin + 1) / (float)xBinTarget;
    454     if (xSize - (int)xSize > 0) {
    455         xSize += 1;
    456     }
    457     float ySize = (float)(yMax - yMin + 1) / (float)yBinTarget;
    458     if (ySize - (int)ySize > 0) {
    459         ySize += 1;
    460     }
    461 
    462     psTrace("psModules.camera", 3, "Spliced image will be %dx%d\n", (int)xSize, (int)ySize);
    463     psImage *mosaic = psImageAlloc((int)xSize, (int)ySize, type); // The mosaic image
    464     psImageInit(mosaic, 0);
    465 
    466     // Next pass through the images to do the mosaicking
    467     for (int i = 0; i < source->n; i++) {
    468         psImage *image = source->data[i]; // The image of interest
    469         if (!image) {
    470             continue;
    471         }
    472         int xParity = xFlip->data.U8[i] ? -1 : 1; // Parity difference, in x
    473         int yParity = yFlip->data.U8[i] ? -1 : 1; // Parity difference, in y
    474         int xTargetBase = (x0->data.S32[i] - xMin) / xBinTarget; // The base x position in the target frame
    475         int yTargetBase = (y0->data.S32[i] - yMin) / yBinTarget; // The base y position in the target frame
    476         if (xBinSource->data.S32[i] == xBinTarget && yBinSource->data.S32[i] == yBinTarget &&
    477                 xFlip->data.U8[i] == 0 && yFlip->data.U8[i] == 0) {
    478             // Let someone else do the hard work
    479             psImageOverlaySection(mosaic, image, xTargetBase, yTargetBase, "+");
    480         } else if (xBinSource->data.S32[i] == xBinTarget && yBinSource->data.S32[i] == yBinTarget) {
    481             // There's a difference with the parities, but we don't have to worry about binning
    482 
    483             #define COPY_WITH_PARITY_DIFFERENCE(TYPE) \
     384// supporting macros used by imageMosaic()
     385// copy pixels without binning
     386#define COPY_WITH_PARITY_DIFFERENCE(TYPE) \
    484387        case PS_TYPE_##TYPE: { \
    485388                for (int y = 0; y < image->numRows; y++) { \
     
    493396            break;
    494397
    495             switch (type) {
    496                 COPY_WITH_PARITY_DIFFERENCE(F32);
    497                 COPY_WITH_PARITY_DIFFERENCE(U8);
    498             default:
    499                 psAbort("Should never get here.\n");
    500             }
    501 
    502         } else {
    503             // We have to do all of the hard work ourself
    504 
    505             // In case the original image is binned but the mosaic is not, we need to fill in the
    506             // values in the mosaic.
    507             #define FILL_IN(TYPE) \
     398// In case the original image is binned but the mosaic is not, we need to fill in the values in
     399// the mosaic.  this operation should be replaced with a call to one of the functions defined
     400// in psImageBinning
     401#define FILL_IN(TYPE) \
    508402        case PS_TYPE_##TYPE: \
    509403            for (int y = 0; y < image->numRows; y++) { \
     
    522416            break;
    523417
     418// Mosaic multiple images, with flips, binning and offsets
     419static psImage *imageMosaic(const psArray *source, // Images to splice in
     420                            const psVector *xFlip, const psVector *yFlip, // Need to flip x and y?
     421                            const psVector *xBinSource, // Binning in x of source images
     422                            const psVector *yBinSource, // Binning in y of source images
     423                            int xBinTarget, int yBinTarget, // Binning in x and y of target images
     424                            const psVector *x0, const psVector *y0 // Offsets for source images on target
     425                           )
     426{
     427    assert(source);
     428    assert(xFlip && xFlip->type.type == PS_TYPE_U8);
     429    assert(yFlip && yFlip->type.type == PS_TYPE_U8);
     430    assert(xBinSource && xBinSource->type.type == PS_TYPE_S32);
     431    assert(yBinSource && yBinSource->type.type == PS_TYPE_S32);
     432    assert(x0 && x0->type.type == PS_TYPE_S32);
     433    assert(y0 && y0->type.type == PS_TYPE_S32);
     434    assert(xFlip->n == source->n);
     435    assert(yFlip->n == source->n);
     436    assert(xBinSource->n == source->n);
     437    assert(yBinSource->n == source->n);
     438    assert(x0->n == source->n);
     439    assert(y0->n == source->n);
     440
     441    if (source->n == 0) {
     442        return NULL;
     443    }
     444
     445    // Get the maximum extent of the mosaic image
     446    int xMin = INT_MAX;
     447    int xMax = - INT_MAX;
     448    int yMin = INT_MAX;
     449    int yMax = - INT_MAX;
     450    psElemType type = 0;
     451    int numImages = 0;                  // Number of images
     452    psTrace("psModules.camera", 3, "Mosaicking %ld cells.\n", source->n);
     453    for (int i = 0; i < source->n; i++) {
     454        psImage *image = source->data[i]; // The image of interest
     455        if (!image) {
     456            continue;
     457        }
     458        numImages++;
     459
     460        // Only implemented for F32 and U8 images so far.
     461        assert(image->type.type == PS_TYPE_F32 || image->type.type == PS_TYPE_U8);
     462        // All input types must be the same
     463        if (type == 0) {
     464            type = image->type.type;
     465        }
     466        assert(type == image->type.type);
     467
     468        // Size of cell in x and y
     469        int xParity = xFlip->data.U8[i] ? -1 : 1;
     470        int yParity = yFlip->data.U8[i] ? -1 : 1;
     471        psTrace("psModules.camera", 5, "Extent of cell %d: %d -> %d , %d -> %d\n", i, x0->data.S32[i],
     472                x0->data.S32[i] + xParity * xBinSource->data.S32[i] * image->numCols, y0->data.S32[i],
     473                y0->data.S32[i] + yParity * yBinSource->data.S32[i] * image->numRows);
     474
     475        COMPARE(x0->data.S32[i], xMin, xMax);
     476        COMPARE(y0->data.S32[i], yMin, yMax);
     477        // Subtract the parity to get the inclusive limit (not exclusive)
     478        COMPARE(x0->data.S32[i] + xParity * xBinSource->data.S32[i] * image->numCols - xParity, xMin, xMax);
     479        COMPARE(y0->data.S32[i] + yParity * yBinSource->data.S32[i] * image->numRows - yParity, yMin, yMax);
     480    }
     481    if (numImages == 0) {
     482        return NULL;
     483    }
     484
     485    // Set up the image
     486    // Since both upper and lower values are inclusive, we need to add one to the size
     487    float xSize = (float)(xMax - xMin + 1) / (float)xBinTarget;
     488    if (xSize - (int)xSize > 0) {
     489        xSize += 1;
     490    }
     491    float ySize = (float)(yMax - yMin + 1) / (float)yBinTarget;
     492    if (ySize - (int)ySize > 0) {
     493        ySize += 1;
     494    }
     495
     496    psTrace("psModules.camera", 3, "Spliced image will be %dx%d\n", (int)xSize, (int)ySize);
     497    psImage *mosaic = psImageAlloc((int)xSize, (int)ySize, type); // The mosaic image
     498    psImageInit(mosaic, 0);
     499
     500    // Next pass through the images to do the mosaicking
     501    // XXX this function uses summing for the output: is this the right choice?
     502    for (int i = 0; i < source->n; i++) {
     503        psImage *image = source->data[i]; // The image of interest
     504        if (!image) {
     505            continue;
     506        }
     507        int xParity = xFlip->data.U8[i] ? -1 : 1; // Parity difference, in x
     508        int yParity = yFlip->data.U8[i] ? -1 : 1; // Parity difference, in y
     509        int xTargetBase = (x0->data.S32[i] - xMin) / xBinTarget; // The base x position in the target frame
     510        int yTargetBase = (y0->data.S32[i] - yMin) / yBinTarget; // The base y position in the target frame
     511
     512        // in the first case, we are just copy a section pixel-by-pixel
     513        if ((xBinSource->data.S32[i] == xBinTarget) &&
     514            (yBinSource->data.S32[i] == yBinTarget) &&
     515            (xFlip->data.U8[i] == 0) &&
     516            (yFlip->data.U8[i] == 0)) {
     517            // Let someone else do the hard work
     518            psImageOverlaySection(mosaic, image, xTargetBase, yTargetBase, "+");
     519            continue;
     520        }
     521       
     522        // in the second case, there's a difference with the parities, but we don't have to
     523        // worry about binning
     524        if (xBinSource->data.S32[i] == xBinTarget && yBinSource->data.S32[i] == yBinTarget) {
    524525            switch (type) {
    525                 FILL_IN(F32);
    526                 FILL_IN(U8);
    527             default:
     526                COPY_WITH_PARITY_DIFFERENCE(F32);
     527                COPY_WITH_PARITY_DIFFERENCE(U8);
     528              default:
    528529                psAbort("Should never get here.\n");
    529530            }
    530 
    531         } // Various difficulty levels
     531            continue;
     532        }
     533       
     534        // In the third case, the images are flipped and have different binnnig.
     535        // We have to do all of the hard work ourselves
     536        switch (type) {
     537            FILL_IN(F32);
     538            FILL_IN(U8);
     539          default:
     540            psAbort("Should never get here.\n");
     541        }
    532542    } // Iterating over images
    533543
    534544    return mosaic;
    535545}
    536 
    537546
    538547// Add a cell and its various properties to the arrays
  • trunk/psModules/src/concepts/pmConceptsUpdate.c

    r11749 r12589  
    2525        // Check for cell concepts updates
    2626
     27        bool xStatus, yStatus; // Status of MD lookups
     28        psImageBinning *binning = psImageBinningAlloc();
     29        binning->nXbin = psMetadataLookupS32(&xStatus, cell->concepts, "CELL.XBIN");
     30        binning->nYbin = psMetadataLookupS32(&yStatus, cell->concepts, "CELL.YBIN");
     31        if (!xStatus || !yStatus) {
     32            // XXX should this be an error condition?
     33            psFree (binning);
     34            return true;
     35        }
     36        if (!binning->nXbin || !binning->nXbin) {
     37            // XXX should this be an error condition?
     38            psFree (binning);
     39            return true;
     40        }
     41
    2742        // CELL.TRIMSEC needs to be updated for the binning
    2843        if (psMetadataLookup(cell->concepts, "CELL.TRIMSEC.UPDATE")) {
    29             bool xStatus, yStatus; // Status of MD lookups
    30             int xBin = psMetadataLookupS32(&xStatus, cell->concepts, "CELL.XBIN");
    31             int yBin = psMetadataLookupS32(&yStatus, cell->concepts, "CELL.YBIN");
    32             if (xStatus && yStatus && xBin != 0 && yBin != 0) {
    33                 psRegion *trimsec = psMetadataLookupPtr(NULL, cell->concepts, "CELL.TRIMSEC"); // Trim section
    34                 trimsec->x0 /= xBin;
    35                 trimsec->x1 /= xBin;
    36                 trimsec->y0 /= yBin;
    37                 trimsec->y1 /= yBin;
    38 
    39                 psMetadataRemoveKey(cell->concepts, "CELL.TRIMSEC.UPDATE");
    40             }
     44            psRegion *trimsec = psMetadataLookupPtr(NULL, cell->concepts, "CELL.TRIMSEC"); // Trim section
     45            *trimsec = psImageBinningSetRuffRegion (binning, *trimsec);
     46            psMetadataRemoveKey(cell->concepts, "CELL.TRIMSEC.UPDATE");
    4147        }
    4248
    4349        // CELL.BIASSEC needs to be updated for the binning
    4450        if (psMetadataLookup(cell->concepts, "CELL.BIASSEC.UPDATE")) {
    45             bool xStatus, yStatus; // Status of MD lookups
    46             int xBin = psMetadataLookupS32(&xStatus, cell->concepts, "CELL.XBIN");
    47             int yBin = psMetadataLookupS32(&yStatus, cell->concepts, "CELL.YBIN");
    48             if (xStatus && yStatus && xBin != 0 && yBin != 0) {
    49                 psList *biassecs = psMetadataLookupPtr(NULL, cell->concepts, "CELL.BIASSEC"); // Bias sections
    50                 psListIterator *biassecsIter = psListIteratorAlloc(biassecs, PS_LIST_HEAD, true); // Iterator
    51                 psRegion *bias; // Bias region, from iteration
    52                 while ((bias = psListGetAndIncrement(biassecsIter))) {
    53                     bias->x0 /= xBin;
    54                     bias->x1 /= xBin;
    55                     bias->y0 /= yBin;
    56                     bias->y1 /= yBin;
    57                 }
    58                 psFree(biassecsIter);
    59 
    60                 psMetadataRemoveKey(cell->concepts, "CELL.BIASSEC.UPDATE");
    61             }
     51            psList *biassecs = psMetadataLookupPtr(NULL, cell->concepts, "CELL.BIASSEC"); // Bias sections
     52            psListIterator *biassecsIter = psListIteratorAlloc(biassecs, PS_LIST_HEAD, true); // Iterator
     53            psRegion *biassec; // Bias region, from iteration
     54            while ((biassec = psListGetAndIncrement(biassecsIter))) {
     55                *biassec = psImageBinningSetRuffRegion (binning, *biassec);
     56            }
     57            psFree(biassecsIter);
     58            psMetadataRemoveKey(cell->concepts, "CELL.BIASSEC.UPDATE");
    6259        }
    63 
     60        psFree (binning);
    6461    }
    6562
Note: See TracChangeset for help on using the changeset viewer.