示例#1
0
void mexFunction(int nlhs, mxArray *plhs[],
  int nrhs, const mxArray *prhs[])
{
  char me[]="nrrdSave", *filename, *errPtr, errBuff[AIR_STRLEN_MED];
  int filenameLen, ntype;
  size_t sizeZ[NRRD_DIM_MAX];
  unsigned int dim, axIdx;
  Nrrd *nrrd;
  airArray *mop;
  const mxArray *filenameMx, *arrayMx;
  
  if (!(2 == nrhs && mxIsChar(prhs[0]) )) {
    sprintf(errBuff, "%s: requires two args: one string, one array", me);
    mexErrMsgTxt(errBuff);
  }
  filenameMx = prhs[0];
  arrayMx = prhs[1];

  if (mxIsComplex(arrayMx)) {
    sprintf(errBuff, "%s: sorry, array must be real", me);
    mexErrMsgTxt(errBuff);
  }
  ntype = typeMtoN(mxGetClassID(arrayMx));
  if (nrrdTypeUnknown == ntype) {
    sprintf(errBuff, "%s: sorry, can't handle type %s",
            me, mxGetClassName(arrayMx));
    mexErrMsgTxt(errBuff);
  }
  dim = mxGetNumberOfDimensions(arrayMx);
  if (!( 1 <= dim && dim <= NRRD_DIM_MAX )) {
    sprintf(errBuff, "%s: number of array dimensions %d outside range [1,%d]",
            me, dim, NRRD_DIM_MAX);
    mexErrMsgTxt(errBuff);
  }
  
  filenameLen = mxGetM(filenameMx)*mxGetN(filenameMx)+1;
  filename = mxCalloc(filenameLen, sizeof(mxChar));    /* managed by Matlab */
  mxGetString(filenameMx, filename, filenameLen);
  
  for (axIdx=0; axIdx<dim; axIdx++) {
    sizeZ[axIdx] = mxGetDimensions(arrayMx)[axIdx];
  }
  nrrd = nrrdNew();
  mop = airMopNew();
  airMopAdd(mop, nrrd, (airMopper)nrrdNix, airMopAlways);
  if (nrrdWrap_nva(nrrd, mxGetPr(arrayMx), ntype, dim, sizeZ)
      || nrrdSave(filename, nrrd, NULL)) {
    errPtr = biffGetDone(NRRD);
    airMopAdd(mop, errPtr, airFree, airMopAlways);
    sprintf(errBuff, "%s: error saving NRRD:\n%s", me, errPtr);
    airMopError(mop);
    mexErrMsgTxt(errBuff);
  }

  airMopOkay(mop);
  return;
}
示例#2
0
/*
******** nrrdAlloc_nva()
**
** allocates data array and sets information.  If this is a block type
** nrrd, it is necessary to set nrrd->blockSize PRIOR to calling
** this function.
**
** This function will always allocate more memory (via calloc), but
** it will free() nrrd->data if it is non-NULL when passed in.
**
** This function takes the same "don't mess with peripheral information"
** attitude as nrrdWrap().
**
** Note to Gordon: don't get clever and change ANY axis-specific
** information here.  It may be very convenient to set that before
** nrrdAlloc or nrrdMaybeAlloc
**
** Note: This function DOES use biff
*/
int
nrrdAlloc_nva(Nrrd *nrrd, int type, unsigned int dim, const size_t *size)
{
  char me[]="nrrdAlloc_nva", err[BIFF_STRLEN];
  size_t num;
  int esize;

  if (!(nrrd && size))
  {
    sprintf(err, "%s: got NULL pointer", me);
    biffAdd(NRRD, err);
    return 1;
  }
  if (airEnumValCheck(nrrdType, type))
  {
    sprintf(err, "%s: type (%d) is invalid", me, type);
    biffAdd(NRRD, err);
    return 1;
  }
  if (nrrdTypeBlock == type)
  {
    if (!(0 < nrrd->blockSize))
    {
      sprintf(err, "%s: given nrrd->blockSize " _AIR_SIZE_T_CNV " invalid",
              me, nrrd->blockSize);
      biffAdd(NRRD, err);
      return 1;
    }
  }
  if (!AIR_IN_CL(1, dim, NRRD_DIM_MAX))
  {
    sprintf(err, "%s: dim (%d) not in valid range [1,%d]",
            me, dim, NRRD_DIM_MAX);
    biffAdd(NRRD, err);
    return 1;
  }

  nrrd->data = airFree(nrrd->data);
  if (nrrdWrap_nva(nrrd, NULL, type, dim, size))
  {
    sprintf(err, "%s:", me);
    biffAdd(NRRD, err);
    return 1 ;
  }
  num = nrrdElementNumber(nrrd);
  esize = nrrdElementSize(nrrd);
  nrrd->data = calloc(num, esize);
  if (!(nrrd->data))
  {
    sprintf(err, "%s: calloc(" _AIR_SIZE_T_CNV ",%d) failed",
            me, num, esize);
    biffAdd(NRRD, err);
    return 1 ;
  }

  return 0;
}
示例#3
0
int
_nrrdCopy(Nrrd *nout, const Nrrd *nin, int bitflag) {
  char me[]="_nrrdCopy", err[BIFF_STRLEN];
  size_t size[NRRD_DIM_MAX];

  if (!(nin && nout)) {
    sprintf(err, "%s: got NULL pointer", me);
    biffAdd(NRRD, err); return 1;
  }
  if (nout == nin) {
    /* its not the case that we have nothing to do- the semantics of
       copying cannot be achieved if the input and output nrrd are
       the same; this is an error */
    sprintf(err, "%s: nout==nin disallowed", me);
    biffAdd(NRRD, err); return 1;
  }
  if (!nrrdElementSize(nin)) {
    sprintf(err, "%s: input nrrd reports zero element size!", me);
    biffAdd(NRRD, err); return 1;
  }
  nrrdAxisInfoGet_nva(nin, nrrdAxisInfoSize, size);
  if (nin->data) {
    if (nrrdMaybeAlloc_nva(nout, nin->type, nin->dim, size)) {
      sprintf(err, "%s: couldn't allocate data", me);
      biffAdd(NRRD, err); return 1;
    }
    memcpy(nout->data, nin->data,
           nrrdElementNumber(nin)*nrrdElementSize(nin));
  } else {
    /* someone is trying to copy structs without data, fine fine fine */
    if (nrrdWrap_nva(nout, NULL, nin->type, nin->dim, size)) {
      sprintf(err, "%s: couldn't allocate data", me);
      biffAdd(NRRD, err); return 1;
    }
  }
  nrrdAxisInfoCopy(nout, nin, NULL, NRRD_AXIS_INFO_SIZE_BIT);
  /* if nin->data non-NULL (second branch above), this will 
     harmlessly unset and set type and dim */
  nrrdBasicInfoInit(nout, NRRD_BASIC_INFO_DATA_BIT | bitflag);
  if (nrrdBasicInfoCopy(nout, nin, NRRD_BASIC_INFO_DATA_BIT | bitflag)) {
    sprintf(err, "%s: trouble copying basic info", me);
    biffAdd(NRRD, err); return 1;
  }

  return 0;
}
示例#4
0
/*
******** nrrdWrap_va()
**
** Minimal var args wrapper around nrrdWrap_nva, with the advantage of 
** taking all the axes sizes as the var args.
**
** This is THE BEST WAY to wrap a nrrd around existing raster data,
** assuming that the dimension is known at compile time.
**
** If successful, returns 0, otherwise, 1.
** This does use biff.
*/
int
nrrdWrap_va(Nrrd *nrrd, void *data, int type, unsigned int dim, ...) {
  char me[]="nrrdWrap_va", err[BIFF_STRLEN];
  va_list ap;
  size_t size[NRRD_DIM_MAX];
  unsigned int ai;
  
  if (!(nrrd && data)) {
    sprintf(err, "%s: got NULL pointer", me);
    biffAdd(NRRD, err); return 1;
  }
  va_start(ap, dim);
  for (ai=0; ai<dim; ai++) {
    size[ai] = va_arg(ap, size_t);
  }
  va_end(ap);
  
  return nrrdWrap_nva(nrrd, data, type, dim, size);
}
示例#5
0
/*
******** nrrdMaybeAlloc_nva
**
** calls nrrdAlloc_nva if the requested space is different than
** what is currently held
**
** also subscribes to the "don't mess with peripheral information" philosophy
*/
int
nrrdMaybeAlloc_nva(Nrrd *nrrd, int type,
                   unsigned int dim, const size_t *size)
{
  char me[]="nrrdMaybeAlloc_nva", err[BIFF_STRLEN];
  size_t sizeWant, sizeHave, numWant, elementSizeWant;
  int need;
  unsigned int ai;

  if (!nrrd)
  {
    sprintf(err, "%s: got NULL pointer", me);
    biffAdd(NRRD, err);
    return 1;
  }
  if (airEnumValCheck(nrrdType, type))
  {
    sprintf(err, "%s: type (%d) is invalid", me, type);
    biffAdd(NRRD, err);
    return 1;
  }
  if (nrrdTypeBlock == type)
  {
    if (nrrdTypeBlock == nrrd->type)
    {
      sprintf(err, "%s: can't change from one block nrrd to another", me);
      biffAdd(NRRD, err);
      return 1;
    }
    if (!(0 < nrrd->blockSize))
    {
      sprintf(err, "%s: given nrrd->blockSize " _AIR_SIZE_T_CNV " invalid",
              me, nrrd->blockSize);
      biffAdd(NRRD, err);
      return 1;
    }
    elementSizeWant = nrrd->blockSize;
  }
  else
  {
    elementSizeWant = nrrdTypeSize[type];
  }
  if (_nrrdSizeCheck(size, dim, AIR_TRUE))
  {
    sprintf(err, "%s:", me);
    biffAdd(NRRD, err);
    return 1;
  }

  if (!(nrrd->data))
  {
    need = 1;
  }
  else
  {
    numWant = 1;
    for (ai=0; ai<dim; ai++)
    {
      numWant *= size[ai];
    }
    if (!nrrdElementSize(nrrd))
    {
      sprintf(err, "%s: nrrd reports zero element size!", me);
      biffAdd(NRRD, err);
      return 1;
    }
    sizeHave = nrrdElementNumber(nrrd) * nrrdElementSize(nrrd);
    /* fprintf(stderr, "##%s: sizeHave = %d * %d = %d\n", me,
            (int)(nrrdElementNumber(nrrd)),
            (int)(nrrdElementSize(nrrd)), (int)sizeHave); */
    sizeWant = numWant * elementSizeWant;
    /* fprintf(stderr, "##%s: sizeWant = %d * %d = %d\n", me,
            (int)(numWant),
            (int)(elementSizeWant), (int)sizeWant); */
    need = sizeHave != sizeWant;
    /* fprintf(stderr, "##%s: need = %d\n", me, need); */
  }
  if (need)
  {
    if (nrrdAlloc_nva(nrrd, type, dim, size))
    {
      sprintf(err, "%s:", me);
      biffAdd(NRRD, err);
      return 1;
    }
  }
  else
  {
    if (nrrdWrap_nva(nrrd, nrrd->data, type, dim, size))
    {
      sprintf(err, "%s:", me);
      biffAdd(NRRD, err);
      return 1;
    }
    /* but we do have to initialize memory! */
    memset(nrrd->data, 0, nrrdElementNumber(nrrd)*nrrdElementSize(nrrd));
  }

  return 0;
}
示例#6
0
/*
******** nrrdFFT
**
** First pass at a wrapper around FFTW.  This was implemented out of need for a
** specific project; and better decisions and different interfaces will become
** apparent with time and experience; these can be in Teem 2.0.
**
** currently *requires* that input be complex-valued, in that axis 0 has to
** have size 2.  nrrdKindComplex would be sensible for input axis 0 but we don't
** require it, though it is set on the output.
*/
int
nrrdFFT(Nrrd *nout, const Nrrd *_nin,
        unsigned int *axes, unsigned int axesNum,
        int sign, int rescale, int rigor) {
  static const char me[]="nrrdFFT";
  size_t inSize[NRRD_DIM_MAX], II, NN, nprod;
  double *inData, *outData;
  airArray *mop;
  Nrrd *nin;
  unsigned int axi, axisDo[NRRD_DIM_MAX];
  fftw_plan plan;
  void *dataBef;
  unsigned int txfRank, howRank, flags;
  size_t stride;
  fftw_iodim txfDims[NRRD_DIM_MAX], howDims[NRRD_DIM_MAX];

  if (!(nout && _nin && axes)) {
    biffAddf(NRRD, "%s: got NULL pointer", me);
    return 1;
  }
  if (!( _nin->dim > 1 && 2 == _nin->axis[0].size )) {
    biffAddf(NRRD, "%s: nin doesn't look like a complex-valued array", me);
    return 1;
  }
  if (!( axesNum >= 1 )) {
    biffAddf(NRRD, "%s: axesNum 0, no axes to transform?", me);
    return 1;
  }
  for (axi=0; axi<_nin->dim; axi++) {
    axisDo[axi] = 0;
  }
  for (axi=0; axi<axesNum; axi++) {
    if (0 == axes[axi]) {
      biffAddf(NRRD, "%s: can't transform axis 0 (axes[%u]) for "
               "real/complex values", me, axi);
      return 1;
    }
    if (!( axes[axi] < _nin->dim )) {
      biffAddf(NRRD, "%s: axis %u (axes[%u]) out of range [1,%u]", me,
               axes[axi], axi, _nin->dim-1);
      return 1;
    }
    axisDo[axes[axi]]++;
    if (2 == axisDo[axes[axi]]) {
      biffAddf(NRRD, "%s: axis %u (axes[%u]) already transformed",
               me, axes[axi], axi);
      return 1;
    }
  }

  NN = nrrdElementNumber(_nin);
  /* We always make a new buffer to hold the double-type copy of input for two
     reasons: if input is not double we have to convert it, and we want input
     to be const, and we can't have const with the plan creation over-writing
     the input (except with FFTW_ESTIMATE).  Given that, we might as well use
     the memory-alignment-savvy fftw_malloc; the freeing is handled by both
     _nrrdFftwFreeWrapper and nrrdNix. */
  /* (NN = 2 * number of complex values) */
  inData = AIR_CAST(double *, fftw_malloc(NN*sizeof(double)));
  if (!inData) {
    biffAddf(NRRD, "%s: couldn't allocate input data copy", me);
    return 1;
  }
  mop = airMopNew();
  airMopAdd(mop, inData, _nrrdFftwFreeWrapper, airMopAlways);
  nin = nrrdNew();
  airMopAdd(mop, nin, (airMopper)nrrdNix /* NOT Nuke */, airMopAlways);
  nrrdAxisInfoGet_nva(_nin, nrrdAxisInfoSize, inSize);
  /* we don't copy data yet; it may be over-written during plan creation */
  if (nrrdWrap_nva(nin, inData, nrrdTypeDouble, _nin->dim, inSize)) {
    biffAddf(NRRD, "%s: couldn't wrap or copy input", me);
    airMopError(mop);
    return 1;
  }
  /* But on the output, we just use regular malloc, because we don't (yet) have
     a way of telling nrrd to use fftw_malloc/fftw_free instead of the generic
     malloc/free, and we don't want two whole copies of the output (one that is
     memory-aligned, internal to this function, and one that isn't, in nout) */
  if (nrrdMaybeAlloc_nva(nout, nrrdTypeDouble, _nin->dim, inSize)) {
    biffAddf(NRRD, "%s: couldn't allocate output", me);
    airMopError(mop);
    return 1;
  }
  outData = AIR_CAST(double *, nout->data);

  /* As far as GLK can tell, the guru interface is needed, and the "advanced"
     fftw_plan_many_dft won't work, because its simplistic accounting of stride
     can't handle having non-contiguous non-transformed axes (e.g. transforming
     only axes 2 and not 1, 3 in a 3-D complex-valued array) */
  txfRank = howRank = 0;
  stride = 1;
  nprod = 1;
  for (axi=1; axi<nin->dim; axi++) {
    if (axisDo[axi]) {
      txfDims[txfRank].n = AIR_CAST(int, inSize[axi]);
      txfDims[txfRank].is = txfDims[txfRank].os = AIR_CAST(int, stride);
      nprod *= inSize[axi];
      txfRank++;
    } else {
      howDims[howRank].n = AIR_CAST(int, inSize[axi]);
      howDims[howRank].is = howDims[howRank].os = AIR_CAST(int, stride);
      howRank++;
    }
    stride *= inSize[axi];
  }