Changeset 25975 for branches/pap/psModules/src/imcombine/pmStack.c
- Timestamp:
- Oct 30, 2009, 5:46:42 PM (17 years ago)
- File:
-
- 1 edited
-
branches/pap/psModules/src/imcombine/pmStack.c (modified) (14 diffs)
Legend:
- Unmodified
- Added
- Removed
-
branches/pap/psModules/src/imcombine/pmStack.c
r25967 r25975 30 30 #define PIXEL_LIST_BUFFER 100 // Number of entries to add to pixel list at a time 31 31 #define PIXEL_MAP_BUFFER 2 // Number of entries to add to pixel map at a time 32 #define ADD_VARIANCE // Allow additional variance (besides variance factor)?32 //#define ADD_VARIANCE // Allow additional variance (besides variance factor)? 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 1500-1 // x coordinate to examine37 #define TEST_Y 4000-1 // y coordinate to examine37 #define TEST_X 4177-1 // x coordinate to examine 38 #define TEST_Y 2964-1 // y coordinate to examine 38 39 39 40 … … 291 292 // Mark a pixel for inspection 292 293 // Value in pixel doesn't seem to agree with the stack, so need to look closer 293 static inline void combine Inspect(const psArray *inputs, // Stack data294 int x, int y, // Pixel295 int source // Source image index296 )294 static inline void combineMarkInspect(const psArray *inputs, // Stack data 295 int x, int y, // Pixel 296 int source // Source image index 297 ) 297 298 { 298 299 pmStackData *data = inputs->data[source]; // Stack data of interest … … 308 309 // Cannot possibly inspect this pixel and confirm that it's good. 309 310 // e.g., Only a single input 310 static inline void combine Reject(const psArray *inputs, // Stack data311 int x, int y, // Pixel312 int source // Source image index313 )311 static inline void combineMarkReject(const psArray *inputs, // Stack data 312 int x, int y, // Pixel 313 int source // Source image index 314 ) 314 315 { 315 316 pmStackData *data = inputs->data[source]; // Stack data of interest … … 322 323 } 323 324 325 // General test for multiple pixels 326 // Returns false if we need to re-run without suspect pixels 327 static bool combineTestGeneral(int num, // Number of good pixels 328 bool suspect, // Are there suspect pixels in the list? 329 psArray *inputs, // Original inputs (for flagging) 330 combineBuffer *buffer, // Buffer with vectors 331 int x, int y, // Coordinates of interest; frame of output image 332 int numIter, // Number of rejection iterations 333 float rej, // Number of standard deviations at which to reject 334 float sys, // Relative systematic error 335 float olympic,// Fraction of values to discard (Olympic weighted mean) 336 bool useVariance, // Use variance for rejection when combining? 337 bool safe, // Combine safely? 338 bool allowSuspect // Allow suspect values? 339 ) 340 { 341 psVector *pixelData = buffer->pixels; // Values for the pixel of interest 342 psVector *pixelMasks = buffer->masks; // Masks for the pixel of interest 343 psVector *pixelVariances = buffer->variances; // Variances for the pixel of interest 344 psVector *pixelWeights = buffer->weights; // Image weights for the pixel of interest 345 psVector *pixelSources = buffer->sources; // Sources for the pixel of interest 346 psVector *pixelLimits = buffer->limits; // Limits for the pixel of interest 347 psVector *sort = buffer->sort; // Sort buffer 348 349 350 pixelMasks->n = num; 351 psVectorInit(pixelMasks, 0); 352 353 // Set up rejection limits 354 if (useVariance) { 355 // Convert to rejection limits --- saves doing it later. 356 // Using squared rejection limit because it's cheaper than sqrts 357 float rej2 = PS_SQR(rej); // Rejection level squared 358 double sumWeights = 0.0; 359 for (int i = 0; i < num; i++) { 360 sumWeights += pixelWeights->data.F32[i]; 361 } 362 for (int i = 0; i < num; i++) { 363 // Systematic error contributes to the rejection level 364 float sysVar = PS_SQR(sys * pixelData->data.F32[i]); 365 #ifdef TESTING 366 // Correct variance for comparison against weighted mean including itself 367 float compare = 1.0 - pixelWeights->data.F32[i] / sumWeights; 368 if (x == TEST_X && y == TEST_Y) { 369 fprintf(stderr, "Variance %d (%d): %f %f %f\n", i, pixelSources->data.U16[i], 370 pixelVariances->data.F32[i], sysVar, compare); 371 } 372 #endif 373 pixelLimits->data.F32[i] = rej2 * (pixelVariances->data.F32[i] + sysVar); 374 } 375 } 376 377 int numClipped = INT_MAX; // Number of pixels clipped per iteration 378 int totalClipped = 0; // Total number of pixels clipped 379 for (int i = 0; i < numIter && numClipped > 0 && num - totalClipped > 2; i++) { 380 numClipped = 0; 381 float median = NAN; // Middle of distribution 382 float limit = NAN; // Rejection limit 383 if (!useVariance) { 384 float stdev; // Median and stdev of the combination, for rejection 385 if (!combinationMedianStdev(&median, useVariance ? NULL : &stdev, 386 pixelData, pixelMasks, sort)) { 387 if (i == 0 && suspect) { 388 // Something's not right --- repeat 389 return false; 390 } 391 for (int j = 0; j < num; j++) { 392 combineMarkReject(inputs, x, y, pixelSources->data.U16[j]); 393 } 394 return true; 395 } 396 limit = rej * stdev; 397 #ifdef TESTING 398 if (x == TEST_X && y == TEST_Y) { 399 fprintf(stderr, "Flag without variance; limit: %f\n", limit); 400 } 401 #endif 402 } else { 403 #ifdef TESTING 404 if (x == TEST_X && y == TEST_Y) { 405 fprintf(stderr, "Flag with variance...\n"); 406 } 407 #endif 408 median = combinationWeightedOlympic(pixelData, pixelWeights, pixelMasks, olympic, sort); 409 } 410 411 #ifdef TESTING 412 if (x == TEST_X && y == TEST_Y) { 413 fprintf(stderr, "Median: %f\n", median); 414 } 415 #endif 416 417 // Mask a pixel for inspection 418 #define MASK_PIXEL_FOR_INSPECTION() \ 419 if (i == 0 && suspect) { \ 420 /* Something's inconsistent, so want repeat, throwing out all suspect pixels */ \ 421 return false; \ 422 } \ 423 pixelMasks->data.PS_TYPE_VECTOR_MASK_DATA[j] = 0xFF; \ 424 combineMarkInspect(inputs, x, y, pixelSources->data.U16[j]); \ 425 numClipped++; \ 426 totalClipped++; 427 // End 428 429 for (int j = 0; j < num; j++) { 430 if (pixelMasks->data.PS_TYPE_VECTOR_MASK_DATA[j]) { 431 continue; 432 } 433 float diff = pixelData->data.F32[j] - median; // Difference from expected 434 #ifdef TESTING 435 if (x == TEST_X && y == TEST_Y) { 436 fprintf(stderr, "Testing input %d: %f\n", j, diff); 437 } 438 #endif 439 if (useVariance) { 440 // Comparing squares --- cheaper than lots of sqrts 441 // pixelVariances includes the rejection limit, from above 442 if (PS_SQR(diff) > pixelLimits->data.F32[j]) { 443 MASK_PIXEL_FOR_INSPECTION(); 444 #ifdef TESTING 445 if (x == TEST_X && y == TEST_Y) { 446 fprintf(stderr, "Flagging input %d based on variance: %f > %f\n", 447 j, diff, sqrtf(pixelLimits->data.F32[j])); 448 } 449 #endif 450 } 451 } else if (fabsf(diff) > limit) { 452 MASK_PIXEL_FOR_INSPECTION(); 453 #ifdef TESTING 454 if (x == TEST_X && y == TEST_Y) { 455 fprintf(stderr, "Flagging input %d based on distribution: %f > %f\n", 456 j, diff, limit); 457 } 458 #endif 459 } 460 } 461 } 462 463 return true; 464 } 465 466 467 // Extract vectors for simple combination/rejection operations 468 static void combineExtract(int *num, // Number of good pixels 469 bool *suspect, // Any suspect pixels? 470 combineBuffer *buffer, // Buffer with vectors 471 psImage *image, // Combined image, for output 472 psImage *mask, // Combined mask, for output 473 psImage *variance, // Combined variance map, for output 474 const psArray *inputs, // Stack data 475 const psVector *weights, // Global (single value) weights for data, or NULL 476 const psVector *addVariance, // Additional variance for data 477 const psVector *reject, // Indices of pixels to reject, or NULL 478 int x, int y, // Coordinates of interest; frame of output image 479 psImageMaskType maskVal, // Value to mask 480 psImageMaskType maskSuspect, // Value to suspect 481 bool allowSuspect // Allow suspect values? 482 ) 483 { 484 // Rudimentary error checking 485 assert(buffer); 486 assert(image); 487 assert(mask); 488 assert(inputs); 489 490 psVector *pixelData = buffer->pixels; // Values for the pixel of interest 491 psVector *pixelVariances = variance ? buffer->variances : NULL; // Variances for the pixel of interest 492 psVector *pixelWeights = buffer->weights; // Image weights for the pixel of interest 493 psVector *pixelSources = buffer->sources; // Sources for the pixel of interest 494 psVector *pixelLimits = buffer->limits; // Limits for the pixel of interest 495 496 // Extract the pixel and mask data 497 int numGood = 0; // Number of good pixels 498 for (int i = 0, j = 0; i < inputs->n; i++) { 499 // Check if this pixel has been rejected. Assumes that the rejection pixel list is sorted --- it 500 // should be because of how pixelMapGenerate works 501 if (reject && reject->data.U16[j] == i) { 502 j++; 503 continue; 504 } 505 506 pmStackData *data = inputs->data[i]; // Stack data of interest 507 if (!data) { 508 continue; 509 } 510 511 int xIn = x - data->readout->col0, yIn = y - data->readout->row0; // Coordinates on input readout 512 psImage *mask = data->readout->mask; // Mask of interest 513 if (mask->data.PS_TYPE_IMAGE_MASK_DATA[yIn][xIn] & maskVal) { 514 continue; 515 } 516 if (mask->data.PS_TYPE_IMAGE_MASK_DATA[yIn][xIn] & maskSuspect) { 517 if (!allowSuspect) { 518 combineMarkReject(inputs, x, y, i); 519 continue; 520 } 521 if (suspect) { 522 *suspect = true; 523 } 524 } 525 526 psImage *image = data->readout->image; // Image of interest 527 psImage *variance = data->readout->variance; // Variance map of interest 528 pixelData->data.F32[numGood] = image->data.F32[yIn][xIn]; 529 if (variance) { 530 pixelVariances->data.F32[numGood] = variance->data.F32[yIn][xIn] * addVariance->data.F32[i]; 531 } 532 pixelWeights->data.F32[numGood] = data->weight; 533 pixelSources->data.U16[numGood] = i; 534 numGood++; 535 } 536 pixelData->n = numGood; 537 if (variance) { 538 pixelVariances->n = numGood; 539 } 540 pixelWeights->n = numGood; 541 pixelSources->n = numGood; 542 pixelLimits->n = numGood; 543 *num = numGood; 544 545 #ifdef TESTING 546 if (x == TEST_X && y == TEST_Y) { 547 for (int i = 0; i < numGood; i++) { 548 fprintf(stderr, "Input %d (%" PRIu16 "): %f %f (%f) %f\n", 549 i, pixelSources->data.U16[i], pixelData->data.F32[i], pixelVariances->data.F32[i], 550 addVariance->data.F32[i], pixelWeights->data.F32[i]); 551 } 552 } 553 #endif 554 555 return; 556 } 557 558 559 // Combine pixels 560 static void combinePixels(psImage *image, // Combined image, for output 561 psImage *mask, // Combined mask, for output 562 psImage *variance, // Combined variance map, for output 563 int num, // Number of good pixels 564 combineBuffer *buffer, // Buffer with vectors 565 int x, int y, // Coordinates of interest; frame of output image 566 psImageMaskType bad, // Value for bad pixels 567 bool safe // Safe combination? 568 ) 569 { 570 psVector *pixelData = buffer->pixels; // Values for the pixel of interest 571 psVector *pixelVariances = variance ? buffer->variances : NULL; // Variances for the pixel of interest 572 psVector *pixelWeights = buffer->weights; // Image weights for the pixel of interest 573 574 // Default option is that the pixel is bad 575 float imageValue = NAN, varianceValue = NAN; // Value for combined image and variance map 576 psImageMaskType maskValue = bad; // Value for combined mask 577 switch (num) { 578 case 0: { 579 // Nothing to combine: it's bad 580 #ifdef TESTING 581 if (x == TEST_X && y == TEST_Y) { 582 fprintf(stderr, "No inputs to combine, pixel is bad.\n"); 583 } 584 #endif 585 break; 586 } 587 case 1: { 588 // Accept the single pixel unless we have to be safe 589 if (!safe) { 590 #ifdef TESTING 591 if (x == TEST_X && y == TEST_Y) { 592 fprintf(stderr, "Single input to combine, safety off.\n"); 593 } 594 #endif 595 imageValue = pixelData->data.F32[0]; 596 if (variance) { 597 varianceValue = pixelVariances->data.F32[0]; 598 } 599 maskValue = 0; 600 } 601 #ifdef TESTING 602 else if (x == TEST_X && y == TEST_Y) { 603 fprintf(stderr, "Single input to combine, safety on, pixel is bad.\n"); 604 } 605 #endif 606 break; 607 } 608 case 2: { 609 // Automatically accept the mean of the pixels only if we're not playing safe 610 if (!safe) { 611 float mean, var; // Mean and variance from combination 612 if (combinationMeanVariance(&mean, &var, pixelData, pixelVariances, pixelWeights)) { 613 imageValue = mean; 614 varianceValue = var; 615 maskValue = 0; 616 #ifdef TESTING 617 if (x == TEST_X && y == TEST_Y) { 618 fprintf(stderr, "Two inputs to combine using unsafe --> %f %f\n", mean, var); 619 } 620 #endif 621 } 622 } 623 #ifdef TESTING 624 else { 625 if (x == TEST_X && y == TEST_Y) { 626 fprintf(stderr, "Two inputs to combine, safety on, pixel is bad\n"); 627 } 628 } 629 #endif 630 break; 631 } 632 default: { 633 // Can combine without too much worrying 634 float mean, var; // Mean and variance of the combination 635 if (!combinationMeanVariance(&mean, &var, pixelData, pixelVariances, pixelWeights)) { 636 break; 637 } 638 imageValue = mean; 639 varianceValue = var; 640 maskValue = 0; 641 #ifdef TESTING 642 if (x == TEST_X && y == TEST_Y) { 643 fprintf(stderr, "Combined inputs: %f %f\n", mean, var); 644 } 645 #endif 646 break; 647 } 648 } 649 650 image->data.F32[y][x] = imageValue; 651 mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] = maskValue; 652 if (variance) { 653 variance->data.F32[y][x] = varianceValue; 654 } 655 656 return; 657 } 658 659 660 // Test pixels to be combined 661 // Returns false to repeat without suspect pixels 662 static bool combineTest(int num, // Number of good pixels 663 bool suspect, // Does the stack contain suspect pixels? 664 psArray *inputs, // Original inputs (for flagging) 665 combineBuffer *buffer, // Buffer with vectors 666 int x, int y, // Coordinates of interest; frame of output image 667 int numIter, // Number of rejection iterations 668 float rej, // Number of standard deviations at which to reject 669 float sys, // Relative systematic error 670 float olympic,// Fraction of values to discard (Olympic weighted mean) 671 bool useVariance, // Use variance for rejection when combining? 672 bool safe, // Combine safely? 673 bool allowSuspect // Allow suspect pixels in the combination? 674 ) 675 { 676 if (numIter <= 0) { 677 return true; 678 } 679 680 psVector *pixelData = buffer->pixels; // Values for the pixel of interest 681 psVector *pixelVariances = buffer->variances; // Variances for the pixel of interest 682 psVector *pixelSources = buffer->sources; // Sources for the pixel of interest 683 684 switch (num) { 685 case 0: 686 break; 687 case 1: 688 if (safe) { 689 combineMarkReject(inputs, x, y, pixelSources->data.U16[0]); 690 } 691 break; 692 case 2: { 693 if (useVariance) { 694 // Use variance to check that the two are consistent 695 float diff = 0.5 * (pixelData->data.F32[0] - pixelData->data.F32[1]); // Mean flux difference 696 float var1 = pixelVariances->data.F32[0]; // Variance of first 697 float var2 = pixelVariances->data.F32[1]; // Variance of second 698 // Systematic error contributes to the rejection level 699 var1 += PS_SQR(sys * pixelData->data.F32[0]); 700 var2 += PS_SQR(sys * pixelData->data.F32[1]); 701 702 float sigma2 = var1 + var2; // Combined variance 703 if (PS_SQR(diff) > PS_SQR(rej) * sigma2) { 704 // Not consistent: don't believe either! 705 if (allowSuspect && suspect) { 706 combineMarkReject(inputs, x, y, pixelSources->data.U16[0]); 707 combineMarkReject(inputs, x, y, pixelSources->data.U16[1]); 708 } else { 709 combineMarkInspect(inputs, x, y, pixelSources->data.U16[0]); 710 combineMarkInspect(inputs, x, y, pixelSources->data.U16[1]); 711 } 712 #ifdef TESTING 713 if (x == TEST_X && y == TEST_Y) { 714 fprintf(stderr, "Flagged both pixels (%f > %f x %f\n)", 715 diff, rej, sqrtf(sigma2)); 716 } 717 #endif 718 } 719 } else if (safe) { 720 // Can't test them, and we want to be safe, so reject 721 combineMarkReject(inputs, x, y, pixelSources->data.U16[0]); 722 combineMarkReject(inputs, x, y, pixelSources->data.U16[1]); 723 } 724 break; 725 } 726 case 3: { 727 // Want to be a bit careful on the rejection than for a larger number of inputs 728 if (!useVariance) { 729 return combineTestGeneral(num, suspect, inputs, buffer, x, y, numIter, rej, sys, 730 olympic, useVariance, safe, allowSuspect); 731 } 732 733 // Differences between pixel values 734 float diff01 = pixelData->data.F32[0] - pixelData->data.F32[1]; 735 float diff12 = pixelData->data.F32[1] - pixelData->data.F32[2]; 736 float diff20 = pixelData->data.F32[2] - pixelData->data.F32[0]; 737 // Variance for each pixel 738 float var0 = pixelVariances->data.F32[0] + PS_SQR(sys * pixelData->data.F32[0]); 739 float var1 = pixelVariances->data.F32[1] + PS_SQR(sys * pixelData->data.F32[1]); 740 float var2 = pixelVariances->data.F32[2] + PS_SQR(sys * pixelData->data.F32[2]); 741 float rej2 = PS_SQR(rej); // Rejection level squared 742 // Errors in pixel differences 743 float err01 = var0 + var1; 744 float err12 = var1 + var2; 745 float err20 = var2 + var0; 746 747 int badPairs = 0; // Number of bad pairs 748 bool bad01 = false, bad12 = false, bad20 = false; // Pair is bad? 749 if (PS_SQR(diff01) > rej2 * err01) { 750 bad01 = true; 751 badPairs++; 752 } 753 if (PS_SQR(diff12) > rej2 * err12) { 754 bad12 = true; 755 badPairs++; 756 } 757 if (PS_SQR(diff20) > rej2 * err20) { 758 bad20 = true; 759 badPairs++; 760 } 761 762 if (badPairs > 0 && allowSuspect && suspect) { 763 return false; 764 } 765 766 switch (badPairs) { 767 case 0: 768 // Nothing to worry about! 769 break; 770 case 1: 771 // Can't tell which image is bad, so be sure to get it 772 if (bad01) { 773 combineMarkInspect(inputs, x, y, pixelSources->data.U16[0]); 774 combineMarkInspect(inputs, x, y, pixelSources->data.U16[1]); 775 break; 776 } 777 if (bad12) { 778 combineMarkInspect(inputs, x, y, pixelSources->data.U16[1]); 779 combineMarkInspect(inputs, x, y, pixelSources->data.U16[2]); 780 break; 781 } 782 if (bad20) { 783 combineMarkInspect(inputs, x, y, pixelSources->data.U16[2]); 784 combineMarkInspect(inputs, x, y, pixelSources->data.U16[0]); 785 break; 786 } 787 psAbort("Should never get here"); 788 case 2: 789 if (bad01 && bad12) { 790 // 2 and 0 are good 791 combineMarkInspect(inputs, x, y, pixelSources->data.U16[1]); 792 break; 793 } 794 if (bad12 && bad20) { 795 // 0 and 1 are good 796 combineMarkInspect(inputs, x, y, pixelSources->data.U16[2]); 797 break; 798 } 799 if (bad20 && bad01) { 800 // 1 and 2 are good 801 combineMarkInspect(inputs, x, y, pixelSources->data.U16[0]); 802 break; 803 } 804 psAbort("Should never get here"); 805 case 3: 806 // Everything's bad 807 combineMarkInspect(inputs, x, y, pixelSources->data.U16[0]); 808 combineMarkInspect(inputs, x, y, pixelSources->data.U16[1]); 809 combineMarkInspect(inputs, x, y, pixelSources->data.U16[2]); 810 break; 811 } 812 break; 813 } 814 default: { 815 return combineTestGeneral(num, suspect, inputs, buffer, x, y, numIter, rej, sys, 816 olympic, useVariance, safe, allowSuspect); 817 } 818 } 819 820 return true; 821 } 822 823 824 825 #if 0 324 826 // Given a stack of images, combine with optional rejection. 325 827 // Pixels in the stack that are rejected are marked for subsequent inspection … … 333 835 int x, int y, // Coordinates of interest; frame of output image 334 836 psImageMaskType maskVal, // Value to mask 837 psImageMaskType suspect, // Value to suspect 335 838 psImageMaskType bad, // Value to give bad pixels 336 839 int numIter, // Number of rejection iterations … … 341 844 bool safe, // Combine safely? 342 845 bool rejection, // Reject values marked for inspection from combination? 343 combineBuffer *buffer // Buffer for combination; to avoid multiple allocations 846 combineBuffer *buffer, // Buffer for combination; to avoid multiple allocations 847 bool allowSuspect // Allow suspect pixels in the combination? 344 848 ) 345 849 { … … 361 865 psVector *sort = buffer->sort; // Sort buffer 362 866 363 // Extract the pixel and mask data364 int num = 0; // Number of good images365 for (int i = 0, j = 0; i < inputs->n; i++) {366 // Check if this pixel has been rejected. Assumes that the rejection pixel list is sorted --- it367 // should be because of how pixelMapGenerate works368 if (reject && reject->data.U16[j] == i) {369 j++;370 continue;371 }372 373 pmStackData *data = inputs->data[i]; // Stack data of interest374 if (!data) {375 continue;376 }377 378 int xIn = x - data->readout->col0, yIn = y - data->readout->row0; // Coordinates on input readout379 psImage *mask = data->readout->mask; // Mask of interest380 if (mask->data.PS_TYPE_IMAGE_MASK_DATA[yIn][xIn] & maskVal) {381 continue;382 }383 384 psImage *image = data->readout->image; // Image of interest385 psImage *variance = data->readout->variance; // Variance map of interest386 pixelData->data.F32[num] = image->data.F32[yIn][xIn];387 if (variance) {388 pixelVariances->data.F32[num] = variance->data.F32[yIn][xIn] * addVariance->data.F32[i];389 }390 pixelWeights->data.F32[num] = data->weight;391 pixelSources->data.U16[num] = i;392 num++;393 }394 pixelData->n = num;395 if (variance) {396 pixelVariances->n = num;397 }398 pixelWeights->n = num;399 pixelSources->n = num;400 pixelLimits->n = num;401 402 #ifdef TESTING403 if (x == TEST_X && y == TEST_Y) {404 for (int i = 0; i < num; i++) {405 fprintf(stderr, "Input %d (%" PRIu16 "): %f %f %f\n",406 i, pixelSources->data.U16[i], pixelData->data.F32[i], pixelVariances->data.F32[i],407 pixelWeights->data.F32[i]);408 }409 }410 int numRejected = 0; // Number of rejected inputs411 #endif412 867 413 868 // The sensible thing to do varies according to how many good pixels there are. … … 439 894 } else { 440 895 if (!rejection) { 441 combine Reject(inputs, x, y, pixelSources->data.U16[0]);896 combineMarkReject(inputs, x, y, pixelSources->data.U16[0]); 442 897 } 443 898 #ifdef TESTING … … 478 933 float sigma2 = var1 + var2; // Combined variance 479 934 if (PS_SQR(diff) > PS_SQR(rej) * sigma2) { 480 // Not consistent: mark both for inspection935 // Not consistent: don't believe either! 481 936 if (rejection) { 482 937 imageValue = NAN; 483 938 varianceValue = NAN; 484 939 maskValue = bad; 940 } else if (allowSuspect && numSuspect > 0) { 941 combineMarkReject(inputs, x, y, pixelSources->data.U16[0]); 942 combineMarkReject(inputs, x, y, pixelSources->data.U16[1]); 485 943 } else { 486 combine Inspect(inputs, x, y, pixelSources->data.U16[0]);487 combine Inspect(inputs, x, y, pixelSources->data.U16[1]);944 combineMarkInspect(inputs, x, y, pixelSources->data.U16[0]); 945 combineMarkInspect(inputs, x, y, pixelSources->data.U16[1]); 488 946 } 489 947 #ifdef TESTING … … 494 952 numRejected = 2; 495 953 #endif 954 } 955 } 956 break; 957 } 958 case 3: { 959 // Can combine without too much worrying, but want to be a bit careful on the rejection 960 float mean, var; // Mean and variance of the combination 961 if (!combinationMeanVariance(&mean, &var, pixelData, pixelVariances, pixelWeights)) { 962 break; 963 } 964 imageValue = mean; 965 varianceValue = var; 966 maskValue = 0; 967 #ifdef TESTING 968 if (x == TEST_X && y == TEST_Y) { 969 fprintf(stderr, "Combined inputs: %f %f\n", mean, var); 970 } 971 #endif 972 973 if (numIter > 0) { 974 if (!useVariance) { 975 combineRejectionGeneral(); 976 } else { 977 // Differences between pixel values 978 float diff01 = pixelData->data.F32[0] - pixelData->data.F32[1]; 979 float diff12 = pixelData->data.F32[1] - pixelData->data.F32[2]; 980 float diff20 = pixelData->data.F32[2] - pixelData->data.F32[0]; 981 // Variance for each pixel 982 float var0 = pixelVariances->data.F32[0] + PS_SQR(sys * pixelData->data.F32[0]); 983 float var1 = pixelVariances->data.F32[1] + PS_SQR(sys * pixelData->data.F32[1]); 984 float var2 = pixelVariances->data.F32[2] + PS_SQR(sys * pixelData->data.F32[2]); 985 float rej2 = PS_SQR(rej); // Rejection level squared 986 // Errors in pixel differences 987 float err01 = var0 + var1; 988 float err12 = var1 + var2; 989 float err20 = var2 + var0; 990 991 int badPairs = 0; // Number of bad pairs 992 bool bad01 = false, bad12 = false, bad20 = false; // Pair is bad? 993 if (PS_SQR(diff01) > rej2 * err01) { 994 bad01 = true; 995 badPairs++; 996 } 997 if (PS_SQR(diff12) > rej2 * err12) { 998 bad12 = true; 999 badPairs++; 1000 } 1001 if (PS_SQR(diff20) > rej2 * err20) { 1002 bad20 = true; 1003 badPairs++; 1004 } 1005 1006 switch (badPairs) { 1007 case 0: 1008 // Nothing to worry about! 1009 break; 1010 case 1: 1011 // Can't tell which image is bad, so be sure to get it 1012 if (bad01) { 1013 combineInspect(inputs, x, y, pixelSources->data.U16[0]); 1014 combineInspect(inputs, x, y, pixelSources->data.U16[1]); 1015 break; 1016 } 1017 if (bad12) { 1018 combineInspect(inputs, x, y, pixelSources->data.U16[1]); 1019 combineInspect(inputs, x, y, pixelSources->data.U16[2]); 1020 break; 1021 } 1022 if (bad20) { 1023 combineInspect(inputs, x, y, pixelSources->data.U16[2]); 1024 combineInspect(inputs, x, y, pixelSources->data.U16[0]); 1025 break; 1026 } 1027 psAbort("Should never get here"); 1028 case 2: 1029 if (bad01 && bad12) { 1030 // 2 and 0 are good 1031 combineInspect(inputs, x, y, pixelSources->data.U16[1]); 1032 break; 1033 } 1034 if (bad12 && bad20) { 1035 // 0 and 1 are good 1036 combineInspect(inputs, x, y, pixelSources->data.U16[2]); 1037 break; 1038 } 1039 if (bad20 && bad01) { 1040 // 1 and 2 are good 1041 combineInspect(inputs, x, y, pixelSources->data.U16[0]); 1042 break; 1043 } 1044 psAbort("Should never get here"); 1045 case 3: 1046 // Everything's bad 1047 combineInspect(inputs, x, y, pixelSources->data.U16[0]); 1048 combineInspect(inputs, x, y, pixelSources->data.U16[1]); 1049 combineInspect(inputs, x, y, pixelSources->data.U16[2]); 1050 break; 1051 } 496 1052 } 497 1053 } … … 515 1071 516 1072 // Prepare for clipping iteration 517 if (numIter > 0) {518 pixelMasks->n = num;519 psVectorInit(pixelMasks, 0);520 if (useVariance) {521 // Convert to rejection limits --- saves doing it later.522 // Using squared rejection limit because it's cheaper than sqrts523 float rej2 = PS_SQR(rej); // Rejection level squared524 double sumWeights = 0.0;525 for (int i = 0; i < num; i++) {526 sumWeights += pixelWeights->data.F32[i];527 }528 for (int i = 0; i < num; i++) {529 // Systematic error contributes to the rejection level530 float sysVar = PS_SQR(sys * pixelData->data.F32[i]);531 #ifdef TESTING532 // Correct variance for comparison against weighted mean including itself533 float compare = 1.0 - pixelWeights->data.F32[i] / sumWeights;534 if (x == TEST_X && y == TEST_Y) {535 fprintf(stderr, "Variance %d (%d): %f %f %f\n", i, pixelSources->data.U16[i],536 pixelVariances->data.F32[i], sysVar, compare);537 }538 #endif539 540 pixelLimits->data.F32[i] = rej2 * (pixelVariances->data.F32[i] + sysVar);541 }542 }543 }544 545 // The clipping that follows is solely to identify suspect pixels.546 // These suspect pixels will be inspected in more detail by other functions.547 int numClipped = INT_MAX; // Number of pixels clipped per iteration548 int totalClipped = 0; // Total number of pixels clipped549 for (int i = 0; i < numIter && numClipped > 0 && num - totalClipped > 2; i++) {550 numClipped = 0;551 float median = NAN; // Middle of distribution552 float limit = NAN; // Rejection limit553 if (!useVariance) {554 float stdev; // Median and stdev of the combination, for rejection555 if (!combinationMedianStdev(&median, useVariance ? NULL : &stdev,556 pixelData, pixelMasks, sort)) {557 psWarning("Bad median/stdev at %d,%d", x, y);558 break;559 }560 limit = rej * stdev;561 #ifdef TESTING562 if (x == TEST_X && y == TEST_Y) {563 fprintf(stderr, "Rejecting without variance; rejection limit: %f\n", limit);564 }565 #endif566 } else {567 #ifdef TESTING568 if (x == TEST_X && y == TEST_Y) {569 fprintf(stderr, "Rejecting with variance...\n");570 }571 #endif572 median = combinationWeightedOlympic(pixelData, pixelWeights, pixelMasks, olympic, sort);573 }574 575 #ifdef TESTING576 if (x == TEST_X && y == TEST_Y) {577 fprintf(stderr, "Median: %f\n", median);578 }579 #endif580 581 582 // Mask a pixel for inspection583 #define MASK_PIXEL_FOR_INSPECTION() \584 pixelMasks->data.PS_TYPE_VECTOR_MASK_DATA[j] = 0xff; \585 if (!rejection) { \586 combineInspect(inputs, x, y, pixelSources->data.U16[j]); \587 } \588 numClipped++; \589 totalClipped++;590 591 for (int j = 0; j < num; j++) {592 if (pixelMasks->data.PS_TYPE_VECTOR_MASK_DATA[j]) {593 continue;594 }595 float diff = pixelData->data.F32[j] - median; // Difference from expected596 #ifdef TESTING597 if (x == TEST_X && y == TEST_Y) {598 fprintf(stderr, "Testing input %d for rejection: %f\n", j, diff);599 }600 #endif601 if (useVariance) {602 // Comparing squares --- cheaper than lots of sqrts603 // pixelVariances includes the rejection limit, from above604 if (PS_SQR(diff) > pixelLimits->data.F32[j]) {605 MASK_PIXEL_FOR_INSPECTION();606 #ifdef TESTING607 if (x == TEST_X && y == TEST_Y) {608 fprintf(stderr, "Rejecting input %d based on variance: %f > %f\n",609 j, diff, sqrtf(pixelLimits->data.F32[j]));610 }611 numRejected++;612 #endif613 }614 } else if (fabsf(diff) > limit) {615 MASK_PIXEL_FOR_INSPECTION();616 #ifdef TESTING617 if (x == TEST_X && y == TEST_Y) {618 fprintf(stderr, "Rejecting input %d based on distribution: %f > %f\n",619 j, diff, limit);620 }621 numRejected++;622 #endif623 }624 }625 }626 627 if (rejection && totalClipped > 0) {628 // Get rid of the masked values629 // The alternative to this is to make combinationMeanVariance() accept a mask630 int good = 0; // Index of good value631 for (int i = 0; i < num; i++) {632 if (pixelMasks->data.PS_TYPE_VECTOR_MASK_DATA[i]) {633 continue;634 }635 if (i != good) {636 pixelData->data.F32[good] = pixelData->data.F32[i];637 pixelVariances->data.F32[good] = pixelVariances->data.F32[i];638 pixelWeights->data.F32[good] = pixelWeights->data.F32[i];639 pixelData->data.F32[good] = pixelData->data.F32[i];640 }641 good++;642 }643 pixelData->n = good;644 pixelVariances->n = good;645 pixelWeights->n = good;646 if (combinationMeanVariance(&mean, &var, pixelData, pixelVariances, pixelWeights)) {647 imageValue = mean;648 varianceValue = var;649 maskValue = 0;650 } else {651 imageValue = NAN;652 varianceValue = NAN;653 maskValue = bad;654 }655 }656 1073 657 1074 break; … … 659 1076 } 660 1077 661 image->data.F32[y][x] = imageValue;662 mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] = maskValue;663 if (variance) {664 variance->data.F32[y][x] = varianceValue;665 }666 667 #ifdef TESTING668 mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] = num;669 if (variance) {670 variance->data.F32[y][x] = num > 0 ? 1.0 - (float)numRejected / (float)num : 0.0;671 }672 #endif673 674 1078 return; 675 1079 } 676 1080 #endif 677 1081 678 1082 // Ensure the input array of pmStackData is valid, and get some details out of it … … 830 1234 831 1235 /// Stack input images 832 bool pmStackCombine(pmReadout *combined, psArray *input, psImageMaskType maskVal, psImageMaskType bad,833 int kernelSize, int numIter, float rej, float sys, float olympic,1236 bool pmStackCombine(pmReadout *combined, psArray *input, psImageMaskType maskVal, psImageMaskType maskSuspect, 1237 psImageMaskType bad, int kernelSize, int numIter, float rej, float sys, float olympic, 834 1238 bool useVariance, bool safe, bool rejection) 835 1239 { … … 946 1350 if (x == TEST_X && y == TEST_Y) { 947 1351 fprintf(stderr, "Rejected inputs: "); 948 for (int i = 0; i < reject->n; i++) { 949 fprintf(stderr, "%d ", reject->data.U16[i]); 1352 if (!reject) { 1353 fprintf(stderr, "<none>\n"); 1354 } else { 1355 for (int i = 0; i < reject->n; i++) { 1356 fprintf(stderr, "%d ", reject->data.U16[i]); 1357 } 1358 fprintf(stderr, "\n"); 950 1359 } 951 fprintf(stderr, "\n");952 1360 } 953 1361 #endif 954 1362 } 955 combinePixels(combinedImage, combinedMask, combinedVariance, input, weights, 956 addVariance, reject, x, y, maskVal, bad, numIter, rej, sys, olympic, 957 useVariance, safe, rejection, buffer); 1363 1364 int num; // Number of good pixels 1365 bool suspect; // Suspect pixels in stack? 1366 combineExtract(&num, &suspect, buffer, combinedImage, combinedMask, combinedVariance, 1367 input, weights, addVariance, reject, x, y, maskVal, maskSuspect, true); 1368 if (numIter == 0) { 1369 combinePixels(combinedImage, combinedMask, combinedVariance, 1370 num, buffer, x, y, bad, safe); 1371 } else { 1372 if (combineTest(num, suspect, input, buffer, x, y, numIter, rej, sys, olympic, 1373 useVariance, safe, true)) { 1374 // Need to repeat without suspect pixels 1375 combineExtract(&num, &suspect, buffer, combinedImage, combinedMask, combinedVariance, 1376 input, weights, addVariance, reject, x, y, maskVal, maskSuspect, false); 1377 combineTest(num, suspect, input, buffer, x, y, numIter, rej, sys, olympic, 1378 useVariance, safe, false); 1379 } 1380 } 958 1381 } 959 1382 }
Note:
See TracChangeset
for help on using the changeset viewer.
