1
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2
* filename: m-rslice.c *
4
* UTIL C-source: Medical Image Conversion Utility *
6
* purpose : reslice in different projections *
8
* project : (X)MedCon by Erik Nolf *
10
* Functions : MdcGetImageProjection() - Retrieve image projection *
11
* MdcGetNewPatSliceOrient() - Get new patient slice orient *
12
* MdcCheckReslice() - Check before reslicing *
13
* MdcResliceImages() - Reslice image (tra,cor,sag) *
15
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
16
/* $Id: m-rslice.c,v 1.22 2004/05/02 21:12:28 enlf Exp $
20
Copyright (C) 1997-2004 by Erik Nolf
22
This program is free software; you can redistribute it and/or modify it
23
under the terms of the GNU General Public License as published by the
24
Free Software Foundation; either version 2, or (at your option) any later
27
This program is distributed in the hope that it will be useful, but
28
WITHOUT ANY WARRANTY; without even the implied warranty of
29
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
30
Public License for more details.
32
You should have received a copy of the GNU General Public License along
33
with this program; if not, write to the Free Software Foundation, Inc.,
34
59 Place - Suite 330, Boston, MA 02111-1307, USA. */
36
/****************************************************************************
38
****************************************************************************/
57
/****************************************************************************
60
****************************************************************************/
62
#define MDC_VOLUME_REQUIRED 10 /* minimum slices considered viewable */
64
/****************************************************************************
66
****************************************************************************/
68
Int8 MdcGetSliceProjection(FILEINFO *cur)
70
Int8 slice_projection = cur->slice_projection;
72
if (cur->slice_projection == MDC_UNKNOWN) {
74
switch (cur->pat_slice_orient) {
76
case MDC_SUPINE_HEADFIRST_TRANSAXIAL :
77
case MDC_SUPINE_FEETFIRST_TRANSAXIAL :
78
case MDC_PRONE_HEADFIRST_TRANSAXIAL :
79
case MDC_PRONE_FEETFIRST_TRANSAXIAL : slice_projection = MDC_TRANSAXIAL;
81
case MDC_SUPINE_HEADFIRST_SAGITTAL :
82
case MDC_SUPINE_FEETFIRST_SAGITTAL :
83
case MDC_PRONE_HEADFIRST_SAGITTAL :
84
case MDC_PRONE_FEETFIRST_SAGITTAL : slice_projection = MDC_SAGITTAL;
86
case MDC_SUPINE_HEADFIRST_CORONAL :
87
case MDC_SUPINE_FEETFIRST_CORONAL :
88
case MDC_PRONE_HEADFIRST_CORONAL :
89
case MDC_PRONE_FEETFIRST_CORONAL : slice_projection = MDC_CORONAL;
91
default: slice_projection = MDC_TRANSAXIAL;
97
return(slice_projection);
101
Int8 MdcGetNewPatSliceOrient(FILEINFO *cur, Int8 newproj)
103
Int8 pat_slice_orient=MDC_UNKNOWN;
105
switch (cur->pat_slice_orient) {
106
case MDC_SUPINE_HEADFIRST_TRANSAXIAL :
107
case MDC_SUPINE_HEADFIRST_SAGITTAL :
108
case MDC_SUPINE_HEADFIRST_CORONAL :
110
case MDC_TRANSAXIAL :
111
pat_slice_orient = MDC_SUPINE_HEADFIRST_TRANSAXIAL;
114
pat_slice_orient = MDC_SUPINE_HEADFIRST_SAGITTAL;
117
pat_slice_orient = MDC_SUPINE_HEADFIRST_CORONAL;
121
case MDC_PRONE_HEADFIRST_TRANSAXIAL :
122
case MDC_PRONE_HEADFIRST_SAGITTAL :
123
case MDC_PRONE_HEADFIRST_CORONAL :
126
pat_slice_orient = MDC_PRONE_HEADFIRST_TRANSAXIAL;
129
pat_slice_orient = MDC_PRONE_HEADFIRST_SAGITTAL;
132
pat_slice_orient = MDC_PRONE_HEADFIRST_CORONAL;
136
case MDC_SUPINE_FEETFIRST_TRANSAXIAL :
137
case MDC_SUPINE_FEETFIRST_SAGITTAL :
138
case MDC_SUPINE_FEETFIRST_CORONAL :
140
case MDC_TRANSAXIAL :
141
pat_slice_orient = MDC_SUPINE_FEETFIRST_TRANSAXIAL;
144
pat_slice_orient = MDC_SUPINE_FEETFIRST_SAGITTAL;
147
pat_slice_orient = MDC_SUPINE_FEETFIRST_CORONAL;
151
case MDC_PRONE_FEETFIRST_TRANSAXIAL :
152
case MDC_PRONE_FEETFIRST_SAGITTAL :
153
case MDC_PRONE_FEETFIRST_CORONAL :
155
case MDC_TRANSAXIAL :
156
pat_slice_orient = MDC_PRONE_FEETFIRST_TRANSAXIAL;
159
pat_slice_orient = MDC_PRONE_FEETFIRST_SAGITTAL;
162
pat_slice_orient = MDC_PRONE_FEETFIRST_CORONAL;
168
return(pat_slice_orient);
172
char *MdcCheckReslice(FILEINFO *cur, Int8 newproj)
176
curproj = MdcGetSliceProjection(cur);
178
/* some sanity checks before allowing reslicing */
180
if (cur->planar == MDC_YES) {
181
strcpy(mdcbufr,"Planar study inappropriate"); return(mdcbufr);
184
/* don't fail in a batched job */
185
if (XMDC_GUI == MDC_YES) {
186
if (newproj == curproj) {
188
case MDC_TRANSAXIAL :
189
sprintf(mdcbufr,"Already in XY - TRANSVERSE projection");
192
sprintf(mdcbufr,"Already in YZ - SAGITTAL projection");
195
sprintf(mdcbufr,"Already in XZ - CORONAL projection");
201
if (curproj == MDC_UNKNOWN) {
202
strcpy(mdcbufr,"Current projection unknown"); return(mdcbufr);
204
if (cur->diff_type == MDC_YES) {
205
strcpy(mdcbufr,"Identical pixel types required"); return(mdcbufr);
207
if (cur->diff_size == MDC_YES) {
208
strcpy(mdcbufr,"Identical image sizes required"); return(mdcbufr);
210
if (cur->dim[3] <= 2) {
211
strcpy(mdcbufr,"No volume detected"); return(mdcbufr);
213
if (cur->dim[3] <= MDC_VOLUME_REQUIRED) {
214
strcpy(mdcbufr,"Volume too small"); return(mdcbufr);
216
if (cur->reconstructed == MDC_NO) {
217
strcpy(mdcbufr,"Reconstructed data required"); return(mdcbufr);
224
/* X, Y, Z: the true indices for x,y,z in our arrays */
225
/* OX, OY, OZ: old dim = new dim (do the reslice) */
226
/* DX, DY, DZ: new dim = old dim (get the sizes ) */
227
char *MdcResliceImages(FILEINFO *cur, Int8 newproj)
230
IMG_DATA *newid, *curid;
231
Uint32 nbytes, obytes, pixels, olength;
232
Uint32 newX, newY, newZ, curX=0, curY=0, curZ=0, f, frames;
233
Uint32 X=1, Y=2, Z=3, OX=X, OY=Y, OZ=Z, DX=X, DY=Y, DZ=Z;
239
curproj = MdcGetSliceProjection(cur);
241
/* some sanity checks before doing reslice */
242
msg = MdcCheckReslice(cur,newproj);
243
if (msg != NULL) return(msg);
245
/* get temporary FILEINFO structure */
246
new = (FILEINFO *)malloc(sizeof(FILEINFO));
247
if (new == NULL) return("Couldn't malloc FILEINFO struct");
248
MdcCopyFI(new,cur,MDC_NO,MDC_YES);
250
/* change orientation information */
251
new->pat_slice_orient = MdcGetNewPatSliceOrient(cur,newproj);
252
strcpy(new->pat_orient,MdcGetStrPatOrient(new->pat_slice_orient));
254
/* prepare dimension mappings */
256
case MDC_TRANSAXIAL :
258
case MDC_TRANSAXIAL : OX=X; OY=Y; OZ=Z; /* T -> T (===) */
261
case MDC_SAGITTAL : OX=Y; OY=Z; OZ=X; /* S -> T (sag) */
264
case MDC_CORONAL : OX=X; OY=Z; OZ=Y; /* C -> T (cor) */
271
case MDC_TRANSAXIAL : OX=Z; OY=X; OZ=Y; /* T -> S (sag) */
274
case MDC_SAGITTAL : OX=X; OY=Y; OZ=Z; /* S -> S (===) */
277
case MDC_CORONAL : OX=Z; OY=Y; OZ=X; /* C -> S (c2s) */
284
case MDC_TRANSAXIAL : OX=X; OY=Z; OZ=Y; /* T -> C (cor) */
287
case MDC_SAGITTAL : OX=Z; OY=Y; OZ=X; /* S -> C (s2c) */
290
case MDC_CORONAL : OX=X; OY=Y; OZ=Z; /* C -> C (===) */
297
/* first remove gaps between slices */
298
cur->pixdim[Z] = cur->image[0].slice_spacing;
300
/* number of frames stay the same */
301
new->dim[0] = cur->dim[0];
302
for (frames=1, f=4; f<=cur->dim[0]; f++) {
303
frames *= cur->dim[f]; new->dim[f] = cur->dim[f];
305
new->pixdim[0] = cur->pixdim[0];
306
for (f=4; f<=cur->pixdim[0]; f++) new->pixdim[f] = cur->pixdim[f];
308
/* fill in new dimension values */
309
if (OX == 3) new->number = cur->dim[X] * frames;
310
else if (OY == 3) new->number = cur->dim[Y] * frames;
311
else if (OZ == 3) new->number = cur->dim[Z] * frames;
313
new->dim[X] = cur->dim[DX]; new->pixdim[X] = cur->pixdim[DX];
314
new->dim[Y] = cur->dim[DY]; new->pixdim[Y] = cur->pixdim[DY];
315
new->dim[Z] = cur->dim[DZ]; new->pixdim[Z] = cur->pixdim[DZ];
317
new->mwidth = new->dim[X]; new->mheight = new->dim[Y];
319
/* handle pixel stuff */
320
if (MDC_QUANTIFY || MDC_CALIBRATE) {
321
new->type = FLT32; new->bits = MdcType2Bits(new->type);
323
new->type = cur->type; new->bits = cur->bits;
325
pixels = new->dim[X] * new->dim[Y];
326
obytes = MdcType2Bytes(cur->type);
327
nbytes = MdcType2Bytes(new->type);
329
/* get new IMG_DATA structs */
330
if (!MdcGetStructID(new,new->number)) {
331
MdcCleanUpFI(new); return("Couldn't malloc IMG_DATA structs");
334
/* reslice images and fill in structures */
335
olength = cur->dim[X];
336
for (f=0; f<frames; f++) for (newZ=0; newZ<new->dim[Z]; newZ++) {
337
newid = &new->image[newZ + (f * new->dim[Z])];
338
newid->buf = MdcGetImgBuffer(pixels * nbytes);
339
if (newid->buf == NULL) {
340
MdcCleanUpFI(new); return("Couldn't malloc image buffer");
344
newid->width = new->mwidth;
345
newid->height= new->mheight;
346
newid->bits = new->bits;
347
newid->type = new->type;
349
newid->pixel_xsize = new->pixdim[X];
350
newid->pixel_ysize = new->pixdim[Y];
351
newid->slice_width = new->pixdim[Z];
352
newid->slice_spacing= new->pixdim[Z];
354
MdcFillImgPos(new,newZ,newZ,0.);
355
MdcFillImgOrient(new,newZ);
357
for (newY=0; newY<new->dim[Y]; newY++) {
358
for (newX=0; newX<new->dim[X]; newX++) {
361
if (OX == X) curX = newX;
362
else if (OX == Y) curX = newY;
363
else if (OX == Z) curX = newZ;
365
if (OY == X) curY = newX;
366
else if (OY == Y) curY = newY;
367
else if (OY == Z) curY = newZ;
369
if (OZ == X) curZ = newX;
370
else if (OZ == Y) curZ = newY;
371
else if (OZ == Z) curZ = newZ;
373
curid = &cur->image[curZ + (f * cur->dim[Z])];
374
curp = curid->buf + (((curY * olength) + curX) * obytes);
375
if (MDC_QUANTIFY || MDC_CALIBRATE) {
376
pixval = MdcGetDoublePixel(curp,curid->type);
377
pixval *= (double)curid->rescale_slope;
378
pixval += (double)curid->rescale_intercept;
379
MdcPutDoublePixel(newp,pixval,newid->type);
381
memcpy(newp,curp,nbytes);
388
if (cur->acquisition_type == MDC_ACQUISITION_GATED ||
389
cur->acquisition_type == MDC_ACQUISITION_GSPECT) {
390
/* alter a gated parameter to keep things in line */
391
/* through different reslices: based on HeartRate */
392
/* since this depends on number of images per frame */
393
if (cur->gdata != NULL && new->gdata != NULL) {
394
new->gdata[0].time_per_proj = cur->gdata[0].time_per_proj;
395
new->gdata[0].time_per_proj *= (float)cur->dim[Z];
396
new->gdata[0].time_per_proj /= (float)new->dim[Z];
400
if (cur->acquisition_type == MDC_ACQUISITION_TOMO ||
401
cur->acquisition_type == MDC_ACQUISITION_DYNAMIC) {
402
/* Just fix nr_of_slices for each DYNAMIC_DATA struct. */
403
/* All other entries can be preserved for tomo study. */
404
for (f=0; f<new->dynnr; f++) new->dyndata[f].nr_of_slices = new->dim[3];
407
/* set new slice projection */
408
new->slice_projection = newproj;
410
/* check integrity */
411
if ((msg = MdcImagesPixelFiddle(new)) != NULL) {
412
MdcCleanUpFI(new); MdcFree(new) return(msg);
415
/* remove cur, copy new, free new but not the images */
417
MdcCopyFI(cur,new,MDC_NO,MDC_YES);
418
cur->number= new->number; new->number = 0; /* copy & mask away */
419
cur->image = new->image; new->image = NULL; /* copy & mask away */
420
MdcCleanUpFI(new); MdcFree(new);