about summary refs log tree commit diff
path: root/generator
diff options
context:
space:
mode:
authorgiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2013-12-19 23:18:13 +0000
committergiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2013-12-19 23:18:13 +0000
commitf3117dbb027bef24d8d5aaade2ddbd7a8a874792 (patch)
tree3c2abe696d142925fd01cebec26cb9ad46693600 /generator
parentc2e9cd928e183e09ad9515ec336b2e13ec093019 (diff)
downloadnetpbm-mirror-f3117dbb027bef24d8d5aaade2ddbd7a8a874792.tar.gz
netpbm-mirror-f3117dbb027bef24d8d5aaade2ddbd7a8a874792.tar.xz
netpbm-mirror-f3117dbb027bef24d8d5aaade2ddbd7a8a874792.zip
cleanup
git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@2067 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'generator')
-rw-r--r--generator/pgmkernel.c267
1 files changed, 200 insertions, 67 deletions
diff --git a/generator/pgmkernel.c b/generator/pgmkernel.c
index b741d596..d6c75cdc 100644
--- a/generator/pgmkernel.c
+++ b/generator/pgmkernel.c
@@ -1,8 +1,8 @@
-/* pgmkernel.c - generate a portable graymap convolution kernel
+/* pgmkernel.c - generate a PGM convolution kernel
 **
-** Creates a Portable Graymap file containing a convolution filter
-** with max value = 255 and minimum value > 127 that can be used as a 
-** smoothing kernel for pnmconvol.
+** Creates a PGM image containing a convolution filter with max value = 255
+** and minimum value > 127 that can be used as a smoothing kernel for
+** pnmconvol.
 **
 ** Copyright (C) 1992 by Alberto Accomazzi, Smithsonian Astrophysical
 ** Observatory.
@@ -16,76 +16,209 @@
 */
 
 #include <math.h>
-#include "pgm.h"
+#include "pm_c_util.h"
+#include "shhopt.h"
 #include "mallocvar.h"
+#include "pgm.h"
 
