int _nrrdReadNrrdParse_axis_maxs (FILE *file, Nrrd *nrrd, NrrdIoState *nio, int useBiff) { char me[]="_nrrdReadNrrdParse_axis_maxs", err[BIFF_STRLEN]; unsigned int ret; double val[NRRD_DIM_MAX]; char *info; AIR_UNUSED(file); info = nio->line + nio->pos; _CHECK_HAVE_DIM; ret = airParseStrD(val, info, _nrrdFieldSep, nrrd->dim); _CHECK_GOT_ALL_VALUES; nrrdAxisInfoSet_nva(nrrd, nrrdAxisInfoMax, val); /* HEY: this is a very imperfect check of excess info */ if (nrrd->dim+1 == airParseStrD(val, info, _nrrdFieldSep, nrrd->dim+1)) { sprintf(err, "%s: seem to have more than expected %d axis maxs", me, nrrd->dim); biffMaybeAdd(NRRD, err, useBiff); return 1; } if (_nrrdFieldCheck[nrrdField_axis_maxs](nrrd, useBiff)) { sprintf(err, "%s: trouble", me); biffMaybeAdd(NRRD, err, useBiff); return 1; } return 0; }
int _nrrdReadNrrdParse_sizes (FILE *file, Nrrd *nrrd, NrrdIoState *nio, int useBiff) { char me[]="_nrrdReadNrrdParse_sizes", err[BIFF_STRLEN]; unsigned int ret; size_t val[NRRD_DIM_MAX]; char *info; AIR_UNUSED(file); info = nio->line + nio->pos; _CHECK_HAVE_DIM; // MOD-BY-LEETEN 04/21/2012-FROM: ret = airParseStrZ(val, info, _nrrdFieldSep, nrrd->dim); { unsigned int *puTemp = malloc(sizeof(puTemp[0]) * nrrd->dim); size_t d; ret = airParseStrUI(puTemp, info, _nrrdFieldSep, nrrd->dim); for(d = 0; d < nrrd->dim; d++) val[d] = puTemp[d]; free(puTemp); } // MOD-BY-LEETEN 04/21/2012-END _CHECK_GOT_ALL_VALUES; nrrdAxisInfoSet_nva(nrrd, nrrdAxisInfoSize, val); /* HEY: this is a very imperfect check of excess info */ if (nrrd->dim+1 == airParseStrZ(val, info, _nrrdFieldSep, nrrd->dim+1)) { sprintf(err, "%s: seem to have more than expected %d sizes", me, nrrd->dim); biffMaybeAdd(NRRD, err, useBiff); return 1; } if (_nrrdFieldCheck[nrrdField_sizes](nrrd, useBiff)) { sprintf(err, "%s: trouble", me); biffMaybeAdd(NRRD, err, useBiff); return 1; } return 0; }
/* ******** nrrdWrap_nva() ** ** wraps a given Nrrd around a given array ** ** we don't touch any of the peripheral information (content, comments, ** blocksize, min/max) because it is entirely reasonable to be setting ** this before or after this call. "type" could be passed as ** nrrdTypeBlock, in which case it is the user's responsibility to ** set nrrd->blockSize at some other time. */ int nrrdWrap_nva(Nrrd *nrrd, void *data, int type, unsigned int dim, const size_t *size) { char me[]="nrrdWrap_nva", err[BIFF_STRLEN]; if (!(nrrd && size)) { sprintf(err, "%s: got NULL pointer", me); biffAdd(NRRD, err); return 1; } nrrd->data = data; nrrd->type = type; nrrd->dim = dim; if (_nrrdSizeCheck(size, dim, AIR_TRUE)) { sprintf(err, "%s:", me); biffAdd(NRRD, err); return 1; } nrrdAxisInfoSet_nva(nrrd, nrrdAxisInfoSize, size); return 0; }
/* ******** nrrdAxisInfoSet_va() ** ** var args front-end for nrrdAxisInfoSet_nva ** ** types to pass, one for each dimension: ** nrrdAxisInfoSize: size_t ** nrrdAxisInfoSpacing: double ** nrrdAxisInfoThickness: double ** nrrdAxisInfoMin: double ** nrrdAxisInfoMax: double ** nrrdAxisInfoSpaceDirection: double* ** nrrdAxisInfoCenter: int ** nrrdAxisInfoKind: int ** nrrdAxisInfoLabel: char* ** nrrdAxisInfoUnits: char* */ void nrrdAxisInfoSet_va(Nrrd *nrrd, int axInfo, ...) { NRRD_TYPE_BIGGEST *buffer[NRRD_DIM_MAX]; _nrrdAxisInfoSetPtrs info; unsigned int ai, si; va_list ap; double *dp, svec[NRRD_DIM_MAX][NRRD_SPACE_DIM_MAX]; if (!( nrrd && AIR_IN_CL(1, nrrd->dim, NRRD_DIM_MAX) && AIR_IN_OP(nrrdAxisInfoUnknown, axInfo, nrrdAxisInfoLast) )) { return; } info.P = buffer; va_start(ap, axInfo); for (ai=0; ai<nrrd->dim; ai++) { switch (axInfo) { case nrrdAxisInfoSize: info.ST[ai] = va_arg(ap, size_t); /* printf("!%s: got int[%d] = %d\n", "nrrdAxisInfoSet", d, info.I[ai]); */ break; case nrrdAxisInfoSpaceDirection: dp = va_arg(ap, double*); /* punting on using info enum */ /* printf("!%s: got dp = %lu\n", "nrrdAxisInfoSet", (unsigned long)(dp)); */ for (si=0; si<nrrd->spaceDim; si++) { /* nrrd->axis[ai].spaceDirection[si] = dp[si]; */ svec[ai][si] = dp[si]; } for (si=nrrd->spaceDim; si<NRRD_SPACE_DIM_MAX; si++) { /* nrrd->axis[ai].spaceDirection[si] = AIR_NAN; */ svec[ai][si] = dp[si]; } break; case nrrdAxisInfoCenter: case nrrdAxisInfoKind: info.I[ai] = va_arg(ap, int); /* printf("!%s: got int[%d] = %d\n", "nrrdAxisInfoSet", d, info.I[ai]); */ break; case nrrdAxisInfoSpacing: case nrrdAxisInfoThickness: case nrrdAxisInfoMin: case nrrdAxisInfoMax: info.D[ai] = va_arg(ap, double); /* printf("!%s: got double[%d] = %g\n", "nrrdAxisInfoSet", d, info.D[ai]); */ break; case nrrdAxisInfoLabel: /* we DO NOT do the airStrdup() here because this pointer value is just going to be handed to nrrdAxisInfoSet_nva(), which WILL do the airStrdup(); we're not violating the rules for axis labels */ info.CP[ai] = va_arg(ap, char *); /* printf("!%s: got char*[%d] = |%s|\n", "nrrdAxisInfoSet", d, info.CP[ai]); */ break; case nrrdAxisInfoUnits: /* see not above */ info.CP[ai] = va_arg(ap, char *); break; } } va_end(ap); if (nrrdAxisInfoSpaceDirection != axInfo) { /* now set the quantities which we've gotten from the var args */ nrrdAxisInfoSet_nva(nrrd, axInfo, info.P); } else { nrrdAxisInfoSet_nva(nrrd, axInfo, svec); } return; }
int main() { airArray *mop, *submop; char *err; int typi; unsigned int supi, probePass, cti /* context copy index */, pvlIdx[NRRD_TYPE_MAX+1], sx, sy, sz, subnum; size_t sizes[3] = {42,61,50} /* one of these must be even */, ii, nn; Nrrd *norigScl, *nucharScl, *nunquant, *nqdiff, *nconvScl[NRRD_TYPE_MAX+1]; unsigned char *ucharScl; gageContext *gctx[2][KERN_SIZE_MAX+1]; gagePerVolume *gpvl[2][NRRD_TYPE_MAX+1][KERN_SIZE_MAX+1]; const double *vansScl[2][NRRD_TYPE_MAX+1][KERN_SIZE_MAX+1], *gansScl[2][NRRD_TYPE_MAX+1][KERN_SIZE_MAX+1], *hansScl[2][NRRD_TYPE_MAX+1][KERN_SIZE_MAX+1]; double *origScl, omin, omax, dsx, dsy, dsz, spcOrig[NRRD_SPACE_DIM_MAX] = {0.0, 0.0, 0.0}, spcVec[3][NRRD_SPACE_DIM_MAX] = { {1.1, 0.0, 0.0}, {0.0, 2.2, 0.0}, {0.0, 0.0, 3.3}}; mop = airMopNew(); #define NRRD_NEW(name, mop) \ (name) = nrrdNew(); \ airMopAdd((mop), (name), (airMopper)nrrdNuke, airMopAlways) /* --------------------------------------------------------------- */ /* Creating initial volume */ NRRD_NEW(norigScl, mop); if (nrrdMaybeAlloc_nva(norigScl, nrrdTypeDouble, 3, sizes)) { airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "trouble allocating:\n%s", err); airMopError(mop); return 1; } origScl = AIR_CAST(double *, norigScl->data); nn = nrrdElementNumber(norigScl); airSrandMT(42*42); for (ii=0; ii<nn/2; ii++) { airNormalRand(origScl + 2*ii + 0, origScl + 2*ii + 1); } /* learn real range */ omin = omax = origScl[0]; for (ii=1; ii<nn; ii++) { omin = AIR_MIN(omin, origScl[ii]); omax = AIR_MAX(omax, origScl[ii]); } ELL_3V_SET(spcOrig, 0.0, 0.0, 0.0); if (nrrdSpaceSet(norigScl, nrrdSpaceRightAnteriorSuperior) || nrrdSpaceOriginSet(norigScl, spcOrig)) { airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "trouble setting space:\n%s", err); airMopError(mop); return 1; } nrrdAxisInfoSet_nva(norigScl, nrrdAxisInfoSpaceDirection, spcVec); dsx = AIR_CAST(double, sizes[0]); dsy = AIR_CAST(double, sizes[1]); dsz = AIR_CAST(double, sizes[2]); sx = AIR_CAST(unsigned int, sizes[0]); sy = AIR_CAST(unsigned int, sizes[1]); sz = AIR_CAST(unsigned int, sizes[2]); subnum = AIR_CAST(unsigned int, PROBE_NUM*0.9); /* --------------------------------------------------------------- */ /* Quantizing to 8-bits and checking */ submop = airMopNew(); NRRD_NEW(nucharScl, mop); NRRD_NEW(nunquant, submop); NRRD_NEW(nqdiff, submop); if (nrrdQuantize(nucharScl, norigScl, NULL, 8) || nrrdUnquantize(nunquant, nucharScl, nrrdTypeDouble) || nrrdArithBinaryOp(nqdiff, nrrdBinaryOpSubtract, norigScl, nunquant)) { airMopAdd(mop, err = biffGetDone(NRRD), airFree, airMopAlways); fprintf(stderr, "trouble quantizing and back:\n%s", err); airMopError(submop); airMopError(mop); return 1; } if (!( nucharScl->oldMin == omin && nucharScl->oldMax == omax )) { fprintf(stderr, "quantization range [%g,%g] != real range [%g,%g]\n", nucharScl->oldMin, nucharScl->oldMax, omin, omax); airMopError(submop); airMopError(mop); return 1; } { double *qdiff, *unquant; /* empirically determined tolerance, which had to be increased in order to work under valgrind (!)- perhaps because of a difference in the use of 80-bit registers */ double epsilon=0.50000000000004; qdiff = AIR_CAST(double *, nqdiff->data); unquant = AIR_CAST(double *, nunquant->data); for (ii=0; ii<nn; ii++) { double dd; /* with infinite precision, the max difference between original and quantized values should be exactly half the width (in value) of 1/256 of value range ==> dd = 0.5 */ dd = qdiff[ii]*256/(omax - omin); if (AIR_ABS(dd) > epsilon) { unsigned int ui; ui = AIR_CAST(unsigned int, ii); fprintf(stderr, "|orig[%u]=%.17g - unquant=%.17g|*256/%.17g " "= %.17g > %.17g!\n", ui, origScl[ii], unquant[ii], omax - omin, AIR_ABS(dd), epsilon); airMopError(submop); airMopError(mop); return 1; } } }
int NrrdWriter(HxUniformScalarField3* field, const char* filename, int encoding) { // Identify data type int nrrdType = nrrdTypeUnknown; switch ( field->primType() ) { case McPrimType::mc_uint8: nrrdType = nrrdTypeUChar; break; case McPrimType::mc_int8: nrrdType = nrrdTypeChar; break; case McPrimType::mc_uint16: nrrdType = nrrdTypeUShort; break; case McPrimType::mc_int16: nrrdType = nrrdTypeShort; break; case McPrimType::mc_int32: nrrdType = nrrdTypeInt; break; case McPrimType::mc_float: nrrdType = nrrdTypeFloat; break; case McPrimType::mc_double: nrrdType = nrrdTypeDouble; break; default: break; } if(nrrdType == nrrdTypeUnknown) { theMsg->printf("ERROR: unsupported output type: %s for nrrd",field->primType().getName()); return 0; } void* data = field->lattice.dataPtr(); Nrrd *nrrd = nrrdNew(); NrrdIoState *nios = nrrdIoStateNew(); if ( encoding == nrrdEncodingTypeGzip) { if (nrrdEncodingGzip->available() ) { nrrdIoStateEncodingSet( nios, nrrdEncodingGzip ); nrrdIoStateSet( nios, nrrdIoStateZlibLevel, 9 ); } else theMsg->printf("WARNING: Nrrd library does not support Gzip compression encoding.\n Make sure Teem_ZLIB is on in CMAKE when building Nrrd library.\n"); } else if ( encoding == nrrdEncodingTypeBzip2) { if (nrrdEncodingBzip2->available() ) { nrrdIoStateEncodingSet( nios, nrrdEncodingBzip2 ); // nrrdIoStateSet( nios, nrrdIoStateBzip2BlockSize, 9 ); } else theMsg->printf("WARNING: Nrrd library does not support Bzip2 compression encoding.\n Make sure Teem_BZIP2 is on in CMAKE when building Nrrd library.\n"); } else if ( encoding == nrrdEncodingTypeAscii) { nrrdIoStateEncodingSet( nios, nrrdEncodingAscii ); } else { theMsg->printf("ERROR: Unimplemented nrrd encoding type: %d\n",encoding); return 0; } try { if ( nrrdWrap_va( nrrd, data, nrrdType, (size_t)3, (size_t)field->lattice.dimsInt()[0], (size_t)field->lattice.dimsInt()[1], (size_t)field->lattice.dimsInt()[2] ) ) { throw( biffGetDone(NRRD) ); } nrrdSpaceDimensionSet( nrrd, 3 ); // TODO: Would be nice to set space units. How does Amira store this? // if ( writeVolume->MetaKeyExists(CMTK_META_SPACE_UNITS_STRING) ) // { // nrrd->spaceUnits[0] = strdup( writeVolume->m_MetaInformation[CMTK_META_SPACE_UNITS_STRING].c_str() ); // nrrd->spaceUnits[1] = strdup( writeVolume->m_MetaInformation[CMTK_META_SPACE_UNITS_STRING].c_str() ); // nrrd->spaceUnits[2] = strdup( writeVolume->m_MetaInformation[CMTK_META_SPACE_UNITS_STRING].c_str() ); // } int kind[NRRD_DIM_MAX] = { nrrdKindDomain, nrrdKindDomain, nrrdKindDomain }; nrrdAxisInfoSet_nva( nrrd, nrrdAxisInfoKind, kind ); // TODO: Would be nice to write some kind of space if this exists // Fetch bounding box information and voxel size float* bbox = field->bbox(); McVec3f voxelSize = field->getVoxelSize(); // Just deal with space directions orthogonal to data axes // TODO: Fetch transformation and use that double spaceDir[NRRD_DIM_MAX][NRRD_SPACE_DIM_MAX]; for ( int i = 0; i < 3; ++i ) { for ( int j = 0; j < 3; ++j ) { if (i == j) spaceDir[i][j] = (double) voxelSize[i]; else spaceDir[i][j] = 0.0; // Can't assume that memory is zeroed } } nrrdAxisInfoSet_nva( nrrd, nrrdAxisInfoSpaceDirection, spaceDir ); double origin[NRRD_DIM_MAX] = { bbox[0], bbox[2], bbox[4] }; if ( nrrdSpaceOriginSet( nrrd, origin ) ) { throw( biffGetDone(NRRD) ); } nrrdAxisInfoSet_va( nrrd, nrrdAxisInfoLabel, "x", "y", "z" ); if ( nrrdSave( filename, nrrd, nios ) ) { throw( biffGetDone(NRRD) ); } } catch ( char* err ) { theMsg->printf("ERROR: hxNrrdIO library returned error '%s'\n", err); free( err ); return 0; } nrrdIoStateNix( nios ); nrrdNix(nrrd); return 1; }