- Timestamp:
- Jul 17, 2014, 12:30:45 PM (12 years ago)
- Location:
- branches/eam_branches/ipp-ops-20130712/psModules
- Files:
-
- 3 edited
-
. (modified) (1 prop)
-
src/objects (modified) (1 prop)
-
src/objects/pmSourceMoments.c (modified) (19 diffs)
Legend:
- Unmodified
- Added
- Removed
-
branches/eam_branches/ipp-ops-20130712/psModules
- Property svn:mergeinfo deleted
-
branches/eam_branches/ipp-ops-20130712/psModules/src/objects
- Property svn:ignore
-
old new 12 12 pmSourceIO_CMF_PS1_V1.v1.c 13 13 pmSourceIO_CMF_PS1_V4.c 14 pmSourceIO_CMF_PS1_V5.c 14 15 pmSourceIO_CMF_PS1_SV1.c 15 16 pmSourceIO_CMF_PS1_SV2.c 17 pmSourceIO_CMF_PS1_SV3.c 16 18 pmSourceIO_CMF_PS1_DV1.c 17 19 pmSourceIO_CMF_PS1_DV2.c 18 20 pmSourceIO_CMF_PS1_DV3.c 19 21 pmSourceIO_CMF_PS1_DV4.c
-
- Property svn:ignore
-
branches/eam_branches/ipp-ops-20130712/psModules/src/objects/pmSourceMoments.c
r35560 r37066 35 35 #include "pmMoments.h" 36 36 #include "pmModelFuncs.h" 37 #include "pmModelClass.h" 37 38 #include "pmModel.h" 38 39 #include "pmModelUtils.h" 39 #include "pmModelClass.h"40 40 #include "pmSourceMasks.h" 41 41 #include "pmSourceExtendedPars.h" 42 42 #include "pmSourceDiffStats.h" 43 43 #include "pmSourceSatstar.h" 44 #include "pmSourceLensing.h" 44 45 #include "pmSource.h" 45 46 … … 65 66 void pmSourceMomentsSetVerbose(bool state){ beVerbose = state; } 66 67 68 bool pmSourceMomentsHighOrder (pmSource *source, float radius, float sigma, float minSN, psImageMaskType maskVal); 69 bool pmSourceMomentsRadialMoment (pmSource *source, float radius, float minKronRadius, psImageMaskType maskVal); 70 bool pmSourceMomentsKronFluxes (pmSource *source, float sigma, float minSN, psImageMaskType maskVal); 71 67 72 // if mode & EXTERNAL or mode2 & MATCHED, do not re-calculate the centroid (use peak as centroid) 68 69 73 bool pmSourceMoments(pmSource *source, float radius, float sigma, float minSN, float minKronRadius, psImageMaskType maskVal) 70 74 { … … 74 78 PS_ASSERT_FLOAT_LARGER_THAN(radius, 0.0, false); 75 79 76 // this function assumes the sky has been well-subtracted for the image77 float sky = 0.0;78 79 80 if (source->moments == NULL) { 80 81 source->moments = pmMomentsAlloc(); 81 82 } 82 83 float Sum = 0.0;84 float Var = 0.0;85 float SumCore = 0.0;86 float VarCore = 0.0;87 float R2 = PS_SQR(radius);88 float minSN2 = PS_SQR(minSN);89 float rsigma2 = 0.5 / PS_SQR(sigma);90 83 91 84 // a note about coordinates: coordinates of objects throughout psphot refer to the primary … … 110 103 // of any object drops pretty quickly outside 1-2 sigmas. (The exception is bright 111 104 // saturated stars, for which we need to use a very large radius here) 105 // NOTE: if (mode & EXTERNAL) or (mode2 & MATCHED), do not re-calculate the centroid (use peak as centroid) 106 // (we still call this function because it sets moments->Sum,SN,Peak,nPixels 112 107 if (!pmSourceMomentsGetCentroid (source, 1.5*sigma, 0.0, minSN, maskVal, source->peak->xf, source->peak->yf)) { 113 108 return false; 114 109 } 115 110 111 pmSourceMomentsHighOrder (source, radius, sigma, minSN, maskVal); 112 113 // now calculate the 1st radial moment (for kron flux) using symmetrical averaging 114 pmSourceMomentsRadialMoment (source, radius, minKronRadius, maskVal); 115 116 // now calculate the kron flux values using the 1st radial moment 117 pmSourceMomentsKronFluxes (source, sigma, minSN, maskVal); 118 119 psTrace ("psModules.objects", 4, "Mrf: %f KronFlux: %f Mxx: %f Mxy: %f Myy: %f Mxxx: %f Mxxy: %f Mxyy: %f Myyy: %f Mxxxx: %f Mxxxy: %f Mxxyy: %f Mxyyy: %f Mxyyy: %f\n", 120 source->moments->Mrf, source->moments->KronFlux, 121 source->moments->Mxx, source->moments->Mxy, source->moments->Myy, 122 source->moments->Mxxx, source->moments->Mxxy, source->moments->Mxyy, source->moments->Myyy, 123 source->moments->Mxxxx, source->moments->Mxxxy, source->moments->Mxxyy, source->moments->Mxyyy, source->moments->Myyyy); 124 125 psTrace ("psModules.objects", 3, "peak %f %f (%f = %f) Mx: %f My: %f Sum: %f Mxx: %f Mxy: %f Myy: %f Npix: %d\n", 126 source->peak->xf, source->peak->yf, 127 source->peak->rawFlux, sqrt(source->peak->detValue), 128 source->moments->Mx, source->moments->My, 129 source->moments->Sum, 130 source->moments->Mxx, source->moments->Mxy, source->moments->Myy, 131 source->moments->nPixels); 132 133 return(true); 134 } 135 136 bool pmSourceMomentsGetCentroid(pmSource *source, float radius, float sigma, float minSN, psImageMaskType maskVal, float xGuess, float yGuess) { 137 138 // First Pass: calculate the first moments (these are subtracted from the coordinates below) 139 // Sum = SUM (z - sky) 140 // X1 = SUM (x - xc)*(z - sky) 141 // .. etc 142 143 float sky = 0.0; 144 145 float peakPixel = -PS_MAX_F32; 146 psS32 numPixels = 0; 147 float Sum = 0.0; 148 float Var = 0.0; 149 float X1 = 0.0; 150 float Y1 = 0.0; 151 float R2 = PS_SQR(radius); 152 float minSN2 = PS_SQR(minSN); 153 float rsigma2 = 0.5 / PS_SQR(sigma); 154 155 float xPeak = xGuess - source->pixels->col0; // coord of peak in subimage 156 float yPeak = yGuess - source->pixels->row0; // coord of peak in subimage 157 158 // we are guaranteed to have a valid pixel and variance at this location (right? right?) 159 // float weightNorm = source->pixels->data.F32[yPeak][xPeak] / sqrt (source->variance->data.F32[yPeak][xPeak]); 160 // psAssert (isfinite(source->pixels->data.F32[yPeak][xPeak]), "peak must be on valid pixel"); 161 // psAssert (isfinite(source->variance->data.F32[yPeak][xPeak]), "peak must be on valid pixel"); 162 // psAssert (source->variance->data.F32[yPeak][xPeak] > 0, "peak must be on valid pixel"); 163 164 // the moments [Sum(x*f) / Sum(f)] are calculated in pixel index values, and should 165 // not depend on the fractional pixel location of the source. However, the aperture 166 // (radius) and the Gaussian window (sigma) depend subtly on the fractional pixel 167 // position of the expected centroid 168 169 for (psS32 row = 0; row < source->pixels->numRows ; row++) { 170 171 float yDiff = row + 0.5 - yPeak; 172 if (fabs(yDiff) > radius) continue; 173 174 float *vPix = source->pixels->data.F32[row]; 175 float *vWgt = source->variance ? source->variance->data.F32[row] : source->pixels->data.F32[row]; 176 177 psImageMaskType *vMsk = (source->maskObj == NULL) ? NULL : source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[row]; 178 // psImageMaskType *vMsk = (source->maskView == NULL) ? NULL : source->maskView->data.PS_TYPE_IMAGE_MASK_DATA[row]; 179 180 for (psS32 col = 0; col < source->pixels->numCols ; col++, vPix++, vWgt++) { 181 if (vMsk) { 182 if (*vMsk & maskVal) { 183 vMsk++; 184 continue; 185 } 186 vMsk++; 187 } 188 if (isnan(*vPix)) continue; 189 190 float xDiff = col + 0.5 - xPeak; 191 if (fabs(xDiff) > radius) continue; 192 193 // radius is just a function of (xDiff, yDiff) 194 float r2 = PS_SQR(xDiff) + PS_SQR(yDiff); 195 if (r2 > R2) continue; 196 197 float pDiff = *vPix - sky; 198 float wDiff = *vWgt; 199 200 // skip pixels below specified significance level. for a PSFs, this 201 // over-weights the wings of bright stars compared to those of faint stars. 202 // for the estimator used for extended source analysis (where the window 203 // function is allowed to be arbitrarily large), we need to clip to avoid 204 // negative second moments. 205 if (PS_SQR(pDiff) < minSN2*wDiff) continue; // 206 if ((minSN > 0.0) && (pDiff < 0)) continue; // 207 208 // Apply a Gaussian window function. Be careful with the window function. S/N 209 // weighting over weights the sky for faint sources 210 if (sigma > 0.0) { 211 float z = r2*rsigma2; 212 assert (z >= 0.0); 213 float weight = exp(-z); 214 215 wDiff *= weight; 216 pDiff *= weight; 217 } 218 219 Var += wDiff; 220 Sum += pDiff; 221 222 float xWght = xDiff * pDiff; 223 float yWght = yDiff * pDiff; 224 225 X1 += xWght; 226 Y1 += yWght; 227 228 peakPixel = PS_MAX (*vPix, peakPixel); 229 numPixels++; 230 } 231 } 232 233 // if we have less than (1/4) of the possible pixels (in circle or box), force a retry 234 int minPixels = PS_MIN(0.75*R2, source->pixels->numCols*source->pixels->numRows/4.0); 235 236 // XXX EAM - the limit is a bit arbitrary. make it user defined? 237 if ((numPixels < minPixels) || (Sum <= 0)) { 238 psTrace ("psModules.objects", 3, "insufficient valid pixels (%d vs %d; %f) for source\n", numPixels, minPixels, Sum); 239 return (false); 240 } 241 242 // calculate the first moment. 243 float Mx = X1/Sum; 244 float My = Y1/Sum; 245 if ((fabs(Mx) > radius) || (fabs(My) > radius)) { 246 psTrace ("psModules.objects", 3, "extreme centroid swing; invalid peak %d, %d\n", source->peak->x, source->peak->y); 247 return (false); 248 } 249 if ((fabs(Mx) > 2.0) || (fabs(My) > 2.0)) { 250 psTrace ("psModules.objects", 3, " big centroid swing; ok peak? %d, %d\n", source->peak->x, source->peak->y); 251 } 252 253 psTrace ("psModules.objects", 5, "id: %d, sky: %f Mx: %f My: %f Sum: %f X1: %f Y1: %f Npix: %d\n", source->id, sky, Mx, My, Sum, X1, Y1, numPixels); 254 255 // add back offset of peak in primary image 256 // also offset from pixel index to pixel coordinate 257 // (the calculation above uses pixel index instead of coordinate) 258 // 0.5 PIX: moments are calculated using the pixel index and converted here to pixel coords 259 260 // we only update the centroid if the position is not supplied from elsewhere 261 bool skipCentroid = false; 262 skipCentroid |= (source->mode & PM_SOURCE_MODE_EXTERNAL); // skip externally supplied positions 263 skipCentroid |= (source->mode2 & PM_SOURCE_MODE2_MATCHED); // skip sources defined by other image positions 264 265 if (skipCentroid) { 266 source->moments->Mx = source->peak->xf; 267 source->moments->My = source->peak->yf; 268 } else { 269 source->moments->Mx = Mx + xGuess; 270 source->moments->My = My + yGuess; 271 } 272 273 source->moments->Sum = Sum; 274 source->moments->SN = Sum / sqrt(Var); 275 source->moments->Peak = peakPixel; 276 source->moments->nPixels = numPixels; 277 278 return true; 279 } 280 281 float pmSourceMinKronRadius(psArray *sources, float PSF_SN_LIM) { 282 283 psVector *radii = psVectorAllocEmpty(100, PS_TYPE_F32); 284 285 for (int i = 0; i < sources->n; i++) { 286 pmSource *src = sources->data[i]; // Source of interest 287 if (!src || !src->moments) { 288 continue; 289 } 290 291 if (src->mode & PM_SOURCE_MODE_BLEND) { 292 continue; 293 } 294 295 if (!src->moments->nPixels) continue; 296 297 if (src->moments->SN < PSF_SN_LIM) continue; 298 299 // XXX put in Mxx,Myy cut based on clump location 300 301 psVectorAppend(radii, src->moments->Mrf); 302 } 303 304 // find the peak in this image 305 psStats *stats = psStatsAlloc (PS_STAT_SAMPLE_MEDIAN); 306 307 if (!psVectorStats (stats, radii, NULL, NULL, 0)) { 308 psError(PS_ERR_UNKNOWN, false, "Unable to get image statistics.\n"); 309 psFree(stats); 310 return NAN; 311 } 312 313 float minRadius = stats->sampleMedian; 314 315 psFree(radii); 316 psFree(stats); 317 return minRadius; 318 } 319 320 bool pmSourceMomentsHighOrder (pmSource *source, float radius, float sigma, float minSN, psImageMaskType maskVal) { 321 322 // this function assumes the sky has been well-subtracted for the image 323 float Sum = 0.0; 324 float R2 = PS_SQR(radius); 325 float minSN2 = PS_SQR(minSN); 326 float rsigma2 = 0.5 / PS_SQR(sigma); 327 116 328 // Now calculate higher-order moments, using the above-calculated first moments to adjust coordinates 117 // Xn = SUM (x - xc)^n * (z - sky) 329 // Xn = SUM (x - xc)^n * (z - sky) -- note that sky is 0.0 by definition here 118 330 float XX = 0.0; 119 331 float XY = 0.0; … … 129 341 float YYYY = 0.0; 130 342 131 Sum = 0.0; // the second pass may include slightly different pixels, re-determine Sum132 133 // float dX = source->moments->Mx - source->peak->xf;134 // float dY = source->moments->My - source->peak->yf;135 // float dR = hypot(dX, dY);136 // float Xo = (dR < 2.0) ? source->moments->Mx : source->peak->xf;137 // float Yo = (dR < 2.0) ? source->moments->My : source->peak->yf;138 343 float Xo = source->moments->Mx; 139 344 float Yo = source->moments->My; … … 154 359 155 360 psImageMaskType *vMsk = (source->maskObj == NULL) ? NULL : source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[row]; 156 // psImageMaskType *vMsk = (source->maskView == NULL) ? NULL : source->maskView->data.PS_TYPE_IMAGE_MASK_DATA[row];157 361 158 362 for (psS32 col = 0; col < source->pixels->numCols ; col++, vPix++, vWgt++) { … … 173 377 if (r2 > R2) continue; 174 378 175 float fDiff = *vPix - sky;379 float fDiff = *vPix; 176 380 float pDiff = fDiff; 177 381 float wDiff = *vWgt; … … 181 385 // stars. 182 386 if (PS_SQR(pDiff) < minSN2*wDiff) continue; 183 if ((minSN > 0.0) && (pDiff < 0)) continue; //387 if ((minSN > 0.0) && (pDiff < 0)) continue; 184 388 185 389 // Apply a Gaussian window function. Be careful with the window function. S/N 186 // weighting over weights the sky for faint sources390 // weighting over-weights the sky for faint sources 187 391 if (sigma > 0.0) { 188 392 float z = r2 * rsigma2; … … 230 434 XYYY += xyyy; 231 435 YYYY += yyyy; 232 233 // Kron Flux uses the 1st radial moment (NOT Gaussian windowed?)234 // XXX float r = sqrt(r2);235 // XXX float rf = r * fDiff;236 // XXX float rh = sqrt(r) * fDiff;237 // XXX float rs = fDiff;238 // XXX239 // XXX float rfw = r * pDiff;240 // XXX float rhw = sqrt(r) * pDiff;241 // XXX242 // XXX RF += rf;243 // XXX RH += rh;244 // XXX RS += rs;245 // XXX246 // XXX RFW += rfw;247 // XXX RHW += rhw;248 436 } 249 437 } 438 // NOT needed : source->moments->wSum = Sum; 439 250 440 source->moments->Mxx = XX/Sum; 251 441 source->moments->Mxy = XY/Sum; … … 263 453 source->moments->Myyyy = YYYY/Sum; 264 454 265 // *** now calculate the 1st radial moment (for kron flux) -- symmetrical averaging 455 return true; 456 } 457 458 bool pmSourceMomentsRadialMoment (pmSource *source, float radius, float minKronRadius, psImageMaskType maskVal) { 459 266 460 267 461 float **vPix = source->pixels->data.F32; 268 float **vWgt = source->variance ? source->variance->data.F32 : source->pixels->data.F32;269 462 psImageMaskType **vMsk = (source->maskObj == NULL) ? NULL : source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA; 270 463 … … 272 465 float RH = 0.0; 273 466 float RS = 0.0; 467 468 // centroid around which to calculate the moments 469 float Xo = source->moments->Mx; 470 float Yo = source->moments->My; 471 472 // center of mass in subimage. Note: the calculation below uses pixel index, so we correct 473 // xCM, yCM from pixel coords to pixel index here. 474 float xCM = Xo - 0.5 - source->pixels->col0; // coord of peak in subimage 475 float yCM = Yo - 0.5 - source->pixels->row0; // coord of peak in subimage 476 477 float R2 = PS_SQR(radius); 274 478 275 479 for (psS32 row = 0; row < source->pixels->numRows ; row++) { … … 304 508 if (r2 > R2) continue; 305 509 306 float fDiff1 = vPix[row][col] - sky;307 float fDiff2 = vPix[yFlip][xFlip] - sky;510 float fDiff1 = vPix[row][col]; 511 float fDiff2 = vPix[yFlip][xFlip]; 308 512 float pDiff = (fDiff1 > 0.0) ? sqrt(fabs(fDiff1*fDiff2)) : -sqrt(fabs(fDiff1*fDiff2)); 309 513 … … 329 533 kronRefRadius = MIN(radius, kronRefRadius); 330 534 } 331 source->moments->Mrf = kronRefRadius; 332 333 // *** now calculate the kron flux values using the 1st radial moment 334 335 float radKinner = 1.0*kronRefRadius; 336 float radKron = 2.5*kronRefRadius; 337 float radKouter = 4.0*kronRefRadius; 535 536 // if source is externally supplied and it already has a finite Mrf do not change it 537 if (! ((source->mode & PM_SOURCE_MODE_EXTERNAL) && isfinite(source->moments->Mrf))) { 538 source->moments->Mrf = kronRefRadius; 539 } 540 541 return true; 542 } 543 544 bool pmSourceMomentsKronFluxes (pmSource *source, float sigma, float minSN, psImageMaskType maskVal) { 545 546 float **vPix = source->pixels->data.F32; 547 float **vWgt = source->variance ? source->variance->data.F32 : source->pixels->data.F32; 548 psImageMaskType **vMsk = (source->maskObj == NULL) ? NULL : source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA; 549 550 float radKinner = 1.0*source->moments->Mrf; 551 float radKron = 2.5*source->moments->Mrf; 552 float radKouter = 4.0*source->moments->Mrf; 338 553 339 554 int nKronPix = 0; … … 341 556 int nInner = 0; 342 557 int nOuter = 0; 343 Sum = Var = 0.0; 558 559 float Sum = 0.0; 560 float Var = 0.0; 561 float SumCore = 0.0; 562 float VarCore = 0.0; 344 563 float SumInner = 0.0; 345 564 float SumOuter = 0.0; 565 566 // centroid around which to calculate the moments 567 float Xo = source->moments->Mx; 568 float Yo = source->moments->My; 569 570 // center of mass in subimage. Note: the calculation below uses pixel index, so we correct 571 // xCM, yCM from pixel coords to pixel index here. 572 float xCM = Xo - 0.5 - source->pixels->col0; // coord of peak in subimage 573 float yCM = Yo - 0.5 - source->pixels->row0; // coord of peak in subimage 574 575 float minSN2 = PS_SQR(minSN); 346 576 347 577 // calculate the Kron flux, and related fluxes (NO symmetrical averaging) … … 362 592 float r2 = PS_SQR(xDiff) + PS_SQR(yDiff); 363 593 364 float fDiff1 = vPix[row][col] - sky;594 float fDiff1 = vPix[row][col]; 365 595 float pDiff = fDiff1; 366 596 float wDiff = vWgt[row][col]; … … 376 606 Var += wDiff; 377 607 nKronPix ++; 378 // if (beVerbose) fprintf (stderr, "mome: %d %d %f %f %f\n", col, row, sky, *vPix, Sum);379 608 } 380 609 … … 397 626 } 398 627 // *** should I rescale these fluxes by pi R^2 / nNpix? 399 // XXX source->moments->KronCore = SumCore * M_PI * PS_SQR(sigma) / nCorePix;400 // XXX source->moments->KronCoreErr = sqrt(VarCore) * M_PI * PS_SQR(sigma) / nCorePix;401 // XXX source->moments->KronFlux = Sum * M_PI *PS_SQR(radKron) / nKronPix;402 // XXX source->moments->KronFluxErr = sqrt(Var) * M_PI *PS_SQR(radKron) / nKronPix;403 // XXX source->moments->KronFinner = SumInner* M_PI * (PS_SQR(radKron) - PS_SQR(radKinner)) / nInner;404 // XXX source->moments->KronFouter = SumOuter* M_PI * (PS_SQR(radKouter) - PS_SQR(radKron)) / nOuter;628 // XXX source->moments->KronCore = SumCore * M_PI * PS_SQR(sigma) / nCorePix; 629 // XXX source->moments->KronCoreErr = sqrt(VarCore) * M_PI * PS_SQR(sigma) / nCorePix; 630 // XXX source->moments->KronFlux = Sum * M_PI * PS_SQR(radKron) / nKronPix; 631 // XXX source->moments->KronFluxErr = sqrt(Var) * M_PI * PS_SQR(radKron) / nKronPix; 632 // XXX source->moments->KronFinner = SumInner * M_PI * (PS_SQR(radKron) - PS_SQR(radKinner)) / nInner; 633 // XXX source->moments->KronFouter = SumOuter * M_PI * (PS_SQR(radKouter) - PS_SQR(radKron)) / nOuter; 405 634 406 635 source->moments->KronCore = SumCore; … … 408 637 source->moments->KronFlux = Sum; 409 638 source->moments->KronFluxErr = sqrt(Var); 410 source->moments->KronFinner = SumInner;411 source->moments->KronFouter = SumOuter;639 source->moments->KronFinner = SumInner; 640 source->moments->KronFouter = SumOuter; 412 641 413 642 // XXX not sure I should save this here... … … 416 645 source->moments->KronRadiusPSF = source->moments->Mrf; 417 646 418 psTrace ("psModules.objects", 4, "Mrf: %f KronFlux: %f Mxx: %f Mxy: %f Myy: %f Mxxx: %f Mxxy: %f Mxyy: %f Myyy: %f Mxxxx: %f Mxxxy: %f Mxxyy: %f Mxyyy: %f Mxyyy: %f\n",419 source->moments->Mrf, source->moments->KronFlux,420 source->moments->Mxx, source->moments->Mxy, source->moments->Myy,421 source->moments->Mxxx, source->moments->Mxxy, source->moments->Mxyy, source->moments->Myyy,422 source->moments->Mxxxx, source->moments->Mxxxy, source->moments->Mxxyy, source->moments->Mxyyy, source->moments->Myyyy);423 424 psTrace ("psModules.objects", 3, "peak %f %f (%f = %f) Mx: %f My: %f Sum: %f Mxx: %f Mxy: %f Myy: %f sky: %f Npix: %d\n",425 source->peak->xf, source->peak->yf, source->peak->rawFlux, sqrt(source->peak->detValue), source->moments->Mx, source->moments->My, Sum, source->moments->Mxx, source->moments->Mxy, source->moments->Myy, sky, source->moments->nPixels);426 427 return(true);428 }429 430 bool pmSourceMomentsGetCentroid(pmSource *source, float radius, float sigma, float minSN, psImageMaskType maskVal, float xGuess, float yGuess) {431 432 // First Pass: calculate the first moments (these are subtracted from the coordinates below)433 // Sum = SUM (z - sky)434 // X1 = SUM (x - xc)*(z - sky)435 // .. etc436 437 float sky = 0.0;438 439 float peakPixel = -PS_MAX_F32;440 psS32 numPixels = 0;441 float Sum = 0.0;442 float Var = 0.0;443 float X1 = 0.0;444 float Y1 = 0.0;445 float R2 = PS_SQR(radius);446 float minSN2 = PS_SQR(minSN);447 float rsigma2 = 0.5 / PS_SQR(sigma);448 449 float xPeak = xGuess - source->pixels->col0; // coord of peak in subimage450 float yPeak = yGuess - source->pixels->row0; // coord of peak in subimage451 452 // we are guaranteed to have a valid pixel and variance at this location (right? right?)453 // float weightNorm = source->pixels->data.F32[yPeak][xPeak] / sqrt (source->variance->data.F32[yPeak][xPeak]);454 // psAssert (isfinite(source->pixels->data.F32[yPeak][xPeak]), "peak must be on valid pixel");455 // psAssert (isfinite(source->variance->data.F32[yPeak][xPeak]), "peak must be on valid pixel");456 // psAssert (source->variance->data.F32[yPeak][xPeak] > 0, "peak must be on valid pixel");457 458 // the moments [Sum(x*f) / Sum(f)] are calculated in pixel index values, and should459 // not depend on the fractional pixel location of the source. However, the aperture460 // (radius) and the Gaussian window (sigma) depend subtly on the fractional pixel461 // position of the expected centroid462 463 for (psS32 row = 0; row < source->pixels->numRows ; row++) {464 465 float yDiff = row + 0.5 - yPeak;466 if (fabs(yDiff) > radius) continue;467 468 float *vPix = source->pixels->data.F32[row];469 float *vWgt = source->variance ? source->variance->data.F32[row] : source->pixels->data.F32[row];470 471 psImageMaskType *vMsk = (source->maskObj == NULL) ? NULL : source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[row];472 // psImageMaskType *vMsk = (source->maskView == NULL) ? NULL : source->maskView->data.PS_TYPE_IMAGE_MASK_DATA[row];473 474 for (psS32 col = 0; col < source->pixels->numCols ; col++, vPix++, vWgt++) {475 if (vMsk) {476 if (*vMsk & maskVal) {477 vMsk++;478 continue;479 }480 vMsk++;481 }482 if (isnan(*vPix)) continue;483 484 float xDiff = col + 0.5 - xPeak;485 if (fabs(xDiff) > radius) continue;486 487 // radius is just a function of (xDiff, yDiff)488 float r2 = PS_SQR(xDiff) + PS_SQR(yDiff);489 if (r2 > R2) continue;490 491 float pDiff = *vPix - sky;492 float wDiff = *vWgt;493 494 // skip pixels below specified significance level. for a PSFs, this495 // over-weights the wings of bright stars compared to those of faint stars.496 // for the estimator used for extended source analysis (where the window497 // function is allowed to be arbitrarily large), we need to clip to avoid498 // negative second moments.499 if (PS_SQR(pDiff) < minSN2*wDiff) continue; //500 if ((minSN > 0.0) && (pDiff < 0)) continue; //501 502 // Apply a Gaussian window function. Be careful with the window function. S/N503 // weighting over weights the sky for faint sources504 if (sigma > 0.0) {505 float z = r2*rsigma2;506 assert (z >= 0.0);507 float weight = exp(-z);508 509 wDiff *= weight;510 pDiff *= weight;511 }512 513 Var += wDiff;514 Sum += pDiff;515 516 float xWght = xDiff * pDiff;517 float yWght = yDiff * pDiff;518 519 X1 += xWght;520 Y1 += yWght;521 522 peakPixel = PS_MAX (*vPix, peakPixel);523 numPixels++;524 }525 }526 527 // if we have less than (1/4) of the possible pixels (in circle or box), force a retry528 int minPixels = PS_MIN(0.75*R2, source->pixels->numCols*source->pixels->numRows/4.0);529 530 // XXX EAM - the limit is a bit arbitrary. make it user defined?531 if ((numPixels < minPixels) || (Sum <= 0)) {532 psTrace ("psModules.objects", 3, "insufficient valid pixels (%d vs %d; %f) for source\n", numPixels, minPixels, Sum);533 return (false);534 }535 536 // calculate the first moment.537 float Mx = X1/Sum;538 float My = Y1/Sum;539 if ((fabs(Mx) > radius) || (fabs(My) > radius)) {540 psTrace ("psModules.objects", 3, "extreme centroid swing; invalid peak %d, %d\n", source->peak->x, source->peak->y);541 return (false);542 }543 if ((fabs(Mx) > 2.0) || (fabs(My) > 2.0)) {544 psTrace ("psModules.objects", 3, " big centroid swing; ok peak? %d, %d\n", source->peak->x, source->peak->y);545 }546 547 psTrace ("psModules.objects", 5, "id: %d, sky: %f Mx: %f My: %f Sum: %f X1: %f Y1: %f Npix: %d\n", source->id, sky, Mx, My, Sum, X1, Y1, numPixels);548 549 // add back offset of peak in primary image550 // also offset from pixel index to pixel coordinate551 // (the calculation above uses pixel index instead of coordinate)552 // 0.5 PIX: moments are calculated using the pixel index and converted here to pixel coords553 554 // we only update the centroid if the position is not supplied from elsewhere555 bool skipCentroid = false;556 skipCentroid |= (source->mode & PM_SOURCE_MODE_EXTERNAL); // skip externally supplied positions557 skipCentroid |= (source->mode2 & PM_SOURCE_MODE2_MATCHED); // skip sources defined by other image positions558 559 if (skipCentroid) {560 source->moments->Mx = source->peak->xf;561 source->moments->My = source->peak->yf;562 } else {563 source->moments->Mx = Mx + xGuess;564 source->moments->My = My + yGuess;565 }566 567 source->moments->Sum = Sum;568 source->moments->SN = Sum / sqrt(Var);569 source->moments->Peak = peakPixel;570 source->moments->nPixels = numPixels;571 572 647 return true; 573 648 } 574 575 float pmSourceMinKronRadius(psArray *sources, float PSF_SN_LIM) {576 577 psVector *radii = psVectorAllocEmpty(100, PS_TYPE_F32);578 579 for (int i = 0; i < sources->n; i++) {580 pmSource *src = sources->data[i]; // Source of interest581 if (!src || !src->moments) {582 continue;583 }584 585 if (src->mode & PM_SOURCE_MODE_BLEND) {586 continue;587 }588 589 if (!src->moments->nPixels) continue;590 591 if (src->moments->SN < PSF_SN_LIM) continue;592 593 // XXX put in Mxx,Myy cut based on clump location594 595 psVectorAppend(radii, src->moments->Mrf);596 }597 598 // find the peak in this image599 psStats *stats = psStatsAlloc (PS_STAT_SAMPLE_MEDIAN);600 601 if (!psVectorStats (stats, radii, NULL, NULL, 0)) {602 psError(PS_ERR_UNKNOWN, false, "Unable to get image statistics.\n");603 psFree(stats);604 return NAN;605 }606 607 float minRadius = stats->sampleMedian;608 609 psFree(radii);610 psFree(stats);611 return minRadius;612 }613
Note:
See TracChangeset
for help on using the changeset viewer.
