Changeset 6985
- Timestamp:
- Apr 25, 2006, 2:28:15 PM (20 years ago)
- Location:
- trunk/psModules/src
- Files:
-
- 4 edited
-
astrom/Makefile.am (modified) (2 diffs)
-
astrom/pmChipMosaic.c (modified) (12 diffs)
-
astrom/pmChipMosaic.h (modified) (1 diff)
-
psmodules.h (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psModules/src/astrom/Makefile.am
r6933 r6985 14 14 pmHDUUtils.c \ 15 15 pmReadout.c \ 16 pmChipMosaic.c \ 16 17 pmConcepts.c \ 17 18 pmConceptsRead.c \ … … 39 40 pmHDUUtils.h \ 40 41 pmReadout.h \ 42 pmChipMosaic.h \ 41 43 pmConcepts.h \ 42 44 pmConceptsRead.h \ -
trunk/psModules/src/astrom/pmChipMosaic.c
r6872 r6985 1 1 #include <stdio.h> 2 2 #include <assert.h> 3 4 3 #include "pslib.h" 5 4 #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)) 9 19 10 20 // Compare a value with a maximum and minimum … … 17 27 } 18 28 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 38 static 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 102 static 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 19 221 // Mosaic multiple images, with flips, binning and offsets 20 psImage *p_pmImageMosaic(const psArray *source, // Images to splice in21 const psVector *xFlip, const psVector *yFlip, // Need to flip x and y?22 const psVector *xBinSource, const psVector *yBinSource, // Binning in x and y of23 //source images24 int xBinTarget, int yBinTarget, // Binning in x and y of target images25 const psVector *x0, const psVector *y0 // Offsets for source images on target26 )222 static 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 ) 27 229 { 28 230 assert(source); … … 33 235 assert(x0 && x0->type.type == PS_TYPE_S32); 34 236 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 } 35 247 36 248 // Get the maximum extent of the mosaic image … … 40 252 int yMax = - INT_MAX; 41 253 psElemType type = 0; 254 int numImages = 0; // Number of images 42 255 for (int i = 0; i < source->n; i++) { 43 256 psImage *image = source->data[i]; // The image of interest … … 45 258 continue; 46 259 } 260 numImages++; 47 261 48 262 // Only implemented for F32 and U8 images so far. … … 66 280 COMPARE(x0->data.S32[i] + xParity * xBinSource->data.S32[i] * image->numCols - xParity, xMin, xMax); 67 281 COMPARE(y0->data.S32[i] + yParity * yBinSource->data.S32[i] * image->numRows - yParity, yMin, yMax); 282 } 283 if (numImages == 0) { 284 return NULL; 68 285 } 69 286 … … 137 354 static bool cellConcepts(pmCell *target,// Target cell 138 355 psArray *sources, // Source cells 139 int xBin, int yBin // Binning 356 int xBin, int yBin, // Binning 357 psRegion *trimsec // The trim section 140 358 ) 141 359 { … … 143 361 float gain = 0.0; // Gain 144 362 float readnoise = 0.0; // Read noise 145 float saturation = 0.0;// Saturation level146 float bad = 0.0;// Bad level363 float saturation = INFINITY; // Saturation level 364 float bad = -INFINITY; // Bad level 147 365 float exposure = 0.0; // Exposure time 148 366 float darktime = 0.0; // Dark time … … 160 378 gain += psMetadataLookupF32(NULL, cell->concepts, "CELL.GAIN"); 161 379 readnoise += psMetadataLookupF32(NULL, cell->concepts, "CELL.READNOISE"); 162 saturation += psMetadataLookupF32(NULL, cell->concepts, "CELL.SATURATION");163 bad += psMetadataLookupF32(NULL, cell->concepts, "CELL.BAD");164 380 exposure += psMetadataLookupF32(NULL, cell->concepts, "CELL.EXPOSURE"); 165 381 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); 167 384 if (i == 0) { 168 385 timeSys = psMetadataLookupS32(NULL, cell->concepts, "CELL.TIMESYS"); … … 172 389 success = false; 173 390 } 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 205 435 206 436 return success; … … 208 438 209 439 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 441 bool 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 ) 215 447 { 216 217 448 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; 227 465 228 466 // 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++) { 231 470 pmCell *cell = cells->data[i]; // The cell of interest 232 471 if (!cell) { 233 472 continue; 234 473 } 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 } 237 485 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) { 245 513 xFlip->data.U8[i] = 1; 246 514 } 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);249 515 xFlip->data.U8[i] = 0; 250 516 } 251 if (yParity == 1) { 252 yFlip->data.U8[i] = 0; 253 } else if (yParity == -1) { 517 if (yParity == -1) { 254 518 yFlip->data.U8[i] = 1; 255 519 } 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);258 520 yFlip->data.U8[i] = 0; 259 521 } … … 271 533 masks->data[i] = psMemIncrRefCounter(readout->mask); 272 534 } 535 273 536 // 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 } 277 542 278 543 // Clean up 279 psFree(x0);280 psFree(y0);281 psFree(xBin);282 psFree(yBin);283 psFree(xFlip);284 psFree(yFlip);285 544 psFree(images); 286 545 psFree(weights); 287 546 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. 586 bool 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 } 294 610 } 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; 322 625 323 626 // Now make a new readout to go in the new cell 324 627 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 5 5 #include "pmFPA.h" 6 6 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 8 bool pmChipMosaic(pmChip *chip // Chip whose cells will be mosaicked 9 ); 25 10 26 11 #endif -
trunk/psModules/src/psmodules.h
r6934 r6985 37 37 #include <pmFPAWrite.h> 38 38 #include <pmFPA_JPEG.h> 39 40 39 #include <pmReadout.h> 41 //#include <pmChipMosaic.h>40 #include <pmChipMosaic.h> 42 41 // #include <pmFPAAstrometry.h> 43 42
Note:
See TracChangeset
for help on using the changeset viewer.
