Пример #1
0
int					regFloat3d		(struct	rParam		*regDataPtr) {

    struct	fitRec		fit, invFit;
    float				*pyrHdl1[maxPyrLevels], *pyrHdl2[maxPyrLevels];
    float				*mskHdl1[maxPyrLevels], *mskHdl2[maxPyrLevels];
    float				*inPtr1, *inPtr2;
    float				*outPtr;
    float				*mskPtr1, *mskPtr2;
    float				*mskPtr;
    float				*u;
    double				origin[3];
    double				epsilon[maxPyrLevels];
    long				nxRange[maxPyrLevels];
    long				nyRange[maxPyrLevels];
    long				nzRange[maxPyrLevels];
    int					ia[hessianSize];
    double				mse, snr;
    double				lambda;
    double				x1, y1, z1;
    double				x2, y2, z2;
    double				mean;
    int					nx, ny, nz;
    int					k, l;
    int					x, y, z;

    switch (regDataPtr->directives.convergence) {
    case gravity:
        if (regDataPtr->directives.isoScaling || regDataPtr->directives.xRot
                || regDataPtr->directives.yRot || regDataPtr->directives.zRot
                || regDataPtr->directives.xSkew || regDataPtr->directives.ySkew
                || regDataPtr->directives.zSkew || regDataPtr->directives.matchGrey) {
            message("ERROR - Gravity center can only be translated");
            return(ERROR);
        }
        else if ((regDataPtr->directives.importFit != 0) && (regDataPtr->directives.xTrans
                 || regDataPtr->directives.yTrans || regDataPtr->directives.zTrans))
            message("WARNING - Ignoring 'importFit' parameter");
        break;
    case Marquardt:
        break;
    default:
        message("ERROR - Unknown convergence specification");
        return(ERROR);
    }
    switch (regDataPtr->directives.interpolation) {
    case zero:
        if (regDataPtr->directives.convergence != gravity) {
            message("ERROR - Nearest neighbor interpolation valid only for gravity");
            return(ERROR);
        }
    case one:
    case three:
        break;
    default:
        message("ERROR - Unknown interpolation specification");
        return(ERROR);
    }
    if (regDataPtr->directives.zSqueeze && (regDataPtr->nz == 1)) {
        message("ERROR - Inconsistent parameters: unable to shrink Z-axis in 2-D");
        return(ERROR);
    }
    if ((!regDataPtr->directives.zSqueeze) && (regDataPtr->nz != 1)
            && regDataPtr->directives.isoScaling) {
        message("ERROR - Inconsistent parameters: zSqueeze needed for isoScaling in 3-D");
        return(ERROR);
    }
    if (regDataPtr->directives.isoScaling && (regDataPtr->directives.xSkew
            || regDataPtr->directives.ySkew || regDataPtr->directives.zSkew)) {
        message("ERROR - Inconsistent parameters: (x,y,z)Skew and isoScaling");
        return(ERROR);
    }
    if ((regDataPtr->directives.xRot || regDataPtr->directives.yRot
            || regDataPtr->directives.zRot) && (regDataPtr->directives.xSkew
                    || regDataPtr->directives.ySkew || regDataPtr->directives.zSkew)) {
        message("ERROR - Inconsistent parameters: (x,y,z)Rot and (x,y,z)Skew");
        return(ERROR);
    }
    if (regDataPtr->directives.xRot && (!regDataPtr->directives.zSqueeze)) {
        message("ERROR - Inconsistent parameters: xRot needs zSqueeze");
        return(ERROR);
    }
    if (regDataPtr->directives.yRot && (!regDataPtr->directives.zSqueeze)) {
        message("ERROR - Inconsistent parameters: yRot needs zSqueeze");
        return(ERROR);
    }
    message("STATUS - Initializing...");
    inPtr1 = regDataPtr->inPtr1;
    inPtr2 = regDataPtr->inPtr2;
    mskPtr1 = regDataPtr->inMsk1;
    mskPtr2 = regDataPtr->inMsk2;
    outPtr = regDataPtr->outPtr;
    mskPtr = regDataPtr->mskPtr;
    nx = regDataPtr->nx;
    ny = regDataPtr->ny;
    nz = regDataPtr->nz;
    initialEstimate(&fit, nx, ny, nz);
    if ((regDataPtr->directives.importFit != 0)
            && (regDataPtr->directives.convergence != gravity)) {
        if (importFit(&fit, regDataPtr->inFit) == ERROR) {
            message("ERROR - Importation of fit variables failed");
            return(ERROR);
        }
        switch (regDataPtr->directives.importFit) {
        case -1:
            if (invertFit(&fit, &invFit) == ERROR) {
                message("ERROR - Unable to compute the backward transformation");
                return(ERROR);
            }
            fit = invFit;
            break;
        case 1:
            break;
        default:
            message("ERROR - Unknown importFit specification");
            return(ERROR);
        }
    }
    switch (regDataPtr->directives.testMask) {
    case blank:
        u = mskPtr1;
        for (z = 0; (z < nz); z++)
            for (y = 0; (y < ny); y++)
                for (x = 0; (x < nx); u++, x++)
                    *u = 1.0F;
        break;
    case provided:
        break;
    case computed:
        if (maskFromData(inPtr1, mskPtr1, nx, ny, nz, regDataPtr->sx, regDataPtr->sy,
                         regDataPtr->sz) == ERROR) {
            message("ERROR - Unable to extract mask from test data");
            return(ERROR);
        }
        break;
    default:
        message("ERROR - Unknown test mask specification");
        return(ERROR);
    }
    switch (regDataPtr->directives.referenceMask) {
    case blank:
        u = mskPtr2;
        for (z = 0; (z < nz); z++)
            for (y = 0; (y < ny); y++)
                for (x = 0; (x < nx); u++, x++)
                    *u = 1.0F;
        break;
    case provided:
        break;
    case computed:
        if (maskFromData(inPtr2, mskPtr2, nx, ny, nz, regDataPtr->sx, regDataPtr->sy,
                         regDataPtr->sz) == ERROR) {
            message("ERROR - Unable to extract mask from reference data");
            return(ERROR);
        }
        break;
    default:
        message("ERROR - Unknown reference mask specification");
        return(ERROR);
    }
    if (regDataPtr->directives.zapMean) {
        mean = averageMskData(inPtr1, mskPtr1, nx, ny, nz);
        zapMean(inPtr1, mean, nx, ny, nz);
        mean = averageMskData(inPtr2, mskPtr2, nx, ny, nz);
        zapMean(inPtr2, mean, nx, ny, nz);
    }
    if ((!regDataPtr->directives.isoScaling) && (!regDataPtr->directives.xTrans)
            && (!regDataPtr->directives.yTrans) && (!regDataPtr->directives.zTrans)
            && (!regDataPtr->directives.xRot) && (!regDataPtr->directives.yRot)
            && (!regDataPtr->directives.zRot) && (!regDataPtr->directives.xSkew)
            && (!regDataPtr->directives.ySkew) && (!regDataPtr->directives.zSkew)
            && (!regDataPtr->directives.matchGrey)) {
        message("WARNING - Nothing to optimize");

        // We save the extracted transformation values to the ouptut structure used in the mex file.
        regDataPtr->fit.dx[0]=fit.dx[0];
        regDataPtr->fit.dx[1]=fit.dx[1];
        regDataPtr->fit.psi=fit.psi;
        regDataPtr->fit.skew[0][2]=fit.skew[0][2];
        regDataPtr->fit.skew[1][2]=fit.skew[1][2];
        regDataPtr->fit.skew[2][2]=fit.skew[2][2];
        regDataPtr->fit.skew[0][1]=fit.skew[0][1];
        regDataPtr->fit.skew[1][1]=fit.skew[1][1];
        regDataPtr->fit.skew[2][1]=fit.skew[2][1];
        regDataPtr->fit.skew[0][0]=fit.skew[0][0];
        regDataPtr->fit.skew[1][0]=fit.skew[1][0];
        regDataPtr->fit.skew[2][0]=fit.skew[2][0];

        regDataPtr->fit.origin[0]=fit.origin[0];
        regDataPtr->fit.origin[1]=fit.origin[1];
        message("STATUS - Creating output...");
        if (dirMskTransform(&fit, inPtr1, outPtr, mskPtr1, mskPtr, nx, ny, nz,
                            regDataPtr->directives.greyRendering, regDataPtr->directives.interpolation)
                == ERROR) {
            message("ERROR - Final transformation of test image failed");
            return(ERROR);
        }
        adornImage(outPtr, mskPtr, nx, ny, nz, nx, ny, nz, regDataPtr->directives.clipping,
                   regDataPtr->backgrnd);
        computeMskSnr(&mse, &snr, inPtr2, outPtr, mskPtr2, mskPtr,
                      regDataPtr->directives.maskCombine, nx, ny, nz);
        if (exportFit(&fit) == ERROR ) {
            message("ERROR - Assignment of transformation variables failed");
            return(ERROR);
        }
        if (exportSummary(&fit, mse, snr) == ERROR ) {
            message("ERROR - Assignment of summary variables failed");
            return(ERROR);
        }
        if (regDataPtr->directives.exportFit)
            if (fExportFit(&fit, regDataPtr->outFit) == ERROR ) {
                message("ERROR - Exportation of transformation variables failed");
                return(ERROR);
            }
        return(!ERROR);
    }
    bilevelFormat(mskPtr1, nx, ny, nz);
    bilevelFormat(mskPtr2, nx, ny, nz);
    if (regDataPtr->directives.convergence == gravity) {
        logicalFormat(mskPtr1, nx, ny, nz);
        logicalFormat(mskPtr2, nx, ny, nz);
        message("STATUS - Aligning centers of gravity...");
        if (getCenter(inPtr1, mskPtr1, nx, ny, nz, &x1, &y1, &z1) == ERROR) {
            message("ERROR - Unable to compute 1st center of gravity");
            return(ERROR);
        }
        if (getCenter(inPtr2, mskPtr2, nx, ny, nz, &x2, &y2, &z2) == ERROR) {
            message("ERROR - Unable to compute 2nd center of gravity");
            return(ERROR);
        }
        fit.dx[0] = x2 - x1;
        fit.dx[1] = y2 - y1;
        fit.dx[2] = z2 - z1;

        // We save the extracted transformation values to the ouptut structure used in the mex file.
        regDataPtr->fit.dx[0]=fit.dx[0];
        regDataPtr->fit.dx[1]=fit.dx[1];
        regDataPtr->fit.psi=fit.psi;
        regDataPtr->fit.skew[0][2]=fit.skew[0][2];
        regDataPtr->fit.skew[1][2]=fit.skew[1][2];
        regDataPtr->fit.skew[2][2]=fit.skew[2][2];
        regDataPtr->fit.skew[0][1]=fit.skew[0][1];
        regDataPtr->fit.skew[1][1]=fit.skew[1][1];
        regDataPtr->fit.skew[2][1]=fit.skew[2][1];
        regDataPtr->fit.skew[0][0]=fit.skew[0][0];
        regDataPtr->fit.skew[1][0]=fit.skew[1][0];
        regDataPtr->fit.skew[2][0]=fit.skew[2][0];

        regDataPtr->fit.origin[0]=fit.origin[0];
        regDataPtr->fit.origin[1]=fit.origin[1];

        message("STATUS - Creating output...");
        if (dirMskTransform(&fit, inPtr1, outPtr, mskPtr1, mskPtr, nx, ny, nz,
                            regDataPtr->directives.greyRendering, regDataPtr->directives.interpolation)
                == ERROR) {
            message("ERROR - Final transformation of test image failed");
            return(ERROR);
        }
        adornImage(outPtr, mskPtr, nx, ny, nz, nx, ny, nz, regDataPtr->directives.clipping,
                   regDataPtr->backgrnd);
        computeMskSnr(&mse, &snr, inPtr2, outPtr, mskPtr2, mskPtr,
                      regDataPtr->directives.maskCombine, nx, ny, nz);
        if (exportFit(&fit) == ERROR ) {
            message("ERROR - Assignment of transformation variables failed");
            return(ERROR);
        }
        if (exportSummary(&fit, mse, snr) == ERROR ) {
            message("ERROR - Assignment of summary variables failed");
            return(ERROR);
        }
        if (regDataPtr->directives.exportFit)
            if (fExportFit(&fit, regDataPtr->outFit) == ERROR ) {
                message("ERROR - Exportation of transformation variables failed");
                return(ERROR);
            }
        return(!ERROR);
    }
    for (l = 0; (l < regDataPtr->levels); l++) {
        pyrHdl1[l] = (float *)NULL;
        pyrHdl2[l] = (float *)NULL;
        mskHdl1[l] = (float *)NULL;
        mskHdl2[l] = (float *)NULL;
    }
    if (pyramid(mskPtr1, regDataPtr->levels, mskHdl1, nxRange, nyRange, nzRange, nx, ny, nz,
                regDataPtr->directives.zSqueeze, regDataPtr->directives.interpolation) == ERROR) {
        freePyramids(pyrHdl1, pyrHdl2, mskHdl1, mskHdl2, regDataPtr->levels);
        message("ERROR - Not enough memory for 1st mask pyramid computation");
        return(ERROR);
    }
    if (pyramid(mskPtr2, regDataPtr->levels, mskHdl2, nxRange, nyRange, nzRange, nx, ny, nz,
                regDataPtr->directives.zSqueeze, regDataPtr->directives.interpolation) == ERROR) {
        freePyramids(pyrHdl1, pyrHdl2, mskHdl1, mskHdl2, regDataPtr->levels);
        message("ERROR - Not enough memory for 2nd mask pyramid computation");
        return(ERROR);
    }
    logicalFormat(mskPtr1, nx, ny, nz);
    logicalFormat(mskPtr2, nx, ny, nz);
    for (l = 0; (l < regDataPtr->levels); l++) {
        logicalFormat(mskHdl1[l], (int)nxRange[l], (int)nyRange[l], (int)nzRange[l]);
        logicalFormat(mskHdl2[l], (int)nxRange[l], (int)nyRange[l], (int)nzRange[l]);
    }
    if (pyramid(inPtr1, regDataPtr->levels, pyrHdl1, nxRange, nyRange, nzRange, nx, ny, nz,
                regDataPtr->directives.zSqueeze, regDataPtr->directives.interpolation) == ERROR) {
        freePyramids(pyrHdl1, pyrHdl2, mskHdl1, mskHdl2, regDataPtr->levels);
        message("ERROR - Not enough memory for 1st pyramid computation");
        return(ERROR);
    }
    if (pyramid(inPtr2, regDataPtr->levels, pyrHdl2, nxRange, nyRange, nzRange, nx, ny, nz,
                regDataPtr->directives.zSqueeze, regDataPtr->directives.interpolation) == ERROR ) {
        freePyramids(pyrHdl1, pyrHdl2, mskHdl1, mskHdl2, regDataPtr->levels);
        message("ERROR - Not enough memory for 2nd pyramid computation");
        return(ERROR);
    }
    epsilon[0] = regDataPtr->epsilon;
    switch (regDataPtr->directives.convergence) {
    case Marquardt:
        for (l = 1; (l < regDataPtr->levels); l++)
            epsilon[l] = epsilon[l - 1];
        break;
    default:
        freePyramids(pyrHdl1, pyrHdl2, mskHdl1, mskHdl2, regDataPtr->levels);
        message("ERROR - Unknown convergence");
        return(ERROR);
    }
    message("STATUS - Optimizing...");
    origin[0] = (double)((nxRange[0] - 1L) / 2L);
    origin[1] = (double)((nyRange[0] - 1L) / 2L);
    origin[2] = (double)((nzRange[0] - 1L) / 2L);
    convertOrigin(&fit, origin);
    for (l = 0; (l < (regDataPtr->levels - 1)); l++)
        downscaleFit(&fit, nxRange, nyRange, nzRange, l, regDataPtr->directives.zSqueeze);
    lambda = regDataPtr->firstLambda;
    for (l = regDataPtr->levels - 1; (l >= 0); l--) {
        if ((l == (regDataPtr->levels - 1)) || (l >= (regDataPtr->lastLevel - 1))) {
            ia[0] = regDataPtr->directives.xTrans;							/* dx[0] */
            ia[1] = regDataPtr->directives.yTrans && (nyRange[l] != 1L);	/* dx[1] */
            ia[2] = regDataPtr->directives.zTrans && (nzRange[l] != 1L);	/* dx[2] */
            for (k = 3; (k < 12); k++)
                ia[k] = FALSE;
            ia[12] = regDataPtr->directives.matchGrey;						/* gamma */
            if (regDataPtr->directives.xSkew) {
                ia[3] = TRUE;													/* skew[0][0] */
                ia[6] = (nyRange[l] != 1L);									/* skew[1][0] */
                ia[9] = (nzRange[l] != 1L);									/* skew[2][0] */
            }
            if (regDataPtr->directives.ySkew) {
                ia[4] = (nyRange[l] != 1L);									/* skew[0][1] */
                ia[7] = (nyRange[l] != 1L);									/* skew[1][1] */
                ia[10] = (nzRange[l] != 1L);									/* skew[2][1] */
            }
            if (regDataPtr->directives.zSkew) {
                ia[5] = (nzRange[l] != 1L);									/* skew[0][2] */
                ia[8] = (nzRange[l] != 1L);									/* skew[1][2] */
                ia[11] = (nzRange[l] != 1L);									/* skew[2][2] */
            }
            if (regDataPtr->directives.xRot || regDataPtr->directives.yRot
                    || regDataPtr->directives.zRot || regDataPtr->directives.isoScaling) {
                ia[3] = regDataPtr->directives.xRot && (nyRange[l] != 1L);	/* phi */
                ia[4] = regDataPtr->directives.yRot && (nzRange[l] != 1L);	/* theta */
                ia[5] = regDataPtr->directives.zRot && (nyRange[l] != 1L);	/* psi */
                ia[6] = regDataPtr->directives.isoScaling;					/* lambda */
                ia[7] = regDataPtr->directives.matchGrey;						/* gamma */
                ia[8] = FALSE;
                ia[9] = FALSE;
                ia[10] = FALSE;
                ia[11] = FALSE;
                ia[12] = FALSE;
            }
            switch (regDataPtr->directives.convergence) {
            case Marquardt:
                if (optimize(&fit, &(regDataPtr->directives), ia, pyrHdl1[l], pyrHdl2[l],
                             mskHdl1[l], mskHdl2[l], outPtr, mskPtr, &lambda, regDataPtr->firstLambda,
                             regDataPtr->lambdaScale, epsilon[l], regDataPtr->minGain,
                             (int)nxRange[l], (int)nyRange[l], (int)nzRange[l]) == ERROR) {
                    freePyramids(pyrHdl1, pyrHdl2, mskHdl1, mskHdl2, regDataPtr->levels);
                    message("ERROR - Optimization failed (Marquardt)");
                    return(ERROR);
                }
                lambda = regDataPtr->firstLambda;
                break;
            default:
                freePyramids(pyrHdl1, pyrHdl2, mskHdl1, mskHdl2, regDataPtr->levels);
                message("ERROR - Unknown convergence");
                return(ERROR);
            }
        }
        if (l != 0)
            upscaleFit(&fit, nxRange, nyRange, nzRange, l, regDataPtr->directives.zSqueeze);
    }
    convertOrigin(&fit, origin);

    // We save the extracted transformation values to the ouptut structure used in the mex file.
    regDataPtr->fit.dx[0]=fit.dx[0];
    regDataPtr->fit.dx[1]=fit.dx[1];

    regDataPtr->fit.psi=fit.psi;

    regDataPtr->fit.skew[0][2]=fit.skew[0][2];
    regDataPtr->fit.skew[1][2]=fit.skew[1][2];
    regDataPtr->fit.skew[2][2]=fit.skew[2][2];
    regDataPtr->fit.skew[0][1]=fit.skew[0][1];
    regDataPtr->fit.skew[1][1]=fit.skew[1][1];
    regDataPtr->fit.skew[2][1]=fit.skew[2][1];
    regDataPtr->fit.skew[0][0]=fit.skew[0][0];
    regDataPtr->fit.skew[1][0]=fit.skew[1][0];
    regDataPtr->fit.skew[2][0]=fit.skew[2][0];

    regDataPtr->fit.origin[0]=fit.origin[0];
    regDataPtr->fit.origin[1]=fit.origin[1];

    message("STATUS - Creating output...");
    if (dirMskTransform(&fit, inPtr1, outPtr, mskPtr1, mskPtr, nx, ny, nz,
                        regDataPtr->directives.greyRendering, regDataPtr->directives.interpolation) == ERROR) {
        freePyramids(pyrHdl1, pyrHdl2, mskHdl1, mskHdl2, regDataPtr->levels);
        message("ERROR - Final transformation of test image failed");
        return(ERROR);
    }
    adornImage(outPtr, mskPtr, nx, ny, nz, (int)nxRange[0], (int)nyRange[0],
               (int)nzRange[0], regDataPtr->directives.clipping, regDataPtr->backgrnd);
    computeMskSnr(&mse, &snr, inPtr2, outPtr, mskPtr2, mskPtr,
                  regDataPtr->directives.maskCombine, nx, ny, nz);
    if (exportFit(&fit) == ERROR ) {
        freePyramids(pyrHdl1, pyrHdl2, mskHdl1, mskHdl2, regDataPtr->levels);
        message("ERROR - Assignment of transformation variables failed");
        return(ERROR);
    }
    if (exportSummary(&fit, mse, snr) == ERROR ) {
        freePyramids(pyrHdl1, pyrHdl2, mskHdl1, mskHdl2, regDataPtr->levels);
        message("ERROR - Assignment of summary variables failed");
        return(ERROR);
    }
    if (regDataPtr->directives.exportFit)
        if (fExportFit(&fit, regDataPtr->outFit) == ERROR ) {
            freePyramids(pyrHdl1, pyrHdl2, mskHdl1, mskHdl2, regDataPtr->levels);
            message("ERROR - Exportation of transformation variables failed");
            return(ERROR);
        }
    freePyramids(pyrHdl1, pyrHdl2, mskHdl1, mskHdl2, regDataPtr->levels);
    return(!ERROR);
} /* End of regFloat3d */
Пример #2
0
int					invTransform	(struct fitRec		*fit,
									 float				*inPtr,
									 double				*splinePtr,
									 float				*outPtr,
									 float				*inMsk,
									 float				*outMsk,
									 int				nx,
									 int				ny,
									 int				nz,
									 enum	iDegree		interpolation) {

		double				*wtx, *wty, *wtz;
		double				*dpi, *dpj;
		float				*fpi, *fpj;
		long				*fdx, *fdy, *fdz;
		double				weightX[5], weightY[5], weightZ[5];
		long				foldX[5], foldY[5], foldZ[5];
		struct fitRec		invFit;
		ptrdiff_t			d;
		double				xO, yO, zO;
		double				xz, yz, zz;
		double				xy, yy, zy;
		double				xIn, yIn, zIn;
		double				xOut, yOut, zOut;
		double				q, qi, qj;
		long				lnx = (long)nx, lny = (long)ny, lnz = (long)nz;
		long				nxy = lnx * lny;
		long				x, y, z;
		long				i, j, k;

		if (invertFit(fit, &invFit) == ERROR) {
		  message("ERROR - Unable to compute the backward transformation");
		  return(ERROR);
		}
		xO = invFit.origin[0];
		yO = invFit.origin[1];
		zO = invFit.origin[2];
		switch (interpolation) {
		  case one:
			for (zOut = -zO; (zOut < ((double)nz - zO)); zOut += 1.0) {
			  xz = invFit.skew[0][2] * zOut - invFit.dx[0] + xO;
			  yz = invFit.skew[1][2] * zOut - invFit.dx[1] + yO;
			  zz = invFit.skew[2][2] * zOut - invFit.dx[2] + zO;
			  for (yOut = -yO; (yOut < ((double)ny - yO)); yOut += 1.0) {
				xy = xz + invFit.skew[0][1] * yOut;
				yy = yz + invFit.skew[1][1] * yOut;
				zy = zz + invFit.skew[2][1] * yOut;
				for (xOut = -xO; (xOut < ((double)nx - xO)); xOut += 1.0) {
				  xIn = xy + invFit.skew[0][0] * xOut + 0.5;
				  yIn = yy + invFit.skew[1][0] * xOut + 0.5;
				  zIn = zy + invFit.skew[2][0] * xOut + 0.5;
				  x = (long)xIn;
				  if (xIn < 0.0)
					x--;
				  y = (long)yIn;
				  if (yIn < 0.0)
					y--;
				  z = (long)zIn;
				  if (zIn < 0.0)
					z--;
				  if ((0L <= x) && (x < lnx) && (0L <= y) && (y < lny) && (0L <= z)
					&& (z < lnz)) {
					d = (ptrdiff_t)(z * nxy + y * lnx + x);
					*outMsk = *(inMsk + d);
				  }
				  else {
					d = (ptrdiff_t)(-1);
					*outMsk = 0.0F;
				  }
				  if (*outMsk++ != 0.0F) {
					xIn -= 0.5;
					yIn -= 0.5;
					zIn -= 0.5;
					wtz = weightZ;
					fdz = foldZ;
					for (k = z - 1L; (k <= (z + 1L)); k++) {
					  *wtz++ = (lnz == 1L) ? (1.0) : (BsplnWght1(k, zIn));
					  *fdz++ = (lnz == 1L) ? (0L) : (fold(k, lnz) * nxy);
					}
					wty = weightY;
					fdy = foldY;
					for (j = y - 1L; (j <= (y + 1L)); j++) {
					  *wty++ = BsplnWght1(j, yIn);
					  *fdy++ = fold(j, lny) * lnx;
					}
					wtx = weightX;
					fdx = foldX;
					for (i = x - 1L; (i <= (x + 1L)); i++) {
					  *wtx++ = BsplnWght1(i, xIn);
					  *fdx++ = fold(i, lnx);
					}
					q = 0.0;
					wtz = weightZ;
					fdz = foldZ;
					for (k = (lnz == 1L) ? (1L) : (3L); (k-- > 0L);) {
					  wty = weightY;
					  fdy = foldY;
					  fpj = inPtr + (ptrdiff_t)(*fdz++);
					  qj = 0.0;
					  for (j = 3L; (j-- > 0L);) {
						wtx = weightX;
						fdx = foldX;
						fpi = fpj + (ptrdiff_t)(*fdy++);
						qi = 0.0;
						for (i = 3L; (i-- > 0L);)
						  qi += *wtx++ * (double)*(fpi + (ptrdiff_t)(*fdx++));
						qj += qi * *wty++;
					  }
					  q += qj * *wtz++;
					}
				  }
				  else
					q = (d == (ptrdiff_t)(-1)) ? (0.0) : ((double)*(inPtr + d)
					  * exp(invFit.gamma));
				  *outPtr++ = (float)q;
				}
			  }
			}
			break;
		  case three:
			for (zOut = -zO; (zOut < ((double)nz - zO)); zOut += 1.0) {
			  xz = invFit.skew[0][2] * zOut - invFit.dx[0] + xO;
			  yz = invFit.skew[1][2] * zOut - invFit.dx[1] + yO;
			  zz = invFit.skew[2][2] * zOut - invFit.dx[2] + zO;
			  for (yOut = -yO; (yOut < ((double)ny - yO)); yOut += 1.0) {
				xy = xz + invFit.skew[0][1] * yOut;
				yy = yz + invFit.skew[1][1] * yOut;
				zy = zz + invFit.skew[2][1] * yOut;
				for (xOut = -xO; (xOut < ((double)nx - xO)); xOut += 1.0) {
				  xIn = xy + invFit.skew[0][0] * xOut + 0.5;
				  yIn = yy + invFit.skew[1][0] * xOut + 0.5;
				  zIn = zy + invFit.skew[2][0] * xOut + 0.5;
				  x = (long)xIn;
				  if (xIn < 0.0)
					x--;
				  y = (long)yIn;
				  if (yIn < 0.0)
					y--;
				  z = (long)zIn;
				  if (zIn < 0.0)
					z--;
				  if ((0L <= x) && (x < lnx) && (0L <= y) && (y < lny) && (0L <= z)
					&& (z < lnz)) {
					d = (ptrdiff_t)(z * nxy + y * lnx + x);
					*outMsk = *(inMsk + d);
				  }
				  else {
					d = (ptrdiff_t)(-1);
					*outMsk = 0.0F;
				  }
				  if (*outMsk++ != 0.0F) {
					xIn -= 0.5;
					yIn -= 0.5;
					zIn -= 0.5;
					wtz = weightZ;
					fdz = foldZ;
					for (k = z - 2L; (k <= (z + 2L)); k++) {
					  *wtz++ = (lnz == 1L) ? (1.0) : (BsplnWght3(k, zIn));
					  *fdz++ = (lnz == 1L) ? (0L) : (fold(k, lnz) * nxy);
					}
					wty = weightY;
					fdy = foldY;
					for (j = y - 2L; (j <= (y + 2L)); j++) {
					  *wty++ = BsplnWght3(j, yIn);
					  *fdy++ = fold(j, lny) * lnx;
					}
					wtx = weightX;
					fdx = foldX;
					for (i = x - 2L; (i <= (x + 2L)); i++) {
					  *wtx++ = BsplnWght3(i, xIn);
					  *fdx++ = fold(i, lnx);
					}
					q = 0.0;
					wtz = weightZ;
					fdz = foldZ;
					for (k = (lnz == 1L) ? (1L) : (5L); (k-- > 0L);) {
					  wty = weightY;
					  fdy = foldY;
					  dpj = splinePtr + (ptrdiff_t)(*fdz++);
					  qj = 0.0;
					  for (j = 5L; (j-- > 0L);) {
						wtx = weightX;
						fdx = foldX;
						dpi = dpj + (ptrdiff_t)(*fdy++);
						qi = 0.0;
						for (i = 5L; (i-- > 0L);)
						  qi += *wtx++ * *(dpi + (ptrdiff_t)(*fdx++));
						qj += qi * *wty++;
					  }
					  q += qj * *wtz++;
					}
				  }
				  else
					q = (d == (ptrdiff_t)(-1)) ? (0.0) : ((double)*(inPtr + d)
					  * exp(invFit.gamma));
				  *outPtr++ = (float)q;
				}
			  }
			}
			break;
		  default:
			message("ERROR - Unknown interpolation specification");
			return(ERROR);
		}
		return(!ERROR);
} /* End of invTransform */