Changeset 29546 for trunk/psModules/src/objects/pmSourceMoments.c
- Timestamp:
- Oct 25, 2010, 2:54:22 PM (16 years ago)
- File:
-
- 1 edited
-
trunk/psModules/src/objects/pmSourceMoments.c (modified) (11 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psModules/src/objects/pmSourceMoments.c
r29044 r29546 64 64 void pmSourceMomentsSetVerbose(bool state){ beVerbose = state; } 65 65 66 // if mode & EXTERNAL or mode2 & MATCHED, do not re-calculate the centroid (use peak as centroid) 67 66 68 bool pmSourceMoments(pmSource *source, psF32 radius, psF32 sigma, psF32 minSN, psImageMaskType maskVal) 67 69 { … … 71 73 PS_ASSERT_FLOAT_LARGER_THAN(radius, 0.0, false); 72 74 73 // use sky from moments if defined, 0.0 otherwise 74 75 // XXX this value comes from the sky model at the source center, and tends to over-estimate 76 // the sky in the vicinity of bright sources. we are better off assuming the model worked 77 // well: 75 // this function assumes the sky has been well-subtracted for the image 78 76 psF32 sky = 0.0; 77 79 78 if (source->moments == NULL) { 80 79 source->moments = pmMomentsAlloc(); 81 80 } 82 // XXX if (source->moments == NULL) { 83 // XXX source->moments = pmMomentsAlloc(); 84 // XXX } else { 85 // XXX sky = source->moments->Sky; 86 // XXX } 87 88 // First Pass: calculate the first moments (these are subtracted from the coordinates below) 89 // Sum = SUM (z - sky) 90 // X1 = SUM (x - xc)*(z - sky) 91 // .. etc 92 93 psF32 peakPixel = -PS_MAX_F32; 94 psS32 numPixels = 0; 81 95 82 psF32 Sum = 0.0; 96 83 psF32 Var = 0.0; 97 psF32 X1 = 0.0;98 psF32 Y1 = 0.0;99 84 psF32 R2 = PS_SQR(radius); 100 85 psF32 minSN2 = PS_SQR(minSN); … … 109 94 // (int) so they can be used in the image index below. 110 95 111 int xOff = source->peak->x; 112 int yOff = source->peak->y; 113 int xPeak = source->peak->x - source->pixels->col0; // coord of peak in subimage 114 int yPeak = source->peak->y - source->pixels->row0; // coord of peak in subimage 115 116 // we are guaranteed to have a valid pixel and variance at this location (right? right?) 117 // psF32 weightNorm = source->pixels->data.F32[yPeak][xPeak] / sqrt (source->variance->data.F32[yPeak][xPeak]); 118 // psAssert (isfinite(source->pixels->data.F32[yPeak][xPeak]), "peak must be on valid pixel"); 119 // psAssert (isfinite(source->variance->data.F32[yPeak][xPeak]), "peak must be on valid pixel"); 120 // psAssert (source->variance->data.F32[yPeak][xPeak] > 0, "peak must be on valid pixel"); 121 122 for (psS32 row = 0; row < source->pixels->numRows ; row++) { 123 124 psF32 yDiff = row - yPeak; 125 if (fabs(yDiff) > radius) continue; 126 127 psF32 *vPix = source->pixels->data.F32[row]; 128 psF32 *vWgt = source->variance->data.F32[row]; 129 psImageMaskType *vMsk = (source->maskObj == NULL) ? NULL : source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[row]; 130 131 for (psS32 col = 0; col < source->pixels->numCols ; col++, vPix++, vWgt++) { 132 if (vMsk) { 133 if (*vMsk & maskVal) { 134 vMsk++; 135 continue; 136 } 137 vMsk++; 138 } 139 if (isnan(*vPix)) continue; 140 141 psF32 xDiff = col - xPeak; 142 if (fabs(xDiff) > radius) continue; 143 144 // radius is just a function of (xDiff, yDiff) 145 if (!VALID_RADIUS(xDiff, yDiff, R2)) continue; 146 147 psF32 pDiff = *vPix - sky; 148 psF32 wDiff = *vWgt; 149 150 // skip pixels below specified significance level. for a PSFs, this 151 // over-weights the wings of bright stars compared to those of faint stars. 152 // for the estimator used for extended source analysis (where the window 153 // function is allowed to be arbitrarily large), we need to clip to avoid 154 // negative second moments. 155 if (PS_SQR(pDiff) < minSN2*wDiff) continue; // 156 if ((minSN > 0.0) && (pDiff < 0)) continue; // 157 158 // Apply a Gaussian window function. Be careful with the window function. S/N 159 // weighting over weights the sky for faint sources 160 if (sigma > 0.0) { 161 // XXX a lot of extra flops; can we pre-calculate? 162 psF32 z = (PS_SQR(xDiff) + PS_SQR(yDiff))*rsigma2; 163 assert (z >= 0.0); 164 psF32 weight = exp(-z); 165 166 wDiff *= weight; 167 pDiff *= weight; 168 } 169 170 Var += wDiff; 171 Sum += pDiff; 172 173 psF32 xWght = xDiff * pDiff; 174 psF32 yWght = yDiff * pDiff; 175 176 X1 += xWght; 177 Y1 += yWght; 178 179 peakPixel = PS_MAX (*vPix, peakPixel); 180 numPixels++; 181 } 182 } 183 184 // if we have less than (1/4) of the possible pixels (in circle or box), force a retry 185 int minPixels = PS_MIN(0.75*R2, source->pixels->numCols*source->pixels->numRows/4.0); 186 187 // XXX EAM - the limit is a bit arbitrary. make it user defined? 188 if ((numPixels < minPixels) || (Sum <= 0)) { 189 psTrace ("psModules.objects", 3, "insufficient valid pixels (%d vs %d; %f) for source\n", numPixels, minPixels, Sum); 190 return (false); 191 } 192 193 // calculate the first moment. 194 float Mx = X1/Sum; 195 float My = Y1/Sum; 196 if ((fabs(Mx) > radius) || (fabs(My) > radius)) { 197 psTrace ("psModules.objects", 3, "large centroid swing; invalid peak %d, %d\n", source->peak->x, source->peak->y); 198 return (false); 199 } 200 201 psTrace ("psModules.objects", 5, "sky: %f Mx: %f My: %f Sum: %f X1: %f Y1: %f Npix: %d\n", sky, Mx, My, Sum, X1, Y1, numPixels); 202 203 // add back offset of peak in primary image 204 // also offset from pixel index to pixel coordinate 205 // (the calculation above uses pixel index instead of coordinate) 206 // 0.5 PIX: moments are calculated using the pixel index and converted here to pixel coords 207 source->moments->Mx = Mx + xOff + 0.5; 208 source->moments->My = My + yOff + 0.5; 209 210 source->moments->Sum = Sum; 211 source->moments->SN = Sum / sqrt(Var); 212 source->moments->Peak = peakPixel; 213 source->moments->nPixels = numPixels; 96 // do 2 passes : the first pass should use a somewhat smaller radius and no sigma window to 97 // get an unbiased (but probably noisy) centroid 98 if (!pmSourceMomentsGetCentroid (source, 0.75*radius, 0.0, minSN, maskVal, source->peak->xf, source->peak->yf)) { 99 return false; 100 } 101 // second pass applies the Gaussian window and uses the centroid from the first pass 102 if (!pmSourceMomentsGetCentroid (source, radius, sigma, minSN, maskVal, source->moments->Mx, source->moments->My)) { 103 return false; 104 } 214 105 215 106 // Now calculate higher-order moments, using the above-calculated first moments to adjust coordinates … … 234 125 Sum = 0.0; // the second pass may include slightly different pixels, re-determine Sum 235 126 236 // center of mass in subimage. Note: the calculation below uses pixel index, so we do not237 // correct xCM, yCM to pixel coordinatehere.238 psF32 xCM = Mx + xPeak; // coord of peak in subimage239 psF32 yCM = My + yPeak; // coord of peak in subimage127 // center of mass in subimage. Note: the calculation below uses pixel index, so we correct 128 // xCM, yCM from pixel coords to pixel index here. 129 psF32 xCM = source->moments->Mx - 0.5 - source->pixels->col0; // coord of peak in subimage 130 psF32 yCM = source->moments->My - 0.5 - source->pixels->row0; // coord of peak in subimage 240 131 241 132 for (psS32 row = 0; row < source->pixels->numRows ; row++) { … … 263 154 // radius is just a function of (xDiff, yDiff) 264 155 psF32 r2 = PS_SQR(xDiff) + PS_SQR(yDiff); 265 psF32 r = sqrt(r2); 266 if (r > radius) continue; 156 if (r2 > R2) continue; 267 157 268 158 psF32 fDiff = *vPix - sky; … … 274 164 // stars. 275 165 if (PS_SQR(pDiff) < minSN2*wDiff) continue; 276 // if (pDiff < 0) continue;166 if ((minSN > 0.0) && (pDiff < 0)) continue; // 277 167 278 168 // Apply a Gaussian window function. Be careful with the window function. S/N 279 169 // weighting over weights the sky for faint sources 280 170 if (sigma > 0.0) { 281 // XXX a lot of extra flops; can we do pre-calculate? 282 // XXX we were re-calculating r2 (maybe the compiler caught this?) 283 // psF32 z = (PS_SQR(xDiff) + PS_SQR(yDiff))*rsigma2; 284 psF32 z = r2 * rsigma2; 171 psF32 z = r2 * rsigma2; 285 172 assert (z >= 0.0); 286 173 psF32 weight = exp(-z); … … 292 179 Sum += pDiff; 293 180 294 # if (1) 295 # if (0) 296 if (fDiff < 0) continue; 297 # endif 181 // Kron Flux uses the 1st radial moment (NOT Gaussian windowed?) 182 psF32 r = sqrt(r2); 298 183 psF32 rf = r * fDiff; 299 184 psF32 rh = sqrt(r) * fDiff; 300 185 psF32 rs = fDiff; 301 # else302 psF32 rf = r * pDiff;303 psF32 rh = sqrt(r) * pDiff;304 psF32 rs = pDiff;305 # endif306 186 307 187 psF32 x = xDiff * pDiff; … … 363 243 364 244 // Calculate the Kron magnitude (make this block optional?) 365 // float radKron = 2.5*source->moments->Mrf;366 245 float radKinner = 1.0*source->moments->Mrf; 367 246 float radKron = 2.5*source->moments->Mrf; … … 397 276 // radKron is just a function of (xDiff, yDiff) 398 277 psF32 r2 = PS_SQR(xDiff) + PS_SQR(yDiff); 399 psF32 r = sqrt(r2);400 278 401 279 psF32 pDiff = *vPix - sky; … … 407 285 if (PS_SQR(pDiff) < minSN2*wDiff) continue; 408 286 287 psF32 r = sqrt(r2); 409 288 if (r < radKron) { 410 289 Sum += pDiff; … … 434 313 435 314 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", 436 source->peak->xf, source->peak->yf, source->peak->flux, source->peak->SN, source->moments->Mx, source->moments->My, Sum, source->moments->Mxx, source->moments->Mxy, source->moments->Myy, sky, numPixels);315 source->peak->xf, source->peak->yf, source->peak->flux, source->peak->SN, source->moments->Mx, source->moments->My, Sum, source->moments->Mxx, source->moments->Mxy, source->moments->Myy, sky, source->moments->nPixels); 437 316 438 317 return(true); 439 318 } 319 320 bool pmSourceMomentsGetCentroid(pmSource *source, psF32 radius, psF32 sigma, psF32 minSN, psImageMaskType maskVal, float xGuess, float yGuess) { 321 322 // First Pass: calculate the first moments (these are subtracted from the coordinates below) 323 // Sum = SUM (z - sky) 324 // X1 = SUM (x - xc)*(z - sky) 325 // .. etc 326 327 psF32 sky = 0.0; 328 329 psF32 peakPixel = -PS_MAX_F32; 330 psS32 numPixels = 0; 331 psF32 Sum = 0.0; 332 psF32 Var = 0.0; 333 psF32 X1 = 0.0; 334 psF32 Y1 = 0.0; 335 psF32 R2 = PS_SQR(radius); 336 psF32 minSN2 = PS_SQR(minSN); 337 psF32 rsigma2 = 0.5 / PS_SQR(sigma); 338 339 float xPeak = xGuess - source->pixels->col0; // coord of peak in subimage 340 float yPeak = yGuess - source->pixels->row0; // coord of peak in subimage 341 342 // we are guaranteed to have a valid pixel and variance at this location (right? right?) 343 // psF32 weightNorm = source->pixels->data.F32[yPeak][xPeak] / sqrt (source->variance->data.F32[yPeak][xPeak]); 344 // psAssert (isfinite(source->pixels->data.F32[yPeak][xPeak]), "peak must be on valid pixel"); 345 // psAssert (isfinite(source->variance->data.F32[yPeak][xPeak]), "peak must be on valid pixel"); 346 // psAssert (source->variance->data.F32[yPeak][xPeak] > 0, "peak must be on valid pixel"); 347 348 // the moments [Sum(x*f) / Sum(f)] are calculated in pixel index values, and should 349 // not depend on the fractional pixel location of the source. However, the aperture 350 // (radius) and the Gaussian window (sigma) depend subtly on the fractional pixel 351 // position of the expected centroid 352 353 for (psS32 row = 0; row < source->pixels->numRows ; row++) { 354 355 psF32 yDiff = row + 0.5 - yPeak; 356 if (fabs(yDiff) > radius) continue; 357 358 psF32 *vPix = source->pixels->data.F32[row]; 359 psF32 *vWgt = source->variance->data.F32[row]; 360 psImageMaskType *vMsk = (source->maskObj == NULL) ? NULL : source->maskObj->data.PS_TYPE_IMAGE_MASK_DATA[row]; 361 362 for (psS32 col = 0; col < source->pixels->numCols ; col++, vPix++, vWgt++) { 363 if (vMsk) { 364 if (*vMsk & maskVal) { 365 vMsk++; 366 continue; 367 } 368 vMsk++; 369 } 370 if (isnan(*vPix)) continue; 371 372 psF32 xDiff = col + 0.5 - xPeak; 373 if (fabs(xDiff) > radius) continue; 374 375 // radius is just a function of (xDiff, yDiff) 376 psF32 r2 = PS_SQR(xDiff) + PS_SQR(yDiff); 377 if (r2 > R2) continue; 378 379 psF32 pDiff = *vPix - sky; 380 psF32 wDiff = *vWgt; 381 382 // skip pixels below specified significance level. for a PSFs, this 383 // over-weights the wings of bright stars compared to those of faint stars. 384 // for the estimator used for extended source analysis (where the window 385 // function is allowed to be arbitrarily large), we need to clip to avoid 386 // negative second moments. 387 if (PS_SQR(pDiff) < minSN2*wDiff) continue; // 388 if ((minSN > 0.0) && (pDiff < 0)) continue; // 389 390 // Apply a Gaussian window function. Be careful with the window function. S/N 391 // weighting over weights the sky for faint sources 392 if (sigma > 0.0) { 393 psF32 z = r2*rsigma2; 394 assert (z >= 0.0); 395 psF32 weight = exp(-z); 396 397 wDiff *= weight; 398 pDiff *= weight; 399 } 400 401 Var += wDiff; 402 Sum += pDiff; 403 404 psF32 xWght = xDiff * pDiff; 405 psF32 yWght = yDiff * pDiff; 406 407 X1 += xWght; 408 Y1 += yWght; 409 410 peakPixel = PS_MAX (*vPix, peakPixel); 411 numPixels++; 412 } 413 } 414 415 // if we have less than (1/4) of the possible pixels (in circle or box), force a retry 416 int minPixels = PS_MIN(0.75*R2, source->pixels->numCols*source->pixels->numRows/4.0); 417 418 // XXX EAM - the limit is a bit arbitrary. make it user defined? 419 if ((numPixels < minPixels) || (Sum <= 0)) { 420 psTrace ("psModules.objects", 3, "insufficient valid pixels (%d vs %d; %f) for source\n", numPixels, minPixels, Sum); 421 return (false); 422 } 423 424 // calculate the first moment. 425 float Mx = X1/Sum; 426 float My = Y1/Sum; 427 if ((fabs(Mx) > radius) || (fabs(My) > radius)) { 428 psTrace ("psModules.objects", 3, "large centroid swing; invalid peak %d, %d\n", source->peak->x, source->peak->y); 429 return (false); 430 } 431 432 psTrace ("psModules.objects", 5, "sky: %f Mx: %f My: %f Sum: %f X1: %f Y1: %f Npix: %d\n", sky, Mx, My, Sum, X1, Y1, numPixels); 433 434 // add back offset of peak in primary image 435 // also offset from pixel index to pixel coordinate 436 // (the calculation above uses pixel index instead of coordinate) 437 // 0.5 PIX: moments are calculated using the pixel index and converted here to pixel coords 438 439 // we only update the centroid if the position is not supplied from elsewhere 440 bool skipCentroid = false; 441 skipCentroid |= (source->mode & PM_SOURCE_MODE_EXTERNAL); // skip externally supplied positions 442 skipCentroid |= (source->mode2 & PM_SOURCE_MODE2_MATCHED); // skip sources defined by other image positions 443 444 if (skipCentroid) { 445 source->moments->Mx = source->peak->xf; 446 source->moments->My = source->peak->yf; 447 } else { 448 source->moments->Mx = Mx + xGuess; 449 source->moments->My = My + yGuess; 450 } 451 452 source->moments->Sum = Sum; 453 source->moments->SN = Sum / sqrt(Var); 454 source->moments->Peak = peakPixel; 455 source->moments->nPixels = numPixels; 456 457 return true; 458 }
Note:
See TracChangeset
for help on using the changeset viewer.
