GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/bin/ilk.c Lines: 0 144 0.0 %
Date: 2017-05-26 Branches: 0 74 0.0 %

Line Branch Exec Source
1
/*
2
  Teem: Tools to process and visualize scientific data and images             .
3
  Copyright (C) 2013, 2012, 2011, 2010, 2009  University of Chicago
4
  Copyright (C) 2008, 2007, 2006, 2005  Gordon Kindlmann
5
  Copyright (C) 2004, 2003, 2002, 2001, 2000, 1999, 1998  University of Utah
6
7
  This library is free software; you can redistribute it and/or
8
  modify it under the terms of the GNU Lesser General Public License
9
  (LGPL) as published by the Free Software Foundation; either
10
  version 2.1 of the License, or (at your option) any later version.
11
  The terms of redistributing and/or modifying this software also
12
  include exceptions to the LGPL that facilitate static linking.
13
14
  This library is distributed in the hope that it will be useful,
15
  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
  Lesser General Public License for more details.
18
19
  You should have received a copy of the GNU Lesser General Public License
20
  along with this library; if not, write to Free Software Foundation, Inc.,
21
  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22
*/
23
24
#include <teem/unrrdu.h>
25
#include <teem/moss.h>
26
27
static const char *ilkInfo =
28
  ("(I)mage (L)inear Trans(X-->K)forms. "
29
   "Applies linear (homogenous coordinate) transforms "
30
   "to a given image, using the given kernel for "
31
   "resampling. ");
