//nl: number of landmarks (returned) float *detect_landmarks(const char *subfile, const char *mdlfile, int &nl, char ppmflg) { char prefix[1024]; char filename[1024]; SHORTIM subim; nifti_1_header hdr; FILE *fpi; int r; // patch radius int R; // search region radius int lm[3], lmcm[3]; float ccmax; float *P; if( niftiFilename(prefix, subfile)==0 ) { exit(0); } subim.v = (short *)read_nifti_image(subfile, &hdr); subim.nx = hdr.dim[1]; subim.ny = hdr.dim[2]; subim.nz = hdr.dim[3]; subim.nv = subim.nx*subim.ny*subim.nz; subim.np = subim.nx*subim.ny; fpi=fopen(mdlfile, "r"); fread(&nl, sizeof(int), 1, fpi); fread(&r, sizeof(int), 1, fpi); fread(&R, sizeof(int), 1, fpi); SPH refsph(r); SPH subsph(r); SPH searchsph(R); P = (float *)calloc(3*nl, sizeof(float)); for(int l=0; l<nl; l++) { fread(&lmcm[0], sizeof(int), 1, fpi); fread(&lmcm[1], sizeof(int), 1, fpi); fread(&lmcm[2], sizeof(int), 1, fpi); fread(refsph.v, sizeof(float), refsph.n, fpi); ccmax = detect_lm(searchsph, subsph, subim, lmcm, refsph, lm); P[0*nl + l]=lm[0]; P[1*nl + l]=lm[1]; P[2*nl + l]=lm[2]; if(ppmflg) { sprintf(filename,"%s_lm_%03d.ppm",prefix,l); makePPM(subim, lm, filename); } } fclose(fpi); return(P); }
// lmfile (landmarks file) - This is a text file with format: // i1 j1 k1 // i2 j2 k2 // i3 j3 k3 // where // (i1, j1, k1) are the coordinates of the AC // (i2, j2, k2) are the coordinates of the PC, and // (i3, j3, k3) are the coordinates of the RP. // subfile (subject file) - 3D T1W volume of type short in NIFTI format // TPIL - output 4x4 rigid-body transformation matrix that would transform // subfile into a standardized PIL orientation void new_PIL_transform(const char *subfile,const char *lmfile,char *orient,float *TPIL, int SAVE_MRX_FLAG) { float Qavg[3]; // average of rows of Q float Pavg[3]; // average of rows of P float TPIL0[16]; // transforms the original image to MSP/AC-PC aligned PIL orientation int n; // number of landmarks float *LM; // (3 x n) matrix of detected landmarks float *invT; char filename[1024]; SHORTIM subimPIL; nifti_1_header PILbraincloud_hdr; // subfile without the directory structure and extension char subfile_prefix[1024]; char imagedir[1024]; char modelfile[1024]=""; if( niftiFilename(subfile_prefix, subfile)==0 ) exit(0); getDirectoryName(subfile, imagedir); getARTHOME(); // initial TPIL0 using old PIL transformation char opt_CENTER_AC_old; opt_CENTER_AC_old = opt_CENTER_AC; // record opt_CENTER_AC opt_CENTER_AC = NO; // temporarily set opt_CENTER_AC to NO standard_PIL_transformation(subfile, lmfile, orient, 0, TPIL0); opt_CENTER_AC = opt_CENTER_AC_old; // restore opt_CENTER_AC ///////////////////////////////////////////////////////// // Read input volume from subfile SHORTIM subim; nifti_1_header subim_hdr; subim.v = (short *)read_nifti_image(subfile, &subim_hdr); if(subim.v==NULL) { printf("Error reading %s, aborting ...\n", subfile); exit(1); } set_dim(subim, subim_hdr); ///////////////////////////////////////////////////////// ///////////////////////////////////////////////////////// // Reslice subim to PIL space sprintf(filename,"%s/PILbrain.nii",ARTHOME); PILbraincloud_hdr=read_NIFTI_hdr(filename); set_dim(subimPIL, PILbraincloud_hdr); invT = inv4(TPIL0); resliceImage(subim, subimPIL, invT, LIN); free(invT); // Detect 8 landmarks on the MSP on the subimPIL volume sprintf(modelfile,"%s/orion.mdl",ARTHOME); LM=detect_landmarks(subimPIL, modelfile, n); convert_to_xyz(LM, n, subimPIL); // This block outputs the locations of the detected landmarks // in (i,j,k) coordinates of the native space of the input volume if(opt_txt) { FILE *fp; float landmark[4]; invT = inv4(TPIL0); sprintf(filename,"%s/%s_orion.txt",imagedir,subfile_prefix); fp=fopen(filename,"w"); if(fp==NULL) file_open_error(filename); for(int i=0; i<n; i++) { landmark[0]=LM[0*n + i]; landmark[1]=LM[1*n + i]; landmark[2]=LM[2*n + i]; landmark[3]=1; multi(invT,4,4,landmark,4,1,landmark); convert_to_ijk(landmark, 1, subim); fprintf(fp,"%5.1f %5.1f %5.1f\n",landmark[0], landmark[1], landmark[2]); } fclose(fp); free(invT); } float *P; float *Q; // Image using Q insted of P' in Eq. (1) of Arun et al. 1987 float TLM[16]; Q = (float *)calloc(3*n,sizeof(float)); P = (float *)calloc(3*n,sizeof(float)); for(int i=0; i<3*n; i++) P[i]=LM[i]; delete subimPIL.v; ///////////////////////////////////////////////////////// // read Q { FILE *fp; int r, r2; int cm[3]; fp=fopen(modelfile, "r"); if(fp==NULL) file_open_error(modelfile); fread(&n, sizeof(int), 1, fp); fread(&r, sizeof(int), 1, fp); fread(&r2, sizeof(int), 1, fp); SPH refsph(r); for(int i=0; i<n; i++) { fread(cm, sizeof(int), 3, fp); fread(refsph.v, sizeof(float), refsph.n, fp); Q[0*n + i]=cm[0]; Q[1*n + i]=cm[1]; Q[2*n + i]=cm[2]; } fclose(fp); convert_to_xyz(Q, n, subimPIL); } Procrustes(Q, Qavg, n, P, Pavg, TLM); multi(TLM,4,4,TPIL0,4,4,TPIL); // create the *LM.ppm image if(opt_ppm || opt_png) { int *lmx, *lmy; float lm[4]; invT = inv4(TPIL); resliceImage(subim, subimPIL, invT, LIN); free(invT); lmx = (int *)calloc(n,sizeof(int)); lmy = (int *)calloc(n,sizeof(int)); for(int i=0; i<n; i++) { lm[0] = P[i] + Pavg[0]; lm[1] = P[n+i] + Pavg[1]; lm[2] = P[2*n+i] + Pavg[2]; lm[3] = 1.0; multi(TLM,4,4,lm,4,1,lm); convert_to_ijk(lm, 1, subimPIL); lmx[i]=(int)( lm[0] + 0.5 ); lmy[i]=(int)( lm[1] + 0.5 ); } sprintf(filename,"%s/%s_orion.ppm",imagedir, subfile_prefix); mspPPM(subimPIL, lmx, lmy, n, filename); delete lmx; delete lmy; delete subimPIL.v; } if(opt_CENTER_AC) { float ac[4]; float Ttmp[16]; ac[0] = P[1] + Pavg[0]; // landmark #1 is AC ac[1] = P[n+1] + Pavg[1]; ac[2] = P[2*n+1] + Pavg[2]; ac[3] = 1.0; multi(TLM,4,4,ac,4,1,ac); Ttmp[0]=1.0; Ttmp[1]=0.0; Ttmp[2]=0.0; Ttmp[3]=-ac[0]; // makes ac the center of the FOV Ttmp[4]=0.0; Ttmp[5]=1.0; Ttmp[6]=0.0; Ttmp[7]=-ac[1]; // ac[1] should be equal to pc[1] Ttmp[8]=0.0; Ttmp[9]=0.0; Ttmp[10]=1.0; Ttmp[11]=0; Ttmp[12]=0.0; Ttmp[13]=0.0; Ttmp[14]=0.0; Ttmp[15]=1.0; multi(Ttmp,4,4,TPIL,4,4,TPIL); } // save the PIL transformation in <subfile_prefix>_PIL.mrx if(SAVE_MRX_FLAG == 1) { FILE *fp; sprintf(filename,"%s/%s_PIL.mrx",imagedir, subfile_prefix); fp=fopen(filename,"w"); if(fp==NULL) file_open_error(filename); printMatrix(TPIL,4,4,"",fp); fclose(fp); } { float ssd1=0.0; float ssd3=0.0; float x[4], y[4]; x[3]=y[3]=1.0; for(int i=0; i<n; i++) { x[0] = Q[i] + Qavg[0]; x[1] = Q[i+n] + Qavg[1]; x[2] = Q[i+2*n] + Qavg[2]; y[0] = P[i]+Pavg[0]; y[1] = P[i+n]+Pavg[1]; y[2] = P[i+2*n]+Pavg[2]; ssd1 += (x[0]-y[0])*(x[0]-y[0]); ssd1 += (x[1]-y[1])*(x[1]-y[1]); ssd1 += (x[2]-y[2])*(x[2]-y[2]); multi(TLM,4,4,y,4,1,y); ssd3 += (x[0]-y[0])*(x[0]-y[0]); ssd3 += (x[1]-y[1])*(x[1]-y[1]); ssd3 += (x[2]-y[2])*(x[2]-y[2]); } //if(opt_v) printf("SSD (MSP + AC/PC transformation) = %f\n",ssd1); //if(opt_v) printf("SSD (MSP + AC/PC + LM transformation) = %f\n",ssd3); } delete subim.v; free(P); free(Q); }