Index: /trunk/ppMerge/src/ppMergeCombine.c
===================================================================
--- /trunk/ppMerge/src/ppMergeCombine.c	(revision 9324)
+++ /trunk/ppMerge/src/ppMergeCombine.c	(revision 9325)
@@ -123,11 +123,14 @@
             }
 
-#if 1
-            // Read bit by bit
-
-            int numRead;  // Number of inputs read
-            int numScan = 0;
-            do {
-                numRead = 0;
+            // Building a shutter correction
+            if (options->shutter) {
+                // Read in the pixels
+                int numRead = 0;  // Number of inputs read
+                psVector *exptimes = psVectorAlloc(filenames->n, PS_TYPE_F32);  // Reference measurements
+                exptimes->n = filenames->n;
+                psVectorInit(exptimes, 0);
+                psArray *images = psArrayAlloc(filenames->n); // Array of images
+                psArray *masks = psArrayAlloc(filenames->n); // Array of masks
+                images->n = masks->n = filenames->n;
                 for (int i = 0; i < filenames->n; i++) {
                     if (! filenames->data[i] || strlen(filenames->data[i]) == 0) {
@@ -136,68 +139,119 @@
                     psFits *fits = data->files->data[i]; // FITS file handle
                     if (!fits) {
-                        psError(PS_ERR_IO, false, "Unable to open input file %s --- ignored.\n",
-                                (char*)filenames->data[i]);
-                        continue;
-                    }
-
-                    if (!stack->data[i]) {
-                        pmFPA *fpaIn = data->in->data[i]; // Input FPA
-                        pmChip *chipIn = fpaIn->chips->data[view->chip]; // Input chip
-                        pmCell *cellIn = chipIn->cells->data[view->cell]; // Input cell
-                        stack->data[i] = pmReadoutAlloc(cellIn); // Input readout
-                    }
-
-                    // Only reading and writing the first readout in each cell (plane 0)
-                    if (pmReadoutReadNext(stack->data[i], fits, 0, options->rows)) {
-                        // For anything except BIAS and DARK, we want a mask
-                        if (options->scale || options->zero) {
-                            pmReadoutSetMask(stack->data[i]);
+                        continue;
+                    }
+                    pmFPA *fpaIn = data->in->data[i]; // Input FPA
+                    pmChip *chipIn = fpaIn->chips->data[view->chip]; // Input chip
+                    pmCell *cellIn = chipIn->cells->data[view->cell]; // Input cell
+                    if (!cellIn->file_exists) {
+                        // || !cellIn->data_exists) {
+                        continue;
+                    }
+                    if (!pmCellRead(cellIn, fits, config->database) || cellIn->readouts->n == 0) {
+                        continue;
+                    }
+                    if (cellIn->readouts->n > 1) {
+                        psWarning("Multiple readouts in file %d, chip %d, cell %d --- "
+                                  "only the first will be used.\n", i, view->chip, view->cell);
+                    }
+                    float exptime = psMetadataLookupF32(NULL, cellIn->concepts, "CELL.EXPOSURE");
+                    if (!isfinite(exptime)) {
+                        psWarning("File %d, chip %d, cell %d has bad exposure time.\n",
+                                  i, view->chip, view->cell);
+                    }
+                    exptimes->data.F32[i] = exptime;
+                    pmReadout *readoutIn = cellIn->readouts->data[0];
+                    images->data[i] = psMemIncrRefCounter(readoutIn->image);
+                    masks->data[i] = psMemIncrRefCounter(readoutIn->mask);
+                    numRead++;
+                }
+                if (numRead > 1) {
+                    readout->image = pmShutterCorrectionMeasure(exptimes, images, masks,
+                                                                options->shutterSize, options->mean,
+                                                                options->stdev, options->combine->maskVal);
+                    psTrace(__func__, 5, "Chip %d, cell %d\n", view->chip, view->cell);
+                } else {
+                    psError(PS_ERR_UNKNOWN, true, "Not enough images to combine: %d\n", numRead);
+                    psFree(images);
+                    psFree(exptimes);
+                    return false;
+                }
+                psFree(images);
+                psFree(exptimes);
+            } else {
+#if 1
+                // Read bit by bit
+
+                int numRead;  // Number of inputs read
+                int numScan = 0;
+                do {
+                    numRead = 0;
+                    for (int i = 0; i < filenames->n; i++) {
+                        if (! filenames->data[i] || strlen(filenames->data[i]) == 0) {
+                            continue;
                         }
-                        numRead++;
-                    }
+                        psFits *fits = data->files->data[i]; // FITS file handle
+                        if (!fits) {
+                            continue;
+                        }
+
+                        if (!stack->data[i]) {
+                            pmFPA *fpaIn = data->in->data[i]; // Input FPA
+                            pmChip *chipIn = fpaIn->chips->data[view->chip]; // Input chip
+                            pmCell *cellIn = chipIn->cells->data[view->cell]; // Input cell
+                            stack->data[i] = pmReadoutAlloc(cellIn); // Input readout
+                        }
+
+                        // Only reading and writing the first readout in each cell (plane 0)
+                        if (pmReadoutReadNext(stack->data[i], fits, 0, options->rows)) {
+                            // For anything except BIAS and DARK, we want a mask
+                            if (options->scale || options->zero) {
+                                pmReadoutSetMask(stack->data[i]);
+                            }
+                            numRead++;
+                        }
+                    }
+
+                    if (numRead > 0) {
+                        pmReadoutCombine(readout, stack, cellZeros, cellScales, options->combine);
+                        psTrace(__func__, 5, "Chip %d, cell %d, scan %d\n", view->chip, view->cell, numScan);
+                    }
+                    numScan++;
+
+                } while (numRead > 0);
+
+#else
+            // Read whole cells at a time
+
+                printf("Chip %d, cell %d\n", view->chip, view->cell);
+                int numRead = 0;  // Number of inputs read
+                for (int i = 0; i < filenames->n; i++) {
+                    if (! filenames->data[i] || strlen(filenames->data[i]) == 0) {
+                        continue;
+                    }
+                    psFits *fits = data->files->data[i]; // FITS file handle
+                    if (!fits) {
+                        continue;
+                    }
+                    pmFPA *fpaIn = data->in->data[i]; // Input FPA
+                    pmChip *chipIn = fpaIn->chips->data[view->chip]; // Input chip
+                    pmCell *cellIn = chipIn->cells->data[view->cell]; // Input cell
+                    if (!cellIn->file_exists || !cellIn->data_exists) {
+                        continue;
+                    }
+                    if (!pmCellRead(cellIn, fits, config->database) || cellIn->readouts->n == 0) {
+                        continue;
+                    }
+                    stack->data[i] = cellIn->readouts->data[0];
+                    numRead++;
                 }
-
                 if (numRead > 0) {
                     pmReadoutCombine(readout, stack, cellZeros, cellScales, options->combine);
-                    psTrace(__func__, 5, "Chip %d, cell %d, scan %d\n", view->chip, view->cell, numScan);
+                    psTrace(__func__, 5, "Chip %d, cell %d\n", view->chip, view->cell);
                 }
-                numScan++;
-
-            } while (numRead > 0);
-
-#else
-            // Read whole cells at a time
-
-            printf("Chip %d, cell %d\n", view->chip, view->cell);
-            int numRead = 0;  // Number of inputs read
-            for (int i = 0; i < filenames->n; i++) {
-                if (! filenames->data[i] || strlen(filenames->data[i]) == 0) {
-                    continue;
-                }
-                psFits *fits = data->files->data[i]; // FITS file handle
-                if (!fits) {
-                    psError(PS_ERR_IO, false, "Unable to open input file %s --- ignored.\n",
-                            filenames->data[i]);
-                    continue;
-                }
-                pmFPA *fpaIn = data->in->data[i]; // Input FPA
-                pmChip *chipIn = fpaIn->chips->data[view->chip]; // Input chip
-                pmCell *cellIn = chipIn->cells->data[view->cell]; // Input cell
-                if (!cellIn->file_exists || !cellIn->data_exists) {
-                    continue;
-                }
-                if (!pmCellRead(cellIn, fits, config->database) || cellIn->readouts->n == 0) {
-                    continue;
-                }
-                stack->data[i] = cellIn->readouts->data[0];
-                numRead++;
-            }
-            if (numRead > 0) {
-                pmReadoutCombine(readout, stack, cellZeros, cellScales, options->combine);
-                psTrace(__func__, 5, "Chip %d, cell %d\n", view->chip, view->cell);
-            }
-
-            memCheck();
+
+                memCheck();
 #endif
+            }
 
             psFree(readout);            // Drop reference
Index: /trunk/ppMerge/src/ppMergeOptions.c
===================================================================
--- /trunk/ppMerge/src/ppMergeOptions.c	(revision 9324)
+++ /trunk/ppMerge/src/ppMergeOptions.c	(revision 9325)
@@ -35,6 +35,9 @@
     options->scale = false;
     options->exptime = false;
+    options->shutter = false;
     options->sample = 1;
-    options->background = PS_STAT_SAMPLE_MEDIAN;
+    options->mean = PS_STAT_SAMPLE_MEDIAN;
+    options->stdev = PS_STAT_SAMPLE_STDEV;
+    options->shutterSize = 10;
     options->onOff = 0;
     options->combine = pmCombineParamsAlloc(PS_STAT_SAMPLE_MEAN);
@@ -72,22 +75,5 @@
         return 0;
     }
