/* * $Id: spm_brainwarp.c 4453 2011-09-02 10:47:25Z guillaume $ * John Ashburner */ #include #include "mex.h" #include "spm_mapping.h" #define RINT(A) floor((A)+0.5) extern int AbackslashB(double *, double *, double *); extern void MtimesX(double *, double *, double *); /* INPUTS T[3*nz*ny*nx + ni*4] - current transform VF - image to normalize ni - number of templates vols2[ni] - templates nx - number of basis functions in x B0[dim1[0]*nx] - basis functions in x dB0[dim1[0]*nx] - derivatives of basis functions in x ny - number of basis functions in y B1[dim1[1]*ny] - basis functions in y dB1[dim1[1]*ny] - derivatives of basis functions in y nz - number of basis functions in z B2[dim1[2]*nz] - basis functions in z dB2[dim1[2]*nz] - derivatives of basis functions in z M[4*4] - transformation matrix samp[3] - frequency of sampling template. OUTPUTS alpha[(3*nz*ny*nx+ni*4)^2] - A'A beta[(3*nz*ny*nx+ni*4)] - A'b pss[1*1] - sum of squares difference pnsamp[1*1] - number of voxels sampled ss_deriv[3] - sum of squares of derivatives of residuals */ static void matmul(int m, int l, int n, double B[], double C[], double A[]) { int i, j, k; double tmp; for(i=0; imat, VF->mat, MW1)) mexErrMsgTxt("Can't invert matrix"); matmul(4,4,4, M, MW1, MW); } dim1 = VG[0].dim; bx3[0] = dB0; bx3[1] = B0; bx3[2] = B0; by3[0] = B1; by3[1] = dB1; by3[2] = B1; bz3[0] = B2; bz3[1] = B2; bz3[2] = dB2; ni4 = ni*4; /* rate of change of voxel with respect to change in parameters */ dvdt = (double *)mxCalloc( 3*nx + ni4 , sizeof(double)); /* Intermediate storage arrays */ Tz = (double *)mxCalloc( 3*nx*ny , sizeof(double)); Ty = (double *)mxCalloc( 3*nx , sizeof(double)); betax = (double *)mxCalloc( 3*nx + ni4 , sizeof(double)); betaxy = (double *)mxCalloc( 3*nx*ny + ni4 , sizeof(double)); alphax = (double *)mxCalloc((3*nx + ni4)*(3*nx + ni4), sizeof(double)); alphaxy = (double *)mxCalloc((3*nx*ny + ni4)*(3*nx*ny + ni4), sizeof(double)); for (i1=0; i1<3; i1++) { for(i2=0; i2<3; i2++) { Jz[i1][i2] = (double *)mxCalloc(nx*ny, sizeof(double)); Jy[i1][i2] = (double *)mxCalloc(nx , sizeof(double)); } } /* pointer to scales for each of the template images */ scal = T + 3*nx*ny*nz; /* only zero half the matrix */ m1 = 3*nx*ny*nz+ni4; for (x1=0;x1=1+edgeskip[0] && s2[0]dim[0]-edgeskip[0] && s2[1]>=1+edgeskip[1] && s2[1]dim[1]-edgeskip[1] && s2[2]>=1+edgeskip[2] && s2[2]dim[2]-edgeskip[2] ) { double f, df[3], dv, dvds0[3]; double wtf, wtg, wt; double s0d[3]; s0d[0]=s0[0];s0d[1]=s0[1];s0d[2]=s0[2]; resample_d(1,VF,&f,&df[0],&df[1],&df[2],s2,s2+1,s2+2, 1, 0.0); transform_grads(M, df); if (VWG != (MAPTYPE *)0) resample(1,VWG,&wtg,s0d,s0d+1,s0d+2, 1, 0.0); else wtg = 1.0; if (VWF != (MAPTYPE *)0) { double s3[3]; MtimesX(MW, trans, s3); resample(1,VWF,&wtf,s3,s3+1,s3+2, 1, 0.0); } else wtf = 1.0; if (wtf && wtg) wt = sqrt(1.0 /(1.0/wtf + 1.0/wtg)); else wt = 0.0; /* nonlinear transform the gradients to the same space as the template */ dvds0[0] = J[0][0]*df[0] + J[0][1]*df[1] + J[0][2]*df[2]; dvds0[1] = J[1][0]*df[0] + J[1][1]*df[1] + J[1][2]*df[2]; dvds0[2] = J[2][0]*df[0] + J[2][1]*df[1] + J[2][2]*df[2]; dv = f; for(i1=0; i1(b)) ? (b) : (a)) void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { MAPTYPE *map1, *map2, *mapw, /** object */ *mapw2; int i, nx,ny,nz,ni=1, samp[3], edgeskip[3]; double *M, *B0, *B1, *B2, *dB0, *dB1, *dB2, *T, fwhm = 0, fwhm2 = 0, fwhm3, df, chi2=0.0, ss_deriv[3]; double pixdim[3], nsamp; /* also accept 13th argument - object volume weighting */ int iW; if (((nrhs != 11) && (nrhs != 12) && (nrhs != 13)) || (nlhs > 4)) { mexErrMsgTxt("Incorrect usage."); } map1 = get_maps(prhs[0], &ni); map2 = get_maps(prhs[1], &i); if (i!=1) { free_maps(map1, ni); free_maps(map2, i); mexErrMsgTxt("Incorrect usage."); } for (i=2; i<=10; i++) if (!mxIsNumeric(prhs[i]) || mxIsComplex(prhs[i]) || mxIsSparse(prhs[i]) || !mxIsDouble(prhs[i])) { free_maps(map1, ni); free_maps(map2, 1); mexErrMsgTxt("Inputs must be numeric, real, full and double."); } if (mxGetM(prhs[2]) != 4 || mxGetN(prhs[2]) != 4) { free_maps(map1, ni); free_maps(map2, 1); mexErrMsgTxt("Transformation matrix must be 4x4."); } M = mxGetPr(prhs[2]); if ( mxGetM(prhs[3]) != map1[0].dim[0]) { free_maps(map1, ni); free_maps(map2, 1); mexErrMsgTxt("Wrong sized X basis functions."); } nx = mxGetN(prhs[3]); B0 = mxGetPr(prhs[3]); if ( mxGetM(prhs[6]) != map1[0].dim[0] || mxGetN(prhs[6]) != nx) { free_maps(map1, ni); free_maps(map2, 1); mexErrMsgTxt("Wrong sized X basis function derivatives."); } dB0 = mxGetPr(prhs[6]); if ( mxGetM(prhs[4]) != map1[0].dim[1]) { free_maps(map1, ni); free_maps(map2, 1); mexErrMsgTxt("Wrong sized Y basis functions."); } ny = mxGetN(prhs[4]); B1 = mxGetPr(prhs[4]); if ( mxGetM(prhs[7]) != map1[0].dim[1] || mxGetN(prhs[7]) != ny) { free_maps(map1, ni); free_maps(map2, 1); mexErrMsgTxt("Wrong sized Y basis function derivatives."); } dB1 = mxGetPr(prhs[7]); if ( mxGetM(prhs[5]) != map1[0].dim[2]) { free_maps(map1, ni); free_maps(map2, 1); mexErrMsgTxt("Wrong sized Z basis functions."); } nz = mxGetN(prhs[5]); B2 = mxGetPr(prhs[5]); if ( mxGetM(prhs[8]) != map1[0].dim[2] || mxGetN(prhs[8]) != nz) { free_maps(map1, ni); free_maps(map2, 1); mexErrMsgTxt("Wrong sized Z basis function derivatives."); } dB2 = mxGetPr(prhs[8]); T = mxGetPr(prhs[9]); if (mxGetM(prhs[9])*mxGetN(prhs[9]) != 3*nx*ny*nz+ni*4) { free_maps(map1, ni); free_maps(map2, 1); mexErrMsgTxt("Transform is wrong size."); } if (mxGetM(prhs[10])*mxGetN(prhs[10]) == 1) { fwhm = mxGetPr(prhs[10])[0]; fwhm2 = mxGetPr(prhs[10])[0]; } else if (mxGetM(prhs[10])*mxGetN(prhs[10]) == 2) { fwhm = mxGetPr(prhs[10])[0]; fwhm2 = mxGetPr(prhs[10])[1]; } else mexErrMsgTxt("FWHM should contain one or two values."); voxdim(&map2[0],pixdim); /* Because of edge effects from the smoothing, ignore voxels that are too close */ edgeskip[0] = RINT(fwhm/pixdim[0]); edgeskip[0] = ((edgeskip[0]<1) ? 0 : edgeskip[0]); edgeskip[1] = RINT(fwhm/pixdim[1]); edgeskip[1] = ((edgeskip[1]<1) ? 0 : edgeskip[1]); edgeskip[2] = RINT(fwhm/pixdim[2]); edgeskip[2] = ((edgeskip[2]<1) ? 0 : edgeskip[2]); voxdim(&map1[0],pixdim); /* sample about every fwhm/2 */ samp[0] = RINT(fwhm/2.0/pixdim[0]); samp[0] = ((samp[0]<1) ? 1 : samp[0]); samp[1] = RINT(fwhm/2.0/pixdim[1]); samp[1] = ((samp[1]<1) ? 1 : samp[1]); samp[2] = RINT(fwhm/2.0/pixdim[2]); samp[2] = ((samp[2]<1) ? 1 : samp[2]); for(i=0; i=12) { /* No call to map routine if null */ if (!mxIsEmpty(prhs[11])) { mapw = get_maps(prhs[11], &i); if (i!=1) { free_maps(map1, ni); free_maps(map2, 1); free_maps(mapw, i); mexErrMsgTxt("Incorrect usage."); } } /* Check for object weighting image */ if (nrhs>=13 && !mxIsEmpty(prhs[12])) { mapw2 = get_maps(prhs[12], &iW); if (iW!=1) { free_maps(map1, ni); free_maps(map2, 1); free_maps(mapw2, iW); free_maps(mapw, i); mexErrMsgTxt("Incorrect usage."); } } } mrqcof(T, mxGetPr(plhs[0]), mxGetPr(plhs[1]), &chi2, map2, ni,map1, nx,B0,dB0, ny,B1,dB1, nz,B2,dB2, M, samp, edgeskip, &nsamp, ss_deriv, mapw, mapw2); fwhm3 = ((pixdim[0]/sqrt(2.0*ss_deriv[0]/chi2))*sqrt(8.0*log(2.0)) + (pixdim[1]/sqrt(2.0*ss_deriv[1]/chi2))*sqrt(8.0*log(2.0)) + (pixdim[2]/sqrt(2.0*ss_deriv[2]/chi2))*sqrt(8.0*log(2.0)))/3.0; *mxGetPr(plhs[3]) = fwhm3; if (fwhm3