IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
Oct 30, 2009, 5:46:42 PM (17 years ago)
Author:
Paul Price
Message:

Reworking mammoth combinePixels() function into discrete parts.
Adding case to test 3 pixels (occurs often when there are 4 input images) which the general case doesn't treat well, often rejecting all inputs.
Not yet tested!

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/pap/psModules/src/imcombine/pmStack.c

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