-int
-main ( argc, argv )
-    int argc;
-    char *argv[];
-{
-    register    int i, j;
-    int     argn = 1, ixsize, iysize, maxval = 255;
-    double  fxsize = 0.0, fysize = 0.0, w = 6.0, kxcenter, kycenter, 
-        tmax = 0, *fkernel;
-    const char  *usage = "[-weight f] width [height]";
-
-    pgm_init( &argc, argv );
-
-    while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' )
-    {
-        if ( pm_keymatch( argv[argn], "-weight", 2 )) {
-            if (++argn >= argc)
-                pm_usage( usage );
-            else if (sscanf(argv[argn], "%lf", &w) != 1)
-                pm_usage( usage );
-        }
-        else
-            pm_usage( usage );
-        argn++;
-    }
 
-    if (argn == argc)
-        pm_usage( usage );
-    
-    if (sscanf(argv[argn], "%lf", &fxsize) != 1) 
-        pm_error( "error reading input kernel x size, (%s)\n", argv[argn]);
 
-    ++argn;
-    if (argn == argc - 1) {
-        if (sscanf(argv[argn], "%lf", &fysize) != 1)
-            pm_error( "error reading input kernel y size, (%s)\n", argv[argn]);
+struct CmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    unsigned int cols;
+    unsigned int rows;
+    float weight;
+};
+
+
+
+static void
+parseCommandLine(int argc, const char ** argv,
+                 struct CmdlineInfo * const cmdlineP) {
+/*----------------------------------------------------------------------------
+  Convert program invocation arguments (argc,argv) into a format the 
+  program can use easily, struct cmdlineInfo.  Validate arguments along
+  the way and exit program with message if invalid.
+
+  Note that some string information we return as *cmdlineP is in the storage 
+  argv[] points to.
+-----------------------------------------------------------------------------*/
+    optEntry *option_def;
+        /* Instructions to OptParseOptions2 on how to parse our options.
+         */
+    optStruct3 opt;
+
+    unsigned int weightSpec;
+    unsigned int option_def_index;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENTRY */
+    OPTENT3(0,   "weight",  OPT_FLOAT, &cmdlineP->weight, 
+            &weightSpec,     0);
+
+    opt.opt_table = option_def;
+    opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
+    opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
+
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    if (!weightSpec)
+        cmdlineP->weight = 6.0;
+
+    if (argc-1 < 1)
+        pm_error("Need at least one argument: size of (square) kernel");
+    else if (argc-1 == 1) {
+        if (atoi(argv[1]) <= 0)
+            pm_error("Dimension must be a positive number.  "
+                     "You specified '%s'", argv[1]);
+        cmdlineP->cols = atoi(argv[1]);
+        cmdlineP->rows = atoi(argv[1]);
+    } else if (argc-1 == 2) {
+        if (atoi(argv[1]) <= 0)
+            pm_error("Width must be a positive number.  "
+                     "You specified '%s'", argv[1]);
+        if (atoi(argv[2]) <= 0)
+            pm_error("Height must be a positive number.  "
+                     "You specified '%s'", argv[2]);
+        cmdlineP->cols = atoi(argv[1]);
+        cmdlineP->rows = atoi(argv[2]);
+    } else
+        pm_error("At most two arguments allowed.  "
+                 "You specified %u", argc-1);
+}
+
+
+
+static double
+t(double const dx2,
+  double const dy2,
+  double const weight) {
+/*----------------------------------------------------------------------------
+  The t value for a pixel that is (dx, dy) pixels away from the center of
+  the kernel, where 'dx2' is SQR(dx) and 'dy2' is SQR(dy), if the distance is
+  weighted by 'weight'.
+-----------------------------------------------------------------------------*/
+
+    return 1.0 / (1.0 + weight * sqrt(dx2 + dy2));
+}
+
+
+
+static double
+tMaxAllKernel(unsigned int const cols,
+              unsigned int const rows,
+              double       const weight) {
+/*----------------------------------------------------------------------------
+   The maximum t value over all pixels in the kernel, if the kernel is
+   'cols' by 'rows' pixels and distance is weighted by 'weight'.
+-----------------------------------------------------------------------------*/
+
+    /* It depends upon whether there is an even or odd number of rows
+       and columns.  If both dimensions are odd, there is a pixel right
+       at the center, and it has the greatest t value.  If both dimensions
+       are even, the center of the image is in the center of a 4-pixel
+       square and each of those 4 pixels has the greatest t value.  If
+       one dimension is even and the other odd, the center of the kernel
+       is midway between two pixels, horizontally or vertically, and one
+       of those two pixels has the greatest t value.
+    */
+
+    double dxMax, dyMax;
+
+    switch (cols % 2 + rows % 2) {
+    case 0:
+        dxMax = 0.5;
+        dyMax = 0.5;
+        break;
+    case 1:
+        dxMax = 0.5;
+        dyMax = 0.0;
+        break;
+    case 2:
+        dxMax = 0.0;
+        dyMax = 0.0;
     }
-    else if (argn == argc)
-        fysize = fxsize;
-    else
-        pm_usage( usage );
-
-    if (fxsize <= 1 || fysize <= 1)
-        pm_usage( usage );
-
-    kxcenter = (fxsize - 1) / 2.0;
-    kycenter = (fysize - 1) / 2.0;
-    ixsize = fxsize + 0.999;
-    iysize = fysize + 0.999;
-    MALLOCARRAY(fkernel, ixsize * iysize);
-    for (i = 0; i < iysize; i++) 
-        for (j = 0; j < ixsize; j++) {
-            fkernel[i*ixsize+j] = 1.0 / (1.0 + w * sqrt((double)
-                                                        (i-kycenter)*(i-kycenter)+
-                                                        (j-kxcenter)*(j-kxcenter)));
-            if (tmax < fkernel[i*ixsize+j])
-                tmax = fkernel[i*ixsize+j];
-        }
 
-    /* output PGM header + data (ASCII format only) */
-    printf("P2\n%d %d\n%d\n", ixsize, iysize, maxval);
+    return t(SQR(dxMax), SQR(dyMax), weight);
+}
+
+
+
+static void
+writeKernel(FILE *       const ofP,
+            unsigned int const cols,
+            unsigned int const rows,
+            gray         const maxval,
+            gray **      const halfKernel,
+            unsigned int const halfRows) {
+
+    unsigned int row;
     
-    for (i = 0; i < iysize; i++, printf("\n"))
-        for (j = 0; j < ixsize; j++)
-            printf(" %3d", (int)(maxval * (fkernel[i*ixsize+j] / 
-                                           (2*tmax) + 0.5)));
+    pgm_writepgminit(stdout, cols, rows, maxval, 0);
+
+    for (row = 0; row < halfRows; ++row)
+        pgm_writepgmrow(stdout, halfKernel[row], cols, maxval, 0);
+
+    /* Now write out the same rows in reverse order. */
     
-    exit(0);
+    for (; row < rows; ++row)
+        pgm_writepgmrow(stdout, halfKernel[rows-1-row], cols, maxval, 0);
 }
 
+
+
+int
+main(int argc, const char * argv[]) {
+
+    gray const maxval = 255;
+
+    struct CmdlineInfo cmdline;
+    unsigned int arows;
+    int arow;
+    double xcenter, ycenter;
+        /* row, column "number" of center of kernel */
+    double tMax;
+        /* The maximum t value over all pixels */
+    gray ** destarray;
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    xcenter = ((double) cmdline.cols - 1) / 2.0;
+    ycenter = ((double) cmdline.rows - 1) / 2.0;
+
+    tMax = tMaxAllKernel(cmdline.cols, cmdline.rows, cmdline.weight);
+
+    /* Output matrix is symmetric vertically and horizontally. */
+
+    arows = (cmdline.rows + 1) / 2;
+        /* Half the number of rows.  Add 1 if odd. */
+    destarray = pgm_allocarray(cmdline.cols, arows);
+
+    for (arow = 0; arow < arows; ++arow) {
+        double const dy2 = SQR(arow - ycenter);
+
+        unsigned int col;
+
+        for (col = 0; col < cmdline.cols; ++col) {
+            double const dx2 = SQR(col - xcenter);
+
+            double const normalized = t(dx2, dy2, cmdline.weight) / 2 / tMax;
+
+            destarray[arow][col] = destarray[arow][cmdline.cols - col - 1] =
+                ROUNDU(maxval * (0.5 + normalized));
+        }
+    }
+
+    writeKernel(stdout, cmdline.cols, cmdline.rows, maxval,
+                destarray, arows);
+
+    pgm_freearray(destarray, arows);
+
+    return 0;
+}