Changeset 31634 for trunk/psModules/src/imcombine/pmStack.c
- Timestamp:
- Jun 15, 2011, 6:10:15 PM (15 years ago)
- File:
-
- 1 edited
-
trunk/psModules/src/imcombine/pmStack.c (modified) (14 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psModules/src/imcombine/pmStack.c
r31203 r31634 22 22 #include <pslib.h> 23 23 24 #include <gsl/gsl_cdf.h> 25 24 26 #include "pmHDU.h" 25 27 #include "pmFPA.h" … … 35 37 36 38 37 # if (0)39 //# if (0) 38 40 #define TESTING // Enable test output 39 #define TEST_X 3145 // x coordinate to examine 40 #define TEST_Y 2334 // y coordinate to examine 41 /* #define TEST_X 5745 // x coordinate to examine */ 42 /* #define TEST_Y 5331 // y coordinate to examine */ 43 #define TEST_X 25 44 #define TEST_Y 25 41 45 #define TEST_RADIUS 0.5 // Radius to examine 42 # endif46 //# endif 43 47 44 48 # ifdef TESTING … … 100 104 return; 101 105 } 106 107 // KMM functions to do bimodality rejection of pixels 108 float gaussian(float x, float m, float s) { 109 return(pow(s * sqrt(2 * M_PI),-1) * exp(-0.5 * pow( (x - m) / s, 2))); 110 } 111 112 static void KMMcalculate(const psVector *values, 113 float *Punimodal,int *iter, 114 float *mU, float *sU, 115 float *pi1, float *m1, float *s1, 116 float *pi2, float *m2, float *s2) { 117 assert(values); 118 assert(values->type.type == PS_TYPE_F32); 119 120 double logL_bimodal = 0, logL_unimodal; 121 psVector *P1 = psVectorAlloc(values->n,PS_TYPE_F32); 122 psVector *P2 = psVectorAlloc(values->n,PS_TYPE_F32); 123 int i; 124 /* int debug = 0; */ 125 126 // Calculate unimodal properties 127 *mU = 0; 128 *sU = 0; 129 logL_unimodal = 0; 130 for (i = 0; i < values->n; i++) { // Calculate mean 131 *mU += values->data.F32[i]; 132 } 133 *mU /= values->n; 134 for (i = 0; i < values->n; i++) { // Calculate sigma 135 *sU += pow(values->data.F32[i] - *mU,2); 136 } 137 *sU = sqrt(*sU / values->n); 138 for (i = 0; i < values->n; i++) { // Calculate log likelihood 139 logL_unimodal += log(gaussian(values->data.F32[i],*mU,*sU)); 140 } 141 142 // Do EM loop 143 float dL = 0; 144 float oldL = -999; 145 *iter = 0; 146 logL_bimodal = logL_unimodal; 147 *m1 = *mU - 3 * *sU; 148 *m2 = *mU + 3 * *sU; 149 *s1 = *sU / 2; 150 *s2 = *sU / 2; 151 *pi1 = 0.5; 152 *pi2 = 0.5; 153 154 float g1,g2,norm; 155 float w1,w2; 156 157 // These should be options. 158 float KMM_TOLERANCE = 1e-6; 159 int KMM_MAX_ITERATIONS = 500; 160 float KMM_SMALL_NUMBER = 1e-5; 161 while (((dL > KMM_TOLERANCE)||(*iter < 3))&&(*iter < KMM_MAX_ITERATIONS)) { 162 *iter += 1; 163 dL = fabs(logL_bimodal - oldL); 164 oldL = logL_bimodal; 165 /* if (debug == 1) { */ 166 /* fprintf(stderr,"KMM: %d %f %f %f %f (%f %f %f) (%f %f %f)\n", */ 167 /* *iter,logL_unimodal,logL_bimodal,oldL,dL, */ 168 /* *m1,*s1,*pi1, */ 169 /* *m2,*s2,*pi2); */ 170 /* } */ 171 // Expectation/P-stage 172 for (i = 0; i < values->n; i++) { // Calculate probabilities for each mode 173 g1 = gaussian(values->data.F32[i],*m1,*s1); 174 g2 = gaussian(values->data.F32[i],*m2,*s2); 175 norm = (*pi1 * g1 + *pi2 * g2); 176 P1->data.F32[i] = (*pi1 * g1) / norm; 177 P2->data.F32[i] = (*pi2 * g2) / norm; 178 } 179 // Maximization/M-stage 180 logL_bimodal = 0; 181 w1 = 0; 182 w2 = 0; 183 for (i = 0; i < values->n; i++) { // Calculate log likelihood 184 if (!((*pi1 == 0)||(*pi2 == 0))) { 185 logL_bimodal += log(*pi1 * gaussian(values->data.F32[i],*m1,*s1) + 186 *pi2 * gaussian(values->data.F32[i],*m2,*s2)); 187 } 188 } 189 *m1 = 0; 190 *m2 = 0; 191 *s1 = 0; 192 *s2 = 0; 193 for (i = 0; i < values->n; i++) { // Calculate new means and weights 194 *m1 += values->data.F32[i] * P1->data.F32[i]; 195 *m2 += values->data.F32[i] * P2->data.F32[i]; 196 197 w1 += P1->data.F32[i]; 198 w2 += P2->data.F32[i]; 199 } 200 *m1 /= w1; 201 *m2 /= w2; 202 for (i = 0; i < values->n; i++) { // Calculate new sigmas 203 *s1 += pow(values->data.F32[i] - *m1,2) * P1->data.F32[i]; 204 *s2 += pow(values->data.F32[i] - *m2,2) * P2->data.F32[i]; 205 } 206 *s1 = sqrt(*s1 / w1); 207 *s2 = sqrt(*s2 / w2); 208 209 *pi1 = w1 / values->n; 210 *pi2 = w2 / values->n; 211 212 if (!isfinite(*pi1)) { // finite checks 213 *pi1 = 0.0; 214 } 215 if (!isfinite(*pi2)) { // finite checks 216 *pi2 = 0.0; 217 } 218 if (*s1 == 0) { // sigma may not be zero 219 *s1 = KMM_SMALL_NUMBER * *m1; 220 } 221 if (*s2 == 0) { // sigma may not be zero 222 *s2 = KMM_SMALL_NUMBER * *m2; 223 } 224 } // End EM phase 225 226 // Calculate Punimodal 227 double lambda = -2.0 * (logL_unimodal - logL_bimodal); 228 int df = 2 + 2 * 1; // I can't find my reference on this. 229 if (lambda > 0) { 230 *Punimodal = gsl_cdf_chisq_Q(lambda,df); 231 } 232 else { // If lambda <= 0, then logL_unimodal > logL_bimodal, so Punimodal must be by definition 1.0 233 *Punimodal = 1.0; 234 } 235 psFree(P1); 236 psFree(P2); 237 } 238 239 static void KMMFindPopular(const psVector *values, float *Punimodal, float *mean, float *sigma, float *pi) { 240 float KMM_MINIMUM_PVALUE = 0.05; // Should be an option. 241 float mU,sU; 242 float pi1,m1,s1,pi2,m2,s2; 243 int iter; 244 245 assert(values); 246 assert(values->type.type == PS_TYPE_F32); 247 248 KMMcalculate(values,Punimodal,&iter, 249 &mU,&sU, 250 &pi1,&m1,&s1, 251 &pi2,&m2,&s2); 252 253 if (*Punimodal > KMM_MINIMUM_PVALUE) { 254 // Is unimodal 255 *mean = mU; 256 *sigma = sU; 257 *pi = 1.0; 258 } 259 else { 260 // Is bimodal. Select most popular mode. 261 if (pi1 >= pi2) { 262 *mean = m1; 263 *sigma = s1; 264 *pi = pi1; 265 } 266 else { 267 *mean = m2; 268 *sigma = s2; 269 *pi = pi2; 270 } 271 } 272 } 273 274 102 275 103 276 … … 285 458 return; 286 459 } 287 460 #if (0) 461 // Currently unused function to reject inputs for a given pixel(x,y) based on the selecting the 462 // most popular mode after running the KMM test, and rejecting all inputs that belong to the 463 // least popular mode. 464 static void KMMRejectUnpopular(const psArray *inputs, int x, int y) { 465 float KMM_MINIMUM_PVALUE = 0.05; 466 float mU,sU; 467 float Punimodal,pi1,m1,s1,pi2,m2,s2; 468 int iter; 469 int j,k; 470 471 psVector *values = psVectorAlloc(inputs->n, PS_TYPE_F32); 472 k = 0; 473 for (j = 0; j < inputs->n; j++) { 474 pmStackData *data = inputs->data[j]; // Stack data of interest 475 if (!data) { 476 k++; 477 continue; 478 } 479 psImage *image = data->readout->image; // Image of interest 480 int xIn = x - data->readout->col0, yIn = y - data->readout->row0; // Coordinates on input readout 481 values->data.F32[j - k] = image->data.F32[yIn][xIn]; 482 } 483 484 KMMcalculate(values,&Punimodal,&iter, 485 &mU,&sU, 486 &pi1,&m1,&s1, 487 &pi2,&m2,&s2); 488 489 CHECKPIX(x, y, 490 "KMM Unpopular Test: %d,%d: Puni: %g in %d",x,y,Punimodal,iter); 491 if (Punimodal < KMM_MINIMUM_PVALUE) { 492 int i; 493 float g1,g2,norm; 494 float P1,P2; 495 496 for (i = 0; i < values->n; i++) { // Calculate probabilities for each mode 497 g1 = gaussian(values->data.F32[i],m1,s1); 498 g2 = gaussian(values->data.F32[i],m2,s2); 499 norm = (pi1 * g1 + pi2 * g2); 500 P1 = (pi1 * g1) / norm; 501 P2 = (pi2 * g2) / norm; 502 503 CHECKPIX(x, y, "KMM Unpopular Rejection: %d,%d: %f(%d): %d %f %f:(%f %f %f ) %f:(%f %f %f) rejection? %d %d\n", 504 x, y, 505 Punimodal,iter, 506 i, values->data.F32[i], 507 P1,m1,s1,pi1, 508 P2,m2,s2,pi2, 509 (pi1 > pi2)&&(P1 < P2), 510 (pi1 < pi2)&&(P1 > P2)); 511 if ((pi1 > pi2)&&(P1 < P2)) { // mode 1 is more popular, but this element belongs to mode 2 512 combineMarkReject(inputs,x,y,i); 513 } 514 if ((pi1 < pi2)&&(P1 > P2)) { // mode 2 is more popular, but this element belongs to mode 1 515 combineMarkReject(inputs,x,y,i); 516 } 517 } 518 } 519 psFree(values); 520 // else do nothing. 521 } 522 523 // Currently unused function to reject inputs for a given pixel(x,y) based on the selecting the 524 // faintest mode as determined by the KMM test, and rejecting all inputs that belong to the brighest. 525 static void KMMRejectBright(const psArray *inputs, int x, int y) { 526 float KMM_MINIMUM_PVALUE = 0.05; 527 float mU,sU; 528 float Punimodal,pi1,m1,s1,pi2,m2,s2; 529 int iter; 530 int j; 531 532 psVector *values = psVectorAlloc(inputs->n, PS_TYPE_F32); 533 for (j = 0; j < inputs->n; j++) { 534 pmStackData *data = inputs->data[j]; // Stack data of interest 535 psImage *image = data->readout->image; // Image of interest 536 int xIn = x - data->readout->col0, yIn = y - data->readout->row0; // Coordinates on input readout 537 values->data.F32[j] = image->data.F32[yIn][xIn]; 538 } 539 540 KMMcalculate(values,&Punimodal,&iter, 541 &mU,&sU, 542 &pi1,&m1,&s1, 543 &pi2,&m2,&s2); 544 if (Punimodal < KMM_MINIMUM_PVALUE) { 545 int i; 546 float g1,g2,norm; 547 float P1,P2; 548 549 for (i = 0; i < values->n; i++) { // Calculate probabilities for each mode 550 g1 = gaussian(values->data.F32[i],m1,s1); 551 g2 = gaussian(values->data.F32[i],m2,s2); 552 norm = (pi1 * g1 + pi2 * g2); 553 P1 = (pi1 * g1) / norm; 554 P2 = (pi2 * g2) / norm; 555 556 if ((m1 > m2)&&(P1 > P2)) { // m1 is larger, and this element belongs to mode 1 557 combineMarkReject(inputs,x,y,i); 558 } 559 if ((m1 < m2)&&(P1 < P2)) { // m2 is larger, and this element belongs to mode 2 560 combineMarkReject(inputs,x,y,i); 561 } 562 } 563 } 564 psFree(values); 565 // else do nothing. 566 } 567 #endif // End if(0) to prevent KMMReject{Unpopular|Bright} from being defined. 288 568 289 569 // Extract vectors for simple combination/rejection operations … … 332 612 memset (nGoodBits, 0, 16*sizeof(int)); 333 613 334 // Extract the pixel and mask data 614 615 // Extract the pixel and mask data 335 616 int numGood = 0; // Number of good pixels 336 617 for (int i = 0, j = 0; i < inputs->n; i++) { … … 364 645 continue; 365 646 } 366 647 367 648 int xIn = x - data->readout->col0, yIn = y - data->readout->row0; // Coordinates on input readout 368 649 psImage *mask = data->readout->mask; // Mask of interest … … 400 681 CHECKPIX(x, y, "keep: %d : %x (badMask = %x)\n", i, mask->data.PS_TYPE_IMAGE_MASK_DATA[yIn][xIn], *badMask); 401 682 } 683 402 684 pixelData->n = numGood; 403 685 if (variance) { … … 426 708 if (PS_SQR(x - TEST_X) + PS_SQR(y - TEST_Y) <= PS_SQR(TEST_RADIUS)) { 427 709 for (int i = 0; i < numGood; i++) { 428 fprintf(stderr,"Input %d, pixel %d,%d (%" PRIu16 "): %f %f (%f) %f %f %d %x %x -> %x %x\n",710 fprintf(stderr,"Input %d, pixel %d,%d (%" PRIu16 "): %f %f (%f) %f %f %d %x %x -> %x %x\n", 429 711 i, x, y, pixelSources->data.U16[i], pixelData->data.F32[i], pixelVariances->data.F32[i], 430 712 addVariance->data.F32[i], pixelWeights->data.F32[i], pixelExps->data.F32[i], … … 567 849 psVector *pixelLimits = buffer->limits; // Is the pixel suspect? 568 850 851 // KMM values; 852 float Punimodal = 1.0,KMMmean = NAN,KMMsigma = NAN,KMMpi = NAN; 853 int KMM_MINIMUM_INPUTS = 6; 854 bool useKMM = false; 855 if (num >= KMM_MINIMUM_INPUTS) { 856 useKMM = true; 857 } 858 569 859 // Set up rejection limits 570 860 float rej2 = PS_SQR(rej); // Rejection level squared … … 573 863 // Using squared rejection limit because it's cheaper than sqrts 574 864 double sumWeights = 0.0; 865 866 // Determine the systematic error from the most popular population in the sample 867 // This should probably be an option 868 if (useKMM) { 869 KMMFindPopular(pixelData,&Punimodal,&KMMmean,&KMMsigma,&KMMpi); 870 CHECKPIX(x,y,"KMM Popularity Contest: (%d,%d) Puni: %g Mean: %f Sigma %f Pi: %f\n", 871 x,y,Punimodal,KMMmean,KMMsigma,KMMpi); 872 } 575 873 for (int i = 0; i < num; i++) { 576 874 sumWeights += pixelWeights->data.F32[i]; 577 875 } 578 876 for (int i = 0; i < num; i++) { 579 // Systematic error contributes to the rejection level 580 float sysVar = PS_SQR(sys * pixelData->data.F32[i]); 877 // Systematic error contributes to the rejection level 878 float sysVar; 879 if (useKMM) { // If we can trust KMM results, set the systematic variance 880 sysVar = PS_SQR(KMMsigma); 881 } 882 else { // Otherwise, use the 10% systematic variance we've done in the past. 883 sysVar = PS_SQR(sys * pixelData->data.F32[i]); 884 } 885 581 886 CHECKPIX(x, y, "Variance %d (%d), pixel %d,%d: %f %f %f\n", 582 887 i, pixelSources->data.U16[i], x, y, … … 727 1032 default: { 728 1033 if (useVariance) { 729 float median = combinationWeightedOlympic(pixelData, pixelWeights, 730 olympic, buffer->sort); // Median for stack 1034 float median; 1035 if ((useKMM)&&(Punimodal < 0.05)) { 1036 median = KMMmean; 1037 } 1038 else { 1039 median = combinationWeightedOlympic(pixelData, pixelWeights, 1040 olympic, buffer->sort); // Median for stack 1041 } 1042 731 1043 CHECKPIX(x, y, "Flag with variance pixel %d,%d: median = %f\n", x, y, median); 732 1044 float worst = -INFINITY; // Largest deviation 733 1045 for (int j = 0; j < num; j++) { 734 float diff = pixelData->data.F32[j] - median; // Difference from expected1046 float diff = pixelData->data.F32[j] - median; // Difference from expected 735 1047 CHECKPIX(x, y, "Testing input %d for pixel %d,%d: %f\n", j, x, y, diff); 736 1048 … … 738 1050 // pixelVariances includes the rejection limit, from above 739 1051 float diff2 = PS_SQR(diff); // Square difference 1052 CHECKPIX(x,y, "Input %d, pixel %d,%d (%" PRIu16 "): %f %f (%f) %f %f :: %f %f %f %f\n", 1053 i, x, y, pixelSources->data.U16[j], pixelData->data.F32[j], pixelVariances->data.F32[j], 1054 1.0, pixelWeights->data.F32[j], 1.0, 1055 pixelLimits->data.F32[j], diff2, diff2 / pixelLimits->data.F32[j],worst); 1056 740 1057 if (diff2 > pixelLimits->data.F32[j]) { 741 1058 float dev = diff2 / pixelLimits->data.F32[j]; // Deviation … … 1131 1448 } 1132 1449 1450 /* // Pre-reject inputs using KMM bimodality test. */ 1451 /* if (1) { */ 1452 /* /\* KMMRejectUnpopular(input,x,y); *\/ */ 1453 /* rejection = true; */ 1454 /* } */ 1455 1133 1456 // Set up rejection list 1134 1457 psArray *pixelMap = NULL; // Map of pixels to source … … 1141 1464 for (int x = minInputCols; x < maxInputCols; x++) { 1142 1465 CHECKPIX(x, y, "Combining pixel %d,%d: %x %x %f %f %f %f %d %d %d\n", x, y, badMaskBits, blankMaskBits, iter, rej, sys, olympic, useVariance, safe, rejection); 1466 1467 /* // Pre-reject inputs using KMM bimodality test. */ 1468 /* if (1) { */ 1469 /* KMMRejectUnpopular(input,x,y); */ 1470 /* /\* rejection = true; *\/ */ 1471 /* } */ 1472 /* else { */ 1473 /* KMMRejectBright(input,x,y); */ 1474 /* } */ 1143 1475 1144 1476 #ifdef TESTING
Note:
See TracChangeset
for help on using the changeset viewer.
