IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
Nov 8, 2021, 8:02:21 AM (5 years ago)
Author:
eugene
Message:

merge changes from psModules.20211028 (stack-by-percent)

Location:
branches/eam_branches/ipp-20211108/psModules
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • branches/eam_branches/ipp-20211108/psModules

  • branches/eam_branches/ipp-20211108/psModules/src/imcombine/pmStack.c

    r41892 r41909  
    113113// KMM functions to do bimodality rejection of pixels
    114114double 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)));
    116116}
    117117
     
    122122                         float *pi2, float *m2, float *s2,
    123123                         int xyrdebug) {
    124   assert(values);
    125   assert(values->type.type == PS_TYPE_F32);
     124    assert(values);
     125    assert(values->type.type == PS_TYPE_F32);
    126126 
    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;
    133133/*   int debug = 0; */
    134134 
    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     }
     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        }
    151151   
    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).
     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).
    181181   
    182     discrepant_value = values->data.F32[discrepant_index];
     182        discrepant_value = values->data.F32[discrepant_index];
    183183   
    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    }
    195195   
    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;
     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;
    211211/*     if (debug == 1) { */
    212212/*       fprintf(stderr,"KMM: %d %f %f %f %f (%f %f %f) (%f %f %f)\n", */
     
    216216/*     } */
    217217
     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
    218316    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);
    223319    }
    224320
    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);
    323323}
    324324
    325325static 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);
    333333 
    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);
    338338/*   fprintf(stdout,"%g %g : %g %g %g : %g %g %g : %g %d\t", */
    339339/*        mU,sU, */
     
    347347/*   } */
    348348/*   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;
    361354    }
    362355    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    } 
    368368}
    369369
     
    381381                                    const psVector *exps,      // Exposure times to combine
    382382                                    const psVector *weights // Weights to apply
    383                                     )
     383    )
    384384{
    385385    assert(mean);
     
    411411        sumWeight += weights->data.F32[i];
    412412        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];
    415415        }
    416416        if (exps) {
     
    427427    *mean = sumValueWeight / sumWeight;
    428428    if (var) {
    429       //*var = sumVarianceWeight / PS_SQR(sumWeight);
    430       *var = 1 / sumVarianceWeight;
     429        //*var = sumVarianceWeight / PS_SQR(sumWeight);
     430        *var = 1 / sumVarianceWeight;
    431431    }
    432432    if (exp) {
     
    445445                                   const psVector *values, // Values to combine
    446446                                   psVector *sortBuffer // Buffer for sorting
    447                                    )
     447    )
    448448{
    449449    assert(values);
     
    496496                                        float frac, // Fraction to discard
    497497                                        psVector *sortBuffer // Buffer for sorting
    498                                         )
     498    )
    499499{
    500500    int numGood = values->n;            // Number of good values
     
    527527                                      int x, int y, // Pixel
    528528                                      int source // Source image index
    529                                       )
     529    )
    530530{
    531531    CHECKPIX(x, y, "Marking image %d, pixel %d,%d for inspection\n", source, x, y);
     
    545545                                     int x, int y, // Pixel
    546546                                     int source // Source image index
    547                                      )
     547    )
    548548{
    549549    CHECKPIX(x, y, "Marking pixel image %d, pixel %d,%d for rejection\n", source, x, y);
     
    561561// least popular mode.
    562562static 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 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   }
     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    }
    581581 
    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.
     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.
    619619}
    620620
     
    622622// faintest mode as determined by the KMM test, and rejecting all inputs that belong to the brighest.
    623623static 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 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   }
     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    }
    637637 
    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.
     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.
    664664}
    665665#endif // End if(0) to prevent KMMReject{Unpopular|Bright} from being defined.
     
    682682                           psImageMaskType badMaskBits, // Value to mask as 'bad'
    683683                           psImageMaskType suspectMaskBits // Value to mask as 'suspect'
    684                            )
     684    )
    685685{
    686686    // Rudimentary error checking
     
    795795    // set the mask bits if nGoodBits[i] > f*numGood
    796796    {
    797         # define SUSPECT_FRACTION 0.65
     797# define SUSPECT_FRACTION 0.65
    798798        *goodMask = 0x0000;
    799799        psImageMaskType value = 0x0001;
     
    840840                          int nminpix,         // Minimum number of input per pixel
    841841                          float invTotalWeight    // Inverse of total weight for all inputs
    842                           )
     842    )
    843843{
    844844    psVector *pixelData = buffer->pixels; // Values for the pixel of interest
     
    944944                        bool useVariance, // Use variance for rejection when combining?
    945945                        bool safe    // Combine safely?
    946                         )
     946    )
    947947{
    948948    if (iter <= 0) {
     
    968968    bool useKMM = false;
    969969    if (num >= KMM_MINIMUM_INPUTS) {
    970       useKMM = true;
     970        useKMM = true;
    971971    }
    972972   
     
    986986            }
    987987# 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);
    991991        }
    992992        for (int i = 0; i < num; i++) {
     
    994994        }
    995995        for (int i = 0; i < num; i++) {
    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           }
     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            }
    10041004
    10051005            CHECKPIX(x, y, "Variance %d (%d), pixel %d,%d: %f %f %f\n",
     
    11511151          default: {
    11521152              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 stack
    1160                 }
     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                  }
    11611161               
    11621162                  CHECKPIX(x, y, "Flag with variance pixel %d,%d: median = %f\n", x, y, median);
     
    11701170                      float diff2 = PS_SQR(diff); // Square difference
    11711171                      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);
    11751175
    11761176                      if (diff2 > pixelLimits->data.F32[j]) {
     
    14351435
    14361436bool 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);
    14571511    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);
    15131513}
    15141514
    15151515# define MIN_GOOD_PERCENTILE 2
     1516# define SUSPECT_FRACTION 0.65
     1517
     1518// Comparison and swap functions for sorting values directly
     1519#define SORT_VV_COMPARE(A,B) (pixelData->data.F32[A] < pixelData->data.F32[B])
     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            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); }
     1538
    15161539bool pmStackCombineByPercentile(
    1517     pmReadout *combined,
    1518     psArray *stackData,
    1519     psF64 minRange,
    1520     psF64 maxRange,
     1540    pmReadout *combined,                // output stacked readout
     1541    pmReadout *expmaps,                 // output exposure map information
     1542    psArray *stackData,                 // input exposures
     1543    psF64 rejectFraction,               // outlier fraction of pixels to reject
    15211544    psImageMaskType badMaskBits,        // treat these bits as 'bad'
    15221545    psImageMaskType suspectMaskBits,    // treat these bits as 'suspect'
    15231546    psImageMaskType blankMaskBits       // use this mask value for pixels missing input data (distinguish between Ninput = 0 and Ngood = 0?)
    1524 ) {
     1547    ) {
    15251548    int minInputCols, maxInputCols, minInputRows, maxInputRows; // Smallest and largest values to combine
    15261549    int xSize, ySize;                   // Size of the output image
     
    15411564    psFree(stackReadouts);
    15421565
    1543     psVector *pixelData = psVectorAlloc(stackData->n, PS_TYPE_F32);
    1544     psVector *pixelMask = psVectorAlloc(stackData->n, PS_TYPE_VECTOR_MASK);
     1566    // make sure the output readout matches the inputs, and set to blank by default
     1567    pmReadoutUpdateSize(combined, minInputCols, minInputRows, xSize, ySize, true, true, blankMaskBits);
     1568    if (expmaps) {
     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);
     1571    }
     1572   
     1573    psVector *pixelData      = psVectorAlloc(stackData->n, PS_TYPE_F32);
     1574    psVector *pixelVariances = psVectorAlloc(stackData->n, PS_TYPE_F32);
     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
     1579    int nGoodBits[16]; // accumulate the good pixel bits here for fuzzy logic
     1580    psAssert (sizeof(psImageMaskType) == 2, "psImageMaskType is not the expected size");
     1581    memset (nGoodBits, 0, 16*sizeof(int));
    15451582
    15461583    for (int y = minInputRows; y < maxInputRows; y++) {
     
    15521589                pmStackData *data = stackData->data[i]; // Stack data for this input
    15531590                pmReadout *ro = data->readout;  // Readout of interest
    1554                 psImage *image = ro->image;
    1555                 psImage *mask = ro->mask;
     1591
     1592                psAssert (ro->mask,     "must must exist, but does not");
     1593                psAssert (ro->variance, "variance must exist, but does not");
     1594
     1595                psImage *image    = ro->image;
     1596                psImage *variance = ro->variance;
     1597                psImage *mask     = ro->mask;
    15561598
    15571599                int xIn = x - data->readout->col0;
    15581600                int yIn = y - data->readout->row0; // Coordinates on input readout
    15591601
     1602                // skip obviously bad input data
    15601603                if (!isfinite(image->data.F32[yIn][xIn])) continue;
    1561                 if (fabs(image->data.F32[yIn][xIn]) > 1e5) continue;
    1562                 // XXX need to test the input mask as well here
    1563                 if (mask->data.PS_TYPE_IMAGE_MASK_DATA[yIn][xIn] & badMaskBits);
    1564 
    1565                 // XXX save the count of suspect bits
    1566 
    1567 # if (0)
     1604                if (fabs(image->data.F32[yIn][xIn]) > 1e5) continue; // XXX this cut is a bit arbitrary..
     1605                if (mask->data.PS_TYPE_IMAGE_MASK_DATA[yIn][xIn] & badMaskBits) continue;
     1606
    15681607                // count the number of times a given mask bit is set in the input pixels.
    15691608                // NOTE: since we have explicitly skipped the pixels with any bad bits, these are only
    15701609                // the suspect bits (nGoodBits is a bit of a misnomer: it is more like 'nSuspectBitsForGoodInputs'
    1571                 if (1) {
    1572                   psImageMaskType value = 0x0001;
    1573                   for (int nbit = 0; nbit < 16; nbit ++) {
     1610                psImageMaskType value = 0x0001;
     1611                for (int nbit = 0; nbit < 16; nbit ++) {
    15741612                    if (mask->data.PS_TYPE_IMAGE_MASK_DATA[yIn][xIn] & value) {
    1575                       // XXX nGoodBits[nbit] ++;
     1613                        nGoodBits[nbit] ++;
    15761614                    }
    15771615                    value <<= 1;
    1578                   }
    15791616                }
     1617
     1618                // accumulate pixel data and variance values:
     1619                pixelData->data.F32[nGood] = image->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; }
     1624
     1625                nGood ++;
     1626            }
     1627            pixelData->n = nGood;
     1628
     1629            // rather than define a min and max value,
     1630            // what we really want is a symmetric selection about the middle,
     1631            // or the output is biased.  If N % 2 = 1, then
     1632           
     1633            // we are going to exclude rejectFraction*nGood measurements.  But the
     1634            // rejection needs to be symmetric
     1635
     1636# define AT_LEAST 0
     1637# if (AT_LEAST)
     1638            int Ns = MIN(MAX(1, 0.5*rejectFraction * nGood), nGood);
     1639            int Ne = nGood - Ns;
     1640            int Npt = Ne - Ns;
     1641# else
     1642            int Ns = MIN(MAX(0, 0.5*rejectFraction * nGood), nGood);
     1643            int Ne = nGood - Ns;
     1644            int Npt = Ne - Ns;
    15801645# endif
    1581 
    1582                 pixelData->data.F32[nGood] = image->data.F32[yIn][xIn];
    1583                 nGood ++;
    1584             }
    1585             pixelData->n = nGood;
    1586             psVectorSortInPlace (pixelData);
    1587 
    1588             if (nGood < MIN_GOOD_PERCENTILE) {
     1646            if ((Npt < 1) || (nGood < MIN_GOOD_PERCENTILE)) {
    15891647                combined->image->data.F32[y][x] = NAN;
    15901648                combined->variance->data.F32[y][x] = NAN;
    1591                 combined->mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] = 1;
     1649                combined->mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] = blankMaskBits; // probably not needed since it was set above.
     1650                if (expmaps) {
     1651                    expmaps->image->data.F32[y][x] = NAN; // XXX should this value be NAN or 0?
     1652                    expmaps->variance->data.F32[y][x] = NAN;
     1653                    expmaps->mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] = 0;
     1654                }
    15921655                continue;
    15931656            }
    15941657
    1595 # if (0)
    1596 # define SUSPECT_FRACTION 0.65
    1597             // set the mask bits if nGoodBits[i] > f*numGood
    1598             if (0) {
    1599               psImageMaskType value = 0x0001;
    1600               for (int nbit = 0; nbit < 16; nbit ++) {
    1601                 if (nGoodBits[nbit] > SUSPECT_FRACTION*numGood) {
    1602                   *goodMask |= value;
     1658            // sort pixelData, pixelVariance, expTime (if it exists)
     1659            SORT_VALUES (pixelData->n);
     1660
     1661            // set the given (suspect) mask bit if nGoodBits[i] > f*nGood
     1662            // in other words if more than 65% of the good inputs had one of
     1663            // these bits set, then we should set that bit in the output mask
     1664            psImageMaskType value = 0x0001;
     1665            psImageMaskType outputMask = 0x0000;
     1666            for (int nbit = 0; nbit < 16; nbit ++) {
     1667                if (nGoodBits[nbit] > SUSPECT_FRACTION*nGood) {
     1668                    outputMask |= value;
    16031669                }
    16041670                value <<= 1;
    1605               }
    1606             }
    1607 # endif
    1608 
    1609             int Ns = MIN(MAX(0, minRange * nGood),nGood); // e.g., 0.1 * 50 = 5
    1610             int Ne = MIN(MAX(0, maxRange * nGood),nGood); // e.g., 0.9 * 50 = 45
    1611             int Npt = Ne - Ns;
     1671            }
    16121672
    16131673            float sum = 0.0;
     1674            float varSum = 0.0;
    16141675            for (int n = Ns; n < Ne; n++) {
    16151676                sum += pixelData->data.F32[n];
     1677                varSum += pixelVariances->data.F32[n];
    16161678            }
    16171679            float mean = sum / (float) Npt;
    16181680
    1619             float varSum = 0.0;
    1620             for (int n = Ns; n < Ne; n++) {
    1621                 varSum += SQ(pixelData->data.F32[n] - mean);
    1622             }
     1681            // alternative: calculate the stdev of the pixel values
     1682            // float varSum = 0.0;
     1683            // for (int n = Ns; n < Ne; n++) {
     1684            //  varSum += SQ(pixelData->data.F32[n] - mean);
     1685            // }
    16231686            // variance on the mean (stdev / sqrt(N))^2
    1624             float varValue = varSum / (Npt - 1) / Npt;
    1625 
    1626             // XXX this is probably not the correct variance to save
    1627             // the predicted variance should be the 1 / sum (1/var)
     1687            float varValue = varSum / (Npt*Npt);
    16281688
    16291689            combined->image->data.F32[y][x] = mean;
    16301690            combined->variance->data.F32[y][x] = varValue;
    1631             combined->mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] = 0;
    1632         }
    1633     }
    1634  
     1691            combined->mask->data.PS_TYPE_IMAGE_MASK_DATA[y][x] = outputMask;
     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 (expmaps) { expmaps->mask->data.F32[y][x] = Ne - Ns; }
     1701        }
     1702    }
    16351703    psFree(pixelData);
    1636     psFree(pixelMask);
    1637 
     1704    psFree(pixelVariances);
     1705    psFree(expTime);
    16381706    return (true);
    16391707}
  • branches/eam_branches/ipp-20211108/psModules/src/imcombine/pmStack.h

    r41892 r41909  
    4949bool pmStackCombineByPercentile(
    5050    pmReadout *combined,
     51    pmReadout *expmaps,
    5152    psArray *input,
    52     psF64 minRange,
    53     psF64 maxRange,
     53    psF64 rejectFraction,
    5454    psImageMaskType badMaskBits,        // treat these bits as 'bad'
    5555    psImageMaskType suspectMaskBits,    // treat these bits as 'suspect'
Note: See TracChangeset for help on using the changeset viewer.