Index: trunk/psphot/src/pmFootprint.c
===================================================================
--- trunk/psphot/src/pmFootprint.c	(revision 16048)
+++ trunk/psphot/src/pmFootprint.c	(revision 16820)
@@ -1241,2 +1241,51 @@
    return peaks;
 }
+
+void pmDetectionsFree (pmDetections *detections) {
+
+  if (!detections) return;
+
+  psFree (detections->footprints);
+  psFree (detections->peaks);
+  psFree (detections->oldPeaks);
+  return;
+}
+
+// generate a pmDetections container with empty (allocated) footprints and peaks containers
+pmDetections *pmDetectionsAlloc() {
+
+    pmDetections *detections = (pmDetections *)psAlloc(sizeof(pmDetections));
+    psMemSetDeallocator(detections, (psFreeFunc) pmDetectionsFree);
+
+    detections->footprints = NULL;
+    detections->peaks      = NULL;
+    detections->oldPeaks   = NULL;
+    detections->last       = 0;
+
+    return (detections);
+}
+
+/************************************************************************************************************/
+/*
+ * Cull a set of peaks contained in a psArray of pmFootprints
+ */
+psErrorCode
+psphotCullPeaks(const psImage *image,   // the image wherein lives the footprint
+                const psImage *weight,  // corresponding variance image
+                const psMetadata *recipe,
+                psArray *footprints) {  // array of pmFootprints
+    bool status = false;
+    float nsigma_delta = psMetadataLookupF32(&status, recipe, "FOOTPRINT_CULL_NSIGMA_DELTA");
+    if (!status) {
+        nsigma_delta = 0; // min.
+    }
+    float nsigma_min = psMetadataLookupF32(&status, recipe, "FOOTPRINT_CULL_NSIGMA_MIN");
+    if (!status) {
+        nsigma_min = 0;
+    }
+    const float skyStdev = psMetadataLookupF32(NULL, recipe, "SKY_STDEV");
+
+    return pmFootprintArrayCullPeaks(image, weight, footprints,
+                                     nsigma_delta, nsigma_min*skyStdev);
+}
+
