IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 6985


Ignore:
Timestamp:
Apr 25, 2006, 2:28:15 PM (20 years ago)
Author:
Paul Price
Message:

Adding pmChipMosaic back in after bringing it up to date with the new way of doing things.

Location:
trunk/psModules/src
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/psModules/src/astrom/Makefile.am

    r6933 r6985  
    1414        pmHDUUtils.c \
    1515        pmReadout.c \
     16        pmChipMosaic.c \
    1617        pmConcepts.c \
    1718        pmConceptsRead.c \
     
    3940        pmHDUUtils.h \
    4041        pmReadout.h \
     42        pmChipMosaic.h \
    4143        pmConcepts.h \
    4244        pmConceptsRead.h \
  • trunk/psModules/src/astrom/pmChipMosaic.c

    r6872 r6985  
    11#include <stdio.h>
    22#include <assert.h>
    3 
    43#include "pslib.h"
    54#include "pmFPA.h"
    6 #include "pmChipMosaic.h"
    7 
    8 #define MEM_LEAKS 0
     5#include "pmHDU.h"
     6#include "psRegionIsBad.h"
     7
     8
     9//////////////////////////////////////////////////////////////////////////////////////////////////////////////
     10// File-static (private) functions
     11//////////////////////////////////////////////////////////////////////////////////////////////////////////////
     12
     13// Do two regions overlap?
     14#define REGIONS_OVERLAP(region1, region2) \
     15((region1->x0 > region2->x0 && region1->x0 < region2->x1) || \
     16 (region1->x1 > region2->x0 && region1->x1 < region2->x1) || \
     17 (region1->y0 > region2->y0 && region1->y0 < region2->y1) || \
     18 (region1->y1 > region2->y0 && region1->y1 < region2->y1))
    919
    1020// Compare a value with a maximum and minimum
     
    1727}
    1828
     29// Update a metadata entry directly
     30#define MD_UPDATE(MD, NAME, TYPE, VALUE) \
     31{ \
     32    psMetadataItem *item = psMetadataLookup(MD, NAME); \
     33    item->data.TYPE = VALUE; \
     34}
     35
     36// Are the pixels for the chip contiguous on the HDU?
     37// Work this out by examining all the CELL.TRIMSEC and CELL.BIASSEC regions for the component cells
     38static bool chipContiguous(psRegion *bounds, // The bounds of the image, altered if primary==true
     39                           pmChip *chip, // The chip to examine for contiguity
     40                           bool primary // Is this the primary chip of interest?
     41                          )
     42{
     43    if (primary) {
     44        *bounds = psRegionSet(INFINITY, 0, INFINITY, 0);
     45    }
     46    psArray *cells = chip->cells;       // The array of cells
     47    bool mdok = true;                   // Status of MD lookup
     48    for (int i = 0; i < cells->n; i++) {
     49        pmCell *cell = cells->data[i];  // Cell of interest
     50        psRegion *trimsec = psMetadataLookupPtr(&mdok, cell->concepts, "CELL.TRIMSEC"); // Trim section
     51        if (!mdok || !trimsec || psRegionIsBad(*trimsec)) {
     52            psError(PS_ERR_IO, true, "CELL.TRIMSEC hasn't been set for cell %d.\n", i);
     53            return false;
     54        }
     55
     56        if (primary) {
     57            if (trimsec->x0 < bounds->x0) {
     58                bounds->x0 = trimsec->x0;
     59            }
     60            if (trimsec->x1 > bounds->x1) {
     61                bounds->x1 = trimsec->x1;
     62            }
     63            if (trimsec->y0 < bounds->y0) {
     64                bounds->y0 = trimsec->y0;
     65            }
     66            if (trimsec->y1 > bounds->y1) {
     67                bounds->y1 = trimsec->y1;
     68            }
     69        } else if (REGIONS_OVERLAP(trimsec, bounds)) {
     70            return false;
     71        }
     72
     73        psList *biassecs = psMetadataLookupPtr(&mdok, cell->concepts, "CELL.BIASSEC"); // Bias sections
     74        if (!mdok || !biassecs) {
     75            psError(PS_ERR_IO, true, "CELL.BIASSEC hasn't been set for cell %d.\n", i);
     76            return false;
     77        }
     78        if (biassecs->n == 0) {
     79            // No point allocating an iterator if there's nothing there to iterate on
     80            continue;
     81        }
     82        psListIterator *biassecsIter = psListIteratorAlloc(biassecs, PS_LIST_HEAD, false); // Iterator
     83        psRegion *biassec = NULL;       // Bias section from iteration
     84        while ((biassec = psListGetAndIncrement(biassecsIter))) {
     85            if (psRegionIsBad(*biassec)) {
     86                continue;
     87            }
     88            if (REGIONS_OVERLAP(biassec, bounds)) {
     89                psFree(biassecsIter);
     90                return false;
     91            }
     92        }
     93        psFree(biassecsIter);
     94    }
     95
     96    // If we've gotten this far, everything is fine.
     97    return true;
     98}
     99
     100
     101// Is the chip "nice"?  If so, return the region containing the chip pixels
     102static psRegion *niceChip(int *xBinChip, int *yBinChip, // Binning for chip, to be returned
     103                          pmChip *chip  // Chip to examine for "niceness".
     104                         )
     105{
     106    // Check that we've got the HDU in the chip or the FPA
     107    if ((!chip->hdu || !chip->hdu->images) && (!chip->parent->hdu || !chip->parent->hdu->images)) {
     108        return NULL;
     109    }
     110
     111    // Check parity and binning for component cells
     112    bool mdok = true;                   // Status of MD lookup
     113    *xBinChip = 0;
     114    *yBinChip = 0;
     115    for (int i = 0; i < chip->cells->n; i++) {
     116        pmCell *cell = chip->cells->data[i]; // The cell of interest
     117
     118        // A "nice" chip must have only a single readout
     119        if (cell->readouts->n != 1) {
     120            return NULL;
     121        }
     122
     123        // A "nice" chip must have parity == 1
     124        int xParity = psMetadataLookupS32(&mdok, cell->concepts, "CELL.XPARITY"); // Parity in x
     125        if (!mdok || xParity == 0) {
     126            psError(PS_ERR_IO, true, "CELL.XPARITY hasn't been set for cell %d.\n", i);
     127            return NULL;
     128        }
     129        if (xParity != 1) {
     130            return NULL;
     131        }
     132        int yParity = psMetadataLookupS32(&mdok, cell->concepts, "CELL.YPARITY"); // Parity in y
     133        if (!mdok || yParity == 0) {
     134            psError(PS_ERR_IO, true, "CELL.YPARITY hasn't been set for cell %d.\n", i);
     135            return NULL;
     136        }
     137        if (yParity != 1) {
     138            return NULL;
     139        }
     140
     141        // A "nice" chip must have consistent binning
     142        int xBin = psMetadataLookupS32(&mdok, cell->concepts, "CELL.XBIN"); // Binning in x
     143        if (!mdok || xBin <= 0) {
     144            psError(PS_ERR_IO, true, "CELL.XPARITY hasn't been set for cell %d.\n", i);
     145            return NULL;
     146        }
     147        int yBin = psMetadataLookupS32(&mdok, cell->concepts, "CELL.YBIN"); // Binning in y
     148        if (!mdok || yBin <= 0) {
     149            psError(PS_ERR_IO, true, "CELL.YPARITY hasn't been set for cell %d.\n", i);
     150            return NULL;
     151        }
     152        if (*xBinChip == 0 || *yBinChip == 0) {
     153            *xBinChip = xBin;
     154            *yBinChip = yBin;
     155        } else if (xBin != *xBinChip || yBin != *yBinChip) {
     156            return NULL;
     157        }
     158    }
     159
     160    // Now check that the pixels are all contiguous
     161    psRegion *imageBounds = psRegionAlloc(0, 0, 0, 0); // Bound of image on HDU
     162    if (!chipContiguous(imageBounds, chip, true)) {
     163        psTrace(__func__, 5, "Image isn't contiguous.\n");
     164        psFree(imageBounds);
     165        return NULL;
     166    }
     167
     168    psString region = psRegionToString(*imageBounds);
     169    psTrace(__func__, 7, "Image bounds: %s\n", region);
     170    psFree(region);
     171
     172    for (int i = 0; i < chip->cells->n; i++) {
     173        pmCell *cell = chip->cells->data[i]; // The cell of interest
     174
     175        // A "nice" chip must have the (0,0) pixel at CELL.X0,CELL.Y0
     176        int x0 = psMetadataLookupS32(&mdok, cell->concepts, "CELL.X0"); // Position of (0,0) on chip
     177        if (!mdok) {
     178            psError(PS_ERR_IO, true, "CELL.X0 hasn't been set for cell %d.\n", i);
     179            return NULL;
     180        }
     181        int y0 = psMetadataLookupS32(&mdok, cell->concepts, "CELL.Y0"); // Position of (0,0) on chip
     182        if (!mdok) {
     183            psError(PS_ERR_IO, true, "CELL.Y0 hasn't been set for cell %d.\n", i);
     184            return NULL;
     185        }
     186        pmReadout *readout = cell->readouts->data[0]; // A representative readout
     187        if (!readout) {
     188            return NULL;                // Nothing here
     189        }
     190        if (x0 != readout->col0 + readout->image->col0 - (int)imageBounds->x0 ||
     191                y0 != readout->row0 + readout->image->row0 - (int)imageBounds->y0) {
     192            psTrace(__func__, 5, "CELL.X0,Y0 don't match: %d,%d vs %d,%d\n", x0, y0,
     193                    readout->col0 + readout->image->col0 - (int)imageBounds->x0,
     194                    readout->row0 + readout->image->row0 - (int)imageBounds->y0);
     195            psFree(imageBounds);
     196            return NULL;
     197        }
     198    }
     199
     200    // Need to check all the other chips if the HDU is in the FPA
     201    pmFPA *fpa = chip->parent;          // The parent FPA
     202    if (fpa->hdu && fpa->hdu->images) {
     203        psArray *chips = fpa->chips;    // Array of chips
     204        for (int i = 0; i < chips->n; i++) {
     205            pmChip *testChip = chips->data[i]; // The chip of interest
     206            if (testChip == chip) {
     207                // Already done this one
     208                continue;
     209            }
     210            if (!chipContiguous(imageBounds, testChip, false)) {
     211                psTrace(__func__, 5, "Image isn't contiguous.\n");
     212                psFree(imageBounds);
     213                return NULL;
     214            }
     215        }
     216    }
     217
     218    return imageBounds;
     219}
     220
    19221// Mosaic multiple images, with flips, binning and offsets
    20 psImage *p_pmImageMosaic(const psArray *source, // Images to splice in
    21                          const psVector *xFlip, const psVector *yFlip, // Need to flip x and y?
    22                          const psVector *xBinSource, const psVector *yBinSource, // Binning in x and y of
    23                          // source images
    24                          int xBinTarget, int yBinTarget, // Binning in x and y of target images
    25                          const psVector *x0, const psVector *y0 // Offsets for source images on target
    26                         )
     222static psImage *imageMosaic(const psArray *source, // Images to splice in
     223                            const psVector *xFlip, const psVector *yFlip, // Need to flip x and y?
     224                            const psVector *xBinSource, // Binning in x of source images
     225                            const psVector *yBinSource, // Binning in y of source images
     226                            int xBinTarget, int yBinTarget, // Binning in x and y of target images
     227                            const psVector *x0, const psVector *y0 // Offsets for source images on target
     228                           )
    27229{
    28230    assert(source);
     
    33235    assert(x0 && x0->type.type == PS_TYPE_S32);
    34236    assert(y0 && y0->type.type == PS_TYPE_S32);
     237    assert(xFlip->n == source->n);
     238    assert(yFlip->n == source->n);
     239    assert(xBinSource->n == source->n);
     240    assert(yBinSource->n == source->n);
     241    assert(x0->n == source->n);
     242    assert(y0->n == source->n);
     243
     244    if (source->n == 0) {
     245        return NULL;
     246    }
    35247
    36248    // Get the maximum extent of the mosaic image
     
    40252    int yMax = - INT_MAX;
    41253    psElemType type = 0;
     254    int numImages = 0;                  // Number of images
    42255    for (int i = 0; i < source->n; i++) {
    43256        psImage *image = source->data[i]; // The image of interest
     
    45258            continue;
    46259        }
     260        numImages++;
    47261
    48262        // Only implemented for F32 and U8 images so far.
     
    66280        COMPARE(x0->data.S32[i] + xParity * xBinSource->data.S32[i] * image->numCols - xParity, xMin, xMax);
    67281        COMPARE(y0->data.S32[i] + yParity * yBinSource->data.S32[i] * image->numRows - yParity, yMin, yMax);
     282    }
     283    if (numImages == 0) {
     284        return NULL;
    68285    }
    69286
     
    137354static bool cellConcepts(pmCell *target,// Target cell
    138355                         psArray *sources, // Source cells
    139                          int xBin, int yBin // Binning
     356                         int xBin, int yBin, // Binning
     357                         psRegion *trimsec // The trim section
    140358                        )
    141359{
     
    143361    float gain       = 0.0;             // Gain
    144362    float readnoise  = 0.0;             // Read noise
    145     float saturation = 0.0;             // Saturation level
    146     float bad        = 0.0;             // Bad level
     363    float saturation = INFINITY;        // Saturation level
     364    float bad        = -INFINITY;       // Bad level
    147365    float exposure   = 0.0;             // Exposure time
    148366    float darktime   = 0.0;             // Dark time
     
    160378        gain       += psMetadataLookupF32(NULL, cell->concepts, "CELL.GAIN");
    161379        readnoise  += psMetadataLookupF32(NULL, cell->concepts, "CELL.READNOISE");
    162         saturation += psMetadataLookupF32(NULL, cell->concepts, "CELL.SATURATION");
    163         bad        += psMetadataLookupF32(NULL, cell->concepts, "CELL.BAD");
    164380        exposure   += psMetadataLookupF32(NULL, cell->concepts, "CELL.EXPOSURE");
    165381        darktime   += psMetadataLookupF32(NULL, cell->concepts, "CELL.DARKTIME");
    166         time       += psTimeToMJD(psMetadataLookupPtr(NULL, cell->concepts, "CELL.TIME"));
     382        psTime *cellTime = psMetadataLookupPtr(NULL, cell->concepts, "CELL.TIME");
     383        time       += psTimeToMJD(cellTime);
    167384        if (i == 0) {
    168385            timeSys = psMetadataLookupS32(NULL, cell->concepts, "CELL.TIMESYS");
     
    172389            success = false;
    173390        }
    174     }
    175     gain       /= (float)nCells;
    176     readnoise  /= (float)nCells;
    177     saturation /= (float)nCells;
    178     bad        /= (float)nCells;
    179     exposure   /= (float)nCells;
    180     darktime   /= (float)nCells;
    181     psTime *timePtr = psTimeFromMJD(time/(double)nCells);
    182     timePtr = psTimeConvert(timePtr, timeSys);
    183 
    184     // XXX *REALLY* need a generic "concept update" function that handles the type and comments transparently.
    185     psMetadataAddF32(target->concepts, PS_LIST_TAIL, "CELL.GAIN", PS_META_REPLACE, "Gain (e/ADU)", gain);
    186     psMetadataAddF32(target->concepts, PS_LIST_TAIL, "CELL.READNOISE", PS_META_REPLACE, "Read noise (e)", readnoise);
    187     psMetadataAddF32(target->concepts, PS_LIST_TAIL, "CELL.SATURATION", PS_META_REPLACE, "Saturation level (ADU)", saturation);
    188     psMetadataAddF32(target->concepts, PS_LIST_TAIL, "CELL.BAD", PS_META_REPLACE, "Bad level (ADU)", bad);
    189     psMetadataAddF32(target->concepts, PS_LIST_TAIL, "CELL.EXPOSURE", PS_META_REPLACE, "Exposure time (sec)", exposure);
    190     psMetadataAddF32(target->concepts, PS_LIST_TAIL, "CELL.DARKTIME", PS_META_REPLACE, "Time since last CCD flush (sec)", darktime);
    191     psMetadataAddPtr(target->concepts, PS_LIST_TAIL, "CELL.TIME", PS_DATA_TIME | PS_META_REPLACE, "Time of observation", timePtr);
    192     psMetadataAddS32(target->concepts, PS_LIST_TAIL, "CELL.TIMESYS", PS_META_REPLACE, "Time system", timeSys);
    193     psFree(timePtr);
    194 
    195     // Now fill in the ones I know by other means
    196     psMetadataAddS32(target->concepts, PS_LIST_TAIL, "CELL.X0", PS_META_REPLACE, "Position of (0,0) on the chip", 0);
    197     psMetadataAddS32(target->concepts, PS_LIST_TAIL, "CELL.Y0", PS_META_REPLACE, "Position of (0,0) on the chip", 0);
    198     psMetadataAddS32(target->concepts, PS_LIST_TAIL, "CELL.XPARITY", PS_META_REPLACE, "Orientation in x compared to the rest of the FPA", 1);
    199     psMetadataAddS32(target->concepts, PS_LIST_TAIL, "CELL.YPARITY", PS_META_REPLACE, "Orientation in x compared to the rest of the FPA", 1);
    200     psMetadataAddS32(target->concepts, PS_LIST_TAIL, "CELL.XBIN", PS_META_REPLACE, "Binning in x", xBin);
    201     psMetadataAddS32(target->concepts, PS_LIST_TAIL, "CELL.YBIN", PS_META_REPLACE, "Binning in x", yBin);
    202     psMetadataAddS32(target->concepts, PS_LIST_TAIL, "CELL.READDIR", PS_META_REPLACE, "Read direction (faked)", 1);
    203     psRegion *trimsec = psMetadataLookupPtr(NULL, target->concepts, "CELL.TRIMSEC");
    204     trimsec->x0 = trimsec->x1 = trimsec->y0 = trimsec->y1 = 0.0;
     391
     392        float cellSaturation = psMetadataLookupF32(NULL, cell->concepts, "CELL.SATURATION");
     393        if (cellSaturation < saturation) {
     394            saturation = cellSaturation;
     395        }
     396        float cellBad = psMetadataLookupF32(NULL, cell->concepts, "CELL.BAD");
     397        if (cellBad < bad) {
     398            bad = cellBad;
     399        }
     400    }
     401    gain      /= (float)nCells;
     402    readnoise /= (float)nCells;
     403    exposure  /= (float)nCells;
     404    darktime  /= (float)nCells;
     405    time      /= (double)nCells;
     406
     407    MD_UPDATE(target->concepts, "CELL.GAIN", F32, gain);
     408    MD_UPDATE(target->concepts, "CELL.READNOISE", F32, readnoise);
     409    MD_UPDATE(target->concepts, "CELL.SATURATION", F32, saturation);
     410    MD_UPDATE(target->concepts, "CELL.BAD", F32, bad);
     411    MD_UPDATE(target->concepts, "CELL.EXPOSURE", F32, exposure);
     412    MD_UPDATE(target->concepts, "CELL.DARKTIME", F32, darktime);
     413    MD_UPDATE(target->concepts, "CELL.TIMESYS", S32, timeSys);
     414    MD_UPDATE(target->concepts, "CELL.X0", S32, 0);
     415    MD_UPDATE(target->concepts, "CELL.Y0", S32, 0);
     416    MD_UPDATE(target->concepts, "CELL.XPARITY", S32, 1);
     417    MD_UPDATE(target->concepts, "CELL.YPARITY", S32, 1);
     418    MD_UPDATE(target->concepts, "CELL.XBIN", S32, xBin);
     419    MD_UPDATE(target->concepts, "CELL.YBIN", S32, yBin);
     420
     421    // CELL.TIME needs special care
     422    {
     423        psMetadataItem *timeItem = psMetadataLookup(target->concepts, "CELL.TIME");
     424        psFree(timeItem->data.V);
     425        timeItem->data.V = psTimeFromMJD(time);
     426    }
     427
     428    // CELL.TRIMSEC needs special care
     429    {
     430        psMetadataItem *trimsecItem = psMetadataLookup(target->concepts, "CELL.TRIMSEC");
     431        psFree(trimsecItem->data.V);
     432        trimsecItem->data.V = psMemIncrRefCounter(trimsec);
     433    }
     434
    205435
    206436    return success;
     
    208438
    209439
    210 
    211 // Mosaic a chip together into a single image
    212 int pmChipMosaic(pmChip *chip,// Chip to mosaic
    213                  int xBinChip, int yBinChip // Binning of mosaic image in x and y
    214                 )
     440// Mosaic together the cells in a chip
     441bool chipMosaic(psImage **mosaicImage,  // The mosaic image, to be returned
     442                psImage **mosaicMask,   // The mosaic mask, to be returned
     443                psImage **mosaicWeights, // The mosaic weights, to be returned
     444                int *xBinChip, int *yBinChip, // The binning in x and y, to be returned
     445                pmChip *chip            // Chip to mosaic
     446               )
    215447{
    216 
    217448    psArray *cells = chip->cells;       // The array of cells
    218     psArray *images = psArrayAlloc(cells->n); // Array of images that will be mosaicked
    219     psArray *weights = psArrayAlloc(cells->n); // Array of weight images to be mosaicked
    220     psArray *masks = psArrayAlloc(cells->n); // Array of mask images to be mosaicked
    221     psVector *x0 = psVectorAlloc(cells->n, PS_TYPE_S32); // Origin x coordinates
    222     psVector *y0 = psVectorAlloc(cells->n, PS_TYPE_S32); // Origin y coordinates
    223     psVector *xBin = psVectorAlloc(cells->n, PS_TYPE_S32); // Binning in x
    224     psVector *yBin = psVectorAlloc(cells->n, PS_TYPE_S32); // Binning in y
    225     psVector *xFlip = psVectorAlloc(cells->n, PS_TYPE_U8); // Flip in x?
    226     psVector *yFlip = psVectorAlloc(cells->n, PS_TYPE_U8); // Flip in y?
     449    int numCells = cells->n;            // Number of cells
     450    psArray *images = psArrayAlloc(numCells); // Array of images that will be mosaicked
     451    psArray *weights = psArrayAlloc(numCells); // Array of weight images to be mosaicked
     452    psArray *masks = psArrayAlloc(numCells); // Array of mask images to be mosaicked
     453    psVector *x0 = psVectorAlloc(numCells, PS_TYPE_S32); // Origin x coordinates
     454    psVector *y0 = psVectorAlloc(numCells, PS_TYPE_S32); // Origin y coordinates
     455    psVector *xBin = psVectorAlloc(numCells, PS_TYPE_S32); // Binning in x
     456    psVector *yBin = psVectorAlloc(numCells, PS_TYPE_S32); // Binning in y
     457    psVector *xFlip = psVectorAlloc(numCells, PS_TYPE_U8); // Flip in x?
     458    psVector *yFlip = psVectorAlloc(numCells, PS_TYPE_U8); // Flip in y?
     459    images->n = weights->n = masks->n = numCells;
     460    x0->n = y0->n = xBin->n = yBin->n = xFlip->n = yFlip->n = numCells;
     461
     462    // Binning for the mosaicked chip is the minimum binning allowed by the cells
     463    *xBinChip = INT_MAX;
     464    *yBinChip = INT_MAX;
    227465
    228466    // Set up the required inputs
    229     psTrace(__func__, 1, "Mosaicking %d cells...\n", cells->n);
    230     for (int i = 0; i < cells->n; i++) {
     467    psTrace(__func__, 1, "Mosaicking %d cells...\n", numCells);
     468    bool good = true;                   // Is everything good, well-behaved?
     469    for (int i = 0; i < numCells && good; i++) {
    231470        pmCell *cell = cells->data[i];  // The cell of interest
    232471        if (!cell) {
    233472            continue;
    234473        }
    235         x0->data.S32[i] = psMetadataLookupS32(NULL, cell->concepts, "CELL.X0");
    236         y0->data.S32[i] = psMetadataLookupS32(NULL, cell->concepts, "CELL.Y0");
     474        bool mdok = true;               // Status of MD lookup
     475        x0->data.S32[i] = psMetadataLookupS32(&mdok, cell->concepts, "CELL.X0");
     476        if (!mdok) {
     477            psError(PS_ERR_IO, true, "CELL.X0 for cell %d is not set.\n", i);
     478            good = false;
     479        }
     480        y0->data.S32[i] = psMetadataLookupS32(&mdok, cell->concepts, "CELL.Y0");
     481        if (!mdok) {
     482            psError(PS_ERR_IO, true, "CELL.Y0 for cell %d is not set.\n", i);
     483            good = false;
     484        }
    237485        psTrace(__func__, 5, "Cell %d: x0=%d y0=%d\n", i, x0->data.S32[i], y0->data.S32[i]);
    238         xBin->data.S32[i] = psMetadataLookupS32(NULL, cell->concepts, "CELL.XBIN");
    239         yBin->data.S32[i] = psMetadataLookupS32(NULL, cell->concepts, "CELL.XBIN");
    240         int xParity = psMetadataLookupS32(NULL, cell->concepts, "CELL.XPARITY");
    241         int yParity = psMetadataLookupS32(NULL, cell->concepts, "CELL.YPARITY");
    242         if (xParity == 1) {
    243             xFlip->data.U8[i] = 0;
    244         } else if (xParity == -1) {
     486        xBin->data.S32[i] = psMetadataLookupS32(&mdok, cell->concepts, "CELL.XBIN");
     487        if (!mdok || xBin->data.S32[i] == 0) {
     488            psError(PS_ERR_IO, true, "CELL.XBIN for cell %d is not set.\n", i);
     489            good = false;
     490        }
     491        if (xBin->data.S32[i] < *xBinChip) {
     492            *xBinChip = xBin->data.S32[i];
     493        }
     494        yBin->data.S32[i] = psMetadataLookupS32(&mdok, cell->concepts, "CELL.YBIN");
     495        if (!mdok || yBin->data.S32[i] == 0) {
     496            psError(PS_ERR_IO, true, "CELL.YBIN for cell %d is not set.\n", i);
     497            good = false;
     498        }
     499        if (yBin->data.S32[i] < *yBinChip) {
     500            *yBinChip = yBin->data.S32[i];
     501        }
     502        int xParity = psMetadataLookupS32(&mdok, cell->concepts, "CELL.XPARITY");
     503        if (!mdok || (xParity != 1 && xParity != -1)) {
     504            psError(PS_ERR_IO, true, "CELL.XPARITY for cell %d is not set.\n", i);
     505            good = false;
     506        }
     507        int yParity = psMetadataLookupS32(&mdok, cell->concepts, "CELL.YPARITY");
     508        if (!mdok || (yParity != 1 && yParity != -1)) {
     509            psError(PS_ERR_IO, true, "CELL.YPARITY for cell %d is not set.\n", i);
     510            good = false;
     511        }
     512        if (xParity == -1) {
    245513            xFlip->data.U8[i] = 1;
    246514        } else {
    247             psLogMsg(__func__, PS_LOG_WARN, "The x parity of cell %d is not +/- 1 (it's %d) --- "
    248                      "assuming +1.\n", i, xParity);
    249515            xFlip->data.U8[i] = 0;
    250516        }
    251         if (yParity == 1) {
    252             yFlip->data.U8[i] = 0;
    253         } else if (yParity == -1) {
     517        if (yParity == -1) {
    254518            yFlip->data.U8[i] = 1;
    255519        } else {
    256             psLogMsg(__func__, PS_LOG_WARN, "The y parity of cell %d is not +/- 1 (it's %d) --- "
    257                      "assuming +1.\n", i, yParity);
    258520            yFlip->data.U8[i] = 0;
    259521        }
     
    271533        masks->data[i]   = psMemIncrRefCounter(readout->mask);
    272534    }
     535
    273536    // Mosaic the images together and we're done
    274     psImage *image = p_pmImageMosaic(images, xFlip, yFlip, xBin, yBin, xBinChip, yBinChip, x0, y0);
    275     psImage *weight = p_pmImageMosaic(weights, xFlip, yFlip, xBin, yBin, xBinChip, yBinChip, x0, y0);
    276     psImage *mask = p_pmImageMosaic(masks, xFlip, yFlip, xBin, yBin, xBinChip, yBinChip, x0, y0);
     537    if (good) {
     538        *mosaicImage = imageMosaic(images, xFlip, yFlip, xBin, yBin, *xBinChip, *yBinChip, x0, y0);
     539        *mosaicWeights = imageMosaic(weights, xFlip, yFlip, xBin, yBin, *xBinChip, *yBinChip, x0, y0);
     540        *mosaicMask = imageMosaic(masks, xFlip, yFlip, xBin, yBin, *xBinChip, *yBinChip, x0, y0);
     541    }
    277542
    278543    // Clean up
    279     psFree(x0);
    280     psFree(y0);
    281     psFree(xBin);
    282     psFree(yBin);
    283     psFree(xFlip);
    284     psFree(yFlip);
    285544    psFree(images);
    286545    psFree(weights);
    287546    psFree(masks);
    288     int nCells = cells->n;
    289 
    290     // Fix up the HDU
    291     if (chip->parent->hdu) {
    292         psLogMsg(__func__, PS_LOG_WARN, "The original format has the entire FPA in a single extension.  "
    293                  "The FPA hierarchy may be invalid following the pmChipMosaic.\n");
     547    psFree(xFlip);
     548    psFree(yFlip);
     549    psFree(xBin);
     550    psFree(yBin);
     551    psFree(x0);
     552    psFree(y0);
     553
     554    return good;
     555}
     556
     557//////////////////////////////////////////////////////////////////////////////////////////////////////////////
     558// Public functions
     559//////////////////////////////////////////////////////////////////////////////////////////////////////////////
     560
     561// Mosaic all the cells in a chip together.
     562//
     563// It is desirable to do this without using psImageOverlay (or similar) if it can be at all avoided (because
     564// it's really really slow in that case).  There are therefore two cases:
     565//
     566// 1. The HDU is at the Chip or FPA level.  This is the fast case, and only works if the HDU is "nice", by
     567// which I mean:
     568//
     569//    - the CELL.TRIMSECs are contiguous on the HDU image
     570//    - the CELL.PARITYs are identically +1
     571//    - the CELL.XBIN and CELL.YBIN are all identical
     572//
     573// Then we can just use psImageSubset to get the "mosaicked" chip.
     574//
     575//
     576// 2. The HDU is at the cell level, or the above requirements are not met, in which case we mosaic the cells.
     577// This is the slow case.  We need to:
     578//
     579//    - Throw away the bias regions
     580//    - Convert all cells to common parity
     581//    - Mosaic the cells into an HDU image using CELL.X0 and CELL.Y0
     582//    - Update CELL.TRIMSECs
     583//
     584// Once the demands of case 1 have been met, or case 2 has been performed, then we can create a cell to hold
     585// the mosaic image.
     586bool pmChipMosaic(pmChip *chip      // Chip whose cells will be mosaicked
     587                 )
     588{
     589    psImage *mosaicImage   = NULL;      // The mosaic image
     590    psImage *mosaicMask    = NULL;      // The mosaic mask
     591    psImage *mosaicWeights = NULL;      // The mosaic weights
     592
     593    // Find the HDU
     594    psRegion *chipRegion = NULL;        // Region on the HDU that corresponds to the chip
     595    int xBin = 0, yBin = 0;             // Binning for the chip mosaic
     596    if ((chipRegion = niceChip(&xBin, &yBin, chip))) {
     597        // Case 1 --- we need only cut out the region
     598        psTrace(__func__, 1, "Case 1 mosaicking: simple cut-out.\n");
     599        pmHDU *hdu = chip->hdu;         // The HDU that has the pixels
     600        if (!hdu || !hdu->images) {
     601            hdu = chip->parent->hdu;
     602        }
     603        mosaicImage   = psMemIncrRefCounter(psImageSubset(hdu->images->data[0], *chipRegion));
     604        if (hdu->masks) {
     605            mosaicMask    = psMemIncrRefCounter(psImageSubset(hdu->masks->data[0], *chipRegion));
     606        }
     607        if (hdu->weights) {
     608            mosaicWeights = psMemIncrRefCounter(psImageSubset(hdu->weights->data[0], *chipRegion));
     609        }
    294610    } else {
    295         if (! chip->hdu) {
    296             psString chipName = psMetadataLookupStr(NULL, chip->concepts, "CHIP.NAME");
    297             chip->hdu = p_pmHDUAlloc(chipName);
    298         }
    299         p_pmHDU *hdu = chip->hdu;
    300         psArrayElementsFree(hdu->images);
    301         psArrayElementsFree(hdu->weights);
    302         psArrayElementsFree(hdu->masks);
    303         hdu->images  = psArrayRealloc(hdu->images,1);
    304         hdu->weights = psArrayRealloc(hdu->weights, 1);
    305         hdu->masks   = psArrayRealloc(hdu->masks, 1);
    306         hdu->images->data[0]  = image;
    307         hdu->weights->data[0] = weight;
    308         hdu->masks->data[0]   = mask;
    309         psMetadataAddS32(hdu->header, PS_LIST_TAIL, "NAXIS1", PS_META_REPLACE, "Number of columns", image->numCols);
    310         psMetadataAddS32(hdu->header, PS_LIST_TAIL, "NAXIS2", PS_META_REPLACE, "Number of rows", image->numRows);
    311     }
    312 
    313     // Chop off all the component cells, and construct a new one
    314     pmCell *newCell = pmCellAlloc(NULL, NULL, __func__); // New cell
    315     cellConcepts(newCell, cells, xBinChip, yBinChip);
    316     pmChipFreeCells(chip);
    317     // Have to put in the new cell manually, since we didn't want to put it in before blowing the cells away.
    318     newCell->parent = chip;
    319     psArrayAdd(chip->cells, 1, newCell);
    320     newCell->exists = true;
    321     newCell->process = true;
     611        // Case 2 --- we need to mosaic by cut and paste
     612        psTrace(__func__, 1, "Case 2 mosaicking: cut and paste.\n");
     613        if (!chipMosaic(&mosaicImage, &mosaicMask, &mosaicWeights, &xBin, &yBin, chip)) {
     614            psError(PS_ERR_IO, false, "Unable to mosaic cells.\n");
     615            return false;
     616        }
     617        chipRegion = psRegionAlloc(NAN, NAN, NAN, NAN); // We've cut and paste, so there's no valid trimsec
     618    }
     619
     620    // Construct a new cell, set the concepts, and add the mosaic in
     621    pmCell *newCell = pmCellAlloc(NULL, "MOSAIC"); // New cell
     622    cellConcepts(newCell, chip->cells, xBin, yBin, chipRegion);
     623    psFree(chipRegion);
     624    chip->mosaic = (struct pmCell*)newCell;
    322625
    323626    // Now make a new readout to go in the new cell
    324627    pmReadout *newReadout = pmReadoutAlloc(newCell); // New readout
    325     // Want the readouts to contain a subimage, but that subimage is the whole image.
    326     // This preserves the relationship there was before, where freeing the parent frees the child.
    327     psRegion entire = {0.0, 0.0, 0.0, 0.0};
    328     newReadout->image = psMemIncrRefCounter(psImageSubset(image, entire));
    329     newReadout->weight = psMemIncrRefCounter(psImageSubset(weight, entire));
    330     newReadout->mask = psMemIncrRefCounter(psImageSubset(mask, entire));
    331     // Drop references
    332     psFree(newReadout);
    333     psFree(newCell);
    334 
    335     // Well, we've stuffed around with the camera configuration, so it's no longer valid...
    336     #if 0
    337 
    338     psFree(chip->parent->camera);
    339     chip->parent->camera = NULL;
    340     #endif
    341 
    342     return nCells;
    343 }
    344 
    345 
    346 int pmFPAMosaicCells(pmFPA *fpa,        // FPA
    347                      int xBinChip, int yBinChip // Binning of mosaic image in x and y
    348                     )
    349 {
    350     assert(fpa);
    351 
    352     int numChips = 0;
    353     psArray *chips = fpa->chips;        // Component chips
    354     for (int i = 0; i < chips->n; i++) {
    355         pmChip *chip = chips->data[i];  // The chip of interest
    356         if (! chip || ! chip->exists || ! chip->process) {
    357             continue;
    358         }
    359 
    360         if (pmChipMosaic(chip, xBinChip, yBinChip) > 0) {
    361             numChips++;
    362         }
    363     }
    364 
    365     return numChips;
    366 
    367 }
     628    newReadout->image  = mosaicImage;
     629    newReadout->mask   = mosaicMask;
     630    newReadout->weight = mosaicWeights;
     631    psFree(newReadout);                 // Drop reference
     632
     633    return true;
     634}
  • trunk/psModules/src/astrom/pmChipMosaic.h

    r6872 r6985  
    55#include "pmFPA.h"
    66
    7 // Mosaic multiple images, with flips, binning and offsets
    8 psImage *p_pmImageMosaic(const psArray *source, // Images to splice in
    9                          const psVector *xFlip, const psVector *yFlip, // Need to flip x and y?
    10                          const psVector *xBinSource, const psVector *yBinSource, // Binning in x and y of
    11                          // source images
    12                          int xBinTarget, int yBinTarget, // Binning in x and y of target images
    13                          const psVector *x0, const psVector *y0 // Offsets for source images on target
    14                         );
    15 
    16 // Mosaic a chip together into a single cell with single readout
    17 int pmChipMosaic(pmChip *chip,// Chip to mosaic
    18                  int xBinChip, int yBinChip // Binning of mosaic image in x and y
    19                 );
    20 
    21 // Mosaic all the cells in all (valid) chips together (neglecting the overscans); return number of chips
    22 int pmFPAMosaicCells(pmFPA *fpa,        // FPA
    23                      int xBinChip, int yBinChip // Binning of mosaic image in x and y
    24                     );
     7// Mosaic all cells within a chip
     8bool pmChipMosaic(pmChip *chip      // Chip whose cells will be mosaicked
     9                 );
    2510
    2611#endif
  • trunk/psModules/src/psmodules.h

    r6934 r6985  
    3737#include <pmFPAWrite.h>
    3838#include <pmFPA_JPEG.h>
    39 
    4039#include <pmReadout.h>
    41 // #include <pmChipMosaic.h>
     40#include <pmChipMosaic.h>
    4241// #include <pmFPAAstrometry.h>
    4342
Note: See TracChangeset for help on using the changeset viewer.