32
33
int
34
main(int argc, const char *argv[]) {
35
  const char *me;
36
  char *errS, *outS;
37
  hestOpt *hopt=NULL;
38
  hestParm *hparm;
39
  airArray *mop;
40
  Nrrd *nin, *nout;
41
  NrrdKernelSpec *ksp;
42
  mossSampler *msp;
43
  double mat[6], **matList, *origInfo, origMat[6], origInvMat[6], ox, oy,
44
    min[2], max[2];
45
  int d, bound, ax0, size[2]; /* HEY size[] should be size_t */
46
  unsigned int matListLen, _bkgLen, i, avgNum;
47
  float *bkg, *_bkg, scale[4];
48
49
  me = argv[0];
50
  mop = airMopNew();
51
  hparm = hestParmNew();
52
  airMopAdd(mop, hparm, (airMopper)hestParmFree, airMopAlways);
53
  hparm->elideSingleEnumType = AIR_TRUE;
54
  hparm->elideSingleOtherType = AIR_TRUE;
55
  hparm->elideSingleOtherDefault = AIR_FALSE;
56
  hparm->elideMultipleNonExistFloatDefault = AIR_TRUE;
57
  hparm->respFileEnable = AIR_TRUE;
58
59
  hestOptAdd(&hopt, "i", "image", airTypeOther, 1, 1, &nin, "-",
60
             "input image", NULL, NULL, nrrdHestNrrd);
61
  hestOptAdd(&hopt, "0", "origin", airTypeOther, 1, 1, &origInfo, "p:0,0",
62
             "where to location (0,0) prior to applying transforms.\n "
63
             "\b\bo \"u:<float>,<float>\" locate origin in a unit box "
64
             "[0,1]x[0,1] which covers the original image\n "
65
             "\b\bo \"p:<float>,<float>\" locate origin at a particular "
66
             "pixel location, in the index space of the image",
67
             NULL, NULL, mossHestOrigin);
68
  hestOptAdd(&hopt, "t", "xform0", airTypeOther, 1, -1, &matList, NULL,
69
             "transform(s) to apply to image.  Transforms "
70
             "are applied in the order in which they appear.\n "
71
             "\b\bo \"identity\": no geometric transform, just resampling\n "
72
             "\b\bo \"translate:x,y\": shift image by vector (x,y), as "
73
             "measured in pixels\n "
74
             "\b\bo \"rotate:ang\": rotate CCW by ang degrees\n "
75
             "\b\bo \"scale:xs,ys\": scale by xs in X, and ys in Y\n "
76
             "\b\bo \"shear:fix,amnt\": shear by amnt, keeping fixed "
77
             "the pixels along a direction <fix> degrees from the X axis\n "
78
             "\b\bo \"flip:ang\": flip along axis an angle <ang> degrees from "
79
             "the X axis\n "
80
             "\b\bo \"a,b,tx,c,d,ty\": specify the transform explicitly "
81
             "in row-major order (opposite of PostScript) ",
82
             &matListLen, NULL, mossHestTransform);
83
  hestOptAdd(&hopt, "k", "kernel", airTypeOther, 1, 1, &ksp,
84
             "cubic:0,0.5", "reconstruction kernel",
85
             NULL, NULL, nrrdHestKernelSpec);
86
  hestOptAdd(&hopt, "min", "xMin yMin", airTypeDouble, 2, 2, min, "nan nan",
87
             "lower bounding corner of output image. Default (by not "
88
             "using this option) is the lower corner of input image. ");
89
  hestOptAdd(&hopt, "max", "xMax yMax", airTypeDouble, 2, 2, max, "nan nan",
90
             "upper bounding corner of output image. Default (by not "
91
             "using this option) is the upper corner of input image. ");
92
  hestOptAdd(&hopt, "b", "boundary", airTypeEnum, 1, 1, &bound, "bleed",
93
             "what to do when sampling outside original image.\n "
94
             "\b\bo \"bleed\": copy values at image border outward\n "
95
             "\b\bo \"wrap\": do wrap-around on image locations\n "
96
             "\b\bo \"pad\": use a given background value (via \"-bg\")",
97
             NULL, nrrdBoundary);
98
  hestOptAdd(&hopt, "bg", "bg0 bg1", airTypeFloat, 1, -1, &_bkg, "nan",
99
             "background color to use with boundary behavior \"pad\". "
100
             "Defaults to all zeroes.",
101
             &_bkgLen);
102
  hestOptAdd(&hopt, "s", "xSize ySize", airTypeOther, 2, 2, scale, "x1 x1",
103
             "For each axis, information about how many samples in output:\n "
104
             "\b\bo \"x<float>\": number of output samples is some scaling of "
105
             " the number input of samples; multiplied by <float>\n "
106
             "\b\bo \"<int>\": specify exact number of samples",
107
             NULL, NULL, &unrrduHestScaleCB);
108
  hestOptAdd(&hopt, "a", "avg #", airTypeUInt, 1, 1, &avgNum, "0",
109
             "number of averages (if there there is only one "
110
             "rotation)");
111
  hestOptAdd(&hopt, "o", "filename", airTypeString, 1, 1, &outS, "-",
112
             "file to write output nrrd to");
113
  hestParseOrDie(hopt, argc-1, argv+1, hparm,
114
                 me, ilkInfo, AIR_TRUE, AIR_TRUE, AIR_TRUE);
115
  airMopAdd(mop, hopt, (airMopper)hestOptFree, airMopAlways);
116
  /* HEY: this is commented out because there is a memory bug otherwise;
117
     this needs to be debugged */
118
  /* airMopAdd(mop, hopt, (airMopper)hestParseFree, airMopAlways); */
119
120
  nout = nrrdNew();
121
  airMopAdd(mop, nout, (airMopper)nrrdNuke, airMopAlways);
122
  msp = mossSamplerNew();
123
  airMopAdd(mop, msp, (airMopper)mossSamplerNix, airMopAlways);
124
  msp->boundary = bound;
125
  if (mossSamplerKernelSet(msp, ksp->kernel, ksp->parm)) {
126
    fprintf(stderr, "%s: trouble with sampler:\n%s\n",
127
            me, errS = biffGetDone(MOSS)); free(errS);
128
    airMopError(mop); return 1;
129
  }
130
  if (nrrdBoundaryPad == bound) {
131
    if (_bkgLen != MOSS_NCOL(nin)) {
132
      char stmp[AIR_STRLEN_SMALL];
133
      fprintf(stderr, "%s: got %d background colors, image has %s colors\n",
134
              me, _bkgLen, airSprintSize_t(stmp, MOSS_NCOL(nin)));
135
      airMopError(mop); return 1;
136
    } else {
137
      bkg = _bkg;
138
    }
139
  } else {
140
    /* maybe warn user if they gave a background that won't be used? */
141
    /* No- because hest is stupid, and right now we always parse the
142
       single (default) "nan" for this argument! */
143
    bkg = NULL;
144
  }
145
146
  ax0 = MOSS_AXIS0(nin);
147
  if (!( AIR_EXISTS(nin->axis[ax0+0].min)
148
         && AIR_EXISTS(nin->axis[ax0+0].max))) {
149
    nrrdAxisInfoMinMaxSet(nin, ax0+0, mossDefCenter);
150
  }
151
  if (!( AIR_EXISTS(nin->axis[ax0+1].min)
152
         && AIR_EXISTS(nin->axis[ax0+1].max))) {
153
    nrrdAxisInfoMinMaxSet(nin, ax0+1, mossDefCenter);
154
  }
155
  min[0] = AIR_EXISTS(min[0]) ? min[0] : nin->axis[ax0+0].min;
156
  max[0] = AIR_EXISTS(max[0]) ? max[0] : nin->axis[ax0+0].max;
157
  min[1] = AIR_EXISTS(min[1]) ? min[1] : nin->axis[ax0+1].min;
158
  max[1] = AIR_EXISTS(max[1]) ? max[1] : nin->axis[ax0+1].max;
159
160
  for (d=0; d<2; d++) {
161
    fprintf(stderr, "%s: scale[0 + 2*%d] = %d\n", me, d,
162
            AIR_CAST(int, scale[0 + 2*d]));
163
    switch(AIR_CAST(int, scale[0 + 2*d])) {
164
    case 0:
165
      /* same number of samples as input */
166
      size[d] = AIR_CAST(int, nin->axis[ax0+d].size);
167
      break;
168
    case 1:
169
      /* scaling of input # samples */
170
      size[d] = AIR_CAST(int, scale[1 + 2*d]*nin->axis[ax0+d].size);
171
      break;
172
    case 2:
173
      /* explicit # of samples */
174
      size[d] = AIR_CAST(int, scale[1 + 2*d]);
175
      break;
176
    default:
177
      /* error */
178
      fprintf(stderr, "%s: scale[0 + 2*%d] == %d unexpected\n",
179
              me, AIR_CAST(int, scale[0 + 2*d]), d);
180
      airMopError(mop); return 1;
181
    }
182
  }
183
184
  /* find origin-based pre- and post- translate */
185
  if (0 == origInfo[0]) {
186
    /* absolute pixel position */
187
    mossMatTranslateSet(origMat, -origInfo[1], -origInfo[2]);
188
  } else {
189
    /* in unit box [0,1]x[0,1] */
190
    ox = AIR_AFFINE(0.0, origInfo[1], 1.0,
191
                    nin->axis[ax0+0].min, nin->axis[ax0+0].max);
192
    oy = AIR_AFFINE(0.0, origInfo[2], 1.0,
193
                    nin->axis[ax0+1].min, nin->axis[ax0+1].max);
194
    mossMatTranslateSet(origMat, -ox, -oy);
195
  }
196
  mossMatInvert(origInvMat, origMat);
197
198
  /* form complete transform */
199
  mossMatIdentitySet(mat);
200
  mossMatLeftMultiply(mat, origMat);
201
  for (i=0; i<matListLen; i++) {
202
    mossMatLeftMultiply(mat, matList[i]);
203
  }
204
  mossMatLeftMultiply(mat, origInvMat);
205
206
  if (!AIR_EXISTS(nin->axis[ax0+0].min) || !AIR_EXISTS(nin->axis[ax0+0].max)) {
207
    nrrdAxisInfoMinMaxSet(nin, ax0+0, mossDefCenter);
208
  }
209
  if (!AIR_EXISTS(nin->axis[ax0+1].min) || !AIR_EXISTS(nin->axis[ax0+1].max)) {
210
    nrrdAxisInfoMinMaxSet(nin, ax0+1, mossDefCenter);
211
  }
212
  if (avgNum > 1) {
213
    unsigned int ai;
214
    double angleMax, angle, mrot[6];
215
    Nrrd *ntmp, *nacc;
216
    NrrdIter *itA, *itB;
217
    int E;
218
219
    ntmp = nrrdNew();
220
    airMopAdd(mop, ntmp, (airMopper)nrrdNuke, airMopAlways);
221
    nacc = nrrdNew();
222
    airMopAdd(mop, nacc, (airMopper)nrrdNuke, airMopAlways);
223
    itA = nrrdIterNew();
224
    airMopAdd(mop, itA, (airMopper)nrrdIterNix, airMopAlways);
225
    itB = nrrdIterNew();
226
    airMopAdd(mop, itB, (airMopper)nrrdIterNix, airMopAlways);
227
    E = 0;
228
    angleMax = atan2(mat[3], mat[0]);
229
    fprintf(stderr, "%s: %u angles ", me, avgNum);
230
    for (ai=0; ai<avgNum; ai++) {
231
      fprintf(stderr, "."); fflush(stderr);
232
      angle = (180/AIR_PI)*AIR_AFFINE(0, ai, avgNum-1, angleMax, -angleMax);
233
      mossMatIdentitySet(mat);
234
      mossMatLeftMultiply(mat, origMat);
235
      mossMatRotateSet(mrot, angle);
236
      mossMatLeftMultiply(mat, mrot);
237
      mossMatLeftMultiply(mat, origInvMat);
238
      if (mossLinearTransform(ntmp, nin, bkg,
239
                              mat, msp,
240
                              min[0], max[0], min[1], max[1],
241
                              size[0], size[1])) {
242
        fprintf(stderr, "%s: problem doing transform:\n%s\n",
243
                me, errS = biffGetDone(MOSS)); free(errS);
244
        airMopError(mop); return 1;
245
      }
246
      if (!ai) {
247
        if (!E) E |= nrrdCopy(nacc, ntmp);
248
      } else {
249
        if (!E) E |= nrrdArithBinaryOp(nacc, nrrdBinaryOpAdd, nacc, ntmp);
250
      }
251
      if (E) {
252
        break;
253
      }
254
    }
255
    fprintf(stderr, "\n");
256
    nrrdIterSetNrrd(itA, nacc);
257
    nrrdIterSetValue(itB, avgNum);
258
    if (!E) E |= nrrdArithIterBinaryOp(nout, nrrdBinaryOpDivide,
259
                                       itA, itB);
260
    if (E) {
261
      fprintf(stderr, "%s: problem making output:\n%s\n",
262
              me, errS = biffGetDone(NRRD)); free(errS);
263
      airMopError(mop); return 1;
264
    }
265
  } else {
266
    if (mossLinearTransform(nout, nin, bkg,
267
                            mat, msp,
268
                            min[0], max[0], min[1], max[1],
269
                            size[0], size[1])) {
270
      fprintf(stderr, "%s: problem doing transform:\n%s\n",
271
              me, errS = biffGetDone(MOSS)); free(errS);
272
      airMopError(mop); return 1;
273
    }
274
  }
275
276
  if (nrrdSave(outS, nout, NULL)) {
277
    fprintf(stderr, "%s: problem saving output:\n%s\n",
278
            me, errS = biffGetDone(NRRD)); free(errS);
279
    airMopError(mop); return 1;
280
  }
281
282
  airMopOkay(mop);
283
  exit(0);
284
}