Index: trunk/psLib/src/imageops/Makefile.am
===================================================================
--- trunk/psLib/src/imageops/Makefile.am	(revision 7210)
+++ trunk/psLib/src/imageops/Makefile.am	(revision 7380)
@@ -5,4 +5,5 @@
 libpslibimageops_la_CPPFLAGS = $(SRCINC)
 libpslibimageops_la_SOURCES = \
+	psImageBackground.c \
 	psImageConvolve.c \
 	psImageGeomManip.c \
@@ -11,5 +12,6 @@
 	psImageStats.c \
 	psImageStructManip.c \
-    psImageMaskOps.c
+	psImageMaskOps.c \
+	psImageUnbin.c
 
 EXTRA_DIST = imageops.i
@@ -17,4 +19,5 @@
 pslibincludedir = $(includedir)
 pslibinclude_HEADERS = \
+	psImageBackground.h \
 	psImageConvolve.h \
 	psImageGeomManip.h \
@@ -23,5 +26,6 @@
 	psImageStats.h \
 	psImageStructManip.h \
-    psImageMaskOps.h
+	psImageMaskOps.h \
+	psImageUnbin.h
 
 CLEANFILES = *~
Index: trunk/psLib/src/imageops/psImageBackground.c
===================================================================
--- trunk/psLib/src/imageops/psImageBackground.c	(revision 7380)
+++ trunk/psLib/src/imageops/psImageBackground.c	(revision 7380)
@@ -0,0 +1,87 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "psMemory.h"
+#include "psImage.h"
+#include "psVector.h"
+#include "psStats.h"
+#include "psType.h"
+#include "psConstants.h"
+#include "psRandom.h"
+#include "psError.h"
+
+
+psStats *psImageBackground(const psImage *image, const psImage *mask, psMaskType maskValue,
+                           double fmin, double fmax, long nMax, psRandom *rng)
+{
+    PS_ASSERT_IMAGE_NON_NULL(image, NULL);
+    if (mask) {
+        PS_ASSERT_IMAGE_NON_NULL(mask, NULL);
+        PS_ASSERT_IMAGE_TYPE(mask, PS_TYPE_U8, NULL);
+        PS_ASSERT_IMAGES_SIZE_EQUAL(mask, image, NULL);
+    }
+    PS_ASSERT_FLOAT_LARGER_THAN_OR_EQUAL(fmin, 0.0, NULL);
+    PS_ASSERT_FLOAT_LARGER_THAN_OR_EQUAL(fmax, 0.0, NULL);
+    PS_ASSERT_FLOAT_LESS_THAN_OR_EQUAL(fmin, 1.0, NULL);
+    PS_ASSERT_FLOAT_LESS_THAN_OR_EQUAL(fmax, 1.0, NULL);
+    PS_ASSERT_INT_POSITIVE(nMax, NULL);
+
+    // Size of image
+    long nx = image->numCols;
+    long ny = image->numRows;
+
+    psStats *stats = psStatsAlloc(PS_STAT_ROBUST_MEDIAN | PS_STAT_ROBUST_QUARTILE); // Statistics, for return
+
+    int Nsubset = PS_MIN(nMax, nx*ny);  // Number of pixels in nubset
+    int Npixels = nx*ny;                // Total number of pixels
+
+    psVector *values = psVectorAlloc(Nsubset, PS_TYPE_F32); // Vector containing subsample
+
+    // Minimum and maximum values
+    float min = values->data.F32[0];
+    float max = values->data.F32[0];
+
+    long n = 0;                         // Number of actual pixels in subset
+    for (long i = 0; i < Nsubset; i++) {
+        double frnd = psRandomUniform(rng);
+        int pixel = Npixels * frnd;
+        int ix = pixel % nx;
+        int iy = pixel / nx;
+
+        if (mask && mask->data.U8[iy][ix] & maskValue) {
+            continue;
+        }
+
+        float value = image->data.F32[iy][ix];
+        min = PS_MIN(value, min);
+        max = PS_MIN(value, max);
+        values->data.F32[n] = value;
+        n++;
+    }
+    values->n = n;
+
+    int imin = fmin * n;
+    int imax = fmax * n;
+    int npts = imax - imin + 1;
+
+    if (!psVectorSort(values, values)) {
+        psError(PS_ERR_UNKNOWN, false, "Unable to sort values.\n");
+        psFree(stats);
+        psFree(values);
+        return NULL;
+    }
+
+    float value = 0;
+    for (long i = imin; (i <= imax) && (i < n); i++) {
+        value += values->data.F32[i];
+    }
+    value = value / npts;
+
+    stats->robustMedian = value;
+    stats->robustUQ = values->data.F32[imax];
+    stats->robustLQ = values->data.F32[imin];
+
+    psFree(values);
+    return stats;
+    // XXX correct for selection bias??
+}
Index: trunk/psLib/src/imageops/psImageBackground.h
===================================================================
--- trunk/psLib/src/imageops/psImageBackground.h	(revision 7380)
+++ trunk/psLib/src/imageops/psImageBackground.h	(revision 7380)
@@ -0,0 +1,18 @@
+#ifndef PS_IMAGE_BACKGROUND_H
+#define PS_IMAGE_BACKGROUND_H
+
+#include "psStats.h"
+#include "psImage.h"
+#include "psType.h"
+
+// Get the background for an image
+psStats *psImageBackground(const psImage *image, // Image for which to get the background
+                           const psImage *mask, // Mask image
+                           psMaskType maskValue, // Mask pixels which this mask value
+                           double fmin, // Fraction to return in the lower quartile field (0.25 for LQ)
+                           double fmax, // Fraction to return in the upper quartile field (0.75 for LQ)
+                           long nMax,   // Maximum number of pixels to subsample
+                           psRandom *rng // Random number generator (for pixel selection)
+                          );
+
+#endif // #ifndef PS_IMAGE_BACKGROUND_H
Index: trunk/psLib/src/imageops/psImageGeomManip.c
===================================================================
--- trunk/psLib/src/imageops/psImageGeomManip.c	(revision 7210)
+++ trunk/psLib/src/imageops/psImageGeomManip.c	(revision 7380)
@@ -10,6 +10,6 @@
  *  @author Ross Harman, MHPCC
  *