-    if (strcasecmp(stat, "MEAN") == 0 || strcasecmp(stat, "SAMPLE_MEAN") == 0) {
-        return PS_STAT_SAMPLE_MEAN;
-    }
-    if (strcasecmp(stat, "MEDIAN") == 0 || strcasecmp(stat, "SAMPLE_MEDIAN") == 0) {
-        return PS_STAT_SAMPLE_MEDIAN;
-    }
-    if (strcasecmp(stat, "ROBUST") == 0 || strcasecmp(stat, "ROBUST_MEDIAN") == 0) {
-        return PS_STAT_ROBUST_MEDIAN;
-    }
-    if (strcasecmp(stat, "FITTED") == 0 || strcasecmp(stat, "FITTED_MEAN") == 0) {
-        return PS_STAT_FITTED_MEAN;
-    }
-    if (strcasecmp(stat, "CLIPPED") == 0 || strcasecmp(stat, "CLIPPED_MEAN") == 0) {
-        return PS_STAT_CLIPPED_MEAN;
-    }
-
-    psError(PS_ERR_IO, true, "Unable to interpret statistic: %s\n", name);
-    return 0;
+    return psStatsOptionFromString(stat);
 }
 
@@ -143,6 +129,8 @@
     OPTION_PARSE(options->combine->nKeep,    recipe, "NKEEP",     S32 );
     OPTION_PARSE(options->combine->maskVal,  recipe, "MASKVAL",   S32 );
