Changeset 25372
- Timestamp:
- Sep 14, 2009, 4:15:24 PM (17 years ago)
- Location:
- trunk/psModules/src/camera
- Files:
-
- 2 edited
-
pmFPAMaskWeight.c (modified) (10 diffs)
-
pmFPAMaskWeight.h (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psModules/src/camera/pmFPAMaskWeight.c
r24767 r25372 111 111 // psError(PS_ERR_IO, true, "CELL.SATURATION is not set --- unable to set mask.\n"); 112 112 // return false; 113 psWarning("CELL.SATURATION is not set --- completely masking cell.\n");114 saturation = NAN;113 psWarning("CELL.SATURATION is not set --- completely masking cell.\n"); 114 saturation = NAN; 115 115 } 116 116 float bad = psMetadataLookupF32(&mdok, cell->concepts, "CELL.BAD"); // Bad level … … 118 118 // psError(PS_ERR_IO, true, "CELL.BAD is not set --- unable to set mask.\n"); 119 119 // return false; 120 psWarning("CELL.BAD is not set --- completely masking cell.\n");121 bad = NAN;120 psWarning("CELL.BAD is not set --- completely masking cell.\n"); 121 bad = NAN; 122 122 } 123 123 psTrace("psModules.camera", 5, "Saturation: %f, bad: %f\n", saturation, bad); 124 124 125 // if CELL.GAIN or CELL.READNOISE are not set, then the variance will be set to NAN; 125 // if CELL.GAIN or CELL.READNOISE are not set, then the variance will be set to NAN; 126 126 // in this case, we have to set the mask as well 127 127 float gain = psMetadataLookupF32(&mdok, cell->concepts, "CELL.GAIN"); // Cell gain … … 140 140 // completely mask if SATURATION or BAD are invalid 141 141 if (isnan(saturation) || isnan(bad) || isnan(gain) || isnan(readnoise)) { 142 psImageInit(mask, badMask);143 return true;142 psImageInit(mask, badMask); 143 return true; 144 144 } 145 145 … … 230 230 // return false; 231 231 psWarning("CELL.GAIN is not set --- setting variance to NAN\n"); 232 gain = NAN;232 gain = NAN; 233 233 } 234 234 float readnoise = psMetadataLookupF32(&mdok, cell->concepts, "CELL.READNOISE"); // Cell read noise … … 237 237 // return false; 238 238 psWarning("CELL.READNOISE is not set --- setting variance to NAN\n"); 239 readnoise = NAN;239 readnoise = NAN; 240 240 } 241 241 // if we have a non-NAN readnoise, then we need to ensure it has been updated (not necessary if NAN) … … 248 248 if (isnan(gain) || isnan(readnoise)) { 249 249 if (!readout->variance) { 250 // generate the image if needed250 // generate the image if needed 251 251 readout->variance = psImageAlloc(readout->image->numCols, readout->image->numRows, PS_TYPE_F32); 252 252 } 253 // XXX need to set the mask, if defined253 // XXX need to set the mask, if defined 254 254 psImageInit(readout->variance, NAN); 255 return true;255 return true; 256 256 } 257 257 … … 262 262 263 263 // a negative variance is non-sensical. if the image value drops below 1, the variance must be 1. 264 // XXX this calculation is wrong: limit is 1 e-, but this is in DN264 // XXX this calculation is wrong: limit is 1 e-, but this is in DN 265 265 readout->variance = (psImage*)psUnaryOp(readout->variance, readout->variance, "abs"); 266 266 readout->variance = (psImage*)psBinaryOp(readout->variance, readout->variance, "max", … … 276 276 // apply a supplied readnoise map (NOTE: in DN, not electrons): 277 277 if (noiseMap) { 278 psImage *rdVar = (psImage*)psBinaryOp(NULL, (const psPtr) noiseMap, "*", (const psPtr) noiseMap);279 readout->variance = (psImage*)psBinaryOp(readout->variance, readout->variance, "+", rdVar);280 psFree (rdVar);278 psImage *rdVar = (psImage*)psBinaryOp(NULL, (const psPtr) noiseMap, "*", (const psPtr) noiseMap); 279 readout->variance = (psImage*)psBinaryOp(readout->variance, readout->variance, "+", rdVar); 280 psFree (rdVar); 281 281 } else { 282 readout->variance = (psImage*)psBinaryOp(readout->variance, readout->variance, "+", psScalarAlloc(readnoise*readnoise/gain/gain, PS_TYPE_F32));282 readout->variance = (psImage*)psBinaryOp(readout->variance, readout->variance, "+", psScalarAlloc(readnoise*readnoise/gain/gain, PS_TYPE_F32)); 283 283 } 284 284 … … 362 362 363 363 364 bool pmReadoutVarianceRenorm Pixels(const pmReadout *readout, psImageMaskType maskVal,365 psStatsOptions meanStat, psStatsOptions stdevStat, psRandom *rng)364 bool pmReadoutVarianceRenormalise(const pmReadout *readout, psImageMaskType maskVal, 365 int sample, float minValid, float maxValid) 366 366 { 367 367 PM_ASSERT_READOUT_NON_NULL(readout, false); … … 371 371 psImage *image = readout->image, *mask = readout->mask, *variance = readout->variance; // Readout parts 372 372 373 if (!psMemIncrRefCounter(rng)) { 374 rng = psRandomAlloc(PS_RANDOM_TAUS); 375 } 376 377 psStats *varianceStats = psStatsAlloc(meanStat);// Statistics for mean 378 if (!psImageBackground(varianceStats, NULL, variance, mask, maskVal, rng)) { 379 psError(PS_ERR_UNKNOWN, false, "Unable to measure mean variance for image"); 380 psFree(varianceStats); 381 psFree(rng); 382 return false; 383 } 384 float meanVariance = varianceStats->robustMedian; // Mean variance 385 psFree(varianceStats); 386 387 psStats *imageStats = psStatsAlloc(stdevStat);// Statistics for mean 388 if (!psImageBackground(imageStats, NULL, image, mask, maskVal, rng)) { 389 psError(PS_ERR_UNKNOWN, false, "Unable to measure stdev of image"); 390 psFree(imageStats); 391 psFree(rng); 392 return false; 393 } 394 float stdevImage = imageStats->robustStdev; // Standard deviation of image 395 psFree(imageStats); 396 psFree(rng); 397 398 float correction = PS_SQR(stdevImage) / meanVariance; // Correction to take variance to what it should be 399 psLogMsg("psModules.camera", PS_LOG_INFO, "Renormalising variance map by %f", correction); 400 psBinaryOp(variance, variance, "*", psScalarAlloc(correction, PS_TYPE_F32)); 401 402 return true; 403 } 404 405 406 bool pmReadoutVarianceRenormPhot(const pmReadout *readout, psImageMaskType maskVal, int num, float width, 407 psStatsOptions meanStat, psStatsOptions stdevStat, psRandom *rng) 408 { 409 PM_ASSERT_READOUT_NON_NULL(readout, false); 410 PM_ASSERT_READOUT_IMAGE(readout, false); 411 PM_ASSERT_READOUT_VARIANCE(readout, false); 412 413 if (!psMemIncrRefCounter(rng)) { 414 rng = psRandomAlloc(PS_RANDOM_TAUS); 415 } 416 417 psImage *image = readout->image, *mask = readout->mask, *variance = readout->variance; // Readout images 418 419 // Measure background 420 psStats *bgStats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_STDEV);// Statistics for background 421 if (!psImageBackground(bgStats, NULL, image, mask, maskVal, rng)) { 422 psError(PS_ERR_UNKNOWN, false, "Unable to measure background for image"); 423 psFree(bgStats); 424 psFree(rng); 425 return false; 426 } 427 float bgMean = bgStats->robustMedian; // Background level 428 float bgNoise = bgStats->robustStdev; // Background standard deviation 429 psFree(bgStats); 430 psTrace("psModules.camera", 5, "Background is %f +/- %f\n", bgMean, bgNoise); 431 432 433 // Construct kernels for flux measurement 434 // We use N(0,width) and N(0,width/sqrt(2)) kernels, following psphotSignificanceImage. 435 float sigFactor = 4.0 * M_PI * PS_SQR(width); // Factor for conversion from im/wt ratio to significance 436 int size = RENORM_NUM_SIGMA, fullSize = 2 * size + 1; // Half-size and full size of Gaussian 437 psVector *gauss = psVectorAlloc(fullSize, PS_TYPE_F32); // Gaussian for weighting 438 psVector *gauss2 = psVectorAlloc(fullSize, PS_TYPE_F32); // Gaussian squared 439 for (int i = 0, x = -size; i < fullSize; i++, x++) { 440 gauss->data.F32[i] = expf(-0.5 * PS_SQR(x) / PS_SQR(width)); 441 gauss2->data.F32[i] = expf(-PS_SQR(x) / PS_SQR(width)); 442 } 443 444 // Size of image 445 int numCols = image->numCols, numRows = image->numRows; // Size of images 446 int xSize = numCols - fullSize, ySize = numRows - fullSize; // Size of consideration 447 int xOffset = size, yOffset = size; // Offset to region of consideration 448 449 // Measure fluxes 450 float peakFlux = RENORM_PEAK * bgNoise; // Peak flux for fake sources 451 psVector *noise = psVectorAlloc(num, PS_TYPE_F32); // Measurements of the noise 452 psVector *source = psVectorAlloc(num, PS_TYPE_F32); // Measurements of fake sources 453 psVector *guess = psVectorAlloc(num, PS_TYPE_F32); // Guess at significance 454 psVector *photMask = psVectorAlloc(num, PS_TYPE_VECTOR_MASK); // Mask for fluxes 455 for (int i = 0; i < num; i++) { 456 // Coordinates of interest 457 int xPix = psRandomUniform(rng) * xSize + xOffset + 0.5; 458 int yPix = psRandomUniform(rng) * ySize + yOffset + 0.5; 459 psAssert(xPix - size >= 0 && xPix + size < numCols && 460 yPix - size >= 0 && yPix + size < numRows, 461 "Bad pixel position: %d,%d", xPix, yPix); 462 463 // Weighted aperture photometry 464 // This has the same effect as smoothing the image by the window function 465 float sumNoise = 0.0; // Sum for noise measurement 466 float sumSource = 0.0; // Sum for source measurement 467 float sumVariance = 0.0; // Sum for variance measurement 468 float sumGauss = 0.0, sumGauss2 = 0.0; // Sums of Gaussian kernels 469 for (int v = 0, y = yPix - size; v < fullSize; v++, y++) { 470 float xSumNoise = 0.0; // Sum for noise measurement in x 471 float xSumSource = 0.0; // Sum for source measurement in x 472 float xSumVariance = 0.0; // Sum for variance measurement in x 473 float xSumGauss = 0.0, xSumGauss2 = 0.0; // Sums of Gaussian kernels in x 474 float yGauss = gauss->data.F32[v]; // Value of Gaussian in y 475 for (int u = 0, x = xPix - size; u < fullSize; u++, x++) { 476 if (mask && mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & maskVal) { 373 int numCols = image->numCols, numRows = image->numRows; // Size of image 374 int numPix = numCols * numRows; // Number of pixels 375 int num = PS_MAX(sample, numPix); // Number we care about 376 psVector *signoise = psVectorAllocEmpty(num, PS_TYPE_F32); // Signal-to-noise values 377 378 if (num >= numPix) { 379 // We have an image smaller than Nsubset, so just loop over the image pixels 380 int index = 0; // Index for vector 381 for (int y = 0; y < numRows; y++) { 382 for (int x = 0; x < numCols; x++) { 383 if ((mask && mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & maskVal) || 384 !isfinite(image->data.F32[y][x]) || !isfinite(variance->data.F32[y][x])) { 477 385 continue; 478 386 } 479 float value = image->data.F32[y][x] - bgMean; // Value of image 480 float xGauss = gauss->data.F32[u]; // Value of Gaussian in x 481 float xGauss2 = gauss2->data.F32[u]; // Value of Gaussian^2 in x 482 xSumNoise += value * xGauss; 483 xSumSource += (value + peakFlux * xGauss * yGauss) * xGauss; 484 xSumVariance += variance->data.F32[y][x] * xGauss2; 485 xSumGauss += xGauss; 486 xSumGauss2 += xGauss2; 487 } 488 float yGauss2 = gauss2->data.F32[v]; // Value of Gaussian^2 in y 489 sumNoise += xSumNoise * yGauss; 490 sumSource += xSumSource * yGauss; 491 sumVariance += xSumVariance * yGauss2; 492 sumGauss += xSumGauss * yGauss; 493 sumGauss2 += xSumGauss2 * yGauss2; 494 } 495 496 photMask->data.PS_TYPE_VECTOR_MASK_DATA[i] = ((isfinite(sumNoise) && isfinite(sumSource) && 497 isfinite(sumVariance) && sumGauss > 0 && sumGauss2 > 0) ? 498 0 : 0xFF); 499 500 float smoothImageNoise = sumNoise / sumGauss; // Value of smoothed image pixel for noise 501 float smoothImageSource = sumSource / sumGauss; // Value of smoothed image pixel for source 502 float smoothVariance = sumVariance / sumGauss2; // Value of smoothed variance pixel 503 504 noise->data.F32[i] = smoothImageNoise; 505 source->data.F32[i] = smoothImageSource; 506 guess->data.F32[i] = (sumSource > 0) ? sigFactor * PS_SQR(smoothImageSource) / smoothVariance : 0.0; 507 psTrace("psModules.camera", 10, "Flux %d (%d,%d): %f, %f, %f\n", 508 i, xPix, yPix, smoothImageNoise, smoothImageSource, smoothVariance); 509 } 510 psFree(gauss); 511 psFree(gauss2); 512 psFree(rng); 513 514 // Standard deviation of fluxes gives us the real significance 515 psStats *stdevStats = psStatsAlloc(stdevStat); // Statistics 516 if (!psVectorStats(stdevStats, noise, NULL, photMask, 0xFF)) { 517 psError(PS_ERR_UNKNOWN, false, "Unable to measure standard deviation of fluxes"); 518 psFree(stdevStats); 519 psFree(noise); 520 psFree(source); 521 psFree(guess); 522 psFree(photMask); 387 388 signoise->data.F32[index] = image->data.F32[y][x] / sqrtf(variance->data.F32[y][x]); 389 index++; 390 } 391 } 392 signoise->n = index; 393 } else { 394 psRandom *rng = psRandomAlloc(PS_RANDOM_TAUS); // Random number generator 395 int index = 0; // Index for vector 396 for (long i = 0; i < num; i++) { 397 // Pixel coordinates 398 int pixel = numPix * psRandomUniform(rng); 399 int x = pixel % numCols; 400 int y = pixel / numCols; 401 402 if ((mask && mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] & maskVal) || 403 !isfinite(image->data.F32[y][x]) || !isfinite(variance->data.F32[y][x])) { 404 continue; 405 } 406 407 signoise->data.F32[index] = image->data.F32[y][x] / sqrtf(variance->data.F32[y][x]); 408 index++; 409 } 410 signoise->n = index; 411 psFree(rng); 412 } 413 414 psStats *stats = psStatsAlloc(PS_STAT_ROBUST_STDEV); // Statistics 415 416 if (!psVectorStats(stats, signoise, NULL, NULL, 0)) { 417 psError(PS_ERR_UNKNOWN, false, "Unable to measure statistics on S/N image"); 418 psFree(signoise); 523 419 return false; 524 420 } 525 float stdev = psStatsGetValue(stdevStats, stdevStat); // Standard deviation of fluxes 526 psFree(stdevStats); 527 psFree(noise); 528 psTrace("psModules.camera", 5, "Standard deviation of fluxes is %f\n", stdev); 529 530 // Ratio of measured significance to guessed significance 531 psVector *ratio = psVectorAlloc(num, PS_TYPE_F32); // Ratio of measured to guess 532 for (int i = 0; i < num; i++) { 533 float measuredSig = PS_SQR(source->data.F32[i] / stdev); // Measured significance 534 ratio->data.F32[i] = measuredSig / guess->data.F32[i]; 535 if (guess->data.F32[i] <= 0.0 || source->data.F32[i] <= 0.0 || !isfinite(ratio->data.F32[i])) { 536 photMask->data.PS_TYPE_VECTOR_MASK_DATA[i] = 0xFF; 537 } 538 psTrace("psModules.camera", 9, "Ratio %d: %f, %f, %f\n", 539 i, guess->data.F32[i], measuredSig, ratio->data.F32[i]); 540 } 541 psFree(source); 542 psFree(guess); 543 544 psStats *meanStats = psStatsAlloc(meanStat | stdevStat); // Statistics 545 if (!psVectorStats(meanStats, ratio, NULL, photMask, 0xFF)) { 546 psError(PS_ERR_UNKNOWN, false, "Unable to measure mean ratio"); 547 psFree(meanStats); 548 psFree(ratio); 549 psFree(photMask); 550 return false; 551 } 552 float meanRatio = psStatsGetValue(meanStats, meanStat); // Mean ratio 553 psTrace("psModules.camera", 5, "Mean significance ratio is %f +/- %f\n", 554 meanRatio, psStatsGetValue(meanStats, stdevStat)); 555 psFree(meanStats); 556 psFree(ratio); 557 psFree(photMask); 558 559 psLogMsg("psModules.camera", PS_LOG_INFO, "Renormalising variance map by %f", meanRatio); 560 psBinaryOp(variance, variance, "*", psScalarAlloc(meanRatio, PS_TYPE_F32)); 421 psFree(signoise); 422 423 float correction = stats->robustStdev; // Correction factor 424 psFree(stats); 425 psLogMsg("psModules.camera", PS_LOG_DETAIL, "Variance renormalisation factor is %f", correction); 426 427 // Check valid range of correction factor 428 if ((isfinite(minValid) && correction < minValid) || (isfinite(maxValid) && correction > maxValid)) { 429 psWarning("Variance renormalisation is outside valid range: %f vs %f:%f --- no correction made", 430 correction, minValid, maxValid); 431 return true; 432 } 433 434 psBinaryOp(variance, variance, "*", psScalarAlloc(PS_SQR(correction), PS_TYPE_F32)); 435 436 pmHDU *hdu = pmHDUFromReadout(readout); // HDU for readout 437 if (hdu) { 438 psString history = NULL; 439 psStringAppend(&history, "Rescaled variance by %6.4f (stdev by %6.4f)", 440 PS_SQR(correction), correction); 441 psMetadataAddStr(hdu->header, PS_LIST_TAIL, "HISTORY", PS_META_DUPLICATE_OK, NULL, history); 442 } 561 443 562 444 return true; 563 445 } 564 446 565 566 bool pmReadoutVarianceRenorm(const pmReadout *readout, psImageMaskType maskVal, psStatsOptions meanStat,567 psStatsOptions stdevStat, int width, psRandom *rng)568 {569 PM_ASSERT_READOUT_NON_NULL(readout, false);570 PM_ASSERT_READOUT_IMAGE(readout, false);571 PM_ASSERT_READOUT_VARIANCE(readout, false);572 PS_ASSERT_INT_POSITIVE(width, false);573 574 if (!psMemIncrRefCounter(rng)) {575 rng = psRandomAlloc(PS_RANDOM_TAUS);576 }577 578 psImage *image = readout->image, *mask = readout->mask, *variance = readout->variance; // Readout images579 int numCols = image->numCols, numRows = image->numRows; // Size of images580 int xNum = numCols / width + 1, yNum = numRows / width + 1; // Number of renormalisation regions581 float xSize = numCols / (float)xNum, ySize = numRows / (float)yNum; // Size of renormalisation regions582 583 psStats *meanStats = psStatsAlloc(meanStat), *stdevStats = psStatsAlloc(stdevStat); // Statistics584 psVector *buffer = NULL;585 586 for (int j = 0; j < yNum; j++) {587 // Bounds in y588 int yMin = j * ySize;589 int yMax = (j + 1) * ySize;590 for (int i = 0; i < xNum; i++) {591 // Bounds in x592 int xMin = i * xSize;593 int xMax = (i + 1) * xSize;594 595 psRegion region = psRegionSet(xMin, xMax, yMin, yMax); // Region of interest596 psImage *subImage = psImageSubset(image, region); // Sub-image of the image pixels597 psImage *subVariance = psImageSubset(variance, region); // Sub image of the variance pixels598 psImage *subMask = mask ? psImageSubset(mask, region) : NULL; // Sub-image of the mask pixels599 600 if (!psImageBackground(stdevStats, &buffer, subImage, subMask, maskVal, rng) ||601 !psImageBackground(meanStats, &buffer, subVariance, subMask, maskVal, rng)) {602 // Nothing we can do about it, but don't want to keel over and die, so do our best to flag it.603 psString regionStr = psRegionToString(region); // String with region604 psWarning("Unable to measure statistics over %s", regionStr);605 psFree(regionStr);606 psErrorClear();607 psImageInit(subVariance, NAN);608 if (subMask) {609 psImageInit(subMask, maskVal);610 }611 } else {612 double meanVar = psStatsGetValue(meanStats, meanStat); // Mean of variance map613 double stdev = psStatsGetValue(stdevStats, stdevStat); // Standard deviation of image614 psTrace("psModules.camera", 3,615 "Region [%d:%d,%d:%d] has variance %lf, but mean of variance map is %lf\n",616 xMin, xMax, yMin, yMax, PS_SQR(stdev), meanVar);617 psBinaryOp(subVariance, subVariance, "*", psScalarAlloc(PS_SQR(stdev) / meanVar, PS_TYPE_F32));618 }619 620 psFree(subImage);621 psFree(subVariance);622 psFree(subMask);623 }624 }625 psFree(meanStats);626 psFree(stdevStats);627 psFree(rng);628 psFree(buffer);629 630 return true;631 }632 447 633 448 -
trunk/psModules/src/camera/pmFPAMaskWeight.h
r25116 r25372 80 80 /// 81 81 /// The variance map is adjusted so that the mean matches the actual pixel variance in the image 82 bool pmReadoutVarianceRenormPixels( 83 const pmReadout *readout, ///< Readout to normalise 84 psImageMaskType maskVal, ///< Value to mask 85 psStatsOptions meanStat, ///< Statistic to measure the mean (of the variance map) 86 psStatsOptions stdevStat, ///< Statistic to measure the stdev (of the image) 87 psRandom *rng ///< Random number generator 88 ); 89 90 /// Renormalise the variance map to match the actual photometry variance 91 /// 92 /// The variance map is adjusted so that the actual significance of fake sources matches the 93 /// guestimated significance 94 bool pmReadoutVarianceRenormPhot( 82 bool pmReadoutVarianceRenormalise( 95 83 const pmReadout *readout, ///< Readout to normalise 96 84 psImageMaskType maskVal, ///< Value to mask 97 int num, ///< Number of instances to measure over the image 98 float width, ///< Photometry width 99 psStatsOptions meanStat, ///< Statistic to measure the mean 100 psStatsOptions stdevStat, ///< Statistic to measure the stdev 101 psRandom *rng ///< Random number generator 102 ); 103 104 /// Renormalise the variance map to match the actual variance 105 /// 106 /// The variance in the image is measured in patches, and the variance map is adjusted so that the mean for 107 /// that patch corresponds. 108 bool pmReadoutVarianceRenorm(const pmReadout *readout, // Readout to normalise 109 psImageMaskType maskVal, // Value to mask 110 psStatsOptions meanStat, // Statistic to measure the mean (of the variance map) 111 psStatsOptions stdevStat, // Statistic to measure the stdev (of the image) 112 int width, // Width of patch (pixels) 113 psRandom *rng // Random number generator (for sub-sampling images) 85 int sample, ///< Sample size 86 float minValid, ///< Minimum valid renormalisation, or NAN 87 float maxValid ///< Maximum valid renormalisation, or NAN 114 88 ); 115 89
Note:
See TracChangeset
for help on using the changeset viewer.