- *  @version $Revision: 1.23 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2006-04-06 22:55:18 $
+ *  @version $Revision: 1.24 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2006-06-07 03:22:06 $
  *
  *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -23,4 +23,5 @@
 #include "psImageGeomManip.h"
 
+#include "psAbort.h"
 #include "psError.h"
 #include "psImage.h"
@@ -878,2 +879,89 @@
 }
 
+
+#define FLIP_X_CASE(TYPENAME,TYPE) \
+case TYPENAME: { \
+    long numRows = input->numRows; \
+    long numCols = input->numCols; \
+    for (long i = 0; i < numRows; i++) { \
+        for (long j = 0; j < numCols; j++) { \
+            output->data.TYPE[i][j] = input->data.TYPE[i][numCols - j - 1]; \
+        } \
+    } \
+    break; \
+}
+
+#define FLIP_Y_CASE(TYPENAME,TYPE) \
+case TYPENAME: { \
+    long numRows = input->numRows; \
+    long numCols = input->numCols; \
+    for (long i = 0; i < numRows; i++) { \
+        for (long j = 0; j < numCols; j++) { \
+            output->data.TYPE[i][j] = input->data.TYPE[numRows - i - 1][j]; \
+        } \
+    } \
+    break; \
+}
+
+psImage *psImageFlip(psImage *output, const psImage *input, bool xFlip, bool yFlip)
+{
+    PS_ASSERT_IMAGE_NON_NULL(input, NULL);
+
+    if (xFlip && yFlip) {
+        // This is equivalent to a 180 degree rotation;
+        return psImageRotate(output, input, M_PI, NAN, PS_INTERPOLATE_BILINEAR);
+    }
+
+    if (!xFlip && !yFlip) {
+        // They want something, so let's give it to them
+        return psImageCopy(output, input, input->type.type);
+    }
+
+    output = psImageRecycle(output, input->numCols, input->numRows, input->type.type);
+
+    if (xFlip) {
+        switch (input->type.type) {
+            FLIP_X_CASE(PS_TYPE_U8,  U8);
+            FLIP_X_CASE(PS_TYPE_U16, U16);
+            FLIP_X_CASE(PS_TYPE_U32, U32);
+            FLIP_X_CASE(PS_TYPE_U64, U64);
+            FLIP_X_CASE(PS_TYPE_S8,  S8);
+            FLIP_X_CASE(PS_TYPE_S16, S16);
+            FLIP_X_CASE(PS_TYPE_S32, S32);
+            FLIP_X_CASE(PS_TYPE_S64, S64);
+            FLIP_X_CASE(PS_TYPE_F32, F32);
+            FLIP_X_CASE(PS_TYPE_F64, F64);
+            FLIP_X_CASE(PS_TYPE_C32, C32);
+            FLIP_X_CASE(PS_TYPE_C64, C64);
+        default:
+            psFree(output);
+            psError(PS_ERR_BAD_PARAMETER_TYPE, true, "Unknown type for input image: %x\n", input->type.type);
+            return NULL;
+        }
+        return output;
+    }
+    if (yFlip) {
+        switch (input->type.type) {
+            FLIP_Y_CASE(PS_TYPE_U8,  U8);
+            FLIP_Y_CASE(PS_TYPE_U16, U16);
+            FLIP_Y_CASE(PS_TYPE_U32, U32);
+            FLIP_Y_CASE(PS_TYPE_U64, U64);
+            FLIP_Y_CASE(PS_TYPE_S8,  S8);
+            FLIP_Y_CASE(PS_TYPE_S16, S16);
+            FLIP_Y_CASE(PS_TYPE_S32, S32);
+            FLIP_Y_CASE(PS_TYPE_S64, S64);
+            FLIP_Y_CASE(PS_TYPE_F32, F32);
+            FLIP_Y_CASE(PS_TYPE_F64, F64);
+            FLIP_Y_CASE(PS_TYPE_C32, C32);
+            FLIP_Y_CASE(PS_TYPE_C64, C64);
+        default:
+            psFree(output);
+            psError(PS_ERR_BAD_PARAMETER_TYPE, true, "Unknown type for input image: %x\n", input->type.type);
+            return NULL;
+        }
+        return output;
+    }
+
+    psAbort(__func__, "Should never get here.\n");
+    return NULL;
+}
Index: trunk/psLib/src/imageops/psImageGeomManip.h
===================================================================
--- trunk/psLib/src/imageops/psImageGeomManip.h	(revision 7210)
+++ trunk/psLib/src/imageops/psImageGeomManip.h	(revision 7380)
@@ -8,6 +8,6 @@
  *  @author Robert DeSonia, MHPCC
  *
