/*------------------------------------------------------------------- * CTWriteCTF - write a CTF file *------------------------------------------------------------------- */ static int CTWriteCTF(char *path, CTSlice slice) { FILE *fp; unsigned short delta[512]; int i, j, x, left, right, offsetx, offsety; if ((fp=fopen(path, "w")) == NULL) return(0); /* write header */ for (i=0; i<2048; i++) fputc(255, fp); if (CTSliceWidth(slice) < 512) offsetx = (512-CTSliceWidth(slice))/2; else offsetx = 512; if (CTSliceHeight(slice) < 512) offsety = (512-CTSliceHeight(slice))/2; else offsety = 512; /* write the delta's */ memset(delta, '\0', sizeof(short)*512); for (x=CTSliceMinX(slice); x<=CTSliceMaxX(slice)&&x-CTSliceMinX(slice)<512; x++) { for (left=CTSliceMinY(slice); left<CTSliceYSize(slice)/2; left++) { if (CTSliceData(slice, x, left) != 0) break; } for (right=CTSliceMaxY(slice); right>CTSliceYSize(slice)/2; right--) { if (CTSliceData(slice, x, right) != 0) break; } if (CTSliceYSize(slice)/2-left > right-CTSliceYSize(slice)/2) delta[x] = (CTSliceYSize(slice)/2-left); else delta[x] = (right-CTSliceYSize(slice)/2); } fwrite(delta, 2, 512, fp); /* write out the slice */ for (i=0; i<offsetx/2; i++) { for (i=CTSliceMinX(slice); i<=CTSliceMaxX(slice); i++) { for (j=CTSliceYSize(slice)/2-delta[i]; j<CTSliceYSize(slice)/2+delta[i]; j++) fwrite(&CTSliceShortData(slice, i, j), sizeof(short), 1, fp); } } fclose(fp); return(1); }
/*------------------------------------------------------------------- * CTReadCTF - read a slice from a ctf file *------------------------------------------------------------------- */ static int CTReadCTF(FILE *fp, CTSlice slice, int x1, int y1, int x2, int y2) { unsigned short delta[512], row[512]; int i, del, left, right; long off; /* CTSliceXSize(slice) = 512; CTSliceYSize(slice) = 512; */ if (x1==-1) { slice->x1=slice->y1=x1=y1=0; slice->x2=slice->y2=x2=y2=511; slice->data = (unsigned short *)malloc(sizeof(unsigned short)*(x2-x1+1)* (y2-y1+1)); memset(slice->data, '\0', sizeof(short)*(x2-x1+1)*(y2-y1+1)); CTSliceWidth(slice) = CTSliceHeight(slice) = 512; } /* skip past the 2048 byte header */ fskip(fp, 2048); /* read the number of data values for each line */ fread(delta, 2, 512, fp); /* compute offset for rows up to y1 */ for (off=0, i=0; i<x1; i++) off+=delta[i]*2*2; #ifdef DEBUG printf("skipping %ld values\n", off); #endif /* skip to the x1'th row of data */ if (off != 0) fskip(fp, off); for (; x1<=x2; x1++) { /* skip to y1'th column of data in this row */ del=delta[x1]; /* compute how much data is present */ left = (512)/2 - del; right = (512)/2 + del- 1; memset(row, '\0', 512*sizeof(short)); fread(&row[left], 2, 2*del, fp); memcpy(&CTSliceShortData(slice, x1, y1), &row[y1], sizeof(short)*(y2-y1+1)); } CTSliceCompMinMaxD(slice); return(0); }
/*------------------------------------------------------------------- * CTWritePGM - write a slice in portable greymap format *------------------------------------------------------------------- */ static int CTWritePGM(char *path, CTSlice slice) { FILE *fp; int i, j; // int c, width, height, max; // unsigned char *line; if ((fp=fopen(path, "w")) == NULL) return(0); if (CTSliceMaxD(slice) <= 255) { fprintf(fp, "P5\n%d %d\n%d\n", CTSliceXSize(slice), CTSliceYSize(slice), CTSliceMaxD(slice)); if (CTSliceChars(slice)) { for (i=CTSliceYSize(slice)-1; i>=0; i--) { for (j=0; j<CTSliceXSize(slice); j++) fputc(CTSliceCharData(slice, j, i), fp); } } else if (CTSliceShorts(slice)) { for (i=CTSliceYSize(slice)-1; i>=0; i--) { for (j=0; j<CTSliceXSize(slice); j++) fputc(CTSliceShortData(slice, j, i), fp); } } } else { fprintf(fp, "P2\n%d %d\n%d\n", CTSliceXSize(slice), CTSliceYSize(slice), CTSliceMaxD(slice)); for (i=CTSliceYSize(slice)-1; i>=0; i--) { for (j=0; j<CTSliceXSize(slice); j++) fputc(CTSliceShortData(slice, j, i), fp); } } fclose(fp); return(1); }
/*------------------------------------------------------------------- * CTSliceSetVal - set a value in a CT image *------------------------------------------------------------------- */ void CTSliceSetVal(CTSlice slice, int x, int y, float val) { if (CTSliceShorts(slice)) CTSliceShortData(slice, x, y) = (unsigned short) val; else if (CTSliceChars(slice)) CTSliceCharData(slice, x, y) = (unsigned char) val; else if (CTSliceFloats(slice)) CTSliceFloatData(slice, x, y) = val; }
CTVolume CTVolumeHartley3D(CTVolume vol) { CTVolume vol2; CTSlice slice; int l,m,n,L,M,N,i,j,k; #ifdef USE_PTIME int t1,t2; #endif float *d1,*d2,*X,*D,Z,*w,*w1,*w2; float *Mcas, *Lcos, *Lsin, *Ncos, *Nsin, max, min; double dL, dM, dN, s, c; /* Get source volume info. */ L = CTVolXSize(vol); M = CTVolYSize(vol); N = CTVolNumSlices(vol); dL = (double)L; dM = (double)M; dN = (double)N; /* Initialize the new volume. */ vol2 = CTVolumeCreate(CTH3D,CTVolPrefix(vol),".h3d",CTVolXSize(vol), CTVolYSize(vol),CTVolZSize(vol),CTVolXSep(vol), CTVolYSep(vol),CTVolZSep(vol),CTVolFirstSlice(vol), CTVolLastSlice(vol),1.0e10,CT_MSBF,CT_FLOAT); /* Open the new volume for writing. */ CTVolumeOpen(vol2,CTH3D,CTVolPrefix(vol2),".h3d"); /* Read in the volume data. */ D = (float *)malloc(L*M*N*sizeof(float)); switch (CTVolVoxelBits(vol)) { /* Read in and convert CT_8BIT values to CT_FLOAT. */ case CT_8BIT: for (n=0;n<N;n++) { slice = CTSliceRead(vol,n+CTVolFirstSlice(vol),-1,-1,-1,-1); for (l=0;l<L;l++) { for (m=0;m<M;m++) { D[n+N*(l+L*m)] = (float)CTSliceCharData(slice,l,m); } } CTSliceFree(slice); } break; /* Read in and convert CT_16BIT values to CT_FLOAT. */ case CT_16BIT: for (n=0;n<N;n++) { slice = CTSliceRead(vol,n+CTVolFirstSlice(vol),-1,-1,-1,-1); for (l=0;l<L;l++) { for (m=0;m<M;m++) { D[n+N*(l+L*m)] = (float)CTSliceShortData(slice,l,m); } } CTSliceFree(slice); } break; /* Read in CT_FLOAT values. */ case CT_FLOAT: for (n=0;n<N;n++) { slice = CTSliceRead(vol,n+CTVolFirstSlice(vol),-1,-1,-1,-1); for (l=0;l<L;l++) { for (m=0;m<M;m++) { D[n+N*(l+L*m)] = CTSliceFloatData(slice,l,m); } } CTSliceFree(slice); } break; } /* Precompute necessary sin, cos, and cas function values. */ Lcos = (float *)malloc(sizeof(float)*L*L); Lsin = (float *)malloc(sizeof(float)*L*L); Ncos = (float *)malloc(sizeof(float)*N*N); Nsin = (float *)malloc(sizeof(float)*N*N); Mcas = (float *)malloc(sizeof(float)*M*M); for (i=0;i<L*L;i++) { s = sin(2.0*M_PI*(double)i/dL); c = cos(2.0*M_PI*(double)i/dL); Lcos[i] = (float)c; Lsin[i] = (float)s; } for (i=0;i<N*N;i++) { s = sin(2.0*M_PI*(double)i/dN); c = cos(2.0*M_PI*(double)i/dN); Ncos[i] = (float)c; Nsin[i] = (float)s; } for (i=0;i<M*M;i++) { s = sin(2.0*M_PI*(double)i/dM); c = cos(2.0*M_PI*(double)i/dM); Mcas[i] = (float)(s+c); } /* Algorithm is O(LLMN+LMMN+LMNN). */ X = (float *)malloc(L*M*sizeof(float)); w1 = (float *)malloc(L*M*sizeof(float)); w2 = (float *)malloc(M*sizeof(float)); #ifdef USE_PTIME t1 = t2 = time(NULL); #endif /* Transfrom the original volume and write the new volume one slice at a time, in order. */ for (k=0;k<N;k++) { /* Initialize max and min values for each slice. */ min = 1.0e10; max = -1.0e10; /* Compute w1(i,m,n) */ d1 = D; w = w1; for (m=0;m<M;m++) { for (l=0;l<L;l++) { d2 = &D[N*((L-l)%L+L*((M-m)%M))]; *w = 0.0; for (n=0;n<N;n++) { *w += (*d1++)*Ncos[k*n]+(*d2++)*Nsin[k*n]; } w++; } } /* Compute w2(i,j,n) */ for (i=0;i<L;i++) { w = w2; d1 = w1; for (m=0;m<M;m++) { *w = 0.0; d2 = &w1[L*((M-m)%M)]; for (l=0;l<L;l++) { *w += (*d1++)*Lcos[i*l]+(*d2++)*Lsin[i*l]; } w++; } /* Compute X(i,j,k) */ for (j=0;j<M;j++) { Z = 0.0; w = w2; for (m=0;m<M;m++) { Z += (*w++)*Mcas[j*m]; } if (Z>max) max = Z; if (Z<min) min = Z; X[i+L*j] = Z; } } /* Write the transformed slice. */ slice = CTSliceCreate(L,M,min,max,vol2,k); for (i=0;i<L;i++) { for (j=0;j<M;j++) { CTSliceSetVal(slice,i,j,X[i+L*j]); } } CTSliceWrite(NULL,slice); CTSliceFree(slice); #ifdef USE_PTIME printf("Slice %d/%d, ",k+1,N); ptime((int)((float)(time(NULL)-t1)/(float)(k+1)*(float)(N-k-1))); printf("\n"); #endif } /* Done writing to the new volume. */ CTVolumeClose(vol2); #ifdef USE_PTIME t2 = time(NULL); printf("(3D)Total time: "); ptime(t2-t1); printf("\n"); #endif /* Return the transformed volume. */ return(vol2); }
/*------------------------------------------------------------------------ * CTSliceCompMinMaxD - compute min and max densities for a slice *------------------------------------------------------------------------ */ void CTSliceCompMinMaxD(CTSlice slice) { double val; int i, j; unsigned long nnonzero; CTSliceMaxD(slice) = -1e100; CTSliceMinD(slice) = 1e100; nnonzero=0; if (CTSliceShorts(slice)) { for (i=CTSliceMinX(slice); i<=CTSliceMaxX(slice); i++) { for (j=CTSliceMinY(slice); j<=CTSliceMaxY(slice); j++) { if ((val=CTSliceShortData(slice, i, j)) > CTVolNoise(slice->vol)) continue; if (val > CTSliceMaxD(slice)) CTSliceMaxD(slice) = val; if (val < CTSliceMinD(slice)) CTSliceMinD(slice) = val; if (val != 0) nnonzero++; } } } else if (CTSliceChars(slice)) { for (i=CTSliceMinX(slice); i<=CTSliceMaxX(slice); i++) { for (j=CTSliceMinY(slice); j<=CTSliceMaxY(slice); j++) { if ((val=CTSliceCharData(slice, i, j)) > CTVolNoise(slice->vol)) continue; if (val > CTSliceMaxD(slice)) CTSliceMaxD(slice) = val; if (val < CTSliceMinD(slice)) CTSliceMinD(slice) = val; if (val != 0) nnonzero++; } } } else if (CTSliceFloats(slice)) { for (i=CTSliceMinX(slice); i<=CTSliceMaxX(slice); i++) { for (j=CTSliceMinY(slice); j<=CTSliceMaxY(slice); j++) { if ((val=CTSliceFloatData(slice, i, j)) > CTVolNoise(slice->vol)) continue; if (val > CTSliceMaxD(slice)) CTSliceMaxD(slice) = val; if (val < CTSliceMinD(slice)) CTSliceMinD(slice) = val; if (val != 0) nnonzero++; } } } CTSliceRatio(slice) = nnonzero/ (double)(CTSliceWidth(slice)*CTSliceHeight(slice)); }
/*------------------------------------------------------------------- * CTReadPGM - read a slice from a portable greymap file *------------------------------------------------------------------- */ static int CTReadPGM(FILE *fp, CTSlice slice, int x1, int y1, int x2, int y2) { int c, i, j, width, height, max; unsigned char *line; char buf[1024]; /* read for the magic number, skipping comments */ while ((c=fgetc(fp)) == '#') fgets(buf, 1024, fp); ungetc(c, fp); if (fscanf(fp, "P%d\n", &c) != 1) return(-1); if (c != 2 && c != 5) { /* file is not PGM, fail */ return(-1); } if (c==2) { while ((c=fgetc(fp)) == '#') fgets(buf, 1024, fp); ungetc(c, fp); if (fscanf(fp, "%d%d%d", &width, &height, &max) != 3) return(-1); if (x1==-1) { slice->x1=slice->y1=x1=y1=0; slice->x2=x2=width-1; slice->y2=y2=height-1; slice->data = (unsigned short *)malloc(sizeof(unsigned short)* (x2-x1+1)*(y2-y1+1)); memset(slice->data, 0, sizeof(short)*(x2-x1+1)*(y2-y1+1)); CTSliceWidth(slice) = width; CTSliceHeight(slice) = height; } /* eat extra character */ getc(fp); for (i=height-1; i>=0; i--) { for (j=0; j<width; j++) { int val; fscanf(fp, "%d", &val); CTSliceShortData(slice, j, i) = val; } } CTSliceCompMinMaxD(slice); return(0); } else if (c==5) { while ((c=fgetc(fp)) == '#') fgets(buf, 1024, fp); ungetc(c, fp); if (fscanf(fp, "%d%d%d", &width, &height, &max) != 3) { printf("failed to read width/height/max\n"); return(-1); } if (x1==-1) { slice->x1=slice->y1=x1=y1=0; slice->x2=x2=width-1; slice->y2=y2=height-1; slice->cdata = (unsigned char *)malloc(sizeof(unsigned char)* (x2-x1+1)*(y2-y1+1)); memset(slice->cdata, '\0', sizeof(char)*(x2-x1+1)*(y2-y1+1)); CTSliceWidth(slice) = width; CTSliceHeight(slice) = height; } /* eat extra character */ getc(fp); line = (unsigned char *)malloc(sizeof(char)*width); for (i=height-1; i>=0; i--) { fread(line, 1, width, fp); if (y1 <= i && i <= y2) { for (j=0; j<width; j++) { if (x1 <= j && j <= x2) CTSliceCharData(slice, j, i) = line[j]; } } } free(line); CTSliceCompMinMaxD(slice); return(0); } return(1); }
/*------------------------------------------------------------------- * CTSliceSetVals - set a block of values in a CT image *------------------------------------------------------------------- */ void CTSliceSetVals(CTSlice slice, int x1, int y1, int x2, int y2, int val, int z) { int x, y; if (x1 > x2) { x = x1; x1 = x2; x2 = x; } if (y1 > y2) { y = y1; y1 = y2; y2 = y; } x1 = MAX(x1, slice->x1); y1 = MAX(y1, slice->y1); x2 = MIN(x2, slice->x2); y2 = MIN(y2, slice->y2); if (z) { if (x1 <= x2) { /* set the first line */ if (CTSliceShorts(slice)) { for (y=y1; y<=y2; y++) CTSliceShortData(slice, x1, y) = val; for (x1++; x1<=x2; x1++) memcpy(&CTSliceShortData(slice, x1, y1),&CTSliceShortData(slice, x1-1, y1), sizeof(short)*(y2-y1+1)); } else { for (y=y1; y<=y2; y++) CTSliceCharData(slice, x1, y) = val; for (x1++; x1<=x2; x1++) memcpy(&CTSliceCharData(slice, x1, y1),&CTSliceCharData(slice, x1-1, y1), sizeof(char)*(y2-y1+1)); } } } else { if (CTSliceShorts(slice)) { for (x=x1; x<=x2; x++) { for (y=y1; y<=y2; y++) if (CTSliceShortData(slice, x, y) > 1000) CTSliceShortData(slice, x, y) = val; else CTSliceShortData(slice, x, y) = 0; } } else { for (x=x1; x<=x2; x++) { for (y=y1; y<=y2; y++) if (CTSliceCharData(slice, x, y) > 1000) CTSliceCharData(slice, x, y) = val; else CTSliceCharData(slice, x, y) = 0; } } } }