+    OPTION_PARSE(options->shutterSize,       recipe, "SHUTTERSIZE", S32 );
     options->combine->combine = parseStat(recipe, "COMBINE");
-    options->background       = parseStat(recipe, "BACKGROUND");
+    options->mean             = parseStat(recipe, "MEAN");
+    options->stdev            = parseStat(recipe, "STDEV");
 
     // Now the command-line options.  These are parameters that depend on what type of frame is being combined
@@ -155,16 +143,25 @@
             options->scale = false;
             options->exptime = false;
+            options->shutter = false;
         } else if (strcasecmp(type, "DARK") == 0) {
             options->zero = false;
             options->scale = false;
             options->exptime = true;
+            options->shutter = false;
         } else if (strcasecmp(type, "FLAT") == 0) {
             options->zero = false;
             options->scale = true;
             options->exptime = false;
+            options->shutter = false;
         } else if (strcasecmp(type, "FRINGE") == 0) {
             options->zero = true;
             options->scale = true;
             options->exptime = false;
+            options->shutter = false;
+        } else if (strcasecmp(type, "SHUTTER") == 0) {
+            options->zero = false;
+            options->scale = false;
+            options->exptime = false;
+            options->shutter = true;
         } else {
             psLogMsg(__func__, PS_LOG_WARN, "Unrecognised image type: %s --- assuming BIAS.\n", type);
@@ -172,4 +169,5 @@
             options->scale = false;
             options->exptime = false;
+            options->shutter = false;
         }
     } else {
Index: /trunk/ppMerge/src/ppMergeOptions.h
===================================================================
--- /trunk/ppMerge/src/ppMergeOptions.h	(revision 9324)
+++ /trunk/ppMerge/src/ppMergeOptions.h	(revision 9325)
@@ -22,6 +22,9 @@
     bool scale;                         // Scale by the background before combining?
     bool exptime;                       // Normalise by the exposure time?
+    bool shutter;                       // Generate shutter correction?
     unsigned int sample;                // Sampling factor for measuring the background
-    psStatsOptions background;          // Statistic to use to measure the background
+    psStatsOptions mean;                // Statistic to use to measure the mean
+    psStatsOptions stdev;               // Statistic to use to measure the stdev
+    int shutterSize;                    // Size for shutter measurement regions
     ppOnOff onOff;                      // On/off pairs?
     pmCombineParams *combine;           // Combination parameters
Index: /trunk/ppMerge/src/ppMergeScaleZero.c
===================================================================
--- /trunk/ppMerge/src/ppMergeScaleZero.c	(revision 9324)
+++ /trunk/ppMerge/src/ppMergeScaleZero.c	(revision 9325)
@@ -159,5 +159,5 @@
     psImage *background = psImageAlloc(data->numCells, filenames->n, PS_TYPE_F32); // Background measurements
     psImageInit(background, NAN);
-    psStats *bgStats = psStatsAlloc(options->background); // Statistic to measure the background
+    psStats *bgStats = psStatsAlloc(options->mean); // Statistic to measure the background
     psVector *gains = NULL;             // The gains for each cell
     psImage *exptime = NULL;            // The exposure time for each integration of each cell
@@ -265,5 +265,5 @@
                     psFree(sample);
                     psFree(sampleMask);
-                    background->data.F32[i][cellNum] = getStat(bgStats, options->background);
+                    background->data.F32[i][cellNum] = getStat(bgStats, options->mean);
                     psTrace(__func__, 3, "Background for %s, cell %d is %f\n", name, cellNum,
                             background->data.F32[i][cellNum]);