- *  @version $Revision: 1.15 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2006-04-01 02:43:57 $
+ *  @version $Revision: 1.16 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2006-06-07 03:22:06 $
  *
  *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -151,9 +151,16 @@
     psRegion region,                   ///< the size of the transformed image
     const psPixels* pixels,            /**< if not NULL, consists of psPixelCoords and specifies
-                                            * which pixels in output image shall be transformed;
-                                            * otherwise, entire image generated*/
+                                                * which pixels in output image shall be transformed;
+                                                * otherwise, entire image generated*/
     psImageInterpolateMode mode,       ///< the interpolation scheme to be used
     double exposedValue                ///< Exposed value to which non-corresponding pixels are set
 );
 
+// Flip the input image
+psImage *psImageFlip(psImage *output,   // Output image, or NULL
+                     const psImage *input, // Input image
+                     bool xFlip,        // Flip x axis?
+                     bool yFlip         // Flip y axis?
+                    );
+
 #endif // #ifndef PS_IMAGE_GEOM_MANIP_H
Index: trunk/psLib/src/imageops/psImagePixelManip.c
===================================================================
--- trunk/psLib/src/imageops/psImagePixelManip.c	(revision 7210)
+++ trunk/psLib/src/imageops/psImagePixelManip.c	(revision 7380)
@@ -10,6 +10,6 @@
  *  @author Ross Harman, MHPCC
  *
- *  @version $Revision: 1.17 $ $Name: not supported by cvs2svn $
- *  @date $Date: 2006-05-16 03:27:13 $
+ *  @version $Revision: 1.18 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2006-06-07 03:22:06 $
  *
  *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
@@ -413,3 +413,2 @@
     return numClipped;
 }
-
