int bigsdcgr(double *fr, /* reference image */ double *E, /* the criterion value */ double *gr, /* the gradient */ int degc, /* degree for the coefficients */ int frx, int fry, /* size of the reference image */ int cx, int cy, /* size of the image coefficients */ double *derw, /* first derivatives */ double *fw /* warped test image */ ) { double e ; int ix,iy ; int cnum,imcnt ; double shift,stepx,stepy,hsupp ; double parx,pary ; double *derx,*dery ; int lowx,lowy,highx,highy ; int supp,ind1,ind2,ind3,ind4 ; int jx,jy,jxf,jyf ; int cnd,cxe,cye ; double *tabx,*taby ; double ederx ; double edery ; double betajy,betajxjy ; double (*evspln)(double) ; /* pointer to the evaluation function */ int (*mfold)(int,int) ; double (*mfoldd)(double,int) ; /* for the moment, enforce mirror-off-bound condition */ mfold=mfoldmirroroffbound ; mfoldd=mfolddmirroroffbound ; /* printf("frx=%d fry=%d cx=%d cy=%d degc=%d\n",frx,fry,cx,cy,degc) ; */ if (choosespln(degc,&evspln,&supp,0)) myErrMsg("Unsupported degc") ; hsupp=supp/2.0 ; shift=0.0 ; /* we now put the basis function in the corners */ stepx=(cx-1)/((double)frx-1) ; stepy=(cy-1)/((double)fry-1) ; /* printf("stepx=%f stepy=%f\n",stepx,stepy) ; */ cnum=cx*cy ; cnd=cnum*2 ; /* 2 is the number of dimensions */ imcnt=frx*fry ; derx=derw ; dery=derx+imcnt ; /* zero E and gr */ for(ix=0;ix<cnd;ix++) gr[ix]=0.0 ; *E=0.0 ; /* allocate and precalculate tabx, taby */ cxe=cx+2*supp ;/* 2*supp is too much but who cares... */ myMalloc(tabx,cxe,frx) ; for(ix=0;ix<frx;ix++) { parx=shift+stepx*ix ; lowx=(int)floor(parx-hsupp) ; highx=lowx+supp ; for(jx=lowx;jx<=highx;jx++) tabx[ix*cxe+supp+jx]=(*evspln)(parx-jx) ; } cye=cy+2*supp ;/* 2*supp is too much but who cares... */ myMalloc(taby,cye,fry) ; for(iy=0;iy<fry;iy++) { pary=shift+stepy*iy ; lowy=(int)floor(pary-hsupp) ; highy=lowy+supp ; for(jy=lowy;jy<=highy;jy++) taby[iy*cye+supp+jy]=(*evspln)(pary-jy) ; } /* 2D case gradient and Hessian calculation starts here */ for(iy=0;iy<fry;iy++) { /* loop through all pixels */ pary=shift+stepy*iy ; ind4=iy*cye+supp ; lowy=(int)floor(pary-hsupp) ; highy=lowy+supp ; /*printf("iy=%d pary=%f pary-hsupp=%f lowy=%d highy=%d\n", iy,pary,pary-hsupp,lowy,highy) ;*/ for(ix=0;ix<frx;ix++) { ind1=ix+frx*iy ; ind3=ix*cxe+supp ; e=fw[ind1]-fr[ind1] ; (*E)+=e*e ; /* calculate the range of influential parameters */ parx=shift+stepx*ix ; lowx=(int)floor(parx-hsupp) ; highx=lowx+supp ; ederx=2.0*e*derx[ind1] ; edery=2.0*e*dery[ind1] ; /* precalculate tabx */ for(jy=lowy;jy<=highy;jy++) { /* loop through influential c's */ betajy=taby[ind4+jy] ; jyf=mfold(jy,cy) ; /* printf("mfold(%d,%d)=%d ",jy,cy,jyf) ; */ for(jx=lowx;jx<=highx;jx++) { betajxjy=tabx[ind3+jx]*betajy ; jxf=mfold(jx,cx) ; ind2=jxf+cx*jyf ; gr[ind2]+=betajxjy*ederx ; gr[ind2+cnum]+=betajxjy*edery ; } /* for jx */ } /* for jy */ } /* for ix */ } /* for iy */ myFree(tabx) ; myFree(taby) ; return 0 ; }
void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]){ int i; if(nrhs!=1){ mexPrintf("\nwriteFileNifti(niftiStruct)\n\n"); mexPrintf("Writes a NIFTI image based on fields of a structure that resembles\n"); mexPrintf("the NIFTI 1 standard (see http://nifti.nimh.nih.gov/nifti-1/ ).\n"); mexPrintf("See readFileNifti for details about the expected niftiStruct.\n\n"); return; }else if(nlhs>0) { mexPrintf("Too many output arguments"); return; } /* The first arg must be a nifti struct. */ if(!mxIsStruct(prhs[0])) mexErrMsgTxt("First arg must be a nifti struct."); const mxArray *mxnim = prhs[0]; // Sanity check that this is a complete NIFTI struct if(mxGetField(mxnim,0,"fname")==NULL || mxGetField(mxnim,0,"data")==NULL) myErrMsg("First argument must be a proper NIFTI struct (see readFileNifti).\n\n"); /* Create an empty NIFTI C struct */ nifti_image *nim = (nifti_image *)mxCalloc(1, sizeof(nifti_image)); if(!nim) myErrMsg("failed to allocate nifti image"); nim->nifti_type = 1; // We only support single-file NIFTI format /* Load the C-struct with fields from the matlab struct */ mxArray *fname = mxGetField(mxnim,0,"fname"); mxArray *data = mxGetField(mxnim,0,"data"); // fname field needs to be allocated int buflen = (mxGetN(fname)) + 1; nim->fname = (char *)mxCalloc(buflen, sizeof(char)); if(mxGetString(fname, nim->fname, buflen)) mexWarnMsgTxt("Not enough space- fname string is truncated."); nim->iname = NULL; nim->data = mxGetData(data); nim->ndim = mxGetNumberOfDimensions(data); nim->dim[0] = nim->ndim; const int *dims = mxGetDimensions(data); for(i=0; i<nim->ndim; i++) nim->dim[i+1] = dims[i]; for(i=nim->ndim+1; i<8; i++) nim->dim[i] = 1; // Why do I have to assign these explicitly? nim->nx = nim->dim[1]; nim->ny = nim->dim[2]; nim->nz = nim->dim[3]; nim->nt = nim->dim[4]; nim->nu = nim->dim[5]; nim->nv = nim->dim[6]; nim->nw = nim->dim[7]; //for(i=0; i<8; i++) mexPrintf("%d ",nim->dim[i]); mexPrintf("\n\n"); nim->nvox = mxGetNumberOfElements(data); // *** TO DO: we should support DT_RGB24 type (triplet of uint8) if(mxIsComplex(data)){ switch(mxGetClassID(data)){ case mxSINGLE_CLASS: nim->datatype=DT_COMPLEX64; nim->nbyper=8; break; case mxDOUBLE_CLASS: nim->datatype=DT_COMPLEX128; nim->nbyper=16; break; default: myErrMsg("Unknown data type!"); } }else{ switch(mxGetClassID(data)){ case mxUINT8_CLASS: nim->datatype=DT_UINT8; nim->nbyper=1; break; case mxINT8_CLASS: nim->datatype=DT_INT8; nim->nbyper=1; break; case mxUINT16_CLASS: nim->datatype=DT_UINT16; nim->nbyper=2; break; case mxINT16_CLASS: nim->datatype=DT_INT16; nim->nbyper=2; break; case mxUINT32_CLASS: nim->datatype=DT_UINT32; nim->nbyper=4; break; case mxINT32_CLASS: nim->datatype=DT_INT32; nim->nbyper=4; break; case mxUINT64_CLASS: nim->datatype=DT_UINT64; nim->nbyper=8; break; case mxINT64_CLASS: nim->datatype=DT_INT64; nim->nbyper=8; break; case mxSINGLE_CLASS: nim->datatype=DT_FLOAT32; nim->nbyper=4; break; case mxDOUBLE_CLASS: nim->datatype=DT_FLOAT64; nim->nbyper=8; break; default: mexErrMsgTxt("Unknown data type!"); } } double *pdPtr = (double *)mxGetData(mxGetField(mxnim,0,"pixdim")); int nPixDim = mxGetM(mxGetField(mxnim,0,"pixdim"))*mxGetN(mxGetField(mxnim,0,"pixdim")); if(nPixDim>8) nPixDim=8; for(i=0; i<nPixDim; i++) nim->pixdim[i+1] = (float)pdPtr[i]; // xxx dla fixed bug below (i was not being assigned). // for(nPixDim+1; i<8; i++) nim->pixdim[i] = (float)1.0; for(i = nPixDim+1; i<8; i++) nim->pixdim[i] = (float)1.0; nim->dx = nim->pixdim[1]; nim->dy = nim->pixdim[2]; nim->dz = nim->pixdim[3]; nim->dt = nim->pixdim[4]; nim->du = nim->pixdim[5]; nim->dv = nim->pixdim[6]; nim->dw = nim->pixdim[7]; nim->scl_slope = mxGetScalar(mxGetField(mxnim,0,"scl_slope")); nim->scl_inter = mxGetScalar(mxGetField(mxnim,0,"scl_inter")); nim->cal_min = mxGetScalar(mxGetField(mxnim,0,"cal_min")); nim->cal_max = mxGetScalar(mxGetField(mxnim,0,"cal_max")); nim->qform_code = (int)mxGetScalar(mxGetField(mxnim,0,"qform_code")); nim->sform_code = (int)mxGetScalar(mxGetField(mxnim,0,"sform_code")); nim->freq_dim = (int)mxGetScalar(mxGetField(mxnim,0,"freq_dim")); nim->phase_dim = (int)mxGetScalar(mxGetField(mxnim,0,"phase_dim")); nim->slice_dim = (int)mxGetScalar(mxGetField(mxnim,0,"slice_dim")); nim->slice_code = (int)mxGetScalar(mxGetField(mxnim,0,"slice_code")); nim->slice_start = (int)mxGetScalar(mxGetField(mxnim,0,"slice_start")); nim->slice_end = (int)mxGetScalar(mxGetField(mxnim,0,"slice_end")); nim->slice_duration = mxGetScalar(mxGetField(mxnim,0,"slice_duration")); /* if qform_code > 0, the quatern_*, qoffset_*, and qfac fields determine * the qform output, NOT the qto_xyz matrix; if you want to compute these * fields from the qto_xyz matrix, you can use the utility function * nifti_mat44_to_quatern() */ nim->quatern_b = mxGetScalar(mxGetField(mxnim,0,"quatern_b")); nim->quatern_c = mxGetScalar(mxGetField(mxnim,0,"quatern_c")); nim->quatern_d = mxGetScalar(mxGetField(mxnim,0,"quatern_d")); nim->qoffset_x = mxGetScalar(mxGetField(mxnim,0,"qoffset_x")); nim->qoffset_y = mxGetScalar(mxGetField(mxnim,0,"qoffset_y")); nim->qoffset_z = mxGetScalar(mxGetField(mxnim,0,"qoffset_z")); nim->qfac = mxGetScalar(mxGetField(mxnim,0,"qfac")); nim->pixdim[0] = nim->qfac; // pixdim[0] is the same as qfac (again- why duplicate the field?) double *sxPtr = (double *)mxGetData(mxGetField(mxnim,0,"sto_xyz")); for(i=0; i<16; i++) nim->sto_xyz.m[i%4][i/4] = (float)sxPtr[i]; nim->toffset = mxGetScalar(mxGetField(mxnim,0,"toffset")); // Allow units to be specified as a string char str[16]; mxGetString(mxGetField(mxnim,0,"xyz_units"),str,16); nim->xyz_units = getNiftiUnitCode(str); mxGetString(mxGetField(mxnim,0,"time_units"),str,16); nim->time_units = getNiftiUnitCode(str); nim->intent_code = (int)mxGetScalar(mxGetField(mxnim,0,"intent_code")); nim->intent_p1 = mxGetScalar(mxGetField(mxnim,0,"intent_p1")); nim->intent_p2 = mxGetScalar(mxGetField(mxnim,0,"intent_p2")); nim->intent_p3 = mxGetScalar(mxGetField(mxnim,0,"intent_p3")); mxGetString(mxGetField(mxnim,0,"intent_name"), nim->intent_name, 16); mxGetString(mxGetField(mxnim,0,"descrip"), nim->descrip, 80); mxGetString(mxGetField(mxnim,0,"aux_file"), nim->aux_file, 24); // *** TO DO: support extended header fileds! nim->num_ext = 0; /* I assume that we can rely on the nifti routine to byte-swap for us? */ nifti_image_write(nim); }