Esempio n. 1
0
int
main(int argc, const char *argv[]) {
  const char *me, *info="inverts a moss transform";
  hestOpt *hopt=NULL;
  double *mat, inv[6];

  me = argv[0];
  hestOptAdd(&hopt, "t", "transform", airTypeOther, 1, 1, &mat, "identity",
             "transform(s) to apply to image",
             NULL, NULL, mossHestTransform);
  hestParseOrDie(hopt, argc-1, argv+1, NULL,
                 me, info, AIR_TRUE, AIR_TRUE, AIR_TRUE);

  fprintf(stderr, "%s: got transform:\n", me);
  mossMatPrint(stderr, mat);
  mossMatInvert(inv, mat);
  fprintf(stderr, "\n%s: inverse:\n", me);
  mossMatPrint(stderr, inv);

  exit(0);
}
Esempio n. 2
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);
}
int
mossLinearTransform (Nrrd *nout, Nrrd *nin, float *bg,
                     double *mat, mossSampler *msp,
                     double xMin, double xMax,
                     double yMin, double yMax,
                     int xSize, int ySize) {
  char me[]="mossLinearTransform", err[BIFF_STRLEN];
  int ncol, xi, yi, ci, ax0, xCent, yCent;
  float *val, (*ins)(void *v, size_t I, float f), (*clamp)(float val);
  double inv[6], xInPos, xOutPos, yInPos, yOutPos;

  if (!(nout && nin && mat && msp && !mossImageCheck(nin))) {
    sprintf(err, "%s: got NULL pointer or bad image", me);
    biffAdd(MOSS, err); return 1;
  }
  if (mossSamplerImageSet(msp, nin, bg) || mossSamplerUpdate(msp)) {
    sprintf(err, "%s: trouble with sampler", me);
    biffAdd(MOSS, err); return 1;
  }
  if (!( xMin != xMax && yMin != yMax && xSize > 1 && ySize > 1 )) {
    sprintf(err, "%s: bad args: {x,y}Min == {x,y}Max or {x,y}Size <= 1", me);
    biffAdd(MOSS, err); return 1;
  }
  ax0 = MOSS_AXIS0(nin);
  if (!( AIR_EXISTS(nin->axis[ax0+0].min)
         && AIR_EXISTS(nin->axis[ax0+0].max)
         && AIR_EXISTS(nin->axis[ax0+1].min)
         && AIR_EXISTS(nin->axis[ax0+1].max) )) {
    sprintf(err, "%s: input axis min,max not set on axes %d and %d", me,
            ax0+0, ax0+1); biffAdd(MOSS, err); return 1;
  }

  ncol = MOSS_NCOL(nin);
  if (mossImageAlloc(nout, nin->type, xSize, ySize, ncol)) {
    sprintf(err, "%s: ", me); biffAdd(MOSS, err); return 1;
  }
  val = (float*)calloc(ncol, sizeof(float));
  if (nrrdCenterUnknown == nout->axis[ax0+0].center)
    nout->axis[ax0+0].center = _mossCenter(nin->axis[ax0+0].center);
  xCent = nout->axis[ax0+0].center;
  if (nrrdCenterUnknown == nout->axis[ax0+1].center)
    nout->axis[ax0+1].center = _mossCenter(nin->axis[ax0+1].center);
  yCent = nout->axis[ax0+1].center;
  nout->axis[ax0+0].min = xMin;
  nout->axis[ax0+0].max = xMax;
  nout->axis[ax0+1].min = yMin;
  nout->axis[ax0+1].max = yMax;
  ins = nrrdFInsert[nin->type];
  clamp = nrrdFClamp[nin->type];
  
  if (mossSamplerSample(val, msp, 0, 0)) {
    sprintf(err, "%s: trouble in sampler", me);
    free(val); biffAdd(MOSS, err); return 1;
  }

  mossMatInvert(inv, mat);
  for (yi=0; yi<ySize; yi++) {
    yOutPos = NRRD_POS(yCent, yMin, yMax, ySize, yi);
    for (xi=0; xi<xSize; xi++) {
      /*
      mossVerbose = ( (36 == xi && 72 == yi) ||
                      (37 == xi && 73 == yi) ||
                      (105 == xi && 175 == yi) );
      */
      xOutPos = NRRD_POS(xCent, xMin, xMax, xSize, xi);
      mossMatApply(&xInPos, &yInPos, inv, xOutPos, yOutPos);
      xInPos = NRRD_IDX(xCent, nin->axis[ax0+0].min, nin->axis[ax0+0].max,
                        nin->axis[ax0+0].size, xInPos);
      yInPos = NRRD_IDX(yCent, nin->axis[ax0+1].min, nin->axis[ax0+1].max,
                        nin->axis[ax0+1].size, yInPos);
      mossSamplerSample(val, msp, xInPos, yInPos);
      for (ci=0; ci<ncol; ci++) {
        ins(nout->data, ci + ncol*(xi + xSize*yi), clamp(val[ci]));
      }
    }
  }

  free(val);
  return 0;
}