1 /******************************************************************************
2 pamsummcol
3 *******************************************************************************
4 Summarize the columns of a PAM image with various functions.
5
6 By Bryan Henderson, San Jose CA 2004.02.07.
7
8 Contributed to the public domain
9
10
11 ******************************************************************************/
12
13 #include "pm_c_util.h"
14 #include "pam.h"
15 #include "shhopt.h"
16 #include "mallocvar.h"
17
18 enum function {FN_ADD, FN_MEAN, FN_MIN, FN_MAX};
19
20 struct cmdlineInfo {
21 /* All the information the user supplied in the command line,
22 in a form easy for the program to use.
23 */
24 const char *inputFilespec; /* Filespec of input file */
25 enum function function;
26 unsigned int verbose;
27 };
28
29
30 static void
parseCommandLine(int argc,char ** const argv,struct cmdlineInfo * const cmdlineP)31 parseCommandLine(int argc, char ** const argv,
32 struct cmdlineInfo * const cmdlineP) {
33 /*----------------------------------------------------------------------------
34 Note that the file spec array we return is stored in the storage that
35 was passed to us as the argv array.
36 -----------------------------------------------------------------------------*/
37 optEntry *option_def = malloc(100*sizeof(optEntry));
38 /* Instructions to OptParseOptions2 on how to parse our options.
39 */
40 optStruct3 opt;
41
42 unsigned int option_def_index;
43
44 unsigned int sumSpec, meanSpec, minSpec, maxSpec;
45
46 option_def_index = 0; /* incremented by OPTENTRY */
47 OPTENT3(0, "sum", OPT_FLAG, NULL, &sumSpec, 0);
48 OPTENT3(0, "mean", OPT_FLAG, NULL, &meanSpec, 0);
49 OPTENT3(0, "min", OPT_FLAG, NULL, &minSpec, 0);
50 OPTENT3(0, "max", OPT_FLAG, NULL, &maxSpec, 0);
51 OPTENT3(0, "verbose", OPT_FLAG, NULL, &cmdlineP->verbose, 0);
52
53 opt.opt_table = option_def;
54 opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */
55 opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */
56
57 pm_optParseOptions3(&argc, argv, opt, sizeof(opt), 0);
58 /* Uses and sets argc, argv, and some of *cmdlineP and others. */
59
60 if (sumSpec + minSpec + maxSpec > 1)
61 pm_error("You may specify at most one of -sum, -min, and -max");
62
63 if (sumSpec) {
64 cmdlineP->function = FN_ADD;
65 } else if (meanSpec) {
66 cmdlineP->function = FN_MEAN;
67 } else if (minSpec) {
68 cmdlineP->function = FN_MIN;
69 } else if (maxSpec) {
70 cmdlineP->function = FN_MAX;
71 } else
72 pm_error("You must specify one of -sum, -min, or -max");
73
74 if (argc-1 > 1)
75 pm_error("Too many arguments (%d). File spec is the only argument.",
76 argc-1);
77
78 if (argc-1 < 1)
79 cmdlineP->inputFilespec = "-";
80 else
81 cmdlineP->inputFilespec = argv[1];
82
83 }
84
85
86 struct accum {
87 union {
88 unsigned int sum;
89 unsigned int min;
90 unsigned int max;
91 } u;
92 };
93
94
95
96 static void
createAccumulator(enum function const function,unsigned int const cols,unsigned int const planes,struct accum *** const accumulatorP)97 createAccumulator(enum function const function,
98 unsigned int const cols,
99 unsigned int const planes,
100 struct accum *** const accumulatorP) {
101
102 struct accum ** accumulator;
103 unsigned int col;
104
105 MALLOCARRAY_NOFAIL(accumulator, cols);
106
107 for (col = 0; col < cols; ++col) {
108 unsigned int plane;
109
110 MALLOCARRAY_NOFAIL(accumulator[col], planes);
111
112 for (plane = 0; plane < planes; ++plane) {
113 switch(function) {
114 case FN_ADD: accumulator[col][plane].u.sum = 0; break;
115 case FN_MEAN: accumulator[col][plane].u.sum = 0; break;
116 case FN_MIN: accumulator[col][plane].u.min = UINT_MAX; break;
117 case FN_MAX: accumulator[col][plane].u.max = 0; break;
118 }
119 }
120 }
121 *accumulatorP = accumulator;
122 }
123
124
125
126 static void
destroyAccumulator(struct accum ** accumulator,unsigned int const cols)127 destroyAccumulator(struct accum ** accumulator,
128 unsigned int const cols) {
129
130 unsigned int col;
131 for (col = 0; col < cols; ++col)
132 free(accumulator[col]);
133
134 free(accumulator);
135 }
136
137
138
139 static void
aggregate(struct pam * const inpamP,tuple * const tupleRow,enum function const function,struct accum ** const accumulator)140 aggregate(struct pam * const inpamP,
141 tuple * const tupleRow,
142 enum function const function,
143 struct accum ** const accumulator) {
144
145 unsigned int col;
146
147 for (col = 0; col < inpamP->width; ++col) {
148 unsigned int plane;
149 for (plane = 0; plane < inpamP->depth; ++plane) {
150 switch(function) {
151 case FN_ADD:
152 case FN_MEAN:
153 if (accumulator[col][plane].u.sum >
154 UINT_MAX - tupleRow[col][plane])
155 pm_error("Numerical overflow in Column %u", col);
156 accumulator[col][plane].u.sum += tupleRow[col][plane];
157 break;
158 case FN_MIN:
159 if (tupleRow[col][plane] < accumulator[col][plane].u.min)
160 accumulator[col][plane].u.min = tupleRow[col][plane];
161 break;
162 case FN_MAX:
163 if (tupleRow[col][plane] > accumulator[col][plane].u.min)
164 accumulator[col][plane].u.min = tupleRow[col][plane];
165 break;
166 }
167 }
168 }
169 }
170
171
172
173 static void
makeSummaryRow(struct accum ** const accumulator,unsigned int const count,struct pam * const pamP,enum function const function,tuple * const tupleRow)174 makeSummaryRow(struct accum ** const accumulator,
175 unsigned int const count,
176 struct pam * const pamP,
177 enum function const function,
178 tuple * const tupleRow) {
179
180 unsigned int col;
181
182 for (col = 0; col < pamP->width; ++col) {
183 unsigned int plane;
184 for (plane = 0; plane < pamP->depth; ++plane) {
185 switch(function) {
186 case FN_ADD:
187 tupleRow[col][plane] =
188 MIN(accumulator[col][plane].u.sum, pamP->maxval);
189 break;
190 case FN_MEAN:
191 tupleRow[col][plane] =
192 ROUNDU((double)accumulator[col][plane].u.sum / count);
193 break;
194 case FN_MIN:
195 tupleRow[col][plane] =
196 accumulator[col][plane].u.min;
197 break;
198 case FN_MAX:
199 tupleRow[col][plane] =
200 accumulator[col][plane].u.max;
201 break;
202 }
203 }
204 }
205 }
206
207
208
209 int
main(int argc,char * argv[])210 main(int argc, char *argv[]) {
211
212 FILE* ifP;
213 tuple* inputRow; /* Row from input image */
214 tuple* outputRow; /* Output row */
215 int row;
216 struct cmdlineInfo cmdline;
217 struct pam inpam; /* Input PAM image */
218 struct pam outpam; /* Output PAM image */
219 struct accum ** accumulator; /* malloc'ed two-dimensional array */
220
221 pnm_init( &argc, argv );
222
223 parseCommandLine(argc, argv, &cmdline);
224
225 ifP = pm_openr(cmdline.inputFilespec);
226
227 pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type));
228
229 createAccumulator(cmdline.function, inpam.width, inpam.depth,
230 &accumulator);
231
232 inputRow = pnm_allocpamrow(&inpam);
233
234 outpam = inpam; /* Initial value -- most fields should be same */
235 outpam.file = stdout;
236 outpam.height = 1;
237
238 pnm_writepaminit(&outpam);
239
240 outputRow = pnm_allocpamrow(&outpam);
241
242 for (row = 0; row < inpam.height; row++) {
243 pnm_readpamrow(&inpam, inputRow);
244
245 aggregate(&inpam, inputRow, cmdline.function, accumulator);
246 }
247 makeSummaryRow(accumulator, inpam.height, &outpam, cmdline.function,
248 outputRow);
249 pnm_writepamrow(&outpam, outputRow);
250
251 pnm_freepamrow(outputRow);
252 pnm_freepamrow(inputRow);
253 destroyAccumulator(accumulator, inpam.width);
254 pm_close(inpam.file);
255 pm_close(outpam.file);
256
257 return 0;
258 }
259