Changeset 26076 for trunk/psModules
- Timestamp:
- Nov 9, 2009, 2:53:12 PM (17 years ago)
- Location:
- trunk/psModules/src
- Files:
-
- 9 edited
-
camera (modified) (1 prop)
-
camera/pmFPAMaskWeight.c (modified) (1 diff)
-
camera/pmFPAMaskWeight.h (modified) (1 diff)
-
camera/pmReadoutFake.c (modified) (1 prop)
-
imcombine/pmStack.c (modified) (23 diffs, 1 prop)
-
imcombine/pmStack.h (modified) (1 diff, 1 prop)
-
objects (modified) (1 prop)
-
objects/pmSourceMatch.c (modified) (18 diffs)
-
objects/pmSourceMatch.h (modified) (5 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psModules/src/camera
-
Property svn:mergeinfo
set to (toggle deleted branches)
/branches/czw_branch/cleanup/psModules/src/camera merged eligible /branches/eam_branches/20090522/psModules/src/camera merged eligible /branches/eam_branches/20090715/psModules/src/camera merged eligible /branches/eam_branches/20090820/psModules/src/camera merged eligible /branches/pap/psModules/src/camera merged eligible /branches/pap_mops/psModules/src/camera 25137-25255
-
Property svn:mergeinfo
set to (toggle deleted branches)
-
trunk/psModules/src/camera/pmFPAMaskWeight.c
r25379 r26076 444 444 } 445 445 446 return true; 446 return psMetadataAddF32(readout->analysis, PS_LIST_TAIL, PM_READOUT_ANALYSIS_RENORM, 0, 447 "Renormalisation of variance", PS_SQR(correction)); 447 448 } 448 449 -
trunk/psModules/src/camera/pmFPAMaskWeight.h
r25372 r26076 15 15 /// @addtogroup Camera Camera Layout 16 16 /// @{ 17 18 #define PM_READOUT_ANALYSIS_RENORM "READOUT.RENORM" // Name on analysis metadata for renormalisation 17 19 18 20 /// Set a temporary readout mask using CELL.SATURATION and CELL.BAD -
trunk/psModules/src/camera/pmReadoutFake.c
- Property svn:mergeinfo changed (with no actual effect on merging)
-
trunk/psModules/src/imcombine/pmStack.c
-
Property svn:mergeinfo
set to (toggle deleted branches)
/branches/czw_branch/cleanup/psModules/src/imcombine/pmStack.c merged eligible /branches/eam_branches/20090522/psModules/src/imcombine/pmStack.c merged eligible /branches/eam_branches/20090715/psModules/src/imcombine/pmStack.c merged eligible /branches/eam_branches/20090820/psModules/src/imcombine/pmStack.c merged eligible /branches/pap/psModules/src/imcombine/pmStack.c merged eligible /branches/pap_mops/psModules/src/imcombine/pmStack.c 25137-25255
r25380 r26076 33 33 #define NUM_DIRECT_STDEV 5 // For less than this number of values, measure stdev directly 34 34 35 35 36 //#define TESTING // Enable test output 36 //#define TEST_X 1085// x coordinate to examine37 //#define TEST_Y 3371 // y coordinate to examine37 //#define TEST_X 3122-1 // x coordinate to examine 38 //#define TEST_Y 1028-1 // y coordinate to examine 38 39 39 40 … … 42 43 typedef struct { 43 44 psVector *pixels; // Pixel values 44 psVector *masks; // Pixel masks45 45 psVector *variances; // Pixel variances 46 46 psVector *weights; // Pixel weightings 47 47 psVector *sources; // Pixel sources (which image did they come from?) 48 48 psVector *limits; // Rejection limits 49 psVector *suspects; // Pixel is suspect? 49 50 psVector *sort; // Buffer for sorting (to get a robust estimator of the standard dev) 50 51 } combineBuffer; … … 53 54 { 54 55 psFree(buffer->pixels); 55 psFree(buffer->masks);56 56 psFree(buffer->variances); 57 57 psFree(buffer->weights); 58 58 psFree(buffer->sources); 59 59 psFree(buffer->limits); 60 psFree(buffer->suspects); 60 61 psFree(buffer->sort); 61 62 return; … … 69 70 70 71 buffer->pixels = psVectorAlloc(numImages, PS_TYPE_F32); 71 buffer->masks = psVectorAlloc(numImages, PS_TYPE_VECTOR_MASK);72 72 buffer->variances = psVectorAlloc(numImages, PS_TYPE_F32); 73 73 buffer->weights = psVectorAlloc(numImages, PS_TYPE_F32); 74 74 buffer->sources = psVectorAlloc(numImages, PS_TYPE_U16); 75 75 buffer->limits = psVectorAlloc(numImages, PS_TYPE_F32); 76 buffer->suspects = psVectorAlloc(numImages, PS_TYPE_U8); 76 77 buffer->sort = psVectorAlloc(numImages, PS_TYPE_F32); 77 78 return buffer; … … 143 144 float *stdev, // Standard deviation value, to return 144 145 const psVector *values, // Values to combine 145 const psVector *masks, // Mask to apply146 146 psVector *sortBuffer // Buffer for sorting 147 147 ) 148 148 { 149 149 assert(values); 150 assert(!masks || values->n == masks->n);151 150 assert(values->type.type == PS_TYPE_F32); 152 assert(!masks || masks->type.type == PS_TYPE_VECTOR_MASK);153 151 assert(sortBuffer && sortBuffer->nalloc >= values->n && sortBuffer->type.type == PS_TYPE_F32); 154 152 155 // Need to filter out clipped values 156 int num = 0; // Number of valid values 157 for (int i = 0; i < values->n; i++) { 158 if (!masks || !masks->data.PS_TYPE_VECTOR_MASK_DATA[i]) { 159 sortBuffer->data.F32[num++] = values->data.F32[i]; 160 } 161 } 162 sortBuffer->n = num; 163 if (!psVectorSortInPlace(sortBuffer)) { 153 int num = values->n; // Number of values 154 sortBuffer = psVectorSortIndex(sortBuffer, values); 155 if (!sortBuffer) { 156 *median = NAN; 157 *stdev = NAN; 164 158 return false; 165 159 } … … 167 161 if (num == 3) { 168 162 // Attempt to measure standard deviation with only three values (and one of those possibly corrupted) 169 *median = sortBuffer->data.F32[1];163 *median = values->data.F32[sortBuffer->data.S32[1]]; 170 164 if (stdev) { 171 float diff1 = sortBuffer->data.F32[0] - *median;172 float diff2 = sortBuffer->data.F32[2] - *median;165 float diff1 = values->data.F32[sortBuffer->data.S32[0]] - *median; 166 float diff2 = values->data.F32[sortBuffer->data.S32[2]] - *median; 173 167 // This factor of sqrt(2) might not be exact, but it's about right 174 168 *stdev = M_SQRT2 * PS_MIN(fabsf(diff1), fabsf(diff2)); 175 169 } 176 170 } else { 177 *median = num % 2 ? sortBuffer->data.F32[num / 2] : 178 (sortBuffer->data.F32[num / 2 - 1] + sortBuffer->data.F32[num / 2]) / 2.0; 171 *median = num % 2 ? values->data.F32[sortBuffer->data.S32[num / 2]] : 172 (values->data.F32[sortBuffer->data.S32[num / 2 - 1]] + 173 values->data.F32[sortBuffer->data.S32[num / 2]]) / 2.0; 179 174 if (stdev) { 180 175 if (num <= NUM_DIRECT_STDEV) { … … 182 177 double sum = 0.0; 183 178 for (int i = 0; i < num; i++) { 184 sum += PS_SQR( sortBuffer->data.F32[i] - *median);179 sum += PS_SQR(values->data.F32[sortBuffer->data.S32[i]] - *median); 185 180 } 186 181 *stdev = sqrt(sum / (double)(num - 1)); 187 182 } else { 188 183 // Standard deviation from the interquartile range 189 *stdev = 0.74 * ( sortBuffer->data.F32[(int)(0.75 * num)] -190 sortBuffer->data.F32[(int)(0.25 * num)]);184 *stdev = 0.74 * (values->data.F32[sortBuffer->data.S32[(int)(0.75 * num)]] - 185 values->data.F32[sortBuffer->data.S32[(int)(0.25 * num)]]); 191 186 } 192 187 } … … 195 190 return true; 196 191 } 197 198 #if 0199 // Return the weighted median for the pixels200 // This does not appear to produce as clean images as the weighted Olympic mean201 static float combinationWeightedMedian(const psVector *values, // Values to combine202 const psVector *weights, // Weights to combine203 const psVector *masks, // Mask to apply204 psVector *sortBuffer // Buffer for sorting205 )206 {207 double sumWeight = 0.0; // Sum of weights208 for (int j = 0; j < values->n; j++) {209 if (masks->data.PS_TYPE_VECTOR_MASK_DATA[j]) {210 continue;211 }212 sumWeight += weights->data.F32[j];213 }214 215 sortBuffer = psVectorSortIndex(sortBuffer, values);216 double target = sumWeight / 2.0; // Target weight217 218 int dominant = -1; // Index of dominant value, if any219 double cumulativeWeight = 0.0; // Sum of weights220 for (int j = 0; j < values->n; j++) {221 if (masks->data.PS_TYPE_VECTOR_MASK_DATA[j]) {222 continue;223 }224 int index = sortBuffer->data.S32[j]; // Index of value of interest225 float weight = weights->data.F32[index]; // Weight for value of interest226 if (weight >= target) {227 // Get the weighted median of the rest228 dominant = index;229 sumWeight -= weight;230 target = sumWeight / 2.0;231 continue;232 }233 cumulativeWeight += weight;234 if (cumulativeWeight >= target) {235 float median = values->data.F32[index]; // Weighted median median236 if (dominant != -1) {237 // In the case that a single value contains a disproportionate weight compared to the rest,238 // we use a weighted mean between that dominant value and the weighted median of the rest.239 return (values->data.F32[dominant] * weights->data.F32[dominant] + median * sumWeight) /240 (weights->data.F32[dominant] + sumWeight);241 }242 return median;243 }244 }245 246 return NAN;247 }248 #endif249 192 250 193 // Return the weighted Olympic mean for the pixels 251 194 static float combinationWeightedOlympic(const psVector *values, // Values to combine 252 195 const psVector *weights, // Weights to combine 253 const psVector *masks, // Mask to apply254 196 float frac, // Fraction to discard 255 197 psVector *sortBuffer // Buffer for sorting 256 198 ) 257 199 { 258 int numGood = 0; // Number of good values 259 for (int i = 0; i < values->n; i++) { 260 if (masks->data.PS_TYPE_VECTOR_MASK_DATA[i]) { 261 continue; 262 } 263 numGood++; 264 } 200 int numGood = values->n; // Number of good values 265 201 266 202 int numBad = frac * numGood + 0.5; // Number of bad values … … 272 208 for (int i = 0, j = 0; i < values->n; i++) { 273 209 int index = sortBuffer->data.S32[i]; // Index of interest 274 if (masks->data.PS_TYPE_VECTOR_MASK_DATA[index]) {275 continue;276 }277 210 j++; 278 211 if (j > high) { … … 290 223 291 224 // Mark a pixel for inspection 292 static inline void combineInspect(const psArray *inputs, // Stack data 293 int x, int y, // Pixel 294 int source // Source image index 295 ) 296 { 225 // Value in pixel doesn't seem to agree with the stack, so need to look closer 226 static inline void combineMarkInspect(const psArray *inputs, // Stack data 227 int x, int y, // Pixel 228 int source // Source image index 229 ) 230 { 231 #ifdef TESTING 232 if (x == TEST_X && y == TEST_Y) { 233 fprintf(stderr, "Marking image %d for inspection\n", source); 234 } 235 #endif 297 236 pmStackData *data = inputs->data[source]; // Stack data of interest 298 237 if (!data) { … … 304 243 } 305 244 306 // Given a stack of images, combine with optional rejection. 307 // Pixels in the stack that are rejected are marked for subsequent inspection 308 static void combinePixels(psImage *image, // Combined image, for output 309 psImage *mask, // Combined mask, for output 310 psImage *variance, // Combined variance map, for output 311 const psArray *inputs, // Stack data 312 const psVector *weights, // Global (single value) weights for data, or NULL 313 const psVector *addVariance, // Additional variance for data 314 const psVector *reject, // Indices of pixels to reject, or NULL 315 int x, int y, // Coordinates of interest; frame of output image 316 psImageMaskType maskVal, // Value to mask 317 psImageMaskType bad, // Value to give bad pixels 318 int numIter, // Number of rejection iterations 319 float rej, // Number of standard deviations at which to reject 320 float sys, // Relative systematic error 321 float discard,// Fraction of values to discard (Olympic weighted mean) 322 bool useVariance, // Use variance for rejection when combining? 323 bool safe, // Combine safely? 324 bool rejectInspect, // Reject values marked for inspection from combination? 325 combineBuffer *buffer // Buffer for combination; to avoid multiple allocations 326 ) 245 // Mark a pixel for rejection 246 // Cannot possibly inspect this pixel and confirm that it's good. 247 // e.g., Only a single input 248 static inline void combineMarkReject(const psArray *inputs, // Stack data 249 int x, int y, // Pixel 250 int source // Source image index 251 ) 252 { 253 #ifdef TESTING 254 if (x == TEST_X && y == TEST_Y) { 255 fprintf(stderr, "Marking pixel image %d for rejection\n", source); 256 } 257 #endif 258 pmStackData *data = inputs->data[source]; // Stack data of interest 259 if (!data) { 260 psWarning("Can't find input data for source %d", source); 261 return; 262 } 263 data->reject = psPixelsAdd(data->reject, data->reject->nalloc, x, y); 264 return; 265 } 266 267 268 // Extract vectors for simple combination/rejection operations 269 static void combineExtract(int *num, // Number of good pixels 270 bool *suspect, // Any suspect pixels? 271 combineBuffer *buffer, // Buffer with vectors 272 psImage *image, // Combined image, for output 273 psImage *mask, // Combined mask, for output 274 psImage *variance, // Combined variance map, for output 275 const psArray *inputs, // Stack data 276 const psVector *weights, // Global (single value) weights for data, or NULL 277 const psVector *addVariance, // Additional variance for data 278 const psVector *reject, // Indices of pixels to reject, or NULL 279 int x, int y, // Coordinates of interest; frame of output image 280 psImageMaskType maskVal, // Value to mask 281 psImageMaskType maskSuspect // Value to suspect 282 ) 327 283 { 328 284 // Rudimentary error checking 285 assert(buffer); 329 286 assert(image); 330 287 assert(mask); 331 288 assert(inputs); 332 assert(numIter >= 0);333 assert(buffer);334 assert(addVariance);335 assert((useVariance && variance) || !useVariance);336 289 337 290 psVector *pixelData = buffer->pixels; // Values for the pixel of interest 338 psVector *pixelMasks = buffer->masks; // Masks for the pixel of interest339 291 psVector *pixelVariances = variance ? buffer->variances : NULL; // Variances for the pixel of interest 340 292 psVector *pixelWeights = buffer->weights; // Image weights for the pixel of interest 341 293 psVector *pixelSources = buffer->sources; // Sources for the pixel of interest 342 294 psVector *pixelLimits = buffer->limits; // Limits for the pixel of interest 343 psVector *sort = buffer->sort; // Sort buffer 295 psVector *pixelSuspects = buffer->suspects; // Is the pixel suspect? 296 297 if (suspect) { 298 *suspect = false; 299 } 344 300 345 301 // Extract the pixel and mask data 346 int num = 0; // Number of good images302 int numGood = 0; // Number of good pixels 347 303 for (int i = 0, j = 0; i < inputs->n; i++) { 348 304 // Check if this pixel has been rejected. Assumes that the rejection pixel list is sorted --- it … … 364 320 } 365 321 322 pixelSuspects->data.U8[numGood] = mask->data.PS_TYPE_IMAGE_MASK_DATA[yIn][xIn] & maskSuspect ? 323 true : false; 324 366 325 psImage *image = data->readout->image; // Image of interest 367 326 psImage *variance = data->readout->variance; // Variance map of interest 368 pixelData->data.F32[num ] = image->data.F32[yIn][xIn];327 pixelData->data.F32[numGood] = image->data.F32[yIn][xIn]; 369 328 if (variance) { 370 pixelVariances->data.F32[num ] = variance->data.F32[yIn][xIn] * addVariance->data.F32[i];371 } 372 pixelWeights->data.F32[num ] = data->weight;373 pixelSources->data.U16[num ] = i;374 num ++;375 } 376 pixelData->n = num ;329 pixelVariances->data.F32[numGood] = variance->data.F32[yIn][xIn] * addVariance->data.F32[i]; 330 } 331 pixelWeights->data.F32[numGood] = data->weight; 332 pixelSources->data.U16[numGood] = i; 333 numGood++; 334 } 335 pixelData->n = numGood; 377 336 if (variance) { 378 pixelVariances->n = num; 379 } 380 pixelWeights->n = num; 381 pixelSources->n = num; 382 pixelLimits->n = num; 337 pixelVariances->n = numGood; 338 } 339 pixelWeights->n = numGood; 340 pixelSources->n = numGood; 341 pixelLimits->n = numGood; 342 pixelSuspects->n = numGood; 343 *num = numGood; 383 344 384 345 #ifdef TESTING 385 346 if (x == TEST_X && y == TEST_Y) { 386 for (int i = 0; i < num ; i++) {387 fprintf(stderr, "Input %d (%" PRIu16 "): %f %f %f\n",347 for (int i = 0; i < numGood; i++) { 348 fprintf(stderr, "Input %d (%" PRIu16 "): %f %f (%f) %f %d\n", 388 349 i, pixelSources->data.U16[i], pixelData->data.F32[i], pixelVariances->data.F32[i], 389 pixelWeights->data.F32[i]); 390 } 391 } 392 #endif 393 394 // The sensible thing to do varies according to how many good pixels there are. 350 addVariance->data.F32[i], pixelWeights->data.F32[i], pixelSuspects->data.U8[i]); 351 } 352 } 353 #endif 354 355 return; 356 } 357 358 359 // Combine pixels 360 static void combinePixels(psImage *image, // Combined image, for output 361 psImage *mask, // Combined mask, for output 362 psImage *variance, // Combined variance map, for output 363 int num, // Number of good pixels 364 combineBuffer *buffer, // Buffer with vectors 365 int x, int y, // Coordinates of interest; frame of output image 366 psImageMaskType bad, // Value for bad pixels 367 bool safe // Safe combination? 368 ) 369 { 370 psVector *pixelData = buffer->pixels; // Values for the pixel of interest 371 psVector *pixelVariances = variance ? buffer->variances : NULL; // Variances for the pixel of interest 372 psVector *pixelWeights = buffer->weights; // Image weights for the pixel of interest 373 395 374 // Default option is that the pixel is bad 396 375 float imageValue = NAN, varianceValue = NAN; // Value for combined image and variance map 397 376 psImageMaskType maskValue = bad; // Value for combined mask 398 377 switch (num) { 399 case 0: 400 // Nothing to combine: it's bad 401 #ifdef TESTING 402 if (x == TEST_X && y == TEST_Y) { 403 fprintf(stderr, "No inputs to combine, pixel is bad.\n"); 404 } 405 #endif 406 break; 378 case 0: { 379 // Nothing to combine: it's bad 380 #ifdef TESTING 381 if (x == TEST_X && y == TEST_Y) { 382 fprintf(stderr, "No inputs to combine, pixel is bad.\n"); 383 } 384 #endif 385 break; 386 } 407 387 case 1: { 408 388 // Accept the single pixel unless we have to be safe … … 427 407 } 428 408 case 2: { 429 // Accept the mean of the pixels only if we're going to reject based on the variance, or we're not 430 // playing safe 431 if (useVariance || !safe) { 409 // Automatically accept the mean of the pixels only if we're not playing safe 410 if (!safe) { 432 411 float mean, var; // Mean and variance from combination 433 412 if (combinationMeanVariance(&mean, &var, pixelData, pixelVariances, pixelWeights)) { … … 437 416 #ifdef TESTING 438 417 if (x == TEST_X && y == TEST_Y) { 439 fprintf(stderr, "Two inputs to combine using variance/unsafe --> %f %f\n", 440 mean, var); 418 fprintf(stderr, "Two inputs to combine using unsafe --> %f %f\n", mean, var); 441 419 } 442 420 #endif 443 421 } 444 422 } 445 if (useVariance && numIter > 0) { 446 // Use variance to check that the two are consistent 447 float diff = 0.5 * (pixelData->data.F32[0] - pixelData->data.F32[1]); // Mean flux difference 448 float var1 = pixelVariances->data.F32[0]; // Variance of first 449 float var2 = pixelVariances->data.F32[1]; // Variance of second 450 // Systematic error contributes to the rejection level 451 var1 += PS_SQR(sys * pixelData->data.F32[0]); 452 var2 += PS_SQR(sys * pixelData->data.F32[1]); 453 454 float sigma2 = var1 + var2; // Combined variance 455 if (PS_SQR(diff) > PS_SQR(rej) * sigma2) { 456 // Not consistent: mark both for inspection 457 if (rejectInspect) { 458 imageValue = NAN; 459 varianceValue = NAN; 460 maskValue = bad; 461 } else { 462 combineInspect(inputs, x, y, pixelSources->data.U16[0]); 463 combineInspect(inputs, x, y, pixelSources->data.U16[1]); 464 } 465 #ifdef TESTING 466 if (x == TEST_X && y == TEST_Y) { 467 fprintf(stderr, "Both pixels marked for inspection (%f > %f x %f\n)", 468 diff, rej, sqrtf(sigma2)); 469 } 470 #endif 423 #ifdef TESTING 424 else { 425 if (x == TEST_X && y == TEST_Y) { 426 fprintf(stderr, "Two inputs to combine, safety on, pixel is bad\n"); 471 427 } 472 428 } 429 #endif 473 430 break; 474 431 } 475 432 default: { 476 // Record the value derived with no clipping, because pixels rejected using the harsh clipping 477 // applied in the first pass might later be accepted. 433 // Can combine without too much worrying 478 434 float mean, var; // Mean and variance of the combination 479 435 if (!combinationMeanVariance(&mean, &var, pixelData, pixelVariances, pixelWeights)) { … … 488 444 } 489 445 #endif 490 491 // Prepare for clipping iteration492 if (numIter > 0) {493 pixelMasks->n = num;494 psVectorInit(pixelMasks, 0);495 if (useVariance) {496 // Convert to rejection limits --- saves doing it later.497 // Using squared rejection limit because it's cheaper than sqrts498 float rej2 = PS_SQR(rej); // Rejection level squared499 double sumWeights = 0.0;500 for (int i = 0; i < num; i++) {501 sumWeights += pixelWeights->data.F32[i];502 }503 for (int i = 0; i < num; i++) {504 // Systematic error contributes to the rejection level505 float sysVar = PS_SQR(sys * pixelData->data.F32[i]);506 #ifdef TESTING507 // Correct variance for comparison against weighted mean including itself508 float compare = 1.0 - pixelWeights->data.F32[i] / sumWeights;509 if (x == TEST_X && y == TEST_Y) {510 fprintf(stderr, "Variance %d (%d): %f %f %f\n", i, pixelSources->data.U16[i],511 pixelVariances->data.F32[i], sysVar, compare);512 }513 #endif514 515 pixelLimits->data.F32[i] = rej2 * (pixelVariances->data.F32[i] + sysVar);516 }517 }518 }519 520 // The clipping that follows is solely to identify suspect pixels.521 // These suspect pixels will be inspected in more detail by other functions.522 int numClipped = INT_MAX; // Number of pixels clipped per iteration523 int totalClipped = 0; // Total number of pixels clipped524 for (int i = 0; i < numIter && numClipped > 0 && num - totalClipped > 2; i++) {525 numClipped = 0;526 float median = NAN; // Middle of distribution527 float limit = NAN; // Rejection limit528 if (!useVariance) {529 float stdev; // Median and stdev of the combination, for rejection530 if (!combinationMedianStdev(&median, useVariance ? NULL : &stdev,531 pixelData, pixelMasks, sort)) {532 psWarning("Bad median/stdev at %d,%d", x, y);533 break;534 }535 limit = rej * stdev;536 #ifdef TESTING537 if (x == TEST_X && y == TEST_Y) {538 fprintf(stderr, "Rejecting without variance; rejection limit: %f\n", limit);539 }540 #endif541 } else {542 #ifdef TESTING543 if (x == TEST_X && y == TEST_Y) {544 fprintf(stderr, "Rejecting with variance...\n");545 }546 #endif547 median = combinationWeightedOlympic(pixelData, pixelWeights, pixelMasks, discard, sort);548 }549 550 #ifdef TESTING551 if (x == TEST_X && y == TEST_Y) {552 fprintf(stderr, "Median: %f\n", median);553 }554 #endif555 556 557 // Mask a pixel for inspection558 #define MASK_PIXEL_FOR_INSPECTION() \559 pixelMasks->data.PS_TYPE_VECTOR_MASK_DATA[j] = 0xff; \560 if (!rejectInspect) { \561 combineInspect(inputs, x, y, pixelSources->data.U16[j]); \562 } \563 numClipped++; \564 totalClipped++;565 566 for (int j = 0; j < num; j++) {567 if (pixelMasks->data.PS_TYPE_VECTOR_MASK_DATA[j]) {568 continue;569 }570 float diff = pixelData->data.F32[j] - median; // Difference from expected571 if (useVariance) {572 // Comparing squares --- cheaper than lots of sqrts573 // pixelVariances includes the rejection limit, from above574 if (PS_SQR(diff) > pixelLimits->data.F32[j]) {575 MASK_PIXEL_FOR_INSPECTION();576 #ifdef TESTING577 if (x == TEST_X && y == TEST_Y) {578 fprintf(stderr, "Rejecting input %d based on variance: %f > %f\n",579 j, diff, sqrtf(pixelLimits->data.F32[j]));580 }581 #endif582 }583 } else if (fabsf(diff) > limit) {584 MASK_PIXEL_FOR_INSPECTION();585 #ifdef TESTING586 if (x == TEST_X && y == TEST_Y) {587 fprintf(stderr, "Rejecting input %d based on distribution: %f > %f\n",588 j, diff, limit);589 }590 #endif591 }592 }593 }594 595 if (rejectInspect && totalClipped > 0) {596 // Get rid of the masked values597 // The alternative to this is to make combinationMeanVariance() accept a mask598 int good = 0; // Index of good value599 for (int i = 0; i < num; i++) {600 if (pixelMasks->data.PS_TYPE_VECTOR_MASK_DATA[i]) {601 continue;602 }603 if (i != good) {604 pixelData->data.F32[good] = pixelData->data.F32[i];605 pixelVariances->data.F32[good] = pixelVariances->data.F32[i];606 pixelWeights->data.F32[good] = pixelWeights->data.F32[i];607 pixelData->data.F32[good] = pixelData->data.F32[i];608 }609 good++;610 }611 pixelData->n = good;612 pixelVariances->n = good;613 pixelWeights->n = good;614 if (combinationMeanVariance(&mean, &var, pixelData, pixelVariances, pixelWeights)) {615 imageValue = mean;616 varianceValue = var;617 maskValue = 0;618 } else {619 imageValue = NAN;620 varianceValue = NAN;621 maskValue = bad;622 }623 }624 625 446 break; 626 447 } … … 633 454 } 634 455 456 #ifdef TESTING 457 mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] = num; 458 #endif 459 460 635 461 return; 462 } 463 464 465 // Test pixels to be combined 466 // Returns false to repeat without suspect pixels 467 static bool combineTest(int num, // Number of good pixels 468 bool suspect, // Does the stack contain suspect pixels? 469 psArray *inputs, // Original inputs (for flagging) 470 combineBuffer *buffer, // Buffer with vectors 471 int x, int y, // Coordinates of interest; frame of output image 472 float iter, // Number of rejection iterations per input 473 float rej, // Number of standard deviations at which to reject 474 float sys, // Relative systematic error 475 float olympic,// Fraction of values to discard (Olympic weighted mean) 476 bool useVariance, // Use variance for rejection when combining? 477 bool safe // Combine safely? 478 ) 479 { 480 if (iter <= 0) { 481 return true; 482 } 483 484 int numIter = PS_MAX(iter * num, 1); // Number of iterations 485 486 #ifdef TESTING 487 if (x == TEST_X && y == TEST_Y) { 488 fprintf(stderr, "Testing pixel %d,%d: %d %f %f %f %d %d\n", 489 x, y, numIter, rej, sys, olympic, useVariance, safe); 490 } 491 #endif 492 493 psVector *pixelData = buffer->pixels; // Values for the pixel of interest 494 psVector *pixelWeights = buffer->weights; // Is the pixel suspect? 495 psVector *pixelVariances = buffer->variances; // Variances for the pixel of interest 496 psVector *pixelSources = buffer->sources; // Sources for the pixel of interest 497 psVector *pixelSuspects = buffer->suspects; // Is the pixel suspect? 498 psVector *pixelLimits = buffer->limits; // Is the pixel suspect? 499 500 // Set up rejection limits 501 float rej2 = PS_SQR(rej); // Rejection level squared 502 if (num > 2 && useVariance) { 503 // Convert rejection limits --- saves doing it later multiple times 504 // Using squared rejection limit because it's cheaper than sqrts 505 double sumWeights = 0.0; 506 for (int i = 0; i < num; i++) { 507 sumWeights += pixelWeights->data.F32[i]; 508 } 509 for (int i = 0; i < num; i++) { 510 // Systematic error contributes to the rejection level 511 float sysVar = PS_SQR(sys * pixelData->data.F32[i]); 512 #ifdef TESTING 513 // Correct variance for comparison against weighted mean including itself 514 float compare = 1.0 - pixelWeights->data.F32[i] / sumWeights; 515 if (x == TEST_X && y == TEST_Y) { 516 fprintf(stderr, "Variance %d (%d): %f %f %f\n", i, pixelSources->data.U16[i], 517 pixelVariances->data.F32[i], sysVar, compare); 518 } 519 #endif 520 pixelLimits->data.F32[i] = rej2 * (pixelVariances->data.F32[i] + sysVar); 521 } 522 } 523 524 int maskIndex = 0; // Index of pixel to mask 525 int totalClipped = 0; // Total number of pixels clipped 526 for (int i = 0; i < numIter && maskIndex >= 0; i++) { 527 maskIndex = -1; // Nothing to reject 528 529 switch (num) { 530 case 0: 531 break; 532 case 1: 533 if (i == 0 && safe) { 534 combineMarkReject(inputs, x, y, pixelSources->data.U16[0]); 535 } 536 break; 537 case 2: { 538 if (useVariance) { 539 // Use variance to check that the two are consistent 540 float diff = 0.5 * (pixelData->data.F32[0] - pixelData->data.F32[1]); // Mean flux difference 541 float var1 = pixelVariances->data.F32[0]; // Variance of first 542 float var2 = pixelVariances->data.F32[1]; // Variance of second 543 // Systematic error contributes to the rejection level 544 var1 += PS_SQR(sys * pixelData->data.F32[0]); 545 var2 += PS_SQR(sys * pixelData->data.F32[1]); 546 547 float sigma2 = var1 + var2; // Combined variance 548 if (PS_SQR(diff) > rej2 * sigma2) { 549 // Not consistent: don't believe either! 550 if (i == 0 && suspect) { 551 combineMarkReject(inputs, x, y, pixelSources->data.U16[0]); 552 combineMarkReject(inputs, x, y, pixelSources->data.U16[1]); 553 } else { 554 combineMarkInspect(inputs, x, y, pixelSources->data.U16[0]); 555 combineMarkInspect(inputs, x, y, pixelSources->data.U16[1]); 556 } 557 #ifdef TESTING 558 if (x == TEST_X && y == TEST_Y) { 559 fprintf(stderr, "Flagged both pixels (%f > %f x %f\n)", 560 diff, rej, sqrtf(sigma2)); 561 } 562 #endif 563 } 564 } else if (i == 0 && safe) { 565 // Can't test them, and we want to be safe, so reject 566 combineMarkReject(inputs, x, y, pixelSources->data.U16[0]); 567 combineMarkReject(inputs, x, y, pixelSources->data.U16[1]); 568 } 569 break; 570 } 571 #if 0 572 case 3: { 573 // Want to be a bit careful on the rejection than for a larger number of inputs 574 if (!useVariance) { 575 return combineTestGeneral(num, suspect, inputs, buffer, x, y, numIter, rej, sys, 576 olympic, useVariance, safe, allowSuspect); 577 } 578 579 // Differences between pixel values 580 float diff01 = pixelData->data.F32[0] - pixelData->data.F32[1]; 581 float diff12 = pixelData->data.F32[1] - pixelData->data.F32[2]; 582 float diff20 = pixelData->data.F32[2] - pixelData->data.F32[0]; 583 // Variance for each pixel 584 float var0 = pixelVariances->data.F32[0] + PS_SQR(sys * pixelData->data.F32[0]); 585 float var1 = pixelVariances->data.F32[1] + PS_SQR(sys * pixelData->data.F32[1]); 586 float var2 = pixelVariances->data.F32[2] + PS_SQR(sys * pixelData->data.F32[2]); 587 // Errors in pixel differences 588 float err01 = var0 + var1; 589 float err12 = var1 + var2; 590 float err20 = var2 + var0; 591 592 #ifdef TESTING 593 if (x == TEST_X && y == TEST_Y) { 594 fprintf(stderr, "Diff 0-1: %f %f\n", diff01, err01); 595 fprintf(stderr, "Diff 1-2: %f %f\n", diff12, err12); 596 fprintf(stderr, "Diff 2-0: %f %f\n", diff20, err20); 597 } 598 #endif 599 600 int badPairs = 0; // Number of bad pairs 601 bool bad01 = false, bad12 = false, bad20 = false; // Pair is bad? 602 if (PS_SQR(diff01) > rej2 * err01) { 603 bad01 = true; 604 badPairs++; 605 } 606 if (PS_SQR(diff12) > rej2 * err12) { 607 bad12 = true; 608 badPairs++; 609 } 610 if (PS_SQR(diff20) > rej2 * err20) { 611 bad20 = true; 612 badPairs++; 613 } 614 615 if (badPairs > 0 && allowSuspect && suspect) { 616 return false; 617 } 618 619 switch (badPairs) { 620 case 0: 621 // Nothing to worry about! 622 break; 623 case 1: 624 // Can't tell which image is bad, so be sure to get it 625 if (bad01) { 626 combineMarkInspect(inputs, x, y, pixelSources->data.U16[0]); 627 combineMarkInspect(inputs, x, y, pixelSources->data.U16[1]); 628 break; 629 } 630 if (bad12) { 631 combineMarkInspect(inputs, x, y, pixelSources->data.U16[1]); 632 combineMarkInspect(inputs, x, y, pixelSources->data.U16[2]); 633 break; 634 } 635 if (bad20) { 636 combineMarkInspect(inputs, x, y, pixelSources->data.U16[2]); 637 combineMarkInspect(inputs, x, y, pixelSources->data.U16[0]); 638 break; 639 } 640 psAbort("Should never get here"); 641 case 2: 642 if (bad01 && bad12) { 643 // 2 and 0 are good 644 combineMarkInspect(inputs, x, y, pixelSources->data.U16[1]); 645 break; 646 } 647 if (bad12 && bad20) { 648 // 0 and 1 are good 649 combineMarkInspect(inputs, x, y, pixelSources->data.U16[2]); 650 break; 651 } 652 if (bad20 && bad01) { 653 // 1 and 2 are good 654 combineMarkInspect(inputs, x, y, pixelSources->data.U16[0]); 655 break; 656 } 657 psAbort("Should never get here"); 658 case 3: 659 // Everything's bad 660 combineMarkInspect(inputs, x, y, pixelSources->data.U16[0]); 661 combineMarkInspect(inputs, x, y, pixelSources->data.U16[1]); 662 combineMarkInspect(inputs, x, y, pixelSources->data.U16[2]); 663 break; 664 } 665 break; 666 } 667 #endif 668 default: { 669 if (useVariance) { 670 float median = combinationWeightedOlympic(pixelData, pixelWeights, 671 olympic, buffer->sort); // Median for stack 672 #ifdef TESTING 673 if (x == TEST_X && y == TEST_Y) { 674 fprintf(stderr, "Flag with variance, median = %f\n", median); 675 } 676 #endif 677 float worst = -INFINITY; // Largest deviation 678 for (int j = 0; j < num; j++) { 679 float diff = pixelData->data.F32[j] - median; // Difference from expected 680 #ifdef TESTING 681 if (x == TEST_X && y == TEST_Y) { 682 fprintf(stderr, "Testing input %d: %f\n", j, diff); 683 } 684 #endif 685 686 // Comparing squares --- cheaper than lots of sqrts 687 // pixelVariances includes the rejection limit, from above 688 float diff2 = PS_SQR(diff); // Square difference 689 if (diff2 > pixelLimits->data.F32[j]) { 690 float dev = diff2 / pixelLimits->data.F32[j]; // Deviation 691 if (dev > worst) { 692 worst = dev; 693 maskIndex = j; 694 } 695 } 696 } 697 } else { 698 float median = NAN, stdev = NAN; // Median and stdev of the combination, for rejection 699 combinationMedianStdev(&median, &stdev, pixelData, buffer->sort); 700 float limit = rej * stdev; // Rejection limit 701 #ifdef TESTING 702 if (x == TEST_X && y == TEST_Y) { 703 fprintf(stderr, "Flag without variance; median = %f, stdev = %f, limit = %f\n", 704 median, stdev, limit); 705 } 706 #endif 707 float worst = -INFINITY; // Largest deviation 708 for (int j = 0; j < num; j++) { 709 float diff = fabsf(pixelData->data.F32[j] - median); // Difference from expected 710 711 if (diff > limit) { 712 float dev = diff / limit; // Deviation 713 if (dev > worst) { 714 worst = dev; 715 maskIndex = j; 716 } 717 } 718 } 719 } 720 } 721 } 722 723 // Do the actual rejection of the pixel 724 if (maskIndex >= 0) { 725 if (suspect) { 726 #ifdef TESTING 727 if (x == TEST_X && y == TEST_Y) { 728 fprintf(stderr, "Throwing out all suspect pixels\n"); 729 } 730 #endif 731 // Throw out all suspect pixels 732 int numGood = 0; // Number of good pixels 733 for (int j = 0; j < num; j++) { 734 if (pixelSuspects->data.U8[j]) { 735 combineMarkReject(inputs, x, y, pixelSources->data.U16[j]); 736 continue; 737 } 738 if (numGood == j) { 739 numGood++; 740 continue; 741 } 742 pixelData->data.F32[numGood] = pixelData->data.F32[j]; 743 pixelWeights->data.F32[numGood] = pixelWeights->data.F32[j]; 744 pixelSources->data.U16[numGood] = pixelSources->data.U16[j]; 745 pixelLimits->data.F32[numGood] = pixelLimits->data.F32[j]; 746 pixelVariances->data.F32[numGood] = pixelVariances->data.F32[j]; 747 numGood++; 748 } 749 pixelData->n = numGood; 750 pixelWeights->n = numGood; 751 pixelSources->n = numGood; 752 pixelLimits->n = numGood; 753 pixelVariances->n = numGood; 754 totalClipped += num - numGood; 755 num = numGood; 756 suspect = false; 757 } else { 758 // Throw out masked pixel 759 #ifdef TESTING 760 if (x == TEST_X && y == TEST_Y) { 761 fprintf(stderr, "Throwing out input %d\n", maskIndex); 762 } 763 #endif 764 combineMarkInspect(inputs, x, y, pixelSources->data.U16[maskIndex]); 765 int numGood = 0; // Number of good pixels 766 for (int j = 0; j < num; j++) { 767 if (j == maskIndex) { 768 continue; 769 } 770 if (numGood == j) { 771 numGood++; 772 continue; 773 } 774 pixelData->data.F32[numGood] = pixelData->data.F32[j]; 775 pixelWeights->data.F32[numGood] = pixelWeights->data.F32[j]; 776 pixelSources->data.U16[numGood] = pixelSources->data.U16[j]; 777 pixelLimits->data.F32[numGood] = pixelLimits->data.F32[j]; 778 pixelVariances->data.F32[numGood] = pixelVariances->data.F32[j]; 779 numGood++; 780 } 781 pixelData->n = numGood; 782 pixelWeights->n = numGood; 783 pixelSources->n = numGood; 784 pixelLimits->n = numGood; 785 pixelVariances->n = numGood; 786 totalClipped++; 787 num--; 788 } 789 } 790 } 791 792 return true; 636 793 } 637 794 … … 639 796 // Ensure the input array of pmStackData is valid, and get some details out of it 640 797 static bool validateInputData(bool *haveVariances, // Do we have variance maps in the sky images? 641 bool *haveRejects, // Do we have lists of rejected pixels?642 798 int *num, // Number of inputs 643 799 int *numCols, int *numRows, // Size of (sky) images 644 psArray *input // Input array of pmStackData to validate 800 const psArray *input, // Input array of pmStackData to validate 801 const pmReadout *output // Output readout 645 802 ) 646 803 { … … 668 825 PS_ASSERT_IMAGE_TYPE(data->readout->variance, PS_TYPE_F32, false); 669 826 } 670 *haveRejects = (data->reject != NULL);827 bool haveRejects = (data->reject != NULL); // Do we have rejected pixels? 671 828 672 829 // Make sure the rest correspond with the first … … 681 838 return false; 682 839 } 683 if (( *haveRejects && !data->reject) || (data->reject && !*haveRejects)) {840 if ((haveRejects && !data->reject) || (data->reject && !haveRejects)) { 684 841 psError(PS_ERR_UNEXPECTED_NULL, true, 685 842 "The rejected pixels are specified in some but not all inputs."); … … 697 854 PS_ASSERT_IMAGE_TYPE(data->readout->variance, PS_TYPE_F32, false); 698 855 } 856 } 857 858 PM_ASSERT_READOUT_NON_NULL(output, false); 859 if (output->image) { 860 PS_ASSERT_IMAGE_NON_NULL(output->image, false); 861 PS_ASSERT_IMAGE_TYPE(output->image, PS_TYPE_F32, false); 862 PS_ASSERT_IMAGE_NON_NULL(output->mask, false); 863 PS_ASSERT_IMAGE_TYPE(output->mask, PS_TYPE_IMAGE_MASK, false); 864 PS_ASSERT_IMAGES_SIZE_EQUAL(output->image, output->mask, false); 699 865 } 700 866 … … 782 948 783 949 /// Stack input images 784 bool pmStackCombine(pmReadout *combined, psArray *input, psImageMaskType maskVal, psImageMaskType bad, 785 int kernelSize, int numIter, float rej, float sys, float discard, 786 bool entire, bool useVariance, bool safe, bool rejectInspect) 787 { 788 PS_ASSERT_PTR_NON_NULL(combined, false); 950 bool pmStackCombine(pmReadout *combined, psArray *input, psImageMaskType maskVal, psImageMaskType maskSuspect, 951 psImageMaskType bad, int kernelSize, float iter, float rej, float sys, float olympic, 952 bool useVariance, bool safe, bool rejection) 953 { 789 954 bool haveVariances; // Do we have the variance maps? 790 bool haveRejects; // Do we have lists of rejected pixels?791 955 int num; // Number of inputs 792 956 int numCols, numRows; // Size of (sky) images 793 if (!validateInputData(&haveVariances, & haveRejects, &num, &numCols, &numRows, input)) {957 if (!validateInputData(&haveVariances, &num, &numCols, &numRows, input, combined)) { 794 958 return false; 795 959 } 796 960 PS_ASSERT_INT_NONNEGATIVE(kernelSize, false); 797 961 PS_ASSERT_INT_POSITIVE(bad, false); 798 PS_ASSERT_INT_NONNEGATIVE(numIter, false);799 962 if (isnan(rej)) { 800 PS_ASSERT_ INT_EQUAL(numIter, 0, false);963 PS_ASSERT_FLOAT_EQUAL(iter, 0, false); 801 964 } else { 965 PS_ASSERT_FLOAT_LARGER_THAN(iter, 0, false); 802 966 PS_ASSERT_FLOAT_LARGER_THAN(rej, 0.0, false); 803 }804 if (haveRejects) {805 // This is a subsequent combination, so expect that the image and mask already exist806 PS_ASSERT_IMAGE_NON_NULL(combined->image, false);807 PS_ASSERT_IMAGE_TYPE(combined->image, PS_TYPE_F32, false);808 PS_ASSERT_IMAGE_NON_NULL(combined->mask, false);809 PS_ASSERT_IMAGE_TYPE(combined->mask, PS_TYPE_IMAGE_MASK, false);810 PS_ASSERT_IMAGES_SIZE_EQUAL(combined->image, combined->mask, false);811 967 } 812 968 if (useVariance && !haveVariances) { … … 833 989 } 834 990 #endif 835 if (!haveRejects && !data->inspect) { 836 data->inspect = psPixelsAllocEmpty(PIXEL_LIST_BUFFER); 991 if (!rejection) { 992 // Ensure pixels can be put on the appropriate list 993 if (!data->inspect) { 994 data->inspect = psPixelsAllocEmpty(PIXEL_LIST_BUFFER); 995 } 996 if (!data->reject) { 997 data->reject = psPixelsAllocEmpty(PIXEL_LIST_BUFFER); 998 } 837 999 } 838 1000 } … … 863 1025 combineBuffer *buffer = combineBufferAlloc(num); 864 1026 865 if (haveRejects) { 866 psImage *combinedImage = combined->image; // Combined image 867 psImage *combinedMask = combined->mask; // Combined mask 868 psImage *combinedVariance = combined->variance; // Combined variance map 869 870 psArray *pixelMap = pixelMapGenerate(input, minInputCols, maxInputCols, 871 minInputRows, maxInputRows); // Map of pixels to source 872 psPixels *pixels = NULL; // Total list of pixels, with no duplicates 1027 // Pull the products out, allocate if necessary 1028 psImage *combinedImage = combined->image; // Combined image 1029 if (!combinedImage) { 1030 combined->image = psImageAlloc(numCols, numRows, PS_TYPE_F32); 1031 combinedImage = combined->image; 1032 } 1033 psImage *combinedMask = combined->mask; // Combined mask 1034 if (!combinedMask) { 1035 combined->mask = psImageAlloc(numCols, numRows, PS_TYPE_IMAGE_MASK); 1036 combinedMask = combined->mask; 1037 } 1038 1039 psImage *combinedVariance = combined->variance; // Combined variance map 1040 if (haveVariances && !combinedVariance) { 1041 combined->variance = psImageAlloc(numCols, numRows, PS_TYPE_F32); 1042 combinedVariance = combined->variance; 1043 } 1044 1045 // Set up rejection list 1046 psArray *pixelMap = NULL; // Map of pixels to source 1047 if (rejection) { 1048 pixelMap = pixelMapGenerate(input, minInputCols, maxInputCols, minInputRows, maxInputRows); 1049 } 1050 1051 // Combine each pixel 1052 for (int y = minInputRows; y < maxInputRows; y++) { 1053 for (int x = minInputCols; x < maxInputCols; x++) { 1054 #ifdef TESTING 1055 if (x == TEST_X && y == TEST_Y) { 1056 fprintf(stderr, "Combining pixel %d,%d: %x %x %f %f %f %f %d %d %d\n", 1057 x, y, maskVal, bad, iter, rej, sys, olympic, useVariance, safe, rejection); 1058 } 1059 #endif 1060 psVector *reject = NULL; // Images to reject for this pixel 1061 if (rejection) { 1062 reject = pixelMapQuery(pixelMap, minInputCols, minInputRows, x, y); 1063 #ifdef TESTING 1064 if (x == TEST_X && y == TEST_Y) { 1065 fprintf(stderr, "Rejected inputs: "); 1066 if (!reject) { 1067 fprintf(stderr, "<none>\n"); 1068 } else { 1069 for (int i = 0; i < reject->n; i++) { 1070 fprintf(stderr, "%d ", reject->data.U16[i]); 1071 } 1072 fprintf(stderr, "\n"); 1073 } 1074 } 1075 #endif 1076 } 1077 1078 int num; // Number of good pixels 1079 bool suspect; // Suspect pixels in stack? 1080 combineExtract(&num, &suspect, buffer, combinedImage, combinedMask, combinedVariance, 1081 input, weights, addVariance, reject, x, y, maskVal, maskSuspect); 1082 combinePixels(combinedImage, combinedMask, combinedVariance, num, buffer, x, y, bad, safe); 1083 1084 if (iter > 0) { 1085 combineTest(num, suspect, input, buffer, x, y, iter, rej, sys, olympic, 1086 useVariance, safe); 1087 } 1088 } 1089 } 1090 1091 psFree(pixelMap); 1092 psFree(weights); 1093 psFree(buffer); 1094 1095 1096 1097 #ifndef PS_NO_TRACE 1098 if (!rejection && psTraceGetLevel("psModules.imcombine") >= 5) { 873 1099 for (int i = 0; i < num; i++) { 874 pmStackData *data = input->data[i]; // Stack ing data; contains the list of pixels875 if (!data ) {1100 pmStackData *data = input->data[i]; // Stack data for this input 1101 if (!data || !data->inspect) { 876 1102 continue; 877 1103 } 878 pixels = psPixelsConcatenate(pixels, data->reject); 879 } 880 pixels = psPixelsDuplicates(pixels, pixels); 881 882 if (entire) { 883 // Combine entire image 884 for (int y = minInputRows; y < maxInputRows; y++) { 885 for (int x = minInputCols; x < maxInputCols; x++) { 886 psVector *reject = pixelMapQuery(pixelMap, minInputCols, minInputRows, 887 x, y); // Reject these images 888 combinePixels(combinedImage, combinedMask, combinedVariance, input, weights, 889 addVariance, reject, x, y, maskVal, bad, numIter, rej, sys, discard, 890 useVariance, safe, rejectInspect, buffer); 891 } 892 } 893 } else { 894 // Only combine previously rejected pixels 895 for (int i = 0; i < pixels->n; i++) { 896 // Pixel coordinates are in the frame of the original image 897 int x = pixels->data[i].x, y = pixels->data[i].y; // Coordinates of interest 898 if (x < minInputCols || x >= maxInputCols || y < minInputRows || y >= maxInputRows) { 899 continue; 900 } 901 psVector *reject = pixelMapQuery(pixelMap, minInputCols, minInputRows, 902 x, y); // Reject these images 903 combinePixels(combinedImage, combinedMask, combinedVariance, input, weights, 904 addVariance, reject, x, y, maskVal, bad, numIter, rej, sys, discard, 905 useVariance, safe, rejectInspect, buffer); 906 } 907 } 908 psFree(pixels); 909 psFree(pixelMap); 910 } else { 911 // Pull the products out, allocate if necessary 912 psImage *combinedImage = combined->image; // Combined image 913 if (!combinedImage) { 914 combined->image = psImageAlloc(numCols, numRows, PS_TYPE_F32); 915 combinedImage = combined->image; 916 } 917 psImage *combinedMask = combined->mask; // Combined mask 918 if (!combinedMask) { 919 combined->mask = psImageAlloc(numCols, numRows, PS_TYPE_IMAGE_MASK); 920 combinedMask = combined->mask; 921 } 922 923 psImage *combinedVariance = combined->variance; // Combined variance map 924 if (haveVariances && !combinedVariance) { 925 combined->variance = psImageAlloc(numCols, numRows, PS_TYPE_F32); 926 combinedVariance = combined->variance; 927 } 928 929 for (int y = minInputRows; y < maxInputRows; y++) { 930 for (int x = minInputCols; x < maxInputCols; x++) { 931 combinePixels(combinedImage, combinedMask, combinedVariance, input, weights, 932 addVariance, NULL, x, y, maskVal, bad, numIter, rej, sys, discard, 933 useVariance, safe, rejectInspect, buffer); 934 } 935 } 936 937 #ifndef PS_NO_TRACE 938 if (psTraceGetLevel("psModules.imcombine") >= 5) { 939 for (int i = 0; i < num; i++) { 940 pmStackData *data = input->data[i]; // Stack data for this input 941 if (!data || !data->inspect) { 942 continue; 943 } 944 psTrace("psModules.imcombine", 5, "Image %d: %ld pixels to inspect.\n", i, data->inspect->n); 945 } 946 } 947 #endif 948 } 949 950 psFree(weights); 951 psFree(buffer); 1104 psTrace("psModules.imcombine", 5, "Image %d: %ld pixels to inspect.\n", i, data->inspect->n); 1105 } 1106 } 1107 #endif 952 1108 953 1109 return true; -
Property svn:mergeinfo
set to (toggle deleted branches)
-
trunk/psModules/src/imcombine/pmStack.h
-
Property svn:mergeinfo
set to (toggle deleted branches)
/branches/czw_branch/cleanup/psModules/src/imcombine/pmStack.h merged eligible /branches/eam_branches/20090522/psModules/src/imcombine/pmStack.h merged eligible /branches/eam_branches/20090715/psModules/src/imcombine/pmStack.h merged eligible /branches/eam_branches/20090820/psModules/src/imcombine/pmStack.h merged eligible /branches/pap/psModules/src/imcombine/pmStack.h merged eligible /branches/pap_mops/psModules/src/imcombine/pmStack.h 25137-25255
r23577 r26076 44 44 psArray *input, ///< Input array of pmStackData 45 45 psImageMaskType maskVal, ///< Mask value of bad pixels 46 psImageMaskType suspect, ///< Mask value of suspect pixels 46 47 psImageMaskType bad, ///< Mask value to give rejected pixels 47 48 int kernelSize, ///< Half-size of the convolution kernel 48 int numIter, ///< Number of iterations49 float iter, ///< Number of iterations per input 49 50 float rej, ///< Rejection limit (standard deviations) 50 51 float sys, ///< Relative systematic error 51 52 float discard, ///< Fraction of values to discard for Olympic weighted mean 52 bool entire, ///< Combine entire image even if rejection lists provided?53 53 bool useVariance, ///< Use variance values for rejection? 54 54 bool safe, ///< Play safe with small numbers of input pixels (mask if N <= 2)? -
Property svn:mergeinfo
set to (toggle deleted branches)
-
trunk/psModules/src/objects
-
Property svn:mergeinfo
set to (toggle deleted branches)
/branches/czw_branch/cleanup/psModules/src/objects merged eligible /branches/eam_branches/20090522/psModules/src/objects merged eligible /branches/eam_branches/20090715/psModules/src/objects merged eligible /branches/eam_branches/20090820/psModules/src/objects merged eligible /branches/pap/psModules/src/objects merged eligible /branches/pap_mops/psModules/src/objects 25137-25255
-
Property svn:mergeinfo
set to (toggle deleted branches)
-
trunk/psModules/src/objects/pmSourceMatch.c
r25256 r26076 17 17 #define SOURCES_MAX_LEAF 2 // Maximum number of points on a tree leaf 18 18 #define ARRAY_BUFFER 16 // Buffer for array 19 19 20 20 21 ////////////////////////////////////////////////////////////////////////////////////////////////////////////// … … 124 125 match->mag = psVectorAllocEmpty(ARRAY_BUFFER, PS_TYPE_F32); 125 126 match->magErr = psVectorAllocEmpty(ARRAY_BUFFER, PS_TYPE_F32); 127 match->x = psVectorAllocEmpty(ARRAY_BUFFER, PS_TYPE_F32); 128 match->y = psVectorAllocEmpty(ARRAY_BUFFER, PS_TYPE_F32); 126 129 match->image = psVectorAllocEmpty(ARRAY_BUFFER, PS_TYPE_U32); 127 130 match->index = psVectorAllocEmpty(ARRAY_BUFFER, PS_TYPE_U32); … … 133 136 void pmSourceMatchAdd(pmSourceMatch *match, // Match data 134 137 float mag, float magErr, // Magnitude and error 138 float x, float y, // Position 135 139 int image, // Image index 136 140 int index // Source index … … 141 145 match->mag = psVectorExtend(match->mag, match->mag->nalloc, 1); 142 146 match->magErr = psVectorExtend(match->magErr, match->magErr->nalloc, 1); 147 match->x = psVectorExtend(match->x, match->x->nalloc, 1); 148 match->y = psVectorExtend(match->y, match->y->nalloc, 1); 143 149 match->image = psVectorExtend(match->image, match->image->nalloc, 1); 144 150 match->index = psVectorExtend(match->index, match->index->nalloc, 1); … … 147 153 match->mag->data.F32[num] = mag; 148 154 match->magErr->data.F32[num] = magErr; 155 match->x->data.F32[num] = x; 156 match->y->data.F32[num] = y; 149 157 match->image->data.S32[num] = image; 150 158 match->index->data.S32[num] = index; … … 192 200 pmSourceMatch *match = pmSourceMatchAlloc(); // Match data 193 201 pmSourceMatchAdd(match, magImage->data.F32[j], magErrImage->data.F32[j], 194 i, indices->data.S32[j]);202 xImage->data.F32[j], yImage->data.F32[j], i, indices->data.S32[j]); 195 203 matches->data[j] = match; 196 204 } … … 212 220 pmSourceMatch *match = pmSourceMatchAlloc(); // Match data 213 221 pmSourceMatchAdd(match, magImage->data.F32[j], magErrImage->data.F32[j], 214 i, indices->data.S32[j]);222 xImage->data.F32[j], yImage->data.F32[j], i, indices->data.S32[j]); 215 223 matches->data[k] = match; 216 224 } … … 238 246 pmSourceMatch *match = matches->data[index]; // Match data 239 247 pmSourceMatchAdd(match, magImage->data.F32[j], magErrImage->data.F32[j], 240 i, indices->data.S32[j]);248 xImage->data.F32[j], yImage->data.F32[j], i, indices->data.S32[j]); 241 249 numMatch++; 242 250 } else { … … 244 252 pmSourceMatch *match = pmSourceMatchAlloc(); // Match data 245 253 pmSourceMatchAdd(match, magImage->data.F32[j], magErrImage->data.F32[j], 246 i, indices->data.S32[j]);254 xImage->data.F32[j], yImage->data.F32[j], i, indices->data.S32[j]); 247 255 xMaster->data.F32[numMaster] = xImage->data.F32[j]; 248 256 yMaster->data.F32[numMaster] = yImage->data.F32[j]; … … 304 312 pmSourceMatch *match = matches->data[i]; // Match of interest 305 313 for (int j = 0; j < match->num && !source; j++) { 306 if (!isfinite(match->mag->data.F32[j]) || !isfinite(match->magErr->data.F32[j])) { 314 if (!isfinite(match->mag->data.F32[j]) || !isfinite(match->magErr->data.F32[j]) || 315 !isfinite(match->x->data.F32[j]) || !isfinite(match->y->data.F32[j])) { 307 316 continue; 308 317 } … … 365 374 double star = 0.0, starErr = 0.0; // Accumulators for star 366 375 for (int j = 0; j < match->num; j++) { 367 if (match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] ) {376 if (match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] & PM_SOURCE_MATCH_MASK_PHOT) { 368 377 continue; 369 378 } … … 396 405 pmSourceMatch *match = matches->data[i]; // Matched stars 397 406 for (int j = 0; j < match->num; j++) { 398 if (match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] ) {407 if (match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] & PM_SOURCE_MATCH_MASK_PHOT) { 399 408 continue; 400 409 } … … 424 433 pmSourceMatch *match = matches->data[i]; // Matched stars 425 434 for (int j = 0; j < match->num; j++) { 426 if (match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] ) {435 if (match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] & PM_SOURCE_MATCH_MASK_PHOT) { 427 436 continue; 428 437 } … … 543 552 pmSourceMatch *match = matches->data[i]; // Matched stars 544 553 for (int j = 0; j < match->num; j++) { 545 if (match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] ) {554 if (match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] & PM_SOURCE_MATCH_MASK_PHOT) { 546 555 continue; 547 556 } … … 564 573 if (PS_SQR(dev) > starClip * (PS_SQR(magErr) + sysErr2)) { 565 574 numRejected++; 566 match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] = 0xFF;575 match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] |= PM_SOURCE_MATCH_MASK_PHOT; 567 576 } 568 577 } … … 627 636 return NULL; 628 637 } 629 psTrace("psModules.objects", 3, "Pass 1: Determined %d/%d are photometric ", numPhoto, numImages);638 psTrace("psModules.objects", 3, "Pass 1: Determined %d/%d are photometric\n", numPhoto, numImages); 630 639 631 640 fracRej = sourceMatchRelphotReject(trans, stars, matches, zp, photo, badImage, rej1, sys1); 632 psTrace("psModules.objects", 3, "Pass 1: %f%% of measurements rejected ", fracRej * 100);641 psTrace("psModules.objects", 3, "Pass 1: %f%% of measurements rejected\n", fracRej * 100); 633 642 634 643 chi2 = sourceMatchRelphotIterate(trans, stars, badImage, matches, zp, photo, sys1); … … 649 658 return NULL; 650 659 } 651 psTrace("psModules.objects", 3, "Pass 2: Determined %d/%d are photometric ", numPhoto, numImages);660 psTrace("psModules.objects", 3, "Pass 2: Determined %d/%d are photometric\n", numPhoto, numImages); 652 661 653 662 fracRej = sourceMatchRelphotReject(trans, stars, matches, zp, photo, badImage, rej2, sys2); 654 psTrace("psModules.objects", 3, "Pass 2: %f%% of measurements rejected ", fracRej * 100);663 psTrace("psModules.objects", 3, "Pass 2: %f%% of measurements rejected\n", fracRej * 100); 655 664 656 665 chi2 = sourceMatchRelphotIterate(trans, stars, badImage, matches, zp, photo, sys2); … … 668 677 return trans; 669 678 } 679 680 681 // Iterate on the star positions and image shifts 682 // Returns the solution chi^2 683 static float sourceMatchRelastroIterate(psVector *xShift, psVector *yShift, // Shift for image 684 psVector *xStar, psVector *yStar, // Position for star 685 const psArray *matches // Array of matches 686 ) 687 { 688 psAssert(matches, "Need list of matches"); 689 690 int numImages = xShift->n; // Number of images 691 int numStars = matches->n; // Number of stars 692 693 psAssert(xShift && xShift->type.type == PS_TYPE_F32 && yShift && yShift->type.type == PS_TYPE_F32, 694 "Need shifts"); 695 psAssert(yShift->n == numImages, "Not enough shifts: %ld\n", yShift->n); 696 psAssert(xStar && xStar->type.type == PS_TYPE_F32 && yStar && yStar->type.type == PS_TYPE_F32, 697 "Need star positions"); 698 psAssert(xStar->n == numStars && yStar->n == numStars, "Not enough stars\n"); 699 700 // Solve the star positions 701 psVectorInit(xStar, NAN); 702 psVectorInit(yStar, NAN); 703 psVector *starMask = psVectorAlloc(numStars, PS_TYPE_U8); // Mask for stars 704 psVectorInit(starMask, 0xFF); 705 int numGoodStars = 0; // Number of stars with good measurements 706 for (int i = 0; i < numStars; i++) { 707 pmSourceMatch *match = matches->data[i]; // Matched stars 708 int numMeasurements = 0; // Number of unmasked measurements for star 709 double xSum = 0.0, ySum = 0.0; // Accumulators for star 710 for (int j = 0; j < match->num; j++) { 711 if (match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] & PM_SOURCE_MATCH_MASK_ASTRO) { 712 continue; 713 } 714 numMeasurements++; 715 int index = match->image->data.U32[j]; // Image index 716 717 xSum += match->x->data.F32[j] - xShift->data.F32[index]; 718 ySum += match->y->data.F32[j] - yShift->data.F32[index]; 719 } 720 if (numMeasurements > 1) { 721 // It's only a good star (contributing to the chi^2) if there's more than 1 measurement 722 numGoodStars++; 723 xStar->data.F32[i] = xSum / numMeasurements; 724 yStar->data.F32[i] = ySum / numMeasurements; 725 starMask->data.U8[i] = 0; 726 } 727 } 728 729 // Solve for the shifts 730 psVectorInit(xShift, 0.0); 731 psVectorInit(yShift, 0.0); 732 psVector *num = psVectorAlloc(numImages, PS_TYPE_S32); // Number of stars 733 psVectorInit(num, 0); 734 for (int i = 0; i < numStars; i++) { 735 if (starMask->data.U8[i]) { 736 continue; 737 } 738 pmSourceMatch *match = matches->data[i]; // Matched stars 739 for (int j = 0; j < match->num; j++) { 740 if (match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] & PM_SOURCE_MATCH_MASK_ASTRO) { 741 continue; 742 } 743 int index = match->image->data.U32[j]; // Image index 744 745 xShift->data.F32[index] += match->x->data.F32[j] - xStar->data.F32[i]; 746 yShift->data.F32[index] += match->y->data.F32[j] - yStar->data.F32[i]; 747 num->data.S32[index]++; 748 } 749 } 750 for (int i = 0; i < numImages; i++) { 751 xShift->data.F32[i] /= num->data.S32[i]; 752 yShift->data.F32[i] /= num->data.S32[i]; 753 psTrace("psModules.objects", 3, "Shift for image %d: %f,%f\n", 754 i, xShift->data.F32[i], yShift->data.F32[i]); 755 } 756 psFree(num); 757 758 // Once more through to evaluate chi^2 759 float chi2 = 0.0; // chi^2 for iteration 760 int dof = 0; // Degrees of freedom 761 for (int i = 0; i < numStars; i++) { 762 pmSourceMatch *match = matches->data[i]; // Matched stars 763 if (starMask->data.U8[i]) { 764 continue; 765 } 766 for (int j = 0; j < match->num; j++) { 767 if (match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j]) { 768 continue; 769 } 770 771 int index = match->image->data.U32[j]; // Image index 772 float dx = match->x->data.F32[j] - xShift->data.F32[index] - xStar->data.F32[i]; 773 float dy = match->y->data.F32[j] - yShift->data.F32[index] - yStar->data.F32[i]; 774 775 chi2 += PS_SQR(dx) + PS_SQR(dy); 776 dof++; 777 } 778 } 779 dof -= numGoodStars + numImages; 780 chi2 /= dof; 781 782 return chi2; 783 } 784 785 // Reject star measurements 786 // Returns the fraction of measurements that were rejected 787 static float sourceMatchRelastroReject(const psVector *xShift, const psVector *yShift, // Shifts for each image 788 const psVector *xStar, const psVector *yStar, // Positions for each star 789 const psArray *matches, // Array of matches 790 float chi2, // chi^2 from fit 791 float rej // Rejection threshold 792 ) 793 { 794 psAssert(matches, "Need list of matches"); 795 796 int numImages = xShift->n; // Number of images 797 int numStars = matches->n; // Number of stars 798 799 psAssert(xShift && xShift->type.type == PS_TYPE_F32 && yShift && yShift->type.type == PS_TYPE_F32, 800 "Need shifts"); 801 psAssert(yShift->n == numImages, "Not enough shifts: %ld\n", yShift->n); 802 psAssert(xStar && xStar->type.type == PS_TYPE_F32 && yStar && yStar->type.type == PS_TYPE_F32, 803 "Need star positions"); 804 psAssert(xStar->n == numStars && yStar->n == numStars, "Not enough stars\n"); 805 806 int numRejected = 0; // Number rejected 807 int numMeasurements = 0; // Number of measurements 808 809 float thresh = PS_SQR(rej) * chi2; // Threshold for rejection 810 811 for (int i = 0; i < numStars; i++) { 812 pmSourceMatch *match = matches->data[i]; // Matched stars 813 for (int j = 0; j < match->num; j++) { 814 if (match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] & PM_SOURCE_MATCH_MASK_ASTRO) { 815 continue; 816 } 817 numMeasurements++; 818 int index = match->image->data.U32[j]; // Image index 819 820 float dx = match->x->data.F32[j] - xShift->data.F32[index] - xStar->data.F32[i]; 821 float dy = match->y->data.F32[j] - yShift->data.F32[index] - yStar->data.F32[i]; 822 823 if (PS_SQR(dx) + PS_SQR(dy) > thresh) { 824 numRejected++; 825 match->mask->data.PS_TYPE_VECTOR_MASK_DATA[j] |= PM_SOURCE_MATCH_MASK_ASTRO; 826 } 827 } 828 } 829 830 return (float)numRejected / (float)numMeasurements; 831 } 832 833 psArray *pmSourceMatchRelastro(const psArray *matches, // Array of matches 834 int numImages, // Number of images 835 float tol, // Relative tolerance for convergence 836 int iter1, // Number of iterations for pass 1 837 float rej1, // Limit on rejection between iterations for pass 1 838 int iter2, // Number of iterations for pass 2 839 float rej2, // Limit on rejection between iterations for pass 2 840 float rejLimit // Limit on rejection between iterations 841 ) 842 { 843 PS_ASSERT_ARRAY_NON_NULL(matches, NULL); 844 845 int numStars = matches->n; // Number of stars 846 psVector *xShift = psVectorAlloc(numImages, PS_TYPE_F32); // x shift for each image 847 psVector *yShift = psVectorAlloc(numImages, PS_TYPE_F32); // y shift for each image 848 psVectorInit(xShift, 0.0); 849 psVectorInit(yShift, 0.0); 850 psVector *xStar = psVectorAlloc(numStars, PS_TYPE_F32); // x position for each star 851 psVector *yStar = psVectorAlloc(numStars, PS_TYPE_F32); // y position for each star 852 853 float chi2 = sourceMatchRelastroIterate(xShift, yShift, xStar, yStar, matches); // chi^2 for solution 854 psTrace("psModules.objects", 1, "Initial: chi^2 = %f\n", chi2); 855 float lastChi2 = INFINITY; // chi^2 on last iteration 856 float fracRej = INFINITY; // Fraction of measurements rejected 857 858 // In the first passes, the shifts are not well deteremined: use high systematic error and 859 // rejection thresholds 860 for (int i = 0; i < iter1; i++) { 861 fracRej = sourceMatchRelastroReject(xShift, yShift, xStar, yStar, matches, chi2, rej1); 862 psTrace("psModules.objects", 3, "Pass 1: %f%% of measurements rejected\n", fracRej * 100); 863 864 chi2 = sourceMatchRelastroIterate(xShift, yShift, xStar, yStar, matches); 865 psTrace("psModules.objects", 1, "Pass 1: iter = %d: chi^2 = %f rejected = %f\n", i, chi2, fracRej); 866 } 867 868 for (int i = 0; i < iter2 && (fabsf(lastChi2 - chi2) > tol * chi2 || fracRej > rejLimit); i++) { 869 lastChi2 = chi2; 870 871 fracRej = sourceMatchRelastroReject(xShift, yShift, xStar, yStar, matches, chi2, rej2); 872 psTrace("psModules.objects", 3, "Pass 2: %f%% of measurements rejected\n", fracRej * 100); 873 874 chi2 = sourceMatchRelastroIterate(xShift, yShift, xStar, yStar, matches); 875 psTrace("psModules.objects", 1, "Pass 2: iter = %d: chi^2 = %f rejected = %f\n", i, chi2, fracRej); 876 } 877 878 psFree(xStar); 879 psFree(yStar); 880 881 if (fabsf(lastChi2 - chi2) > tol * chi2 || fracRej > rejLimit) { 882 psWarning("Unable to converge to relphot solution (%f,%f)", (lastChi2 - chi2) / chi2, fracRej); 883 } 884 885 psArray *results = psArrayAlloc(numImages); // Array of results 886 for (int i = 0; i < numImages; i++) { 887 psVector *offset = results->data[i] = psVectorAlloc(2, PS_TYPE_F32); // Offset for image 888 offset->data.F32[0] = xShift->data.F32[i]; 889 offset->data.F32[1] = yShift->data.F32[i]; 890 } 891 psFree(xShift); 892 psFree(yShift); 893 894 return results; 895 } 896 -
trunk/psModules/src/objects/pmSourceMatch.h
r23241 r26076 1 1 #ifndef PM_SOURCE_MATCH_H 2 2 #define PM_SOURCE_MATCH_H 3 4 #include <pslib.h> 5 6 /// Mask values for matched sources 7 typedef enum { 8 PM_SOURCE_MATCH_MASK_PHOT = 0x01, // Source was rejected from photometry fit 9 PM_SOURCE_MATCH_MASK_ASTRO = 0x02, // Source was rejected from astrometry fit 10 } pmSourceMatchMask; 3 11 4 12 /// Matched sources … … 12 20 psVector *mag; // Magnitudes 13 21 psVector *magErr; // Magnitude errors 22 psVector *x, *y; // Positions 14 23 psVector *mask; // Mask for measurements 15 24 } pmSourceMatch; … … 26 35 PS_ASSERT_VECTOR_NON_NULL((MATCH)->mag, RVAL); \ 27 36 PS_ASSERT_VECTOR_NON_NULL((MATCH)->magErr, RVAL); \ 37 PS_ASSERT_VECTOR_NON_NULL((MATCH)->x, RVAL); \ 38 PS_ASSERT_VECTOR_NON_NULL((MATCH)->y, RVAL); \ 28 39 PS_ASSERT_VECTOR_SIZE((MATCH)->image, (MATCH)->num, RVAL); \ 29 40 PS_ASSERT_VECTOR_SIZE((MATCH)->index, (MATCH)->num, RVAL); \ 30 41 PS_ASSERT_VECTOR_SIZE((MATCH)->mag, (MATCH)->num, RVAL); \ 31 42 PS_ASSERT_VECTOR_SIZE((MATCH)->magErr, (MATCH)->num, RVAL); \ 43 PS_ASSERT_VECTOR_SIZE((MATCH)->x, (MATCH)->num, RVAL); \ 44 PS_ASSERT_VECTOR_SIZE((MATCH)->y, (MATCH)->num, RVAL); \ 32 45 } 33 46 … … 38 51 void pmSourceMatchAdd(pmSourceMatch *match, // Match data 39 52 float mag, float magErr, // Magnitude and error 53 float x, float y, // Position 40 54 int image, // Image index 41 55 int index // Source index … … 75 89 ); 76 90 91 /// Perform relative astrometry to calibrate images 92 psArray *pmSourceMatchRelastro(const psArray *matches, // Array of matches 93 int numImages, // Number of images 94 float tol, // Relative tolerance for convergence 95 int iter1, // Number of iterations for pass 1 96 float rej1, // Limit on rejection between iterations for pass 1 97 int iter2, // Number of iterations for pass 2 98 float rej2, // Limit on rejection between iterations for pass 2 99 float rejLimit // Limit on rejection between iterations 100 ); 101 77 102 #endif
Note:
See TracChangeset
for help on using the changeset viewer.
