示例#1
0
int
main(int argc, char *argv[]) {
  char *me, *errS, *outS;
  hestOpt *hopt=NULL;
  hestParm *hparm;
  airArray *mop;
  Nrrd *nin, *nout;
  NrrdKernelSpec *ksp;
  mossSampler *msp;
  double mat[6], **matList, *origInfo, origMat[6], origInvMat[6], ox, oy,
    min[2], max[2];
  int d, bound, ax0, size[2];
  unsigned int matListLen, _bkgLen, i, avgNum;
  float *bkg, *_bkg, scale[4];
  
  me = argv[0];
  mop = airMopNew();
  hparm = hestParmNew();
  airMopAdd(mop, hparm, (airMopper)hestParmFree, airMopAlways);
  hparm->elideSingleEnumType = AIR_TRUE;
  hparm->elideSingleOtherType = AIR_TRUE;
  hparm->elideSingleOtherDefault = AIR_FALSE;
  hparm->elideMultipleNonExistFloatDefault = AIR_TRUE;
  hparm->respFileEnable = AIR_TRUE;
  
  hestOptAdd(&hopt, "i", "image", airTypeOther, 1, 1, &nin, "-",
             "input image", NULL, NULL, nrrdHestNrrd);
  hestOptAdd(&hopt, "0", "origin", airTypeOther, 1, 1, &origInfo, "p:0,0",
             "where to location (0,0) prior to applying transforms.\n "
             "\b\bo \"u:<float>,<float>\" locate origin in a unit box "
             "[0,1]x[0,1] which covers the original image\n "
             "\b\bo \"p:<float>,<float>\" locate origin at a particular "
             "pixel location, in the index space of the image",
             NULL, NULL, mossHestOrigin);
  hestOptAdd(&hopt, "t", "xform0", airTypeOther, 1, -1, &matList, NULL,
             "transform(s) to apply to image.  Transforms "
             "are applied in the order in which they appear.\n "
             "\b\bo \"identity\": no geometric transform, just resampling\n "
             "\b\bo \"translate:x,y\": shift image by vector (x,y), as "
             "measured in pixels\n "
             "\b\bo \"rotate:ang\": rotate CCW by ang degrees\n "
             "\b\bo \"scale:xs,ys\": scale by xs in X, and ys in Y\n "
             "\b\bo \"shear:fix,amnt\": shear by amnt, keeping fixed "
             "the pixels along a direction <fix> degrees from the X axis\n "
             "\b\bo \"flip:ang\": flip along axis an angle <ang> degrees from "
             "the X axis\n "
             "\b\bo \"a,b,tx,c,d,ty\": specify the transform explicitly "
             "in row-major order (opposite of PostScript) ",
             &matListLen, NULL, mossHestTransform);
  hestOptAdd(&hopt, "k", "kernel", airTypeOther, 1, 1, &ksp,
             "cubic:0,0.5", "reconstruction kernel",
             NULL, NULL, nrrdHestKernelSpec);
  hestOptAdd(&hopt, "min", "xMin yMin", airTypeDouble, 2, 2, min, "nan nan",
             "lower bounding corner of output image. Default (by not "
             "using this option) is the lower corner of input image. ");
  hestOptAdd(&hopt, "max", "xMax yMax", airTypeDouble, 2, 2, max, "nan nan",
             "upper bounding corner of output image. Default (by not "
             "using this option) is the upper corner of input image. ");
  hestOptAdd(&hopt, "b", "boundary", airTypeEnum, 1, 1, &bound, "bleed",
             "what to do when sampling outside original image.\n "
             "\b\bo \"bleed\": copy values at image border outward\n "
             "\b\bo \"wrap\": do wrap-around on image locations\n "
             "\b\bo \"pad\": use a given background value (via \"-bg\")",
             NULL, nrrdBoundary);
  hestOptAdd(&hopt, "bg", "bg0 bg1", airTypeFloat, 1, -1, &_bkg, "nan",
             "background color to use with boundary behavior \"pad\". "
             "Defaults to all zeroes.",
             &_bkgLen);
  hestOptAdd(&hopt, "s", "xSize ySize", airTypeOther, 2, 2, scale, "x1 x1",
             "For each axis, information about how many samples in output:\n "
             "\b\bo \"x<float>\": number of output samples is some scaling of "
             " the number input of samples; multiplied by <float>\n "
             "\b\bo \"<int>\": specify exact number of samples",
             NULL, NULL, &unrrduHestScaleCB);
  hestOptAdd(&hopt, "a", "avg #", airTypeUInt, 1, 1, &avgNum, "0",
             "number of averages (if there there is only one "
             "rotation)");
  hestOptAdd(&hopt, "o", "filename", airTypeString, 1, 1, &outS, "-",
             "file to write output nrrd to");
  hestParseOrDie(hopt, argc-1, argv+1, hparm,
                 me, ilkInfo, AIR_TRUE, AIR_TRUE, AIR_TRUE);
  airMopAdd(mop, hopt, (airMopper)hestOptFree, airMopAlways);
  airMopAdd(mop, hopt, (airMopper)hestParseFree, airMopAlways);

  nout = nrrdNew();
  airMopAdd(mop, nout, (airMopper)nrrdNuke, airMopAlways);
  msp = mossSamplerNew();
  airMopAdd(mop, msp, (airMopper)mossSamplerNix, airMopAlways);
  msp->boundary = bound;
  if (mossSamplerKernelSet(msp, ksp->kernel, ksp->parm)) {
    fprintf(stderr, "%s: trouble with sampler:\n%s\n",
            me, errS = biffGetDone(MOSS)); free(errS);
    airMopError(mop); return 1;
  }
  if (nrrdBoundaryPad == bound) {
    if (_bkgLen != MOSS_NCOL(nin)) {
      fprintf(stderr, "%s: got %d background colors, image has "
              _AIR_SIZE_T_CNV " colors\n", 
              me, _bkgLen, MOSS_NCOL(nin));
      airMopError(mop); return 1;
    } else {
      bkg = _bkg;
    }
  } else {
    /* maybe warn user if they gave a background that won't be used? */
    /* No- because hest is stupid, and right now we always parse the
       single (default) "nan" for this argument! */
    bkg = NULL;
  }

  ax0 = MOSS_AXIS0(nin);
  if (!( AIR_EXISTS(nin->axis[ax0+0].min)
         && AIR_EXISTS(nin->axis[ax0+0].max))) {
    nrrdAxisInfoMinMaxSet(nin, ax0+0, mossDefCenter);
  }
  if (!( AIR_EXISTS(nin->axis[ax0+1].min)
         && AIR_EXISTS(nin->axis[ax0+1].max))) {
    nrrdAxisInfoMinMaxSet(nin, ax0+1, mossDefCenter);
  }
  min[0] = AIR_EXISTS(min[0]) ? min[0] : nin->axis[ax0+0].min;
  max[0] = AIR_EXISTS(max[0]) ? max[0] : nin->axis[ax0+0].max;
  min[1] = AIR_EXISTS(min[1]) ? min[1] : nin->axis[ax0+1].min;
  max[1] = AIR_EXISTS(max[1]) ? max[1] : nin->axis[ax0+1].max;
  for (d=0; d<2; d++) {
    switch((int)scale[0 + 2*d]) {
    case 0:
      /* same number of samples as input */
      size[d] = nin->axis[ax0+d].size;
      break;
    case 1:
      /* scaling of input # samples */
      size[d] = (int)(scale[1 + 2*d]*nin->axis[ax0+d].size);
      break;
    case 2:
      /* explicit # of samples */
      size[d] = (int)(scale[1 + 2*d]);
      break;
    }
  }

  /* find origin-based pre- and post- translate */
  if (0 == origInfo[0]) {
    /* absolute pixel position */
    mossMatTranslateSet(origMat, -origInfo[1], -origInfo[2]);
  } else {
    /* in unit box [0,1]x[0,1] */
    ox = AIR_AFFINE(0.0, origInfo[1], 1.0,
                    nin->axis[ax0+0].min, nin->axis[ax0+0].max);
    oy = AIR_AFFINE(0.0, origInfo[2], 1.0, 
                    nin->axis[ax0+1].min, nin->axis[ax0+1].max);
    mossMatTranslateSet(origMat, -ox, -oy);
  }
  mossMatInvert(origInvMat, origMat);

  /* form complete transform */
  mossMatIdentitySet(mat);
  mossMatLeftMultiply(mat, origMat);
  for (i=0; i<matListLen; i++) {
    mossMatLeftMultiply(mat, matList[i]);
  }
  mossMatLeftMultiply(mat, origInvMat);

  if (!AIR_EXISTS(nin->axis[ax0+0].min) || !AIR_EXISTS(nin->axis[ax0+0].max)) {
    nrrdAxisInfoMinMaxSet(nin, ax0+0, mossDefCenter);
  }
  if (!AIR_EXISTS(nin->axis[ax0+1].min) || !AIR_EXISTS(nin->axis[ax0+1].max)) {
    nrrdAxisInfoMinMaxSet(nin, ax0+1, mossDefCenter);
  }
  if (avgNum > 1) {
    unsigned int ai;
    double angleMax, angle, mrot[6];
    Nrrd *ntmp, *nacc;
    NrrdIter *itA, *itB;
    int E;

    ntmp = nrrdNew();
    airMopAdd(mop, ntmp, (airMopper)nrrdNuke, airMopAlways);
    nacc = nrrdNew();
    airMopAdd(mop, nacc, (airMopper)nrrdNuke, airMopAlways);
    itA = nrrdIterNew();
    airMopAdd(mop, itA, (airMopper)nrrdIterNix, airMopAlways);
    itB = nrrdIterNew();
    airMopAdd(mop, itB, (airMopper)nrrdIterNix, airMopAlways);
    E = 0;
    angleMax = atan2(mat[3], mat[0]);
    fprintf(stderr, "%s: %u angles ", me, avgNum);
    for (ai=0; ai<avgNum; ai++) {
      fprintf(stderr, "."); fflush(stderr);
      angle = (180/AIR_PI)*AIR_AFFINE(0, ai, avgNum-1, angleMax, -angleMax);
      mossMatIdentitySet(mat);
      mossMatLeftMultiply(mat, origMat);
      mossMatRotateSet(mrot, angle);
      mossMatLeftMultiply(mat, mrot);
      mossMatLeftMultiply(mat, origInvMat);
      if (mossLinearTransform(ntmp, nin, bkg,
                              mat, msp,
                              min[0], max[0], min[1], max[1],
                              size[0], size[1])) {
        fprintf(stderr, "%s: problem doing transform:\n%s\n",
                me, errS = biffGetDone(MOSS)); free(errS);
        airMopError(mop); return 1;
      }
      if (!ai) {
        if (!E) E |= nrrdCopy(nacc, ntmp);
      } else {
        if (!E) E |= nrrdArithBinaryOp(nacc, nrrdBinaryOpAdd, nacc, ntmp);
      }
      if (E) {
        break;
      }
    }
    fprintf(stderr, "\n");
    nrrdIterSetNrrd(itA, nacc);
    nrrdIterSetValue(itB, avgNum);
    if (!E) E |= nrrdArithIterBinaryOp(nout, nrrdBinaryOpDivide,
                                       itA, itB);
    if (E) {
      fprintf(stderr, "%s: problem making output:\n%s\n",
              me, errS = biffGetDone(NRRD)); free(errS);
      airMopError(mop); return 1;
    }
  } else {
    if (mossLinearTransform(nout, nin, bkg,
                            mat, msp,
                            min[0], max[0], min[1], max[1],
                            size[0], size[1])) {
      fprintf(stderr, "%s: problem doing transform:\n%s\n",
              me, errS = biffGetDone(MOSS)); free(errS);
      airMopError(mop); return 1;
    }
  }

  if (nrrdSave(outS, nout, NULL)) {
    fprintf(stderr, "%s: problem saving output:\n%s\n",
            me, errS = biffGetDone(NRRD)); free(errS);
    airMopError(mop); return 1;
  }

  airMopOkay(mop);
  exit(0);
}
示例#2
0
int
unrrdu_2opMain(int argc, char **argv, char *me, hestParm *hparm) {
  hestOpt *opt = NULL;
  char *out, *err, *seedS;
  NrrdIter *in1, *in2;
  Nrrd *nout, *ntmp=NULL;
  int op, type, E, pret;
  airArray *mop;
  unsigned int seed;

  hestOptAdd(&opt, NULL, "operator", airTypeEnum, 1, 1, &op, NULL,
             "Binary operator. Possibilities include:\n "
             "\b\bo \"+\", \"-\", \"x\", \"/\": "
             "add, subtract, multiply, divide\n "
             "\b\bo \"^\": exponentiation (pow)\n "
             "\b\bo \"spow\": signed exponentiation: sgn(x)pow(abs(x),p)\n "
             "\b\bo \"%\": integer modulo\n "
             "\b\bo \"fmod\": same as fmod() in C\n "
             "\b\bo \"atan2\": same as atan2() in C\n "
             "\b\bo \"min\", \"max\": minimum, maximum\n "
             "\b\bo \"lt\", \"lte\", \"gt\", \"gte\": same as C's <, <=, >, <=\n "
             "\b\bo \"eq\", \"neq\": same as C's == and !=\n "
             "\b\bo \"comp\": -1, 0, or 1 if 1st value is less than, "
             "equal to, or greater than 2nd value\n "
             "\b\bo \"if\": if 1st value is non-zero, use it, "
             "else use 2nd value\n "
             "\b\bo \"exists\": if 1st value exists, use it, "
             "else use 2nd value\n "
             "\b\bo \"nrand\": scale unit-stdv Gaussian noise by 2nd value "
             "and add to first value",
             NULL, nrrdBinaryOp);
  hestOptAdd(&opt, NULL, "in1", airTypeOther, 1, 1, &in1, NULL,
             "First input.  Can be a single value or a nrrd.",
             NULL, NULL, nrrdHestIter);
  hestOptAdd(&opt, NULL, "in2", airTypeOther, 1, 1, &in2, NULL,
             "Second input.  Can be a single value or a nrrd.",
             NULL, NULL, nrrdHestIter);
  hestOptAdd(&opt, "s,seed", "seed", airTypeString, 1, 1, &seedS, "",
             "seed value for RNG for nrand, so that you "
             "can get repeatable results between runs, or, "
             "by not using this option, the RNG seeding will be "
             "based on the current time");
  hestOptAdd(&opt, "t,type", "type", airTypeOther, 1, 1, &type, "default",
             "type to convert all INPUT nrrds to, prior to "
             "doing operation, useful for doing, for instance, the difference "
             "between two unsigned char nrrds.  This will also determine "
             "output type. By default (not using this option), the types of "
             "the input nrrds are left unchanged.",
             NULL, NULL, &unrrduHestMaybeTypeCB);
  OPT_ADD_NOUT(out, "output nrrd");

  mop = airMopNew();
  airMopAdd(mop, opt, (airMopper)hestOptFree, airMopAlways);

  USAGE(_unrrdu_2opInfoL);
  PARSE();
  airMopAdd(mop, opt, (airMopper)hestParseFree, airMopAlways);

  nout = nrrdNew();
  airMopAdd(mop, nout, (airMopper)nrrdNuke, airMopAlways);

  /*
  fprintf(stderr, "%s: op = %d\n", me, op);
  fprintf(stderr, "%s: in1->left = %d, in2->left = %d\n", me, 
          (int)(in1->left), (int)(in2->left));
  */
  if (nrrdTypeDefault != type) {
    /* they wanted to convert nrrds to some other type first */
    E = 0;
    if (in1->ownNrrd) {
      if (!E) E |= nrrdConvert(ntmp=nrrdNew(), in1->ownNrrd, type);
      if (!E) nrrdIterSetOwnNrrd(in1, ntmp);
    }
    if (in2->ownNrrd) {
      if (!E) E |= nrrdConvert(ntmp=nrrdNew(), in2->ownNrrd, type);
      if (!E) nrrdIterSetOwnNrrd(in2, ntmp);
    }
    if (E) {
      airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways);
      fprintf(stderr, "%s: error converting input nrrd(s):\n%s", me, err);
      airMopError(mop);
      return 1;
    }
    /* this will still leave a nrrd in the NrrdIter for nrrdIterNix()
       (called by hestParseFree() called be airMopOkay()) to clear up */
  }
  if (nrrdBinaryOpNormalRandScaleAdd == op) {
    if (airStrlen(seedS)) {
      if (1 != sscanf(seedS, "%u", &seed)) {
        fprintf(stderr, "%s: couldn't parse seed \"%s\" as uint\n", me, seedS);
        airMopError(mop);
        return 1;
      } else {
        airSrandMT(seed);
      }
    } else {
      /* got no request for specific seed */
      airSrandMT(AIR_CAST(unsigned int, airTime()));
    }
  }
  if (nrrdArithIterBinaryOp(nout, op, in1, in2)) {
    airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways);
    fprintf(stderr, "%s: error doing binary operation:\n%s", me, err);
    airMopError(mop);
    return 1;
  }
  
  SAVE(out, nout, NULL);

  airMopOkay(mop);
  return 0;
}