Changeset 42679 for branches/2dbias/ppImage
- Timestamp:
- May 21, 2024, 8:50:38 PM (2 years ago)
- Location:
- branches/2dbias/ppImage/src
- Files:
-
- 3 edited
-
ppImage.h (modified) (1 diff)
-
ppImageDetrendPattern.c (modified) (16 diffs)
-
ppImageDetrendReadout.c (modified) (12 diffs)
Legend:
- Unmodified
- Added
- Removed
-
branches/2dbias/ppImage/src/ppImage.h
r42382 r42679 188 188 189 189 bool ppImageDetrendFree(pmConfig *config, pmFPAview *view); 190 bool ppImageDoPatternForView(bool *doit, const pmConfig *config, const pmChip *chip, const pmFPAview *view, const char *recipeName, const char *recipeValue); 190 191 bool ppImageFringeFree(pmConfig *config, pmFPAview *view); 191 192 -
branches/2dbias/ppImage/src/ppImageDetrendPattern.c
r42382 r42679 5 5 #include "ppImage.h" 6 6 7 #define ESCAPE(STATUS,...) { \ 8 psError(PS_ERR_UNKNOWN, STATUS, __VA_ARGS__); \ 9 psFree(view); \ 10 return false; \ 11 } 12 13 static bool doPatternForView (bool *doit, const pmConfig *config, const pmChip *chip, const pmFPAview *view, const char *recipename, const char *recipevalue); 7 #define ESCAPE(STATUS, ...) \ 8 { \ 9 psError(PS_ERR_UNKNOWN, STATUS, __VA_ARGS__); \ 10 psFree(view); \ 11 return false; \ 12 } 13 14 bool ppImageDoPatternForView(bool *doit, const pmConfig *config, const pmChip *chip, const pmFPAview *view, const char *recipename, const char *recipevalue); 14 15 15 16 bool ppImageDetrendPatternRowApply(pmConfig *config, pmChip *chip, const pmFPAview *inputView, ppImageOptions *options); … … 26 27 assert(inputView->readout == -1); 27 28 28 if (!ppImageDetrendPatternRowApply (config, chip, inputView, options)) { 29 return false; 30 } 31 if (!ppImageDetrendPatternContinuityApply (config, chip, inputView, options)) { 32 return false; 33 } 34 if (!ppImageDetrendPatternCellApply (config, chip, inputView, options)) { 35 return false; 36 } 37 if (!ppImageDetrendPatternDeadCellsApply (config, chip, inputView, options)) { 38 return false; 39 } 40 return(true); 29 if (!ppImageDetrendPatternRowApply(config, chip, inputView, options)) 30 { 31 return false; 32 } 33 if (!ppImageDetrendPatternContinuityApply(config, chip, inputView, options)) 34 { 35 return false; 36 } 37 if (!ppImageDetrendPatternCellApply(config, chip, inputView, options)) 38 { 39 return false; 40 } 41 if (!ppImageDetrendPatternDeadCellsApply(config, chip, inputView, options)) 42 { 43 return false; 44 } 45 return (true); 41 46 } 42 47 … … 45 50 bool status; 46 51 47 if (!options->doPatternRow) return true; 48 52 if (!options->doPatternRow) 53 return true; 54 49 55 assert(inputView->chip != -1); 50 56 assert(inputView->cell == -1); … … 73 79 74 80 pmHDU *hdu = pmHDUFromChip(chip); 75 if (psMetadataLookupBool(&status, hdu->header, "PTRN_ROW")) { 76 psLogMsg("ppImage", PS_LOG_INFO, "Not performing row pattern correction as it has already been done."); 77 return true; 81 if (psMetadataLookupBool(&status, hdu->header, "PTRN_ROW")) 82 { 83 psLogMsg("ppImage", PS_LOG_INFO, "Not performing row pattern correction as it has already been done."); 84 return true; 78 85 } 79 86 … … 85 92 86 93 // grab the PATTERN.ROW.AMP file 87 pmFPAfile *PRAfile = psMetadataLookupPtr (&status, config->files, "PPIMAGE.PATTERN.ROW.AMP"); 88 if (!PRAfile) { 89 psLogMsg("ppImage", PS_LOG_INFO, "Pattern Row Amplitude file not found, applying to all (with limits from ROW.SUBSET) "); 90 } 91 94 pmFPAfile *PRAfile = psMetadataLookupPtr(&status, config->files, "PPIMAGE.PATTERN.ROW.AMP"); 95 if (!PRAfile) 96 { 97 psLogMsg("ppImage", PS_LOG_INFO, "Pattern Row Amplitude file not found, applying to all (with limits from ROW.SUBSET) "); 98 } 99 92 100 pmFPAview *view = pmFPAviewAlloc(0); // View for local processing 93 101 *view = *inputView; 94 102 95 103 pmCell *cell = NULL; 96 while ((cell = pmFPAviewNextCell(view, input->fpa, 1)) != NULL) { 97 // const char *chipName = psMetadataLookupStr(NULL, chip->concepts, "CHIP.NAME"); 98 // const char *cellName = psMetadataLookupStr(NULL, cell->concepts, "CELL.NAME"); 99 // psWarning ("Looping through %s, %s\n", chipName, cellName); 100 101 if (!cell->process || !cell->file_exists) { 102 continue; 103 } 104 105 // this forces pmFPAfileRead of the PATTERN.ROW.AMP file (XXX but is this needed?) 106 if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) { 107 ESCAPE(false, "load failure for Cell"); 108 } 109 110 if (!cell->data_exists) { 111 continue; 112 } 113 114 if (cell->readouts->n > 1) { 115 psWarning ("Skipping Video Cell for ppImageDetrendPatternApply"); 116 continue; 117 } 118 119 // grab the corresponding cell 120 if (PRAfile) { 121 pmCell *PRAcell = pmFPAviewThisCell (view, PRAfile->fpa); 122 psAssert (PRAcell, "found Pattern Row Amplitude file, but not cell?"); 123 124 // find the nominal signal amplitude (check the ghost and/or crosstalk recipe file) 125 float amplitude = psMetadataLookupF32 (&status, PRAcell->analysis, "PTN.ROW.AMP"); 126 if (!status) amplitude = NAN; 127 128 // put the value on the science cell 129 psMetadataAddF32 (cell->analysis, PS_LIST_TAIL, "PTN.ROW.AMP", PS_META_REPLACE, "", amplitude); 130 } 131 132 bool doPattern = false; 133 if (!doPatternForView(&doPattern, config, chip, view, RECIPE_NAME, "PATTERN.ROW.SUBSET")) { 134 ESCAPE(false, "Unable to determine whether row pattern matching should be applied."); 135 } 136 if (!doPattern) continue; 137 138 // switch to test threaded version 139 if (true) { 140 // I need to allocate a view here to be freed by the 141 // called function below. 142 pmFPAview *myView = pmFPAviewAlloc(0); // View for local processing 143 *myView = *view; 144 145 // allocate a job, construct the arguments for this job 146 psThreadJob *job = psThreadJobAlloc("PPIMAGE_PATTERN_ROW_CELL"); 147 psArrayAdd(job->args, 1, config); 148 psArrayAdd(job->args, 1, input->fpa); 149 psArrayAdd(job->args, 1, chip); 150 psArrayAdd(job->args, 1, cell); 151 psArrayAdd(job->args, 1, myView); 152 psArrayAdd(job->args, 1, options); 153 if (!psThreadJobAddPending(job)) { 154 return false; 155 } 156 } else { 157 // bump the counter since it must be freed by the function below. 158 psMemIncrRefCounter (view); // View for local processing 159 if (!ppImageDetrendPatternApplyCell (config, input->fpa, chip, cell, view, options)) { 160 return false; 161 } 162 } 104 while ((cell = pmFPAviewNextCell(view, input->fpa, 1)) != NULL) 105 { 106 // const char *chipName = psMetadataLookupStr(NULL, chip->concepts, "CHIP.NAME"); 107 // const char *cellName = psMetadataLookupStr(NULL, cell->concepts, "CELL.NAME"); 108 // psWarning ("Looping through %s, %s\n", chipName, cellName); 109 110 if (!cell->process || !cell->file_exists) 111 { 112 continue; 113 } 114 115 // this forces pmFPAfileRead of the PATTERN.ROW.AMP file (XXX but is this needed?) 116 if (!pmFPAfileIOChecks(config, view, PM_FPA_BEFORE)) 117 { 118 ESCAPE(false, "load failure for Cell"); 119 } 120 121 if (!cell->data_exists) 122 { 123 continue; 124 } 125 126 if (cell->readouts->n > 1) 127 { 128 psWarning("Skipping Video Cell for ppImageDetrendPatternApply"); 129 continue; 130 } 131 132 // grab the corresponding cell 133 if (PRAfile) 134 { 135 pmCell *PRAcell = pmFPAviewThisCell(view, PRAfile->fpa); 136 psAssert(PRAcell, "found Pattern Row Amplitude file, but not cell?"); 137 138 // find the nominal signal amplitude (check the ghost and/or crosstalk recipe file) 139 float amplitude = psMetadataLookupF32(&status, PRAcell->analysis, "PTN.ROW.AMP"); 140 if (!status) 141 amplitude = NAN; 142 143 // put the value on the science cell 144 psMetadataAddF32(cell->analysis, PS_LIST_TAIL, "PTN.ROW.AMP", PS_META_REPLACE, "", amplitude); 145 } 146 147 bool doPattern = false; 148 if (!ppImageDoPatternForView(&doPattern, config, chip, view, RECIPE_NAME, "PATTERN.ROW.SUBSET")) 149 { 150 ESCAPE(false, "Unable to determine whether row pattern matching should be applied."); 151 } 152 if (!doPattern) 153 continue; 154 155 // switch to test threaded version 156 if (true) 157 { 158 // I need to allocate a view here to be freed by the 159 // called function below. 160 pmFPAview *myView = pmFPAviewAlloc(0); // View for local processing 161 *myView = *view; 162 163 // allocate a job, construct the arguments for this job 164 psThreadJob *job = psThreadJobAlloc("PPIMAGE_PATTERN_ROW_CELL"); 165 psArrayAdd(job->args, 1, config); 166 psArrayAdd(job->args, 1, input->fpa); 167 psArrayAdd(job->args, 1, chip); 168 psArrayAdd(job->args, 1, cell); 169 psArrayAdd(job->args, 1, myView); 170 psArrayAdd(job->args, 1, options); 171 if (!psThreadJobAddPending(job)) 172 { 173 return false; 174 } 175 } 176 else 177 { 178 // bump the counter since it must be freed by the function below. 179 psMemIncrRefCounter(view); // View for local processing 180 if (!ppImageDetrendPatternApplyCell(config, input->fpa, chip, cell, view, options)) 181 { 182 return false; 183 } 184 } 163 185 } 164 186 165 187 // wait here for the threaded jobs to finish 166 // if no threads are allocated, this 167 if (!psThreadPoolWait(true, true)) { 168 psError(PS_ERR_UNKNOWN, false, "Unable to apply bias correction."); 169 return false; 170 } 171 172 psMetadataAddBool(hdu->header, PS_LIST_TAIL, "PTRN_ROW",PS_META_REPLACE,"PATTERN.ROW correction applied",true); 188 // if no threads are allocated, this 189 if (!psThreadPoolWait(true, true)) 190 { 191 psError(PS_ERR_UNKNOWN, false, "Unable to apply bias correction."); 192 return false; 193 } 194 195 psMetadataAddBool(hdu->header, PS_LIST_TAIL, "PTRN_ROW", PS_META_REPLACE, "PATTERN.ROW correction applied", true); 173 196 psFree(view); 174 197 175 198 return true; 176 199 } … … 180 203 bool status; 181 204 182 if (!options->doPatternContinuity) return true; 205 if (!options->doPatternContinuity) 206 return true; 183 207 184 208 assert(inputView->chip != -1); … … 188 212 // see the comment for PATTERN.ROW; the same rules apply for PATTERN.CELL 189 213 190 int numCells = chip->cells->n; // Number of cells214 int numCells = chip->cells->n; // Number of cells 191 215 psVector *tweak = psVectorAlloc(numCells, PS_TYPE_U8); // Tweak cell? 192 pmFPAview *view = pmFPAviewAlloc(0); // View for local processing216 pmFPAview *view = pmFPAviewAlloc(0); // View for local processing 193 217 *view = *inputView; 194 218 195 219 pmHDU *hdu = pmHDUFromChip(chip); 196 if (psMetadataLookupBool(&status, hdu->header, "PTRN_CON")) { 197 psLogMsg("ppImage", PS_LOG_INFO, "Not performing cell continuity correction as it has already been done."); 198 return true; 220 if (psMetadataLookupBool(&status, hdu->header, "PTRN_CON")) 221 { 222 psLogMsg("ppImage", PS_LOG_INFO, "Not performing cell continuity correction as it has already been done."); 223 return true; 199 224 } 200 225 … … 202 227 psLogMsg("ppImage", PS_LOG_INFO, "Performing pattern continuity correction for %s\n", chipName); 203 228 204 for (int i = 0; i < chip->cells->n; i++) { 205 view->cell = i; 206 207 pmCell *cell = chip->cells->data[i]; // Cell of interest 208 209 if (cell->readouts->n > 1) { 210 psLogMsg("ppImage", PS_LOG_INFO, "Not performing cell continuity correction on video cell."); 211 continue; 212 } 213 214 bool doPattern = false; 215 if (!doPatternForView(&doPattern, config, chip, view, RECIPE_NAME, "PATTERN.CONTINUITY.SUBSET")) { 216 ESCAPE(false, "Unable to determine whether row pattern matching should be applied."); 217 } 218 219 if (doPattern) { 220 tweak->data.U8[i] = 0xFF; 221 } 229 for (int i = 0; i < chip->cells->n; i++) 230 { 231 view->cell = i; 232 233 pmCell *cell = chip->cells->data[i]; // Cell of interest 234 235 if (cell->readouts->n > 1) 236 { 237 psLogMsg("ppImage", PS_LOG_INFO, "Not performing cell continuity correction on video cell."); 238 continue; 239 } 240 241 bool doPattern = false; 242 if (!ppImageDoPatternForView(&doPattern, config, chip, view, RECIPE_NAME, "PATTERN.CONTINUITY.SUBSET")) 243 { 244 ESCAPE(false, "Unable to determine whether row pattern matching should be applied."); 245 } 246 247 if (doPattern) 248 { 249 tweak->data.U8[i] = 0xFF; 250 } 222 251 } 223 252 224 253 // Tweak the cells 225 254 if (!pmPatternContinuity(chip, tweak, options->patternCellBG, options->patternCellMean, 226 options->maskValue, options->darkMask,options->patternContinuityEdgeWidth)) { 227 psFree(tweak); 228 psFree(view); 229 return false; 255 options->maskValue, options->darkMask, options->patternContinuityEdgeWidth)) 256 { 257 psFree(tweak); 258 psFree(view); 259 return false; 230 260 } 231 261 psFree(tweak); 232 262 psFree(view); 233 263 234 psMetadataAddBool(hdu->header, PS_LIST_TAIL, "PTRN_CON", PS_META_REPLACE,"PATTERN.CONTINUITY correction applied",true);264 psMetadataAddBool(hdu->header, PS_LIST_TAIL, "PTRN_CON", PS_META_REPLACE, "PATTERN.CONTINUITY correction applied", true); 235 265 return true; 236 266 } … … 240 270 bool status; 241 271 242 if (!options->doPatternCell) return true; 272 if (!options->doPatternCell) 273 return true; 243 274 244 275 assert(inputView->chip != -1); … … 246 277 assert(inputView->readout == -1); 247 278 248 int numCells = chip->cells->n; // Number of cells279 int numCells = chip->cells->n; // Number of cells 249 280 psVector *tweak = psVectorAlloc(numCells, PS_TYPE_U8); // Tweak cell? 250 pmFPAview *view = pmFPAviewAlloc(0); // View for local processing281 pmFPAview *view = pmFPAviewAlloc(0); // View for local processing 251 282 *view = *inputView; 252 283 253 284 pmHDU *hdu = pmHDUFromChip(chip); 254 if (psMetadataLookupBool(&status, hdu->header, "PTRN_CEL")) { 255 psLogMsg("ppImage", PS_LOG_INFO, "Not performing cell pattern correction as it has already been done."); 256 return true; 285 if (psMetadataLookupBool(&status, hdu->header, "PTRN_CEL")) 286 { 287 psLogMsg("ppImage", PS_LOG_INFO, "Not performing cell pattern correction as it has already been done."); 288 return true; 257 289 } 258 290 … … 260 292 psLogMsg("ppImage", PS_LOG_INFO, "Performing cell pattern correction for %s\n", chipName); 261 293 262 for (int i = 0; i < chip->cells->n; i++) { 263 view->cell = i; 264 265 pmCell *cell = chip->cells->data[i]; // Cell of interest 266 267 if (cell->readouts->n > 1) { 268 psLogMsg("ppImage", PS_LOG_INFO, "Not performing cell pattern correction on video cell."); 269 continue; 270 } 271 272 bool doPattern = false; 273 if (!doPatternForView(&doPattern, config, chip, view, RECIPE_NAME, "PATTERN.CELL.SUBSET")) { 274 ESCAPE(false, "Unable to determine whether row pattern matching should be applied."); 275 } 276 if (doPattern) { 277 tweak->data.U8[i] = 0xFF; 278 } 294 for (int i = 0; i < chip->cells->n; i++) 295 { 296 view->cell = i; 297 298 pmCell *cell = chip->cells->data[i]; // Cell of interest 299 300 if (cell->readouts->n > 1) 301 { 302 psLogMsg("ppImage", PS_LOG_INFO, "Not performing cell pattern correction on video cell."); 303 continue; 304 } 305 306 bool doPattern = false; 307 if (!ppImageDoPatternForView(&doPattern, config, chip, view, RECIPE_NAME, "PATTERN.CELL.SUBSET")) 308 { 309 ESCAPE(false, "Unable to determine whether row pattern matching should be applied."); 310 } 311 if (doPattern) 312 { 313 tweak->data.U8[i] = 0xFF; 314 } 279 315 } 280 316 281 317 // Tweak the cells 282 318 if (!pmPatternCell(chip, tweak, options->patternCellBG, options->patternCellMean, 283 options->maskValue, options->darkMask)) { 284 psFree(tweak); 285 psFree(view); 286 return false; 319 options->maskValue, options->darkMask)) 320 { 321 psFree(tweak); 322 psFree(view); 323 return false; 287 324 } 288 325 psFree(tweak); 289 326 psFree(view); 290 327 291 psMetadataAddBool(hdu->header, PS_LIST_TAIL, "PTRN_CEL", PS_META_REPLACE,"PATTERN.CELL correction applied",true);328 psMetadataAddBool(hdu->header, PS_LIST_TAIL, "PTRN_CEL", PS_META_REPLACE, "PATTERN.CELL correction applied", true); 292 329 return true; 293 330 } 294 331 295 bool ppImageDetrendPatternDeadCellsMask (pmChip *chip, psImageMaskType maskVal) { 296 297 int numCells = chip->cells->n; // Number of cells 332 bool ppImageDetrendPatternDeadCellsMask(pmChip *chip, psImageMaskType maskVal) 333 { 334 335 int numCells = chip->cells->n; // Number of cells 298 336 299 337 // now mask bad cells 300 for (int i = 0; i < numCells; i++) { 301 pmCell *cell = chip->cells->data[i]; // Cell of interest 338 for (int i = 0; i < numCells; i++) 339 { 340 pmCell *cell = chip->cells->data[i]; // Cell of interest 302 341 pmReadout *ro = cell->readouts->data[0]; // Readout of interest 303 342 304 psImage *mask = ro->mask; // mask of interest 305 int numCols = mask->numCols, numRows = mask->numRows; // Size of image 306 307 for (int y = 0; y < numRows; y++) { 308 for (int x = 0; x < numCols; x++) { 309 mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] |= maskVal; 310 } 311 } 343 psImage *mask = ro->mask; // mask of interest 344 int numCols = mask->numCols, numRows = mask->numRows; // Size of image 345 346 for (int y = 0; y < numRows; y++) 347 { 348 for (int x = 0; x < numCols; x++) 349 { 350 mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] |= maskVal; 351 } 352 } 312 353 } 313 354 return true; 314 355 } 315 356 316 bool ppImageDetrendPatternDeadCellsXY42 (pmChip *chip, psImageMaskType maskVal) { 357 bool ppImageDetrendPatternDeadCellsXY42(pmChip *chip, psImageMaskType maskVal) 358 { 317 359 318 360 bool status; 319 361 320 362 // extract the MEDIAN_CELL_BACKGROUND values to check for problems 321 int numCells = chip->cells->n; // Number of cells 322 psVector *cellBackground = psVectorAllocEmpty (numCells, PS_DATA_F32); 323 324 for (int i = 0; i < numCells; i++) { 325 pmCell *cell = chip->cells->data[i];; 326 327 if (!cell->process || !cell->file_exists || !cell->data_exists) continue; 328 329 // select the HDU for this cell 330 pmHDU *cellHDU = pmHDUFromCell(cell); // HDU of interest 331 332 psF32 BackValue = psMetadataLookupF32(&status, cellHDU->header, "BACK_VAL"); 333 if (!status) continue; 334 335 psF32 BackError = psMetadataLookupF32(&status, cellHDU->header, "BACK_ERR"); 336 if (!status) continue; 337 338 if (BackValue == 0.0) continue; 339 if (BackError == 0.0) continue; 340 341 psVectorAppend (cellBackground, BackValue / BackError); 342 } 343 344 if (cellBackground->n < 0.375*numCells) { 345 // Chip is bad, mask the whole thing 346 ppImageDetrendPatternDeadCellsMask (chip, maskVal); 347 psFree (cellBackground); 348 return true; 363 int numCells = chip->cells->n; // Number of cells 364 psVector *cellBackground = psVectorAllocEmpty(numCells, PS_DATA_F32); 365 366 for (int i = 0; i < numCells; i++) 367 { 368 pmCell *cell = chip->cells->data[i]; 369 ; 370 371 if (!cell->process || !cell->file_exists || !cell->data_exists) 372 continue; 373 374 // select the HDU for this cell 375 pmHDU *cellHDU = pmHDUFromCell(cell); // HDU of interest 376 377 psF32 BackValue = psMetadataLookupF32(&status, cellHDU->header, "BACK_VAL"); 378 if (!status) 379 continue; 380 381 psF32 BackError = psMetadataLookupF32(&status, cellHDU->header, "BACK_ERR"); 382 if (!status) 383 continue; 384 385 if (BackValue == 0.0) 386 continue; 387 if (BackError == 0.0) 388 continue; 389 390 psVectorAppend(cellBackground, BackValue / BackError); 391 } 392 393 if (cellBackground->n < 0.375 * numCells) 394 { 395 // Chip is bad, mask the whole thing 396 ppImageDetrendPatternDeadCellsMask(chip, maskVal); 397 psFree(cellBackground); 398 return true; 349 399 } 350 400 351 401 // Second, calculate the median 352 psVectorSortInPlace (cellBackground);402 psVectorSortInPlace(cellBackground); 353 403 int midPt = cellBackground->n / 2.0; 354 float median = cellBackground->n % 2 ? cellBackground->data.F32[midPt] : 0.5 *(cellBackground->data.F32[midPt] + cellBackground->data.F32[midPt-1]);355 psFree (cellBackground);404 float median = cellBackground->n % 2 ? cellBackground->data.F32[midPt] : 0.5 * (cellBackground->data.F32[midPt] + cellBackground->data.F32[midPt - 1]); 405 psFree(cellBackground); 356 406 357 407 // XXX hardwired number 358 if (median < 3.0) { 359 // Chip is bad, mask the whole thing 360 ppImageDetrendPatternDeadCellsMask (chip, maskVal); 361 } 362 psFree (cellBackground); 408 if (median < 3.0) 409 { 410 // Chip is bad, mask the whole thing 411 ppImageDetrendPatternDeadCellsMask(chip, maskVal); 412 } 413 psFree(cellBackground); 363 414 return true; 364 415 } 365 416 366 417 // to apply the dead cell pattern, we need to transfer the pattern for this chip from the 367 // pmFPAfile for the pattern to the one for the image being processed. 418 // pmFPAfile for the pattern to the one for the image being processed. 368 419 bool ppImageDetrendPatternDeadCellsApply(pmConfig *config, pmChip *chip, const pmFPAview *inputView, ppImageOptions *options) 369 420 { 370 421 bool status; 371 422 372 if (!options->doPatternDeadCells) return true; 423 if (!options->doPatternDeadCells) 424 return true; 373 425 374 426 assert(inputView->chip != -1); … … 380 432 381 433 pmHDU *hdu = pmHDUFromChip(chip); 382 if (psMetadataLookupBool(&status, hdu->header, "PTRN_DED")) { 383 psLogMsg("ppImage", PS_LOG_INFO, "Not performing dead cell pattern correction as it has already been done."); 384 return true; 385 } 386 387 if (!strcmp (chipName, "XY40") || !strcmp (chipName, "XY42")) { 388 // special case : check for BACK_VAL / BACK_ERR > 3 or < 3 389 psLogMsg("ppImage", PS_LOG_INFO, "Using special case for XY40 and XY42"); 390 ppImageDetrendPatternDeadCellsXY42 (chip, options->blankMask); 391 return true; 434 if (psMetadataLookupBool(&status, hdu->header, "PTRN_DED")) 435 { 436 psLogMsg("ppImage", PS_LOG_INFO, "Not performing dead cell pattern correction as it has already been done."); 437 return true; 438 } 439 440 if (!strcmp(chipName, "XY40") || !strcmp(chipName, "XY42")) 441 { 442 // special case : check for BACK_VAL / BACK_ERR > 3 or < 3 443 psLogMsg("ppImage", PS_LOG_INFO, "Using special case for XY40 and XY42"); 444 ppImageDetrendPatternDeadCellsXY42(chip, options->blankMask); 445 return true; 392 446 } 393 447 394 448 pmFPAfile *pattern = psMetadataLookupPtr(&status, config->files, "PPIMAGE.PATTERN.DEAD.CELLS"); 395 if (!pattern) { 396 psLogMsg("ppImage", PS_LOG_INFO, "Pattern Dead Cells file not found, skipping"); 397 return true; 449 if (!pattern) 450 { 451 psLogMsg("ppImage", PS_LOG_INFO, "Pattern Dead Cells file not found, skipping"); 452 return true; 398 453 } 399 454 … … 401 456 *view = *inputView; 402 457 403 pmChip *patternChip = pmFPAviewThisChip (view, pattern->fpa);458 pmChip *patternChip = pmFPAviewThisChip(view, pattern->fpa); 404 459 405 460 // grab the pattern from the input pattern file chip 406 psImage *deadCellPattern = (psImage *) psMetadataLookupPtr (&status, patternChip->analysis, "PTN.DEAD.CELL"); 407 if (!deadCellPattern) { 461 psImage *deadCellPattern = (psImage *)psMetadataLookupPtr(&status, patternChip->analysis, "PTN.DEAD.CELL"); 462 if (!deadCellPattern) 463 { 408 464 psLogMsg("psModules.detrend", PS_LOG_DETAIL, "No DEAD CELL pattern for chip, skipping\n"); 409 psFree(view);410 return true;465 psFree(view); 466 return true; 411 467 } 412 468 413 469 // copy the pattern pointer to the chip of the image being processed 414 psMetadataAddImage (chip->analysis, PS_LIST_TAIL, "PTN.DEAD.CELL", PS_META_REPLACE, "", deadCellPattern);470 psMetadataAddImage(chip->analysis, PS_LIST_TAIL, "PTN.DEAD.CELL", PS_META_REPLACE, "", deadCellPattern); 415 471 416 472 // extract the MEDIAN_CELL_BACKGROUND values to check for problems 417 int numCells = chip->cells->n; // Number of cells418 psVector *cellBackground = psVectorAllocEmpty (numCells, PS_DATA_F32);473 int numCells = chip->cells->n; // Number of cells 474 psVector *cellBackground = psVectorAllocEmpty(numCells, PS_DATA_F32); 419 475 420 476 pmCell *cell = NULL; 421 while ((cell = pmFPAviewNextCell(view, chip->parent, 1)) != NULL) { 422 if (!cell->process || !cell->file_exists || !cell->data_exists) { 423 psVectorAppend (cellBackground, NAN); 424 continue; 425 } 426 427 // select the HDU for this cell 428 pmHDU *cellHDU = pmHDUFromCell(cell); // HDU of interest 429 430 psF32 value = psMetadataLookupF32(&status, cellHDU->header, "BACK_VAL"); 431 if (!status) { 432 psVectorAppend (cellBackground, NAN); 433 continue; 434 } 435 psVectorAppend (cellBackground, value); 477 while ((cell = pmFPAviewNextCell(view, chip->parent, 1)) != NULL) 478 { 479 if (!cell->process || !cell->file_exists || !cell->data_exists) 480 { 481 psVectorAppend(cellBackground, NAN); 482 continue; 483 } 484 485 // select the HDU for this cell 486 pmHDU *cellHDU = pmHDUFromCell(cell); // HDU of interest 487 488 psF32 value = psMetadataLookupF32(&status, cellHDU->header, "BACK_VAL"); 489 if (!status) 490 { 491 psVectorAppend(cellBackground, NAN); 492 continue; 493 } 494 psVectorAppend(cellBackground, value); 436 495 } 437 496 438 497 // match cellBackground pattern to registered patterns and mask as needed 439 if (!pmPatternDeadCells(chip, cellBackground, options->blankMask)) { 440 psFree(cellBackground); 441 psFree(view); 442 return false; 498 if (!pmPatternDeadCells(chip, cellBackground, options->blankMask)) 499 { 500 psFree(cellBackground); 501 psFree(view); 502 return false; 443 503 } 444 504 psFree(cellBackground); … … 449 509 } 450 510 451 static bool doPatternForView (bool *doit, const pmConfig *config, const pmChip *chip, const pmFPAview *view, const char *recipeName, const char *recipeValue) { 511 bool ppImageDoPatternForView(bool *doit, const pmConfig *config, const pmChip *chip, const pmFPAview *view, const char *recipeName, const char *recipeValue) 512 { 452 513 453 514 *doit = false; … … 456 517 457 518 doPattern = pmConfigRecipeValueByView(config, recipeName, recipeValue, chip->parent, view); 458 459 if (!doPattern) { 519 520 if (!doPattern) 521 { 460 522 psError(PS_ERR_UNKNOWN, false, "Unable to determine whether row pattern matching should be applied."); 461 523 return false; 462 524 } 463 if (doPattern->type == PS_DATA_BOOL) { 525 if (doPattern->type == PS_DATA_BOOL) 526 { 464 527 *doit = doPattern->data.B; 465 528 return true; 466 529 } 467 if (doPattern->type == PS_DATA_STRING) { 530 if (doPattern->type == PS_DATA_STRING) 531 { 468 532 // expect a string of the form "000110001001" with at least view->cell entries 469 533 char *string = doPattern->data.str; 470 if (strlen(string) < view->cell) { 471 psError(PS_ERR_UNKNOWN, true, "error in PATTERN.ROW.SUBSET chip string (too few elements %d)", (int) strlen(string)); 534 if (strlen(string) < view->cell) 535 { 536 psError(PS_ERR_UNKNOWN, true, "error in PATTERN.ROW.SUBSET chip string (too few elements %d)", (int)strlen(string)); 472 537 return false; 473 538 } 474 switch (string[view->cell]) { 475 case '0': 476 case 'f': 477 case 'F': 478 case 'n': 479 case 'N': 539 switch (string[view->cell]) 540 { 541 case '0': 542 case 'f': 543 case 'F': 544 case 'n': 545 case 'N': 480 546 *doit = false; 481 547 return true; 482 case '1':483 case 't':484 case 'T':485 case 'y':486 case 'Y':548 case '1': 549 case 't': 550 case 'T': 551 case 'y': 552 case 'Y': 487 553 *doit = true; 488 554 return true; 489 default:555 default: 490 556 psError(PS_ERR_UNKNOWN, true, "error in PATTERN.ROW.SUBSET chip string %s (unknown value %c))", string, string[view->cell]); 491 557 return false; … … 497 563 } 498 564 499 // thread safety : 500 bool ppImageDetrendPatternApplyCell (pmConfig *config, pmFPA *fpa, pmChip *chip, pmCell *cell, pmFPAview *view, ppImageOptions *options) { 501 565 // thread safety : 566 bool ppImageDetrendPatternApplyCell(pmConfig *config, pmFPA *fpa, pmChip *chip, pmCell *cell, pmFPAview *view, ppImageOptions *options) 567 { 568 502 569 // process each of the readouts 503 pmReadout *readout; // Readout from cell 504 while ((readout = pmFPAviewNextReadout (view, fpa, 1)) != NULL) { 505 if (!readout->data_exists) { 506 continue; 507 } 508 509 // Perform pattern correction 510 if (!pmPatternRow(readout, options->patternRowOrder, options->patternRowIter, 511 options->patternRowRej, options->patternRowThresh, options->patternRowMean, 512 options->patternRowStdev, options->maskValue, options->darkMask)) { 513 psFree (view); 514 return false; 515 } 516 } 517 psFree (view); // supplied view must be freeable 570 pmReadout *readout; // Readout from cell 571 while ((readout = pmFPAviewNextReadout(view, fpa, 1)) != NULL) 572 { 573 if (!readout->data_exists) 574 { 575 continue; 576 } 577 578 // Perform pattern correction 579 if (!pmPatternRow(readout, options->patternRowOrder, options->patternRowIter, 580 options->patternRowRej, options->patternRowThresh, options->patternRowMean, 581 options->patternRowStdev, options->maskValue, options->darkMask)) 582 { 583 psFree(view); 584 return false; 585 } 586 } 587 psFree(view); // supplied view must be freeable 518 588 return true; 519 589 } 520 590 521 psVector *ppImageDetrendPatternCellFailures(pmFPAfile *input, const pmFPAview *inputView) { 522 591 psVector *ppImageDetrendPatternCellFailures(pmFPAfile *input, const pmFPAview *inputView) 592 { 593 523 594 bool status = false; 524 595 pmCell *cell = NULL; 525 596 526 597 pmFPAview *view = pmFPAviewAlloc(0); // View for local processing 527 598 *view = *inputView; 528 599 529 600 // extract the MEDIAN_CELL_BACKGROUND values to check for problems 530 psVector *cellBackground = psVectorAllocEmpty (64, PS_DATA_F32); 531 while ((cell = pmFPAviewNextCell(view, input->fpa, 1)) != NULL) { 532 if (!cell->process || !cell->file_exists || !cell->data_exists) { 533 psVectorAppend (cellBackground, NAN); 534 continue; 535 } 536 537 // select the HDU for this cell 538 pmHDU *hdu = pmHDUFromCell(cell); // HDU of interest 539 540 psF32 value = psMetadataLookupF32(&status, hdu->header, "BACK_VAL"); 541 psVectorAppend (cellBackground, value); 601 psVector *cellBackground = psVectorAllocEmpty(64, PS_DATA_F32); 602 while ((cell = pmFPAviewNextCell(view, input->fpa, 1)) != NULL) 603 { 604 if (!cell->process || !cell->file_exists || !cell->data_exists) 605 { 606 psVectorAppend(cellBackground, NAN); 607 continue; 608 } 609 610 // select the HDU for this cell 611 pmHDU *hdu = pmHDUFromCell(cell); // HDU of interest 612 613 psF32 value = psMetadataLookupF32(&status, hdu->header, "BACK_VAL"); 614 psVectorAppend(cellBackground, value); 542 615 } 543 616 return cellBackground; -
branches/2dbias/ppImage/src/ppImageDetrendReadout.c
r42382 r42679 5 5 #include "ppImage.h" 6 6 7 #define ESCAPE(STATUS, ...) \ 8 { \ 9 psError(PS_ERR_UNKNOWN, STATUS, __VA_ARGS__); \ 10 psFree(view); \ 11 return false; \ 12 } 13 7 14 bool ppImageDetrendReadout(pmConfig *config, ppImageOptions *options, pmFPAview *view) 8 15 { 9 // psTimerStart("detrend.readout");16 // psTimerStart("detrend.readout"); 10 17 11 18 // construct a view for the detrend images (which have only one readout) … … 18 25 19 26 // Check that the gain is set (this is used by both pmReadoutGenerateMask and pmReadoutGenerateVariance) 20 { 21 float gain = psMetadataLookupF32(NULL, input->parent->concepts, "CELL.GAIN"); // Gain for cell 22 if (!isfinite(gain)) { 23 psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, RECIPE_NAME); // Recipe 24 psAssert(recipe, "Should be there!"); 25 bool override = psMetadataLookupBool(NULL, recipe, "GAIN.OVERRIDE"); // Override the bad gain? 26 if (override) { 27 psWarning("CELL.GAIN is not set for readout (%d,%d,%d) --- setting to unity.", view->chip, view->cell, view->readout); 28 psMetadataItem *item = psMetadataLookup(input->parent->concepts, "CELL.GAIN"); // Gain item 29 psAssert(item, "Should be there!"); 30 item->data.F32 = 1.0; 31 32 // for unity gain, there is no modification for the readnoise, note that it has (effectively) been updated 33 psMetadataRemoveKey(input->parent->concepts, "CELL.READNOISE.UPDATE"); 34 } else { 35 psWarning("CELL.GAIN is NAN for readout (%d,%d,%d), image will be masked.", view->chip, view->cell, view->readout); 36 } 37 } 27 { 28 float gain = psMetadataLookupF32(NULL, input->parent->concepts, "CELL.GAIN"); // Gain for cell 29 if (!isfinite(gain)) 30 { 31 psMetadata *recipe = psMetadataLookupMetadata(NULL, config->recipes, RECIPE_NAME); // Recipe 32 psAssert(recipe, "Should be there!"); 33 bool override = psMetadataLookupBool(NULL, recipe, "GAIN.OVERRIDE"); // Override the bad gain? 34 if (override) 35 { 36 psWarning("CELL.GAIN is not set for readout (%d,%d,%d) --- setting to unity.", view->chip, view->cell, view->readout); 37 psMetadataItem *item = psMetadataLookup(input->parent->concepts, "CELL.GAIN"); // Gain item 38 psAssert(item, "Should be there!"); 39 item->data.F32 = 1.0; 40 41 // for unity gain, there is no modification for the readnoise, note that it has (effectively) been updated 42 psMetadataRemoveKey(input->parent->concepts, "CELL.READNOISE.UPDATE"); 43 } 44 else 45 { 46 psWarning("CELL.GAIN is NAN for readout (%d,%d,%d), image will be masked.", view->chip, view->cell, view->readout); 47 } 48 } 38 49 } 39 50 // psLogMsg ("ppImage", 6, "check gain: %f sec\n", psTimerMark ("detrend.readout")); … … 43 54 bool hasVideo = false; 44 55 { 45 // XXX test for GPC1? or CAN_HAVE_VIDEO in camera config? 46 bool status = false; 47 if (!input) goto done_video_check; 48 if (!input->parent) goto done_video_check; 49 if (!input->parent->parent) goto done_video_check; 50 if (!input->parent->parent->hdu) goto done_video_check; 51 if (!input->parent->parent->hdu->header) goto done_video_check; 52 char *ptr = psMetadataLookupStr(&status,input->parent->parent->hdu->header,"CELLMODE"); 53 if (status) { 54 psLogMsg ("ppImage.detrend", PS_LOG_DETAIL, "VIDEO: %d %d %d\n",(int) options->hasVideo,(int) options->useVideoDark, (int) options->useVideoMask); 55 char *Vptr = strchr(ptr,'V'); 56 if (Vptr) { 57 hasVideo = options->hasVideo = true; 58 psLogMsg ("ppImage.detrend", PS_LOG_INFO, "VIDEO: %d %d %d\n",(int) options->hasVideo,(int) options->useVideoDark, (int) options->useVideoMask); 59 } 60 } 61 } 62 done_video_check: 56 // XXX test for GPC1? or CAN_HAVE_VIDEO in camera config? 57 bool status = false; 58 if (!input) 59 goto done_video_check; 60 if (!input->parent) 61 goto done_video_check; 62 if (!input->parent->parent) 63 goto done_video_check; 64 if (!input->parent->parent->hdu) 65 goto done_video_check; 66 if (!input->parent->parent->hdu->header) 67 goto done_video_check; 68 char *ptr = psMetadataLookupStr(&status, input->parent->parent->hdu->header, "CELLMODE"); 69 if (status) 70 { 71 psLogMsg("ppImage.detrend", PS_LOG_DETAIL, "VIDEO: %d %d %d\n", (int)options->hasVideo, (int)options->useVideoDark, (int)options->useVideoMask); 72 char *Vptr = strchr(ptr, 'V'); 73 if (Vptr) 74 { 75 hasVideo = options->hasVideo = true; 76 psLogMsg("ppImage.detrend", PS_LOG_INFO, "VIDEO: %d %d %d\n", (int)options->hasVideo, (int)options->useVideoDark, (int)options->useVideoMask); 77 } 78 } 79 } 80 done_video_check: 63 81 // psLogMsg ("ppImage", 6, "check video: %f sec\n", psTimerMark ("detrend.readout")); 64 82 … … 74 92 75 93 // Masking on the basis of pixel value needs to be done before anything else, so the values are pristine. 76 if (options->doMaskBuild) { 94 if (options->doMaskBuild) 95 { 77 96 psImageMaskType satMask = options->doMaskSat ? options->satMask : 0; 78 97 psImageMaskType lowMask = options->doMaskLow ? options->lowMask : 0; 79 if (!pmReadoutGenerateMask(input, satMask, lowMask)) { 80 psError(PS_ERR_UNKNOWN, false, "Unable to generate a mask."); 81 psFree(detview); 82 return false; 83 } 84 // psLogMsg ("ppImage", 6, "generate mask: %f sec\n", psTimerMark ("detrend.readout")); 98 if (!pmReadoutGenerateMask(input, satMask, lowMask)) 99 { 100 psError(PS_ERR_UNKNOWN, false, "Unable to generate a mask."); 101 psFree(detview); 102 return false; 103 } 104 // psLogMsg ("ppImage", 6, "generate mask: %f sec\n", psTimerMark ("detrend.readout")); 85 105 } 86 106 // apply the externally supplied mask to the input->mask pixels 87 if (options->doMask) { 88 pmReadout *mask; 89 if ((options->useVideoMask)&&(hasVideo)) { 90 mask = pmFPAfileThisReadout(config->files, detview, "PPIMAGE.VIDEOMASK"); 91 } 92 else { 93 mask = pmFPAfileThisReadout(config->files, detview, "PPIMAGE.MASK"); 94 } 95 pmMaskBadPixels(input, mask, options->maskValue); 96 // psLogMsg ("ppImage", 6, "apply mask: %f sec\n", psTimerMark ("detrend.readout")); 107 if (options->doMask) 108 { 109 pmReadout *mask; 110 if ((options->useVideoMask) && (hasVideo)) 111 { 112 mask = pmFPAfileThisReadout(config->files, detview, "PPIMAGE.VIDEOMASK"); 113 } 114 else 115 { 116 mask = pmFPAfileThisReadout(config->files, detview, "PPIMAGE.MASK"); 117 } 118 pmMaskBadPixels(input, mask, options->maskValue); 119 // psLogMsg ("ppImage", 6, "apply mask: %f sec\n", psTimerMark ("detrend.readout")); 97 120 } 98 121 … … 101 124 // extern bool ppImageBurntoolApply(pmConfig *, ppImageOptions *, pmFPAview *, pmReadout *); 102 125 ppImageBurntoolApply(config, options, view, input); 103 // psLogMsg ("ppImage", 6, "apply burntool: %f sec\n", psTimerMark ("detrend.readout")); 104 } 105 106 if (options->doMaskBurntool) { 107 if (options->doApplyBurntool) { 126 // psLogMsg ("ppImage", 6, "apply burntool: %f sec\n", psTimerMark ("detrend.readout")); 127 } 128 129 if (options->doMaskBurntool) 130 { 131 if (options->doApplyBurntool) 132 { 108 133 // build burntool mask from data input burntool table 109 ppImageBurntoolMaskFromTable(config,options,view,input); 110 } else { 134 ppImageBurntoolMaskFromTable(config, options, view, input); 135 } 136 else 137 { 111 138 // build burntool mask from data in the input image's fits extension 112 ppImageBurntoolMask(config, options,view,input);113 } 114 // psLogMsg ("ppImage", 6, "apply burntool mask: %f sec\n", psTimerMark ("detrend.readout"));139 ppImageBurntoolMask(config, options, view, input); 140 } 141 // psLogMsg ("ppImage", 6, "apply burntool mask: %f sec\n", psTimerMark ("detrend.readout")); 115 142 } 116 143 117 144 // Subtract the overscan 118 if (options->doOverscan) { 119 if (!pmOverscanSubtract (input, options->overscan)) { 120 psError(PS_ERR_UNKNOWN, false, "Unable to subtract overscan."); 121 psFree(detview); 122 return false; 123 } 124 // psLogMsg ("ppImage", 6, "subtract overscan: %f sec\n", psTimerMark ("detrend.readout")); 145 if (options->doOverscan) 146 { 147 bool doTwoDOverscan = false; 148 if (options->overscan->TwoD) 149 { 150 pmChip *chip = pmFPAfileThisChip(config->files, view, "PPIMAGE.INPUT"); 151 if (!ppImageDoPatternForView(&doTwoDOverscan, config, chip, view, RECIPE_NAME, "OVERSCAN.2D.SUBSET")) 152 { 153 ESCAPE(false, "Unable to determine whether 2D Overscan subtraction should be applied."); 154 } 155 } 156 if (!pmOverscanSubtract(input, options->overscan, doTwoDOverscan)) 157 { 158 psError(PS_ERR_UNKNOWN, false, "Unable to subtract overscan."); 159 psFree(detview); 160 return false; 161 } 162 // psLogMsg ("ppImage", 6, "subtract overscan: %f sec\n", psTimerMark ("detrend.readout")); 125 163 } 126 164 127 165 // measure the overscan-subtracted readoutBackground here (or subtract the overscan value?) 128 166 // XXX this is the measurements and should be independent of the pattern masking 129 if (options->doPatternDeadCells) { 130 psStats *stats = psStatsAlloc (PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV); 131 psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS); 132 psImageBackground (stats, NULL, input->image, NULL, 0xffff, rng); 133 134 // save this value somewhere 135 pmHDU *hdu = pmHDUFromReadout(input); // HDU of interest 136 psMetadataAddF32(hdu->header, PS_LIST_TAIL, "BACK_VAL", PS_META_REPLACE, "Median cell background", stats->robustMedian); 137 psMetadataAddF32(hdu->header, PS_LIST_TAIL, "BACK_ERR", PS_META_REPLACE, "Stdev of cell background", stats->robustStdev); 138 psFree (stats); 139 psFree (rng); 167 if (options->doPatternDeadCells) 168 { 169 psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV); 170 psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS); 171 psImageBackground(stats, NULL, input->image, NULL, 0xffff, rng); 172 173 // save this value somewhere 174 pmHDU *hdu = pmHDUFromReadout(input); // HDU of interest 175 psMetadataAddF32(hdu->header, PS_LIST_TAIL, "BACK_VAL", PS_META_REPLACE, "Median cell background", stats->robustMedian); 176 psMetadataAddF32(hdu->header, PS_LIST_TAIL, "BACK_ERR", PS_META_REPLACE, "Stdev of cell background", stats->robustStdev); 177 psFree(stats); 178 psFree(rng); 140 179 } 141 180 142 181 // Non-linearity correction 143 if (options->doNonLin) { 144 if (!ppImageDetrendNonLinear(input,detview,config)) { 145 psError(PS_ERR_UNKNOWN, false, "Unable to correct NonLinearity"); 146 psFree(detview); 147 return(false); 148 } 149 // psLogMsg ("ppImage", 6, "nonlinear correction: %f sec\n", psTimerMark ("detrend.readout")); 182 if (options->doNonLin) 183 { 184 if (!ppImageDetrendNonLinear(input, detview, config)) 185 { 186 psError(PS_ERR_UNKNOWN, false, "Unable to correct NonLinearity"); 187 psFree(detview); 188 return (false); 189 } 190 // psLogMsg ("ppImage", 6, "nonlinear correction: %f sec\n", psTimerMark ("detrend.readout")); 150 191 } 151 192 // New Non-linearity correction (exclusive of the above) 152 if (options->doNewNonLin) { 153 if (!ppImageDetrendNewNonLinear(input, detview, config)) { 154 psError(PS_ERR_UNKNOWN, false, "Unable to correct Non-Linearity with new version (2023)"); 155 psFree(detview); 156 return(false); 157 } 158 // psLogMsg ("ppImage", 6, "nonlinear correction: %f sec\n", psTimerMark ("detrend.readout")); 193 if (options->doNewNonLin) 194 { 195 if (!ppImageDetrendNewNonLinear(input, detview, config)) 196 { 197 psError(PS_ERR_UNKNOWN, false, "Unable to correct Non-Linearity with new version (2023)"); 198 psFree(detview); 199 return (false); 200 } 201 // psLogMsg ("ppImage", 6, "nonlinear correction: %f sec\n", psTimerMark ("detrend.readout")); 159 202 } 160 203 161 204 // set up the dark and bias 162 pmCell *dark = NULL; // Multi-dark 163 pmReadout *oldDark = NULL; // Old-fashioned dark 164 pmReadout *bias = NULL; 165 if (options->doBias) { 205 pmCell *dark = NULL; // Multi-dark 206 pmReadout *oldDark = NULL; // Old-fashioned dark 207 pmReadout *bias = NULL; 208 if (options->doBias) 209 { 166 210 bias = pmFPAfileThisReadout(config->files, detview, "PPIMAGE.BIAS"); 167 211 } 168 if (options->doDark) { 169 bool mdok; // Status of MD lookup 170 psMetadata *recipe = psMetadataLookupPtr (&mdok, config->recipes, RECIPE_NAME); 212 if (options->doDark) 213 { 214 bool mdok; // Status of MD lookup 215 psMetadata *recipe = psMetadataLookupPtr(&mdok, config->recipes, RECIPE_NAME); 171 216 assert(mdok && recipe); 172 217 173 if ((options->useVideoDark)&&(hasVideo)) { 174 if (psMetadataLookupBool(&mdok, recipe, "OLDDARK")) { 175 oldDark = pmFPAfileThisReadout(config->files, detview, "PPIMAGE.VIDEODARK"); 176 } else { 177 dark = pmFPAfileThisCell(config->files, detview, "PPIMAGE.VIDEODARK"); 178 } 179 } 180 else { 181 if (psMetadataLookupBool(&mdok, recipe, "OLDDARK")) { 182 oldDark = pmFPAfileThisReadout(config->files, detview, "PPIMAGE.DARK"); 183 } else { 184 dark = pmFPAfileThisCell(config->files, detview, "PPIMAGE.DARK"); 185 } 186 } 218 if ((options->useVideoDark) && (hasVideo)) 219 { 220 if (psMetadataLookupBool(&mdok, recipe, "OLDDARK")) 221 { 222 oldDark = pmFPAfileThisReadout(config->files, detview, "PPIMAGE.VIDEODARK"); 223 } 224 else 225 { 226 dark = pmFPAfileThisCell(config->files, detview, "PPIMAGE.VIDEODARK"); 227 } 228 } 229 else 230 { 231 if (psMetadataLookupBool(&mdok, recipe, "OLDDARK")) 232 { 233 oldDark = pmFPAfileThisReadout(config->files, detview, "PPIMAGE.DARK"); 234 } 235 else 236 { 237 dark = pmFPAfileThisCell(config->files, detview, "PPIMAGE.DARK"); 238 } 239 } 187 240 } 188 241 189 242 // Bias and temperature-independent-dark subtraction are merged. 190 if (options->doBias) { 191 if (!pmBiasSubtract(input, bias, oldDark, view)) { 243 if (options->doBias) 244 { 245 if (!pmBiasSubtract(input, bias, oldDark, view)) 246 { 192 247 psError(PS_ERR_UNKNOWN, false, "Unable to subtract bias."); 193 248 psFree(detview); 194 249 return false; 195 250 } 196 // psLogMsg ("ppImage", 6, "apply bias: %f sec\n", psTimerMark ("detrend.readout"));197 } 198 251 // psLogMsg ("ppImage", 6, "apply bias: %f sec\n", psTimerMark ("detrend.readout")); 252 } 253 199 254 // Weight on the basis of pixel value needs to be done after the overscan has been subtracted 200 if (options->doVarianceBuild) { 255 if (options->doVarianceBuild) 256 { 201 257 // create the target mask and variance images 202 258 psImage *noiseImage = NULL; 203 if (options->doNoiseMap) { 259 if (options->doNoiseMap) 260 { 204 261 // XXX convert the noiseMap image to a binned image 205 262 pmReadout *noiseMap = NULL; 206 263 noiseMap = pmFPAfileThisReadout(config->files, detview, "PPIMAGE.NOISEMAP"); 207 noiseImage = psImageCopy (NULL, input->image, PS_TYPE_F32);208 psImageInit (noiseImage, 0.0);264 noiseImage = psImageCopy(NULL, input->image, PS_TYPE_F32); 265 psImageInit(noiseImage, 0.0); 209 266 210 267 // XXX this works, but is not really quite right: the model shoud include the 211 268 // offset information, we are not really getting exactly the right mapping from the 212 269 // original file. 213 // CZW 2012-03-21: I do not believe this is true anymore. In any case, this seems to be what214 // ppImageReplaceBackground does to do sky subtraction.270 // CZW 2012-03-21: I do not believe this is true anymore. In any case, this seems to be what 271 // ppImageReplaceBackground does to do sky subtraction. 215 272 psImageBinning *binning = psImageBinningAlloc(); 216 273 binning->nXruff = noiseMap->image->numCols; … … 220 277 psImageBinningSetScale(binning, PS_IMAGE_BINNING_LEFT); 221 278 222 psImageUnbin (noiseImage, noiseMap->image, binning); 223 psFree (binning); 224 } 225 226 if (!pmReadoutGenerateVariance(input, noiseImage, true)) { 227 psError(PS_ERR_UNKNOWN, false, "Unable to generate a variance image."); 228 psFree(detview); 229 return false; 230 } 231 psFree (noiseImage); 232 // psLogMsg ("ppImage", 6, "generate variance: %f sec\n", psTimerMark ("detrend.readout")); 233 } 234 235 if (options->doDark && dark) { 236 if (!pmDarkApply(input, dark, options->darkMask)) { 279 psImageUnbin(noiseImage, noiseMap->image, binning); 280 psFree(binning); 281 } 282 283 if (!pmReadoutGenerateVariance(input, noiseImage, true)) 284 { 285 psError(PS_ERR_UNKNOWN, false, "Unable to generate a variance image."); 286 psFree(detview); 287 return false; 288 } 289 psFree(noiseImage); 290 // psLogMsg ("ppImage", 6, "generate variance: %f sec\n", psTimerMark ("detrend.readout")); 291 } 292 293 if (options->doDark && dark) 294 { 295 if (!pmDarkApply(input, dark, options->darkMask)) 296 { 237 297 psError(PS_ERR_UNKNOWN, false, "Unable to subtract dark."); 238 298 psFree(detview); 239 299 return false; 240 300 } 241 // psLogMsg ("ppImage", 6, "apply dark: %f sec\n", psTimerMark ("detrend.readout")); 242 } 243 244 if (options->doRemnance) { 301 // psLogMsg ("ppImage", 6, "apply dark: %f sec\n", psTimerMark ("detrend.readout")); 302 } 303 304 if (options->doRemnance) 305 { 245 306 if (!pmRemnance(input, options->maskValue, options->lowMask, 246 options->remnanceSize, options->remnanceThresh)) { 307 options->remnanceSize, options->remnanceThresh)) 308 { 247 309 psError(PS_ERR_UNKNOWN, false, "Unable to mask remnance."); 248 310 psFree(detview); 249 311 return false; 250 312 } 251 // psLogMsg ("ppImage", 6, "mask remnance: %f sec\n", psTimerMark ("detrend.readout"));313 // psLogMsg ("ppImage", 6, "mask remnance: %f sec\n", psTimerMark ("detrend.readout")); 252 314 } 253 315 254 316 // Shutter correction 255 if (options->doShutter) { 317 if (options->doShutter) 318 { 256 319 pmReadout *shutter = pmFPAfileThisReadout(config->files, detview, "PPIMAGE.SHUTTER"); 257 if (!pmShutterCorrectionApply(input, shutter, pmConfigMaskGet("FLAT", config))) { 258 psFree(detview); 259 return false; 260 } 261 // psLogMsg ("ppImage", 6, "shutter correction: %f sec\n", psTimerMark ("detrend.readout")); 320 if (!pmShutterCorrectionApply(input, shutter, pmConfigMaskGet("FLAT", config))) 321 { 322 psFree(detview); 323 return false; 324 } 325 // psLogMsg ("ppImage", 6, "shutter correction: %f sec\n", psTimerMark ("detrend.readout")); 262 326 } 263 327 264 328 // Flat-field correction (no options used?) 265 if (options->doFlat) { 329 if (options->doFlat) 330 { 266 331 pmReadout *flat = pmFPAfileThisReadout(config->files, detview, "PPIMAGE.FLAT"); 267 if (!pmFlatField(input, flat, options->flatMask)) { 268 psFree(detview); 269 return false; 270 } 271 // psLogMsg ("ppImage", 6, "apply flat: %f sec\n", psTimerMark ("detrend.readout")); 272 } 273 274 /* // Pattern noise correction */ 275 /* if (options->doPattern) { */ 276 /* if (!pmPatternRow(input, options->patternOrder, options->patternIter, options->patternRej, */ 277 /* options->patternThresh, options->patternMean, options->patternStdev, */ 278 /* options->maskValue, options->darkMask)) { */ 279 /* psFree(detview); */ 280 /* return false; */ 281 /* } */ 282 /* } */ 332 if (!pmFlatField(input, flat, options->flatMask)) 333 { 334 psFree(detview); 335 return false; 336 } 337 // psLogMsg ("ppImage", 6, "apply flat: %f sec\n", psTimerMark ("detrend.readout")); 338 } 339 340 /* // Pattern noise correction */ 341 /* if (options->doPattern) { */ 342 /* if (!pmPatternRow(input, options->patternOrder, options->patternIter, options->patternRej, */ 343 /* options->patternThresh, options->patternMean, options->patternStdev, */ 344 /* options->maskValue, options->darkMask)) { */ 345 /* psFree(detview); */ 346 /* return false; */ 347 /* } */ 348 /* } */ 283 349 284 350 // Normalization by a single (known) constant 285 bool mdok; // Status of MD lookup351 bool mdok; // Status of MD lookup 286 352 float norm = psMetadataLookupF32(&mdok, config->arguments, "NORMALIZATION"); 287 if (mdok && isfinite(norm) && norm != 1.0) { 353 if (mdok && isfinite(norm) && norm != 1.0) 354 { 288 355 pmHDU *hdu = pmHDUFromReadout(input); // HDU of interest 289 psString comment = NULL; // Comment to add356 psString comment = NULL; // Comment to add 290 357 psStringAppend(&comment, "Normalization: %f", norm); 291 358 psMetadataAddStr(hdu->header, PS_LIST_TAIL, "HISTORY", PS_META_DUPLICATE_OK, comment, ""); … … 293 360 294 361 psBinaryOp(input->image, input->image, "*", psScalarAlloc(norm, PS_TYPE_F32)); 295 // psLogMsg ("ppImage", 6, "renormalize: %f sec\n", psTimerMark ("detrend.readout"));296 } 297 298 # if (1)362 // psLogMsg ("ppImage", 6, "renormalize: %f sec\n", psTimerMark ("detrend.readout")); 363 } 364 365 #if (1) 299 366 // Normalization by per-class values 300 367 psMetadata *normlist = psMetadataLookupMetadata(&mdok, config->arguments, "NORMALIZATION.TABLE"); 301 if (normlist) { 368 if (normlist) 369 { 302 370 pmFPAfile *inputFile = psMetadataLookupPtr(&mdok, config->files, "PPIMAGE.INPUT"); 303 371 304 372 // get the menu of class IDs 305 373 psMetadata *menu = psMetadataLookupMetadata(&mdok, inputFile->camera, "CLASSID"); 306 if (!menu) { 374 if (!menu) 375 { 307 376 psError(PS_ERR_IO, false, "Unable to find CLASSID metadata in camera configuration"); 308 377 psFree(detview); … … 311 380 // get the rule for class_id for the desired class 312 381 const char *rule = psMetadataLookupStr(&mdok, menu, options->normClass); 313 if (!rule) { 382 if (!rule) 383 { 314 384 psError(PS_ERR_IO, false, "Unable to find NORM.CLASS value %s in CLASSID in camera configuration", options->normClass); 315 385 psFree(detview); … … 318 388 // get the class_id from the rule 319 389 char *classID = pmFPAfileNameFromRule(rule, inputFile, view); 320 if (!classID) { 390 if (!classID) 391 { 321 392 psError(PS_ERR_IO, false, "error converting CLASSID rule %s to name\n", rule); 322 393 psFree(detview); … … 325 396 326 397 // get normalization from the class_id 327 float norm = psMetadataLookupF32 (&mdok, normlist, classID); 328 if (!mdok) { 398 float norm = psMetadataLookupF32(&mdok, normlist, classID); 399 if (!mdok) 400 { 329 401 psError(PS_ERR_IO, false, "failed to find class ID %s in normalization table\n", classID); 330 402 psFree(detview); … … 333 405 334 406 pmHDU *hdu = pmHDUFromReadout(input); // HDU of interest 335 psString comment = NULL; // Comment to add407 psString comment = NULL; // Comment to add 336 408 psStringAppend(&comment, "Normalization: %f", norm); 337 409 psMetadataAddStr(hdu->header, PS_LIST_TAIL, "HISTORY", PS_META_DUPLICATE_OK, comment, ""); … … 341 413 psBinaryOp(input->image, input->image, "*", psScalarAlloc(norm, PS_TYPE_F32)); 342 414 343 psFree (classID); 344 345 // psLogMsg ("ppImage", 6, "renormalize by class: %f sec\n", psTimerMark ("detrend.readout")); 346 } 347 # endif 348 349 if (options->doFringe) { 415 psFree(classID); 416 417 // psLogMsg ("ppImage", 6, "renormalize by class: %f sec\n", psTimerMark ("detrend.readout")); 418 } 419 #endif 420 421 if (options->doFringe) 422 { 350 423 pmCell *fringe = pmFPAfileThisCell(config->files, detview, "PPIMAGE.FRINGE"); 351 if (!ppImageDetrendFringeMeasure(input, fringe, false, options)) { 352 psFree(detview); 353 return false; 354 } 355 // psLogMsg ("ppImage", 6, "measure fringe: %f sec\n", psTimerMark ("detrend.readout")); 424 if (!ppImageDetrendFringeMeasure(input, fringe, false, options)) 425 { 426 psFree(detview); 427 return false; 428 } 429 // psLogMsg ("ppImage", 6, "measure fringe: %f sec\n", psTimerMark ("detrend.readout")); 356 430 } 357 431
Note:
See TracChangeset
for help on using the changeset viewer.
