Index: /branches/eam_branches/ipp-pstamp-20260421/Ohana/src/opihi/cmd.data/Makefile
===================================================================
--- /branches/eam_branches/ipp-pstamp-20260421/Ohana/src/opihi/cmd.data/Makefile	(revision 43039)
+++ /branches/eam_branches/ipp-pstamp-20260421/Ohana/src/opihi/cmd.data/Makefile	(revision 43040)
@@ -44,4 +44,5 @@
 $(SRC)/device.$(ARCH).o	\
 $(SRC)/dft2d.$(ARCH).o	\
+$(SRC)/dilation.$(ARCH).o	\
 $(SRC)/dimendown.$(ARCH).o	\
 $(SRC)/dimenup.$(ARCH).o	\
@@ -53,4 +54,5 @@
 $(SRC)/dbupdate.$(ARCH).o	\
 $(SRC)/erase.$(ARCH).o		\
+$(SRC)/erosion.$(ARCH).o	\
 $(SRC)/extract.$(ARCH).o	\
 $(SRC)/fft1d.$(ARCH).o		\
Index: /branches/eam_branches/ipp-pstamp-20260421/Ohana/src/opihi/cmd.data/dilation.c
===================================================================
--- /branches/eam_branches/ipp-pstamp-20260421/Ohana/src/opihi/cmd.data/dilation.c	(revision 43040)
+++ /branches/eam_branches/ipp-pstamp-20260421/Ohana/src/opihi/cmd.data/dilation.c	(revision 43040)
@@ -0,0 +1,66 @@
+# include "data.h"
+
+int dilation (int argc, char **argv) {
+  
+  Buffer *in, *out;
+
+  if (argc != 4) {
+    gprint (GP_ERR, "USAGE: dilation (input) (output) [kernel]\n");
+    return (FALSE);
+  }
+  
+  // two kernel options: 4pt and 8pt
+  int EightPoint = -1;
+  if (!strcasecmp (argv[3], "4pt")) {
+    EightPoint = FALSE;
+  }
+  if (!strcasecmp (argv[3], "8pt")) {
+    EightPoint = TRUE;
+  }
+  if (EightPoint == -1) {
+    gprint (GP_ERR, "kernel may be 4pt or 8pt\n");
+    return (FALSE);
+  }
+
+  if ((in   = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((out  = SelectBuffer (argv[2], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+
+  int Nx = in[0].matrix.Naxis[0];
+  int Ny = in[0].matrix.Naxis[1];
+
+  // create output buffer with dimensions of the input buffer
+  gfits_free_matrix (&out->matrix);
+  gfits_free_header (&out->header);
+  if (!CreateBuffer (out, Nx, Ny, -32, 0.0, 1.0)) return FALSE;
+
+  // greyscale dilation: output value is max value of input pixels in neighborhood
+
+  // loop over output pixels
+  for (int j = 0; j < Ny; j++) {
+    float *vi_m = (j > 0) ? (float *) in[0].matrix.buffer + (j - 1)*Nx : NULL;
+    float *vi_o = (float *) in[0].matrix.buffer + (j + 0)*Nx;
+    float *vi_p = (j < Ny - 1) ? (float *) in[0].matrix.buffer + (j + 1)*Nx : NULL;
+    float *vo = (float *) out[0].matrix.buffer + (j + 0)*Nx;
+    for (int i = 0; i < Nx; i++) {
+      int ltEdge = (i == 0);
+      int rtEdge = (i == Nx - 1);
+      // input value: vi[i];
+      float maxValue = vi_o[i];
+      maxValue = MAX (maxValue, vi_o[i - 1]);
+      maxValue = !ltEdge ? MAX (maxValue, vi_o[i - 1]) : maxValue;
+      maxValue = !rtEdge ? MAX (maxValue, vi_o[i + 1]) : maxValue;
+      maxValue = vi_m ? MAX (maxValue, vi_m[i]) : maxValue;
+      maxValue = vi_p ? MAX (maxValue, vi_p[i]) : maxValue;
+      // 8 points
+      if (EightPoint) {
+	maxValue = vi_m && !ltEdge ? MAX (maxValue, vi_m[i - 1]) : maxValue;
+	maxValue = vi_p && !ltEdge ? MAX (maxValue, vi_p[i - 1]) : maxValue;
+	maxValue = vi_m && !rtEdge ? MAX (maxValue, vi_m[i + 1]) : maxValue;
+	maxValue = vi_p && !rtEdge ? MAX (maxValue, vi_p[i + 1]) : maxValue;
+      }
+      vo[i] = maxValue;
+    }
+  }
+  return (TRUE);
+}
+
Index: /branches/eam_branches/ipp-pstamp-20260421/Ohana/src/opihi/cmd.data/erosion.c
===================================================================
--- /branches/eam_branches/ipp-pstamp-20260421/Ohana/src/opihi/cmd.data/erosion.c	(revision 43040)
+++ /branches/eam_branches/ipp-pstamp-20260421/Ohana/src/opihi/cmd.data/erosion.c	(revision 43040)
@@ -0,0 +1,66 @@
+# include "data.h"
+
+int erosion (int argc, char **argv) {
+  
+  Buffer *in, *out;
+
+  if (argc != 4) {
+    gprint (GP_ERR, "USAGE: erosion (input) (output) [kernel]\n");
+    return (FALSE);
+  }
+  
+  // two kernel options: 4pt and 8pt
+  int EightPoint = -1;
+  if (!strcasecmp (argv[3], "4pt")) {
+    EightPoint = FALSE;
+  }
+  if (!strcasecmp (argv[3], "8pt")) {
+    EightPoint = TRUE;
+  }
+  if (EightPoint == -1) {
+    gprint (GP_ERR, "kernel may be 4pt or 8pt\n");
+    return (FALSE);
+  }
+
+  if ((in   = SelectBuffer (argv[1], OLDBUFFER, TRUE)) == NULL) return (FALSE);
+  if ((out  = SelectBuffer (argv[2], ANYBUFFER, TRUE)) == NULL) return (FALSE);
+
+  int Nx = in[0].matrix.Naxis[0];
+  int Ny = in[0].matrix.Naxis[1];
+
+  // create output buffer with dimensions of the input buffer
+  gfits_free_matrix (&out->matrix);
+  gfits_free_header (&out->header);
+  if (!CreateBuffer (out, Nx, Ny, -32, 0.0, 1.0)) return FALSE;
+
+  // greyscale erosion: output value is min value of input pixels in neighborhood
+
+  // loop over output pixels
+  for (int j = 0; j < Ny; j++) {
+    float *vi_m = (j > 0) ? (float *) in[0].matrix.buffer + (j - 1)*Nx : NULL;
+    float *vi_o = (float *) in[0].matrix.buffer + (j + 0)*Nx;
+    float *vi_p = (j < Ny - 1) ? (float *) in[0].matrix.buffer + (j + 1)*Nx : NULL;
+    float *vo = (float *) out[0].matrix.buffer + (j + 0)*Nx;
+    for (int i = 0; i < Nx; i++) {
+      int ltEdge = (i == 0);
+      int rtEdge = (i == Nx - 1);
+      // input value: vi[i];
+      float minValue = vi_o[i];
+      minValue = MIN (minValue, vi_o[i - 1]);
+      minValue = !ltEdge ? MIN (minValue, vi_o[i - 1]) : minValue;
+      minValue = !rtEdge ? MIN (minValue, vi_o[i + 1]) : minValue;
+      minValue = vi_m ? MIN (minValue, vi_m[i]) : minValue;
+      minValue = vi_p ? MIN (minValue, vi_p[i]) : minValue;
+      // 8 points
+      if (EightPoint) {
+	minValue = vi_m && !ltEdge ? MIN (minValue, vi_m[i - 1]) : minValue;
+	minValue = vi_p && !ltEdge ? MIN (minValue, vi_p[i - 1]) : minValue;
+	minValue = vi_m && !rtEdge ? MIN (minValue, vi_m[i + 1]) : minValue;
+	minValue = vi_p && !rtEdge ? MIN (minValue, vi_p[i + 1]) : minValue;
+      }
+      vo[i] = minValue;
+    }
+  }
+  return (TRUE);
+}
+
Index: /branches/eam_branches/ipp-pstamp-20260421/Ohana/src/opihi/cmd.data/init.c
===================================================================
--- /branches/eam_branches/ipp-pstamp-20260421/Ohana/src/opihi/cmd.data/init.c	(revision 43039)
+++ /branches/eam_branches/ipp-pstamp-20260421/Ohana/src/opihi/cmd.data/init.c	(revision 43040)
@@ -35,8 +35,10 @@
 int device           PROTO((int, char **));
 int dft2d            PROTO((int, char **));
+int dilation         PROTO((int, char **));
 int dimendown        PROTO((int, char **));
 int dimenup          PROTO((int, char **));
 int distribute       PROTO((int, char **));
 int erase            PROTO((int, char **));
+int erosion          PROTO((int, char **));
 int extract          PROTO((int, char **));
 int fft1d            PROTO((int, char **));
@@ -246,4 +248,5 @@
   {1, "device",       device,           "set / get current graphics device"},
   {1, "dft2d",        dft2d,            "2D discrete fourier transform"},
+  {1, "dilation",     dilation,         "perform the dilation operation"},
   {1, "dimendown",    dimendown,        "convert image to vector"},
   {1, "dimenup",      dimenup,          "convert vector to image"},
@@ -251,4 +254,5 @@
   {1, "dot",          dot,              "plot a single point"},
   {1, "erase",        erase,            "erase objects on an image overlay"},
+  {1, "erosion",      erosion,          "perform the erosion operation"},
   {1, "extract",      extract,          "extract a portion of a image into another image"},
   {1, "fft1d",        fft1d,            "fft on a vector"},
