Changeset 41879
- Timestamp:
- Nov 3, 2021, 12:00:45 PM (5 years ago)
- Location:
- branches/eam_branches/psModules.20211028/src/imcombine
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/eam_branches/psModules.20211028/src/imcombine/pmStack.c
r41873 r41879 113 113 // KMM functions to do bimodality rejection of pixels 114 114 double gaussian(float x, float m, float s) { 115 return(pow(s * sqrt(2 * M_PI),-1) * exp(-0.5 * pow( (x - m) / s, 2)));115 return(pow(s * sqrt(2 * M_PI),-1) * exp(-0.5 * pow( (x - m) / s, 2))); 116 116 } 117 117 … … 122 122 float *pi2, float *m2, float *s2, 123 123 int xyrdebug) { 124 assert(values);125 assert(values->type.type == PS_TYPE_F32);124 assert(values); 125 assert(values->type.type == PS_TYPE_F32); 126 126 127 double logL_bimodal = 0, logL_unimodal;128 psVector *P1 = psVectorAlloc(values->n,PS_TYPE_F32);129 psVector *P2 = psVectorAlloc(values->n,PS_TYPE_F32);130 int i;131 int discrepant_index = -1;132 double discrepant_value = 0;127 double logL_bimodal = 0, logL_unimodal; 128 psVector *P1 = psVectorAlloc(values->n,PS_TYPE_F32); 129 psVector *P2 = psVectorAlloc(values->n,PS_TYPE_F32); 130 int i; 131 int discrepant_index = -1; 132 double discrepant_value = 0; 133 133 /* int debug = 0; */ 134 134 135 // Calculate unimodal properties136 *mU = 0;137 *sU = 0;138 logL_unimodal = 0;139 for (i = 0; i < values->n; i++) { // Calculate mean140 *mU += values->data.F32[i];141 }142 *mU /= values->n;143 for (i = 0; i < values->n; i++) { // Calculate sigma144 *sU += pow(values->data.F32[i] - *mU,2);145 146 // Attempt to guess better starting values147 if (pow(values->data.F32[i] - *mU,2) > discrepant_value) {148 discrepant_value = pow(values->data.F32[i] - *mU,2);149 discrepant_index = i;150 }135 // Calculate unimodal properties 136 *mU = 0; 137 *sU = 0; 138 logL_unimodal = 0; 139 for (i = 0; i < values->n; i++) { // Calculate mean 140 *mU += values->data.F32[i]; 141 } 142 *mU /= values->n; 143 for (i = 0; i < values->n; i++) { // Calculate sigma 144 *sU += pow(values->data.F32[i] - *mU,2); 145 146 // Attempt to guess better starting values 147 if (pow(values->data.F32[i] - *mU,2) > discrepant_value) { 148 discrepant_value = pow(values->data.F32[i] - *mU,2); 149 discrepant_index = i; 150 } 151 151 152 }153 *sU = sqrt(*sU / values->n);154 for (i = 0; i < values->n; i++) { // Calculate log likelihood155 logL_unimodal += log(gaussian(values->data.F32[i],*mU,*sU));156 }157 158 if (xyrdebug == 1) {159 fprintf(stderr,"KMM uni: %d %f %d (%f %f)\n",160 xyrdebug,logL_unimodal,discrepant_index,161 *mU,*sU);162 }163 164 // Do EM loop165 float dL = 0;166 float oldL = -999;167 *iter = 0;168 logL_bimodal = logL_unimodal;169 170 if (discrepant_index == -1) {171 *m1 = *mU - 3 * *sU;172 *m2 = *mU + 3 * *sU;173 *s1 = *sU / 2;174 *s2 = *sU / 2;175 }176 else {177 // This is an attempt to speed up convergence. Find the largest contributor to sigma, and set one mean178 // to that value. Set the other mean to the mean of all other points with this one removed. Next,179 // set the sigmas to be equal to each other. Take the value of sigma to be such that a point equidistant180 // to the initial values of the two modes is equally not believed by either mode (2.5 sigma away).152 } 153 *sU = sqrt(*sU / values->n); 154 for (i = 0; i < values->n; i++) { // Calculate log likelihood 155 logL_unimodal += log(gaussian(values->data.F32[i],*mU,*sU)); 156 } 157 158 if (xyrdebug == 1) { 159 fprintf(stderr,"KMM uni: %d %f %d (%f %f)\n", 160 xyrdebug,logL_unimodal,discrepant_index, 161 *mU,*sU); 162 } 163 164 // Do EM loop 165 float dL = 0; 166 float oldL = -999; 167 *iter = 0; 168 logL_bimodal = logL_unimodal; 169 170 if (discrepant_index == -1) { 171 *m1 = *mU - 3 * *sU; 172 *m2 = *mU + 3 * *sU; 173 *s1 = *sU / 2; 174 *s2 = *sU / 2; 175 } 176 else { 177 // This is an attempt to speed up convergence. Find the largest contributor to sigma, and set one mean 178 // to that value. Set the other mean to the mean of all other points with this one removed. Next, 179 // set the sigmas to be equal to each other. Take the value of sigma to be such that a point equidistant 180 // to the initial values of the two modes is equally not believed by either mode (2.5 sigma away). 181 181 182 discrepant_value = values->data.F32[discrepant_index];182 discrepant_value = values->data.F32[discrepant_index]; 183 183 184 if (discrepant_value > *mU) {185 *m1 = ((*mU * values->n) - discrepant_value) / (values->n - 1);186 *m2 = discrepant_value;187 }188 else {189 *m1 = discrepant_value;190 *m2 = ((*mU * values->n) - discrepant_value) / (values->n - 1);191 }192 *s1 = fabs((*m1 - *m2) / 5);193 *s2 = *s1;194 }184 if (discrepant_value > *mU) { 185 *m1 = ((*mU * values->n) - discrepant_value) / (values->n - 1); 186 *m2 = discrepant_value; 187 } 188 else { 189 *m1 = discrepant_value; 190 *m2 = ((*mU * values->n) - discrepant_value) / (values->n - 1); 191 } 192 *s1 = fabs((*m1 - *m2) / 5); 193 *s2 = *s1; 194 } 195 195 196 *pi1 = 0.5;197 *pi2 = 0.5;198 199 //MEH -- need to be double to help avoid 0 in norm200 double g1,g2,norm;201 float w1,w2;202 203 // These should be options.204 float KMM_TOLERANCE = 1e-6;205 int KMM_MAX_ITERATIONS = 30;206 float KMM_SMALL_NUMBER = 1e-5;207 while (((dL > KMM_TOLERANCE)||(*iter < 3))&&(*iter < KMM_MAX_ITERATIONS)) {208 *iter += 1;209 dL = fabs(logL_bimodal - oldL);210 oldL = logL_bimodal;196 *pi1 = 0.5; 197 *pi2 = 0.5; 198 199 //MEH -- need to be double to help avoid 0 in norm 200 double g1,g2,norm; 201 float w1,w2; 202 203 // These should be options. 204 float KMM_TOLERANCE = 1e-6; 205 int KMM_MAX_ITERATIONS = 30; 206 float KMM_SMALL_NUMBER = 1e-5; 207 while (((dL > KMM_TOLERANCE)||(*iter < 3))&&(*iter < KMM_MAX_ITERATIONS)) { 208 *iter += 1; 209 dL = fabs(logL_bimodal - oldL); 210 oldL = logL_bimodal; 211 211 /* if (debug == 1) { */ 212 212 /* fprintf(stderr,"KMM: %d %f %f %f %f (%f %f %f) (%f %f %f)\n", */ … … 216 216 /* } */ 217 217 218 if (xyrdebug == 1) { 219 fprintf(stderr,"KMM EM iter: %d %f %f %f %f (%f %f %e) (%f %f %e)\n", 220 *iter,logL_unimodal,logL_bimodal,oldL,dL, 221 *m1,*s1,*pi1, 222 *m2,*s2,*pi2); 223 } 224 225 // Expectation/P-stage 226 for (i = 0; i < values->n; i++) { // Calculate probabilities for each mode 227 g1 = gaussian(values->data.F32[i],*m1,*s1); 228 g2 = gaussian(values->data.F32[i],*m2,*s2); 229 norm = (*pi1 * g1 + *pi2 * g2); 230 //MEH -- must protect denom from norm=0 231 if (norm > 0) { 232 P1->data.F32[i] = (*pi1 * g1) / norm; 233 P2->data.F32[i] = (*pi2 * g2) / norm; 234 } else { 235 P1->data.F32[i] = 0.0; 236 P2->data.F32[i] = 0.0; 237 } 238 239 if (xyrdebug == 1) { 240 fprintf(stderr,"KMM EM-P loop: %d %d %le %le %le\n", 241 *iter,i,norm,g1,g2); 242 } 243 244 } 245 // Maximization/M-stage 246 logL_bimodal = 0; 247 w1 = 0; 248 w2 = 0; 249 for (i = 0; i < values->n; i++) { // Calculate log likelihood 250 if (!((*pi1 == 0)||(*pi2 == 0))) { 251 logL_bimodal += log(*pi1 * gaussian(values->data.F32[i],*m1,*s1) + 252 *pi2 * gaussian(values->data.F32[i],*m2,*s2)); 253 } 254 } 255 *m1 = 0; 256 *m2 = 0; 257 *s1 = 0; 258 *s2 = 0; 259 for (i = 0; i < values->n; i++) { // Calculate new means and weights 260 *m1 += values->data.F32[i] * P1->data.F32[i]; 261 *m2 += values->data.F32[i] * P2->data.F32[i]; 262 263 w1 += P1->data.F32[i]; 264 w2 += P2->data.F32[i]; 265 266 if (xyrdebug == 1) { 267 fprintf(stderr,"KMM EM-M loop: %d %d (%f %f %f %e) (%f %f %f %e)\n", 268 *iter,i,*m1,values->data.F32[i],w1,P1->data.F32[i],*m2,values->data.F32[i],w2,P2->data.F32[i]); 269 } 270 271 } 272 *m1 /= w1; 273 *m2 /= w2; 274 for (i = 0; i < values->n; i++) { // Calculate new sigmas 275 *s1 += pow(values->data.F32[i] - *m1,2) * P1->data.F32[i]; 276 *s2 += pow(values->data.F32[i] - *m2,2) * P2->data.F32[i]; 277 } 278 *s1 = sqrt(*s1 / w1); 279 *s2 = sqrt(*s2 / w2); 280 281 *pi1 = w1 / values->n; 282 *pi2 = w2 / values->n; 283 284 if (!isfinite(*pi1)) { // finite checks 285 *pi1 = 0.0; 286 } 287 if (!isfinite(*pi2)) { // finite checks 288 *pi2 = 0.0; 289 } 290 if (*s1 == 0) { // sigma may not be zero -- MEH -- nor <0 and need additive offset if m~0 291 *s1 = fabsf(KMM_SMALL_NUMBER * *m1) + KMM_SMALL_NUMBER; 292 } 293 if (*s2 == 0) { // sigma may not be zero 294 *s2 = fabsf(KMM_SMALL_NUMBER * *m2) + KMM_SMALL_NUMBER; 295 } 296 297 if (xyrdebug == 1) { 298 fprintf(stderr,"KMM EM end: %d %f %f %f %f (%f %e %e %f) (%f %e %e %f)\n", 299 *iter,logL_unimodal,logL_bimodal,oldL,dL, 300 *m1,*s1,*pi1,w1, 301 *m2,*s2,*pi2,w2); 302 } 303 304 } // End EM phase 305 306 // Calculate Punimodal 307 double lambda = -2.0 * (logL_unimodal - logL_bimodal); 308 int df = 2 + 2 * 1; // I can't find my reference on this. 309 if (lambda > 0) { 310 *Punimodal = gsl_cdf_chisq_Q(lambda,df); 311 } 312 else { // If lambda <= 0, then logL_unimodal > logL_bimodal, so Punimodal must be by definition 1.0 313 *Punimodal = 1.0; 314 } 315 218 316 if (xyrdebug == 1) { 219 fprintf(stderr,"KMM EM iter: %d %f %f %f %f (%f %f %e) (%f %f %e)\n", 220 *iter,logL_unimodal,logL_bimodal,oldL,dL, 221 *m1,*s1,*pi1, 222 *m2,*s2,*pi2); 317 fprintf(stderr,"KMM calc Puni: %d %f %d %f\n", 318 xyrdebug,lambda,df,*Punimodal); 223 319 } 224 320 225 // Expectation/P-stage 226 for (i = 0; i < values->n; i++) { // Calculate probabilities for each mode 227 g1 = gaussian(values->data.F32[i],*m1,*s1); 228 g2 = gaussian(values->data.F32[i],*m2,*s2); 229 norm = (*pi1 * g1 + *pi2 * g2); 230 //MEH -- must protect denom from norm=0 231 if (norm > 0) { 232 P1->data.F32[i] = (*pi1 * g1) / norm; 233 P2->data.F32[i] = (*pi2 * g2) / norm; 234 } else { 235 P1->data.F32[i] = 0.0; 236 P2->data.F32[i] = 0.0; 237 } 238 239 if (xyrdebug == 1) { 240 fprintf(stderr,"KMM EM-P loop: %d %d %le %le %le\n", 241 *iter,i,norm,g1,g2); 242 } 243 244 } 245 // Maximization/M-stage 246 logL_bimodal = 0; 247 w1 = 0; 248 w2 = 0; 249 for (i = 0; i < values->n; i++) { // Calculate log likelihood 250 if (!((*pi1 == 0)||(*pi2 == 0))) { 251 logL_bimodal += log(*pi1 * gaussian(values->data.F32[i],*m1,*s1) + 252 *pi2 * gaussian(values->data.F32[i],*m2,*s2)); 253 } 254 } 255 *m1 = 0; 256 *m2 = 0; 257 *s1 = 0; 258 *s2 = 0; 259 for (i = 0; i < values->n; i++) { // Calculate new means and weights 260 *m1 += values->data.F32[i] * P1->data.F32[i]; 261 *m2 += values->data.F32[i] * P2->data.F32[i]; 262 263 w1 += P1->data.F32[i]; 264 w2 += P2->data.F32[i]; 265 266 if (xyrdebug == 1) { 267 fprintf(stderr,"KMM EM-M loop: %d %d (%f %f %f %e) (%f %f %f %e)\n", 268 *iter,i,*m1,values->data.F32[i],w1,P1->data.F32[i],*m2,values->data.F32[i],w2,P2->data.F32[i]); 269 } 270 271 } 272 *m1 /= w1; 273 *m2 /= w2; 274 for (i = 0; i < values->n; i++) { // Calculate new sigmas 275 *s1 += pow(values->data.F32[i] - *m1,2) * P1->data.F32[i]; 276 *s2 += pow(values->data.F32[i] - *m2,2) * P2->data.F32[i]; 277 } 278 *s1 = sqrt(*s1 / w1); 279 *s2 = sqrt(*s2 / w2); 280 281 *pi1 = w1 / values->n; 282 *pi2 = w2 / values->n; 283 284 if (!isfinite(*pi1)) { // finite checks 285 *pi1 = 0.0; 286 } 287 if (!isfinite(*pi2)) { // finite checks 288 *pi2 = 0.0; 289 } 290 if (*s1 == 0) { // sigma may not be zero -- MEH -- nor <0 and need additive offset if m~0 291 *s1 = fabsf(KMM_SMALL_NUMBER * *m1) + KMM_SMALL_NUMBER; 292 } 293 if (*s2 == 0) { // sigma may not be zero 294 *s2 = fabsf(KMM_SMALL_NUMBER * *m2) + KMM_SMALL_NUMBER; 295 } 296 297 if (xyrdebug == 1) { 298 fprintf(stderr,"KMM EM end: %d %f %f %f %f (%f %e %e %f) (%f %e %e %f)\n", 299 *iter,logL_unimodal,logL_bimodal,oldL,dL, 300 *m1,*s1,*pi1,w1, 301 *m2,*s2,*pi2,w2); 302 } 303 304 } // End EM phase 305 306 // Calculate Punimodal 307 double lambda = -2.0 * (logL_unimodal - logL_bimodal); 308 int df = 2 + 2 * 1; // I can't find my reference on this. 309 if (lambda > 0) { 310 *Punimodal = gsl_cdf_chisq_Q(lambda,df); 311 } 312 else { // If lambda <= 0, then logL_unimodal > logL_bimodal, so Punimodal must be by definition 1.0 313 *Punimodal = 1.0; 314 } 315 316 if (xyrdebug == 1) { 317 fprintf(stderr,"KMM calc Puni: %d %f %d %f\n", 318 xyrdebug,lambda,df,*Punimodal); 319 } 320 321 psFree(P1); 322 psFree(P2); 321 psFree(P1); 322 psFree(P2); 323 323 } 324 324 325 325 static void KMMFindPopular(const psVector *values, float *Punimodal, float *mean, float *sigma, float *pi, int xyrdebug) { 326 float KMM_MINIMUM_PVALUE = 0.05; // Should be an option.327 float mU,sU;328 float pi1,m1,s1,pi2,m2,s2;329 int iter;330 331 assert(values);332 assert(values->type.type == PS_TYPE_F32);326 float KMM_MINIMUM_PVALUE = 0.05; // Should be an option. 327 float mU,sU; 328 float pi1,m1,s1,pi2,m2,s2; 329 int iter; 330 331 assert(values); 332 assert(values->type.type == PS_TYPE_F32); 333 333 334 KMMcalculate(values,Punimodal,&iter,335 &mU,&sU,336 &pi1,&m1,&s1,337 &pi2,&m2,&s2,xyrdebug);334 KMMcalculate(values,Punimodal,&iter, 335 &mU,&sU, 336 &pi1,&m1,&s1, 337 &pi2,&m2,&s2,xyrdebug); 338 338 /* fprintf(stdout,"%g %g : %g %g %g : %g %g %g : %g %d\t", */ 339 339 /* mU,sU, */ … … 347 347 /* } */ 348 348 /* fprintf(stdout,"\n"); */ 349 if (*Punimodal > KMM_MINIMUM_PVALUE) { 350 // Is unimodal 351 *mean = mU; 352 *sigma = sU; 353 *pi = 1.0; 354 } 355 else { 356 // Is bimodal. Select most popular mode. 357 if (pi1 >= pi2) { 358 *mean = m1; 359 *sigma = s1; 360 *pi = pi1; 349 if (*Punimodal > KMM_MINIMUM_PVALUE) { 350 // Is unimodal 351 *mean = mU; 352 *sigma = sU; 353 *pi = 1.0; 361 354 } 362 355 else { 363 *mean = m2; 364 *sigma = s2; 365 *pi = pi2; 366 } 367 } 356 // Is bimodal. Select most popular mode. 357 if (pi1 >= pi2) { 358 *mean = m1; 359 *sigma = s1; 360 *pi = pi1; 361 } 362 else { 363 *mean = m2; 364 *sigma = s2; 365 *pi = pi2; 366 } 367 } 368 368 } 369 369 … … 381 381 const psVector *exps, // Exposure times to combine 382 382 const psVector *weights // Weights to apply 383 )383 ) 384 384 { 385 385 assert(mean); … … 411 411 sumWeight += weights->data.F32[i]; 412 412 if (variances) { 413 // sumVarianceWeight += variances->data.F32[i] * PS_SQR(weights->data.F32[i]);414 sumVarianceWeight += 1 / variances->data.F32[i];413 // sumVarianceWeight += variances->data.F32[i] * PS_SQR(weights->data.F32[i]); 414 sumVarianceWeight += 1 / variances->data.F32[i]; 415 415 } 416 416 if (exps) { … … 427 427 *mean = sumValueWeight / sumWeight; 428 428 if (var) { 429 //*var = sumVarianceWeight / PS_SQR(sumWeight);430 *var = 1 / sumVarianceWeight;429 //*var = sumVarianceWeight / PS_SQR(sumWeight); 430 *var = 1 / sumVarianceWeight; 431 431 } 432 432 if (exp) { … … 445 445 const psVector *values, // Values to combine 446 446 psVector *sortBuffer // Buffer for sorting 447 )447 ) 448 448 { 449 449 assert(values); … … 496 496 float frac, // Fraction to discard 497 497 psVector *sortBuffer // Buffer for sorting 498 )498 ) 499 499 { 500 500 int numGood = values->n; // Number of good values … … 527 527 int x, int y, // Pixel 528 528 int source // Source image index 529 )529 ) 530 530 { 531 531 CHECKPIX(x, y, "Marking image %d, pixel %d,%d for inspection\n", source, x, y); … … 545 545 int x, int y, // Pixel 546 546 int source // Source image index 547 )547 ) 548 548 { 549 549 CHECKPIX(x, y, "Marking pixel image %d, pixel %d,%d for rejection\n", source, x, y); … … 561 561 // least popular mode. 562 562 static void KMMRejectUnpopular(const psArray *inputs, int x, int y) { 563 float KMM_MINIMUM_PVALUE = 0.05;564 float mU,sU;565 float Punimodal,pi1,m1,s1,pi2,m2,s2;566 int iter;567 int j,k;568 569 psVector *values = psVectorAlloc(inputs->n, PS_TYPE_F32);570 k = 0;571 for (j = 0; j < inputs->n; j++) {572 pmStackData *data = inputs->data[j]; // Stack data of interest573 if (!data) {574 k++;575 continue;576 }577 psImage *image = data->readout->image; // Image of interest578 int xIn = x - data->readout->col0, yIn = y - data->readout->row0; // Coordinates on input readout579 values->data.F32[j - k] = image->data.F32[yIn][xIn];580 }563 float KMM_MINIMUM_PVALUE = 0.05; 564 float mU,sU; 565 float Punimodal,pi1,m1,s1,pi2,m2,s2; 566 int iter; 567 int j,k; 568 569 psVector *values = psVectorAlloc(inputs->n, PS_TYPE_F32); 570 k = 0; 571 for (j = 0; j < inputs->n; j++) { 572 pmStackData *data = inputs->data[j]; // Stack data of interest 573 if (!data) { 574 k++; 575 continue; 576 } 577 psImage *image = data->readout->image; // Image of interest 578 int xIn = x - data->readout->col0, yIn = y - data->readout->row0; // Coordinates on input readout 579 values->data.F32[j - k] = image->data.F32[yIn][xIn]; 580 } 581 581 582 KMMcalculate(values,&Punimodal,&iter,583 &mU,&sU,584 &pi1,&m1,&s1,585 &pi2,&m2,&s2);586 587 CHECKPIX(x, y,588 "KMM Unpopular Test: %d,%d: Puni: %g in %d",x,y,Punimodal,iter);589 if (Punimodal < KMM_MINIMUM_PVALUE) {590 int i;591 float g1,g2,norm;592 float P1,P2;593 594 for (i = 0; i < values->n; i++) { // Calculate probabilities for each mode595 g1 = gaussian(values->data.F32[i],m1,s1);596 g2 = gaussian(values->data.F32[i],m2,s2);597 norm = (pi1 * g1 + pi2 * g2);598 P1 = (pi1 * g1) / norm;599 P2 = (pi2 * g2) / norm;600 601 CHECKPIX(x, y, "KMM Unpopular Rejection: %d,%d: %f(%d): %d %f %f:(%f %f %f ) %f:(%f %f %f) rejection? %d %d\n",602 x, y,603 Punimodal,iter,604 i, values->data.F32[i],605 P1,m1,s1,pi1,606 P2,m2,s2,pi2,607 (pi1 > pi2)&&(P1 < P2),608 (pi1 < pi2)&&(P1 > P2));609 if ((pi1 > pi2)&&(P1 < P2)) { // mode 1 is more popular, but this element belongs to mode 2610 combineMarkReject(inputs,x,y,i);611 }612 if ((pi1 < pi2)&&(P1 > P2)) { // mode 2 is more popular, but this element belongs to mode 1613 combineMarkReject(inputs,x,y,i);614 }615 }616 }617 psFree(values);618 // else do nothing.582 KMMcalculate(values,&Punimodal,&iter, 583 &mU,&sU, 584 &pi1,&m1,&s1, 585 &pi2,&m2,&s2); 586 587 CHECKPIX(x, y, 588 "KMM Unpopular Test: %d,%d: Puni: %g in %d",x,y,Punimodal,iter); 589 if (Punimodal < KMM_MINIMUM_PVALUE) { 590 int i; 591 float g1,g2,norm; 592 float P1,P2; 593 594 for (i = 0; i < values->n; i++) { // Calculate probabilities for each mode 595 g1 = gaussian(values->data.F32[i],m1,s1); 596 g2 = gaussian(values->data.F32[i],m2,s2); 597 norm = (pi1 * g1 + pi2 * g2); 598 P1 = (pi1 * g1) / norm; 599 P2 = (pi2 * g2) / norm; 600 601 CHECKPIX(x, y, "KMM Unpopular Rejection: %d,%d: %f(%d): %d %f %f:(%f %f %f ) %f:(%f %f %f) rejection? %d %d\n", 602 x, y, 603 Punimodal,iter, 604 i, values->data.F32[i], 605 P1,m1,s1,pi1, 606 P2,m2,s2,pi2, 607 (pi1 > pi2)&&(P1 < P2), 608 (pi1 < pi2)&&(P1 > P2)); 609 if ((pi1 > pi2)&&(P1 < P2)) { // mode 1 is more popular, but this element belongs to mode 2 610 combineMarkReject(inputs,x,y,i); 611 } 612 if ((pi1 < pi2)&&(P1 > P2)) { // mode 2 is more popular, but this element belongs to mode 1 613 combineMarkReject(inputs,x,y,i); 614 } 615 } 616 } 617 psFree(values); 618 // else do nothing. 619 619 } 620 620 … … 622 622 // faintest mode as determined by the KMM test, and rejecting all inputs that belong to the brighest. 623 623 static void KMMRejectBright(const psArray *inputs, int x, int y) { 624 float KMM_MINIMUM_PVALUE = 0.05;625 float mU,sU;626 float Punimodal,pi1,m1,s1,pi2,m2,s2;627 int iter;628 int j;629 630 psVector *values = psVectorAlloc(inputs->n, PS_TYPE_F32);631 for (j = 0; j < inputs->n; j++) {632 pmStackData *data = inputs->data[j]; // Stack data of interest633 psImage *image = data->readout->image; // Image of interest634 int xIn = x - data->readout->col0, yIn = y - data->readout->row0; // Coordinates on input readout635 values->data.F32[j] = image->data.F32[yIn][xIn];636 }624 float KMM_MINIMUM_PVALUE = 0.05; 625 float mU,sU; 626 float Punimodal,pi1,m1,s1,pi2,m2,s2; 627 int iter; 628 int j; 629 630 psVector *values = psVectorAlloc(inputs->n, PS_TYPE_F32); 631 for (j = 0; j < inputs->n; j++) { 632 pmStackData *data = inputs->data[j]; // Stack data of interest 633 psImage *image = data->readout->image; // Image of interest 634 int xIn = x - data->readout->col0, yIn = y - data->readout->row0; // Coordinates on input readout 635 values->data.F32[j] = image->data.F32[yIn][xIn]; 636 } 637 637 638 KMMcalculate(values,&Punimodal,&iter,639 &mU,&sU,640 &pi1,&m1,&s1,641 &pi2,&m2,&s2);642 if (Punimodal < KMM_MINIMUM_PVALUE) {643 int i;644 float g1,g2,norm;645 float P1,P2;646 647 for (i = 0; i < values->n; i++) { // Calculate probabilities for each mode648 g1 = gaussian(values->data.F32[i],m1,s1);649 g2 = gaussian(values->data.F32[i],m2,s2);650 norm = (pi1 * g1 + pi2 * g2);651 P1 = (pi1 * g1) / norm;652 P2 = (pi2 * g2) / norm;653 654 if ((m1 > m2)&&(P1 > P2)) { // m1 is larger, and this element belongs to mode 1655 combineMarkReject(inputs,x,y,i);656 }657 if ((m1 < m2)&&(P1 < P2)) { // m2 is larger, and this element belongs to mode 2658 combineMarkReject(inputs,x,y,i);659 }660 }661 }662 psFree(values);663 // else do nothing.638 KMMcalculate(values,&Punimodal,&iter, 639 &mU,&sU, 640 &pi1,&m1,&s1, 641 &pi2,&m2,&s2); 642 if (Punimodal < KMM_MINIMUM_PVALUE) { 643 int i; 644 float g1,g2,norm; 645 float P1,P2; 646 647 for (i = 0; i < values->n; i++) { // Calculate probabilities for each mode 648 g1 = gaussian(values->data.F32[i],m1,s1); 649 g2 = gaussian(values->data.F32[i],m2,s2); 650 norm = (pi1 * g1 + pi2 * g2); 651 P1 = (pi1 * g1) / norm; 652 P2 = (pi2 * g2) / norm; 653 654 if ((m1 > m2)&&(P1 > P2)) { // m1 is larger, and this element belongs to mode 1 655 combineMarkReject(inputs,x,y,i); 656 } 657 if ((m1 < m2)&&(P1 < P2)) { // m2 is larger, and this element belongs to mode 2 658 combineMarkReject(inputs,x,y,i); 659 } 660 } 661 } 662 psFree(values); 663 // else do nothing. 664 664 } 665 665 #endif // End if(0) to prevent KMMReject{Unpopular|Bright} from being defined. … … 682 682 psImageMaskType badMaskBits, // Value to mask as 'bad' 683 683 psImageMaskType suspectMaskBits // Value to mask as 'suspect' 684 )684 ) 685 685 { 686 686 // Rudimentary error checking … … 795 795 // set the mask bits if nGoodBits[i] > f*numGood 796 796 { 797 # define SUSPECT_FRACTION 0.65797 # define SUSPECT_FRACTION 0.65 798 798 *goodMask = 0x0000; 799 799 psImageMaskType value = 0x0001; … … 840 840 int nminpix, // Minimum number of input per pixel 841 841 float invTotalWeight // Inverse of total weight for all inputs 842 )842 ) 843 843 { 844 844 psVector *pixelData = buffer->pixels; // Values for the pixel of interest … … 944 944 bool useVariance, // Use variance for rejection when combining? 945 945 bool safe // Combine safely? 946 )946 ) 947 947 { 948 948 if (iter <= 0) { … … 968 968 bool useKMM = false; 969 969 if (num >= KMM_MINIMUM_INPUTS) { 970 useKMM = true;970 useKMM = true; 971 971 } 972 972 … … 986 986 } 987 987 # endif 988 KMMFindPopular(pixelData,&Punimodal,&KMMmean,&KMMsigma,&KMMpi,xyrdebug);989 CHECKPIX(x,y,"KMM Popularity Contest: (%d,%d) Puni: %g Mean: %f Sigma %f Pi: %f\n",990 x,y,Punimodal,KMMmean,KMMsigma,KMMpi);988 KMMFindPopular(pixelData,&Punimodal,&KMMmean,&KMMsigma,&KMMpi,xyrdebug); 989 CHECKPIX(x,y,"KMM Popularity Contest: (%d,%d) Puni: %g Mean: %f Sigma %f Pi: %f\n", 990 x,y,Punimodal,KMMmean,KMMsigma,KMMpi); 991 991 } 992 992 for (int i = 0; i < num; i++) { … … 994 994 } 995 995 for (int i = 0; i < num; i++) { 996 // Systematic error contributes to the rejection level997 float sysVar;998 if (useKMM) { // If we can trust KMM results, set the systematic variance999 sysVar = PS_SQR(KMMsigma);1000 }1001 else { // Otherwise, use the 10% systematic variance we've done in the past.1002 sysVar = PS_SQR(sys * pixelData->data.F32[i]);1003 }996 // Systematic error contributes to the rejection level 997 float sysVar; 998 if (useKMM) { // If we can trust KMM results, set the systematic variance 999 sysVar = PS_SQR(KMMsigma); 1000 } 1001 else { // Otherwise, use the 10% systematic variance we've done in the past. 1002 sysVar = PS_SQR(sys * pixelData->data.F32[i]); 1003 } 1004 1004 1005 1005 CHECKPIX(x, y, "Variance %d (%d), pixel %d,%d: %f %f %f\n", … … 1151 1151 default: { 1152 1152 if (useVariance) { 1153 float median;1154 if ((useKMM)&&(Punimodal < 0.05)) {1155 median = KMMmean;1156 }1157 else {1158 median = combinationWeightedOlympic(pixelData, pixelWeights,1159 olympic, buffer->sort); // Median for stack1160 }1153 float median; 1154 if ((useKMM)&&(Punimodal < 0.05)) { 1155 median = KMMmean; 1156 } 1157 else { 1158 median = combinationWeightedOlympic(pixelData, pixelWeights, 1159 olympic, buffer->sort); // Median for stack 1160 } 1161 1161 1162 1162 CHECKPIX(x, y, "Flag with variance pixel %d,%d: median = %f\n", x, y, median); … … 1170 1170 float diff2 = PS_SQR(diff); // Square difference 1171 1171 CHECKPIX(x,y, "Input %d, pixel %d,%d (%" PRIu16 "): %f %f (%f) %f %f :: %f %f %f %f\n", 1172 i, x, y, pixelSources->data.U16[j], pixelData->data.F32[j], pixelVariances->data.F32[j],1173 1.0, pixelWeights->data.F32[j], 1.0,1174 pixelLimits->data.F32[j], diff2, diff2 / pixelLimits->data.F32[j],worst);1172 i, x, y, pixelSources->data.U16[j], pixelData->data.F32[j], pixelVariances->data.F32[j], 1173 1.0, pixelWeights->data.F32[j], 1.0, 1174 pixelLimits->data.F32[j], diff2, diff2 / pixelLimits->data.F32[j],worst); 1175 1175 1176 1176 if (diff2 > pixelLimits->data.F32[j]) { … … 1435 1435 1436 1436 bool pmStackSimpleMedianCombine( 1437 pmReadout *combined, 1438 psArray *input) { 1439 int num = input->n; 1440 // int numCols, numRows; 1441 int minInputCols, maxInputCols, minInputRows, maxInputRows; // Smallest and largest values to combine 1442 int xSize, ySize; // Size of the output image 1443 1444 psArray *stack = psArrayAlloc(num); // Stack of readouts 1445 for (int i = 0; i < num; i++) { 1446 // pmStackData *data = input->data[i]; // Stack data for this input 1447 pmReadout *ro = input->data[i]; // data->readout; // Readout of interest 1448 if (!ro) { 1449 continue; 1450 } 1451 stack->data[i] = psMemIncrRefCounter(ro); 1452 } 1453 1454 if (!pmReadoutStackValidate(&minInputCols, &maxInputCols, &minInputRows, &maxInputRows, &xSize, &ySize, 1455 stack)) { 1456 psError(psErrorCodeLast(), false, "Input stack is not valid."); 1437 pmReadout *combined, 1438 psArray *input) { 1439 int num = input->n; 1440 // int numCols, numRows; 1441 int minInputCols, maxInputCols, minInputRows, maxInputRows; // Smallest and largest values to combine 1442 int xSize, ySize; // Size of the output image 1443 1444 psArray *stack = psArrayAlloc(num); // Stack of readouts 1445 for (int i = 0; i < num; i++) { 1446 // pmStackData *data = input->data[i]; // Stack data for this input 1447 pmReadout *ro = input->data[i]; // data->readout; // Readout of interest 1448 if (!ro) { 1449 continue; 1450 } 1451 stack->data[i] = psMemIncrRefCounter(ro); 1452 } 1453 1454 if (!pmReadoutStackValidate(&minInputCols, &maxInputCols, &minInputRows, &maxInputRows, &xSize, &ySize, 1455 stack)) { 1456 psError(psErrorCodeLast(), false, "Input stack is not valid."); 1457 psFree(stack); 1458 return false; 1459 } 1460 1461 psVector *pixelData = psVectorAlloc(input->n,PS_TYPE_F32); 1462 psVector *pixelMask = psVectorAlloc(input->n,PS_TYPE_VECTOR_MASK); 1463 psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN); 1464 1465 for (int y = minInputRows; y < maxInputRows; y++) { 1466 for (int x = minInputCols; x < maxInputCols; x++) { 1467 for (int i = 0; i < input->n; i++) { 1468 pmReadout *ro = stack->data[i]; 1469 psImage *image = ro->image; 1470 pixelMask->data.PS_TYPE_VECTOR_MASK_DATA[i] = 0; 1471 pixelData->data.F32[i] = image->data.F32[y][x]; 1472 if (isfinite(image->data.F32[y][x])&& 1473 (fabs(image->data.F32[y][x]) < 1e5)) { 1474 pixelMask->data.PS_TYPE_VECTOR_MASK_DATA[i] = 0; 1475 } 1476 else { 1477 pixelMask->data.PS_TYPE_VECTOR_MASK_DATA[i] = 1; 1478 } 1479 #if (0) 1480 if ((x == 59)&&(y > 40)&&(y < 50)) { 1481 fprintf(stderr,"%d %d %d %d %g\n", 1482 x,y,i,pixelMask->data.PS_TYPE_VECTOR_MASK_DATA[i],pixelData->data.F32[i]); 1483 } 1484 #endif 1485 } 1486 if (!psVectorStats(stats,pixelData,NULL,pixelMask,1)) { 1487 psError(PS_ERR_UNKNOWN, false, "Unable to calculate median"); 1488 psFree(stats); 1489 psFree(pixelData); 1490 psFree(pixelMask); 1491 psFree(stack); 1492 return(false); 1493 } 1494 combined->image->data.F32[y][x] = stats->robustMedian; 1495 if (combined->mask) { 1496 combined->mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] = 0; 1497 } 1498 #if (0) 1499 if ((x == 59)&&(y > 40)&&(y < 50)) { 1500 fprintf(stderr,"%d %d %d %d %g\n", 1501 x,y,-1,combined->mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x], 1502 combined->image->data.F32[y][x]); 1503 } 1504 #endif 1505 } 1506 } 1507 1508 psFree(stats); 1509 psFree(pixelData); 1510 psFree(pixelMask); 1457 1511 psFree(stack); 1458 return false; 1459 } 1460 1461 psVector *pixelData = psVectorAlloc(input->n,PS_TYPE_F32); 1462 psVector *pixelMask = psVectorAlloc(input->n,PS_TYPE_VECTOR_MASK); 1463 psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN); 1464 1465 for (int y = minInputRows; y < maxInputRows; y++) { 1466 for (int x = minInputCols; x < maxInputCols; x++) { 1467 for (int i = 0; i < input->n; i++) { 1468 pmReadout *ro = stack->data[i]; 1469 psImage *image = ro->image; 1470 pixelMask->data.PS_TYPE_VECTOR_MASK_DATA[i] = 0; 1471 pixelData->data.F32[i] = image->data.F32[y][x]; 1472 if (isfinite(image->data.F32[y][x])&& 1473 (fabs(image->data.F32[y][x]) < 1e5)) { 1474 pixelMask->data.PS_TYPE_VECTOR_MASK_DATA[i] = 0; 1475 } 1476 else { 1477 pixelMask->data.PS_TYPE_VECTOR_MASK_DATA[i] = 1; 1478 } 1479 #if (0) 1480 if ((x == 59)&&(y > 40)&&(y < 50)) { 1481 fprintf(stderr,"%d %d %d %d %g\n", 1482 x,y,i,pixelMask->data.PS_TYPE_VECTOR_MASK_DATA[i],pixelData->data.F32[i]); 1483 } 1484 #endif 1485 } 1486 if (!psVectorStats(stats,pixelData,NULL,pixelMask,1)) { 1487 psError(PS_ERR_UNKNOWN, false, "Unable to calculate median"); 1488 psFree(stats); 1489 psFree(pixelData); 1490 psFree(pixelMask); 1491 psFree(stack); 1492 return(false); 1493 } 1494 combined->image->data.F32[y][x] = stats->robustMedian; 1495 if (combined->mask) { 1496 combined->mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] = 0; 1497 } 1498 #if (0) 1499 if ((x == 59)&&(y > 40)&&(y < 50)) { 1500 fprintf(stderr,"%d %d %d %d %g\n", 1501 x,y,-1,combined->mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x], 1502 combined->image->data.F32[y][x]); 1503 } 1504 #endif 1505 } 1506 } 1507 1508 psFree(stats); 1509 psFree(pixelData); 1510 psFree(pixelMask); 1511 psFree(stack); 1512 return (true); 1512 return (true); 1513 1513 } 1514 1514 … … 1519 1519 #define SORT_VV_COMPARE(A,B) (pixelData->data.F32[A] < pixelData->data.F32[B]) 1520 1520 #define SORT_VV_SWAP(TYPE,A,B) { \ 1521 if (A != B) { \ 1522 psF32 tempVal = pixelData->data.F32[A]; \ 1523 pixelData->data.F32[A] = pixelData->data.F32[B]; \ 1524 pixelData->data.F32[B] = tempVal; \ 1525 psF32 tempVar = pixelVariances->data.F32[A]; \ 1526 pixelVariances->data.F32[A] = pixelVariances->data.F32[B]; \ 1527 pixelVariances->data.F32[B] = tempVar; \ 1528 } \ 1529 } 1530 1531 #define SORT_VALUE_AND_VAR(A,B) { PSSORT(A->n, SORT_VV_COMPARE, SORT_VV_SWAP, F32); } 1532 1521 if (A != B) { \ 1522 psF32 tempVal = pixelData->data.F32[A]; \ 1523 pixelData->data.F32[A] = pixelData->data.F32[B]; \ 1524 pixelData->data.F32[B] = tempVal; \ 1525 psF32 tempVar = pixelVariances->data.F32[A]; \ 1526 pixelVariances->data.F32[A] = pixelVariances->data.F32[B]; \ 1527 pixelVariances->data.F32[B] = tempVar; \ 1528 if (expTime) { \ 1529 psF32 tempExp = expTime->data.F32[A]; \ 1530 expTime->data.F32[A] = expTime->data.F32[B]; \ 1531 expTime->data.F32[B] = tempExp; \ 1532 } \ 1533 } \ 1534 } 1535 1536 // this macro uses the macros above which assume pixelData, pixelVariances, expTime 1537 #define SORT_VALUES(NVALUES) { PSSORT(NVALUES, SORT_VV_COMPARE, SORT_VV_SWAP, F32); } 1533 1538 1534 1539 bool pmStackCombineByPercentile( … … 1537 1542 psArray *stackData, // input exposures 1538 1543 psF64 rejectFraction, // outlier fraction of pixels to reject 1539 psF64 maxRange,1540 1544 psImageMaskType badMaskBits, // treat these bits as 'bad' 1541 1545 psImageMaskType suspectMaskBits, // treat these bits as 'suspect' 1542 1546 psImageMaskType blankMaskBits // use this mask value for pixels missing input data (distinguish between Ninput = 0 and Ngood = 0?) 1543 ) {1547 ) { 1544 1548 int minInputCols, maxInputCols, minInputRows, maxInputRows; // Smallest and largest values to combine 1545 1549 int xSize, ySize; // Size of the output image … … 1562 1566 // make sure the output readout matches the inputs, and set to blank by default 1563 1567 pmReadoutUpdateSize(combined, minInputCols, minInputRows, xSize, ySize, true, true, blankMaskBits); 1564 1565 psImage *exp = NULL, *expnum = NULL, *expweight = NULL; // Exposure map and exposure number1566 1568 if (expmaps) { 1567 if (!expmaps->image) { exp = expmaps->image = psImageAlloc(numCols, numRows, PS_TYPE_F32); } 1568 if (!expmaps->mask) { expnum = expmaps->mask = psImageAlloc(numCols, numRows, PS_TYPE_IMAGE_MASK); } 1569 if (!expmaps->variance) { expweight = expmaps->variance = psImageAlloc(numCols, numRows, PS_TYPE_F32); } 1569 // if we are generating the expmaps, update to match the images, set blank mask areas to 0 1570 pmReadoutUpdateSize(expmaps, minInputCols, minInputRows, xSize, ySize, expmaps->mask != NULL, expmaps->variance != NULL, 0); 1570 1571 } 1571 1572 1572 1573 psVector *pixelData = psVectorAlloc(stackData->n, PS_TYPE_F32); 1573 1574 psVector *pixelVariances = psVectorAlloc(stackData->n, PS_TYPE_F32); 1574 psVector *pixelMask = psVectorAlloc(stackData->n, PS_TYPE_VECTOR_MASK); 1575 1576 psVector *expTime = expmask ? psVectorAlloc(stackData->n, PS_TYPE_F32) : NULL; 1577 psVector *expNum = expmask ? psVectorAlloc(stackData->n, PS_TYPE_VECTOR_MASK): NULL; 1575 1576 // if we are asking for the exptime maps, generate a storage vector expTime 1577 psVector *expTime = expmaps && expmaps->image ? psVectorAlloc(stackData->n, PS_TYPE_F32) : NULL; 1578 1578 1579 1579 int nGoodBits[16]; // accumulate the good pixel bits here for fuzzy logic … … 1589 1589 pmStackData *data = stackData->data[i]; // Stack data for this input 1590 1590 pmReadout *ro = data->readout; // Readout of interest 1591 1592 psAssert (ro->mask, "must must exist, but does not"); 1593 psAssert (ro->variance, "variance must exist, but does not"); 1591 1594 1592 1595 psImage *image = ro->image; … … 1607 1610 psImageMaskType value = 0x0001; 1608 1611 for (int nbit = 0; nbit < 16; nbit ++) { 1609 if (mask->data.PS_TYPE_IMAGE_MASK_DATA[yIn][xIn] & value) {1610 nGoodBits[nbit] ++;1611 }1612 value <<= 1;1612 if (mask->data.PS_TYPE_IMAGE_MASK_DATA[yIn][xIn] & value) { 1613 nGoodBits[nbit] ++; 1614 } 1615 value <<= 1; 1613 1616 } 1614 1617 1615 // pixelWeights->data.F32[nGood] = data->weight; 1616 // pixelExps->data.F32[nGood] = data->exp; 1617 // pixelSources->data.U16[nGood] = i; 1618 1618 // accumulate pixel data and variance values: 1619 1619 pixelData->data.F32[nGood] = image->data.F32[yIn][xIn]; 1620 if (variance) { pixelVariances->data.F32[nGood] = variance->data.F32[yIn][xIn]; } 1621 if (expmask) { pixelVariances->data.F32[nGood] = variance->data.F32[yIn][xIn]; } 1620 pixelVariances->data.F32[nGood] = variance->data.F32[yIn][xIn]; 1621 1622 // accumulate exposure times if required 1623 if (expTime) { expTime->data.F32[nGood] = data->exp; } 1622 1624 1623 1625 nGood ++; … … 1647 1649 combined->mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] = blankMaskBits; // probably not needed since it was set above. 1648 1650 if (expmaps) { 1649 expmaps->image->F32[y][x] = NAN; 1651 expmaps->image->F32[y][x] = NAN; // XXX should this value be NAN or 0? 1650 1652 expmaps->variance->F32[y][x] = NAN; 1651 1653 expmaps->mask->PS_TYPE_IMAGE_MASK_DATA[y][x] = 0; … … 1654 1656 } 1655 1657 1656 // sort both pixelData and pixelVariance1657 SORT_VALUE _AND_VAR (pixelData, pixelVariances);1658 // sort pixelData, pixelVariance, expTime (if it exists) 1659 SORT_VALUES (pixelData->n); 1658 1660 1659 1661 // set the given (suspect) mask bit if nGoodBits[i] > f*nGood … … 1663 1665 psImageMaskType outputMask = 0x0000; 1664 1666 for (int nbit = 0; nbit < 16; nbit ++) { 1665 if (nGoodBits[nbit] > SUSPECT_FRACTION*nGood) {1666 outputMask |= value;1667 }1668 value <<= 1;1667 if (nGoodBits[nbit] > SUSPECT_FRACTION*nGood) { 1668 outputMask |= value; 1669 } 1670 value <<= 1; 1669 1671 } 1670 1672 … … 1688 1690 combined->variance->data.F32[y][x] = varValue; 1689 1691 combined->mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] = outputMask; 1690 } 1691 } 1692 1692 1693 if (expTime) { 1694 float sum = 0.0; 1695 for (int n = Ns; n < Ne; n++) { 1696 sum += expTime->data.F32[n]; 1697 } 1698 expmaps->image->data.F32[y][x] = sum; 1699 } 1700 if (expNum) { expmaps->mask->data.F32[y][x] = Ne - Ns; } 1701 } 1702 } 1693 1703 psFree(pixelData); 1694 psFree(pixel Mask);1695 1704 psFree(pixelVariance); 1705 psFree(expTime); 1696 1706 return (true); 1697 1707 } -
branches/eam_branches/psModules.20211028/src/imcombine/pmStack.h
r41843 r41879 49 49 bool pmStackCombineByPercentile( 50 50 pmReadout *combined, 51 pmReadout *expmaps, 51 52 psArray *input, 52 psF64 minRange, 53 psF64 maxRange, 53 psF64 rejectFraction, 54 54 psImageMaskType badMaskBits, // treat these bits as 'bad' 55 55 psImageMaskType suspectMaskBits, // treat these bits as 'suspect'
Note:
See TracChangeset
for help on using the changeset viewer.
