/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * filename: m-ecat72.c * * * * UTIL C-source: Medical Image Conversion Utility * * * * purpose : Read ECAT 7.2 files * * * * project : (X)MedCon by Erik Nolf * * * * Functions : MdcCheckECAT7() - Check for ECAT7 format * * MdcEcatPrintMainHdr() - Print content main header * * MdcEcatPrintImgSubHdr() - Print content image subheader * * MdcEcatPrintAttnSubHdr() - Print content attenuation hdr * * MdcEcatPrintScanSubHdr() - Print content scan header * * MdcEcatPrintNormSubHdr() - Print content norm header * * MdcReadECAT7() - Read ECAT7 file * * MdcWriteECAT7() - Write ECAT7 file * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* $Id: m-ecat72.c,v 1.63 2007/06/25 21:31:57 enlf Exp $ */ /* Copyright (C) 1997-2007 by Erik Nolf This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Place - Suite 330, Boston, MA 02111-1307, USA. */ /**************************************************************************** H E A D E R S ****************************************************************************/ #include "m-depend.h" #include #define __USE_POSIX 1 #include #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef HAVE_STRINGS_H #ifndef _WIN32 #include #endif #endif #include "medcon.h" #if MDC_INCLUDE_TPC #define MDC_TPC_SITE 0 /* 0/1 disable/enable TPC site items */ #define __USE_ISOC99 1 #include #include "img.h" #include "ecat7.h" #endif /**************************************************************************** D E F I N E S ****************************************************************************/ #define MDC_NUM_PLANES_FIX MDC_YES /* fix for wrong num_planes = 1 bug */ #define MDC_MAX_ECAT7FILETYPES 15 #define MDC_MAX_ECAT7FILETYPES_SIZE 15 static char MdcEcat7FileTypes [MDC_MAX_ECAT7FILETYPES][MDC_MAX_ECAT7FILETYPES_SIZE]= {"Unknown","Sinogram","Image16","AttnCorr","Norm", "PolarMap","Volume8","Volume16","Projection8", "Projection16","Image8","3DSino16","3DSino8", "3DNorm","3DSinoFlt"}; /**************************************************************************** F U N C T I O N S ****************************************************************************/ int MdcCheckECAT7(FILEINFO *fi) { Mdc_Main_header7 mh; if (mdc_mat_read_main_header7(fi->ifp,&mh)) return MDC_BAD_READ; if (memcmp(mh.magic_number,MDC_ECAT7_SIG,7) ) return(MDC_FRMT_NONE); return MDC_FRMT_ECAT7; } void MdcEcatPrintMainHdr(Mdc_Main_header7 *mh) { int i; MdcPrintLine('-',MDC_HALF_LENGTH); MdcPrntScrn("ECAT7 Main Header (%d bytes)\n",MH_72_SIZE); MdcPrintLine('-',MDC_HALF_LENGTH); MdcGetSafeString(mdcbufr,(char *)mh->magic_number,14,14); MdcPrntScrn("magic_number : %s\n",mdcbufr); MdcGetSafeString(mdcbufr,mh->original_file_name,32,32); MdcPrntScrn("original_file_name : %s\n",mdcbufr); MdcPrntScrn("sw_version : %hd\n",mh->sw_version); MdcPrntScrn("system_type : %hd\n",mh->system_type); MdcPrntScrn("file_type : %hd ",mh->file_type); if ((mh->file_type > -1) && (mh->file_type < 15)) MdcPrntScrn("(= %s)\n",MdcEcat7FileTypes[mh->file_type]); else MdcPrntScrn("(= Unknown)\n"); MdcGetSafeString(mdcbufr,mh->serial_number,10,10); MdcPrntScrn("serial_number : %s\n",mdcbufr); MdcPrntScrn("scan_start_time : %s\n" ,ctime((time_t *)&mh->scan_start_time)); MdcGetSafeString(mdcbufr,mh->isotope_name,8,8); MdcPrntScrn("isotope_name : %s\n",mdcbufr); MdcPrntScrn("isotope_halflife : %f [sec]\n",mh->isotope_halflife); MdcGetSafeString(mdcbufr,mh->radiopharmaceutical,32,32); MdcPrntScrn("radiopharmaceutical : %s\n",mdcbufr); MdcPrntScrn("gantry_tilt : %f [degrees]\n",mh->gantry_tilt); MdcPrntScrn("gantry_rotation : %f [degrees]\n",mh->gantry_rotation); MdcPrntScrn("bed_elevation : %f [cm]\n",mh->bed_elevation); MdcPrntScrn("intrinsic_tilt : %f [degrees]\n",mh->intrinsic_tilt); MdcPrntScrn("wobble_speed : %hd [rpm]\n",mh->wobble_speed); MdcPrntScrn("tansm_source_type : %hd\n",mh->transm_source_type); MdcPrntScrn("distance_scanned : %f [cm]\n",mh->distance_scanned); MdcPrntScrn("transaxial_fov : %f [cm]\n",mh->transaxial_fov); MdcPrntScrn("angular_compression : %hd\n",mh->angular_compression); MdcPrntScrn("coin_samp_mode : %hd\n",mh->coin_samp_mode); MdcPrntScrn("axial_samp_mode : %hd\n",mh->axial_samp_mode); MdcPrntScrn("ecat_calibration_factor : %e\n",mh->ecat_calibration_factor); MdcPrntScrn("calibration_units : %hd\n",mh->calibration_units); MdcPrntScrn("calibration_units_label : %hd\n",mh->calibration_units_label); MdcPrntScrn("compression_code : %hd\n",mh->compression_code); MdcGetSafeString(mdcbufr,mh->study_type,14,14); MdcPrntScrn("study_type : %s\n",mdcbufr); MdcGetSafeString(mdcbufr,mh->patient_id,16,16); MdcPrntScrn("patient_id : %s\n",mdcbufr); MdcGetSafeString(mdcbufr,mh->patient_name,32,32); MdcPrntScrn("patient_name : %s\n",mdcbufr); MdcPrntScrn("patient_sex : "); switch (mh->patient_sex[0]) { case 0: MdcPrntScrn("M\n"); break; case 1: MdcPrntScrn("F\n"); break; default: MdcPrntScrn("U\n"); } MdcPrntScrn("patient_dexterity : %c\n",mh->patient_dexterity[0]); MdcPrntScrn("patient_age : %f\n",mh->patient_age); MdcPrntScrn("patient_height : %f\n",mh->patient_height); MdcPrntScrn("patient_weight : %f\n",mh->patient_weight); MdcPrntScrn("patient_birth_date : %f\n",mh->patient_birth_date); MdcGetSafeString(mdcbufr,mh->physician_name,32,32); MdcPrntScrn("physician_name : %s\n",mdcbufr); MdcGetSafeString(mdcbufr,mh->operator_name,32,32); MdcPrntScrn("operator_name : %s\n",mdcbufr); MdcGetSafeString(mdcbufr,mh->study_description,32,32); MdcPrntScrn("study_description : %s\n",mdcbufr); MdcPrntScrn("acquisition_type : %hd\n",mh->acquisition_type); MdcPrntScrn("patient_orientation : %hd\n",mh->patient_orientation); MdcGetSafeString(mdcbufr,mh->facility_name,20,20); MdcPrntScrn("facility_name : %s\n",mdcbufr); MdcPrntScrn("num_planes : %hd\n",mh->num_planes); MdcPrntScrn("num_frames : %hd\n",mh->num_frames); MdcPrntScrn("num_gates : %hd\n",mh->num_gates); MdcPrntScrn("num_bed_pos : %hd\n",mh->num_bed_pos); MdcPrntScrn("init_bed_position : %f\n",mh->init_bed_position); for (i=0; i<15; i++) MdcPrntScrn("bed_position[%2d] : %f\n",i,mh->bed_position[i]); MdcPrntScrn("plane_separation : %f [cm]\n",mh->plane_separation); MdcPrntScrn("lwr_sctr_thres : %hd [Kev]\n",mh->lwr_sctr_thres); MdcPrntScrn("lwr_true_thres : %hd [Kev]\n",mh->lwr_true_thres); MdcPrntScrn("upr_true_thres : %hd [Kev]\n",mh->upr_true_thres); MdcGetSafeString(mdcbufr,mh->user_process_code,10,10); MdcPrntScrn("user_process_code : %s\n",mdcbufr); MdcPrntScrn("acquisition_mode : %hd\n",mh->acquisition_mode); MdcPrntScrn("bin_size : %f [cm]\n",mh->bin_size); MdcPrntScrn("branching_fraction : %f\n",mh->branching_fraction); MdcPrntScrn("dose_start_time : %s\n" ,ctime((time_t *)&mh->dose_start_time)); MdcPrntScrn("dosage : %e [mCi]\n",mh->dosage); MdcPrntScrn("well_counter_corr_factor : %f\n",mh->well_counter_corr_factor); MdcGetSafeString(mdcbufr,mh->data_units,32,32); MdcPrntScrn("data_units : %s\n",mdcbufr); MdcPrntScrn("septa_state : %hd\n",mh->septa_state); for (i=0; i<6; i++) MdcPrntScrn("fill_cti[%d] : %hd\n",i,mh->fill_cti[i]); } void MdcEcatPrintImgSubHdr(Mdc_Image_subheader7 *ish, int nr) { MdcPrintLine('-',MDC_HALF_LENGTH); MdcPrntScrn("ECAT7 Image Sub Header %05d (%d bytes)\n",nr,ISH_72_SIZE); MdcPrintLine('-',MDC_HALF_LENGTH); MdcPrntScrn("data_type : %hd\n",ish->data_type); MdcPrntScrn("num_dimensions : %hd\n",ish->num_dimensions); MdcPrntScrn("x_dimension : %hd\n",ish->x_dimension); MdcPrntScrn("y_dimension : %hd\n",ish->y_dimension); MdcPrntScrn("z_dimension : %hd\n",ish->z_dimension); MdcPrntScrn("x_offset : %f [cm]\n",ish->x_offset); MdcPrntScrn("y_offset : %f [cm]\n",ish->y_offset); MdcPrntScrn("z_offset : %f [cm]\n",ish->z_offset); MdcPrntScrn("recon_zoom : %f\n",ish->recon_zoom); MdcPrntScrn("scale_factor : %e\n",ish->scale_factor); MdcPrntScrn("image_min : %hd\n",ish->image_min); MdcPrntScrn("image_max : %hd\n",ish->image_max); MdcPrntScrn("x_pixel_size : %f [cm]\n",ish->x_pixel_size); MdcPrntScrn("y_pixel_size : %f [cm]\n",ish->y_pixel_size); MdcPrntScrn("z_pixel_size : %f [cm]\n",ish->z_pixel_size); MdcPrntScrn("frame_duration : %d [ms]\n",ish->frame_duration); MdcPrntScrn("frame_start_time : %d [ms]\n",ish->frame_start_time); MdcPrntScrn("filter_code : %hd\n",ish->filter_code); MdcPrntScrn("x_resolution : %g\n",ish->x_resolution); MdcPrntScrn("y_resolution : %g\n",ish->y_resolution); MdcPrntScrn("z_resolution : %g\n",ish->z_resolution); MdcPrntScrn("num_r_elements : %g\n",ish->num_r_elements); MdcPrntScrn("num_angles : %g\n",ish->num_angles); MdcPrntScrn("z_rotation_angle ; %g\n",ish->z_rotation_angle); MdcPrntScrn("decay_corr_fctr : %g\n",ish->decay_corr_fctr); MdcPrntScrn("processing_code : %d\n",ish->processing_code); MdcPrntScrn("gate_duration : %u\n",ish->gate_duration); MdcPrntScrn("r_wave_offset : %d\n",ish->r_wave_offset); MdcPrntScrn("num_accepted_beats : %d\n",ish->num_accepted_beats); MdcPrntScrn("filter_cutoff_frequency : %g\n",ish->filter_cutoff_frequency); MdcPrntScrn("filter_resolution : %g\n",ish->filter_resolution); MdcPrntScrn("filter_ramp_slope : %g\n",ish->filter_ramp_slope); MdcPrntScrn("filter_order : %hd\n",ish->filter_order); MdcPrntScrn("filter_scatter_fraction : %g\n",ish->filter_scatter_fraction); MdcPrntScrn("filter_scatter_slope : %g\n",ish->filter_scatter_slope); MdcGetSafeString(mdcbufr,ish->annotation,40,40); MdcPrntScrn("annotation : %s\n",mdcbufr); MdcPrntScrn("mt_1_1 : %g\n",ish->mt_1_1); MdcPrntScrn("mt_1_2 : %g\n",ish->mt_1_2); MdcPrntScrn("mt_1_3 : %g\n",ish->mt_1_3); MdcPrntScrn("mt_2_1 : %g\n",ish->mt_2_1); MdcPrntScrn("mt_2_2 : %g\n",ish->mt_2_2); MdcPrntScrn("mt_2_3 : %g\n",ish->mt_2_3); MdcPrntScrn("mt_3_1 : %g\n",ish->mt_3_1); MdcPrntScrn("mt_3_2 : %g\n",ish->mt_3_2); MdcPrntScrn("mt_3_3 : %g\n",ish->mt_3_3); MdcPrntScrn("rfilter_cutoff : %g\n",ish->rfilter_cutoff); MdcPrntScrn("rfilter_resolution : %g\n",ish->rfilter_resolution); MdcPrntScrn("rfilter_code : %hd\n",ish->rfilter_code); MdcPrntScrn("rfilter_order : %hd\n",ish->rfilter_order); MdcPrntScrn("zfilter_cutoff : %g\n",ish->zfilter_cutoff); MdcPrntScrn("zfilter_resolution : %g\n",ish->zfilter_resolution); MdcPrntScrn("zfilter_code : %hd\n",ish->zfilter_code); MdcPrntScrn("zfilter_order : %hd\n",ish->zfilter_order); MdcPrntScrn("mt_1_4 : %g\n",ish->mt_1_4); MdcPrntScrn("mt_2_4 : %g\n",ish->mt_2_4); MdcPrntScrn("mt_3_4 : %g\n",ish->mt_3_4); MdcPrntScrn("scatter_type : %hd\n",ish->scatter_type); MdcPrntScrn("recon_type : %hd\n",ish->recon_type); MdcPrntScrn("recon_views : %hd\n",ish->recon_views); MdcPrntScrn("fill_cti[87] : \n"); MdcPrntScrn("fill_user[48] : \n"); } void MdcEcatPrintAttnSubHdr(Mdc_Attn_subheader7 *ash, int nr) { int i; MdcPrintLine('-',MDC_HALF_LENGTH); MdcPrntScrn("ECAT7 Attenuation Sub Header %05d (%d bytes)\n",nr,ASH_72_SIZE); MdcPrintLine('-',MDC_HALF_LENGTH); MdcPrntScrn("data_type : %hd\n",ash->data_type); MdcPrntScrn("num_dimensions : %hd\n",ash->num_dimensions); MdcPrntScrn("attenuation_type : %hd\n",ash->attenuation_type); MdcPrntScrn("num_r_elements : %hd\n",ash->num_r_elements); MdcPrntScrn("num_angles : %hd\n",ash->num_angles); MdcPrntScrn("num_z_elements : %hd\n",ash->num_z_elements); MdcPrntScrn("ring_difference : %hd\n",ash->ring_difference); MdcPrntScrn("x_resolution : %g [cm]\n",ash->x_resolution); MdcPrntScrn("y_resolution : %g [cm]\n",ash->y_resolution); MdcPrntScrn("z_resolution : %g [cm]\n",ash->z_resolution); MdcPrntScrn("w_resolution : %g\n",ash->w_resolution); MdcPrntScrn("scale_factor : %e\n",ash->scale_factor); MdcPrntScrn("x_offset : %g [cm]\n",ash->x_offset); MdcPrntScrn("y_offset : %g [cm]\n",ash->y_offset); MdcPrntScrn("x_radius : %g [cm]\n",ash->x_radius); MdcPrntScrn("y_radius : %g [cm]\n",ash->y_radius); MdcPrntScrn("tilt_angle : %g [degrees]\n",ash->tilt_angle); MdcPrntScrn("attenuation_coeff : %g [1/cm]\n",ash->attenuation_coeff); MdcPrntScrn("attenuation_min : %g\n",ash->attenuation_min); MdcPrntScrn("attenuation_max : %g\n",ash->attenuation_max); MdcPrntScrn("skull_thickness : %g [cm]\n",ash->skull_thickness); MdcPrntScrn("num_xtra_atten_coeff : %hd\n",ash->num_xtra_atten_coeff); for (i=0; i<8; i++) MdcPrntScrn("xtra_atten_coeff[%d] : %g\n",i,ash->xtra_atten_coeff[i]); MdcPrntScrn("edge_finding_threshold : %g\n",ash->edge_finding_threshold); MdcPrntScrn("storage_order : %hd\n",ash->storage_order); MdcPrntScrn("span : %hd\n",ash->span); for (i=0; i<64; i++) MdcPrntScrn("z_elements[%2d] : %hd\n",i,ash->z_elements[i]); MdcPrntScrn("fill_unused[86] : \n"); MdcPrntScrn("fill_user[50] : \n"); } void MdcEcatPrintScanSubHdr(Mdc_Scan_subheader7 *ssh) { MdcPrntScrn("data_type : %hd\n",ssh->data_type); MdcPrntScrn("num_dimensions : %hd\n",ssh->num_dimensions); MdcPrntScrn("num_r_elements : %hd\n",ssh->num_r_elements); MdcPrntScrn("num_angles : %hd\n",ssh->num_angles); MdcPrntScrn("corrections_applied : %hd\n",ssh->corrections_applied); MdcPrntScrn("num_z_elements : %hd\n",ssh->num_z_elements); MdcPrntScrn("ring_difference : %hd\n",ssh->ring_difference); MdcPrntScrn("x_resolution : %g [cm]\n",ssh->x_resolution); MdcPrntScrn("y_resolution : %g [cm]\n",ssh->y_resolution); MdcPrntScrn("z_resolution : %g [cm]\n",ssh->z_resolution); MdcPrntScrn("w_resolution : %g\n",ssh->w_resolution); MdcPrntScrn("fill[6] : \n"); MdcPrntScrn("gate_duration : %u [ms]\n",ssh->gate_duration); MdcPrntScrn("r_wave_offset : %d [ms]\n",ssh->r_wave_offset); MdcPrntScrn("num_accepted_beats : %d\n",ssh->num_accepted_beats); MdcPrntScrn("scale_factor : %e\n",ssh->scale_factor); MdcPrntScrn("scan_min : %hd\n",ssh->scan_min); MdcPrntScrn("scan_max : %hd\n",ssh->scan_max); MdcPrntScrn("prompts : %d\n",ssh->prompts); MdcPrntScrn("delayed : %d\n",ssh->delayed); MdcPrntScrn("multiples : %d\n",ssh->multiples); MdcPrntScrn("net_trues : %d\n",ssh->net_trues); MdcPrntScrn("cor_singles[16] : \n"); MdcPrntScrn("uncor_singles[16] : \n"); MdcPrntScrn("tot_avg_cor : %g\n",ssh->tot_avg_cor); MdcPrntScrn("tot_avg_uncor : %g\n",ssh->tot_avg_uncor); MdcPrntScrn("total_coin_rate : %d\n",ssh->total_coin_rate); MdcPrntScrn("frame_start_time : %u\n",ssh->frame_start_time); MdcPrntScrn("frame_duration : %u\n",ssh->frame_duration); MdcPrntScrn("deadtime_correction_factor: %g\n" ,ssh->deadtime_correction_factor); MdcPrntScrn("phy_planes[8] : \n"); MdcPrntScrn("cti_fill[90] : \n"); MdcPrntScrn("user_fill[50] : \n"); } void MdcEcatPrintNormSubHdr(Mdc_Norm_subheader7 *nsh) { MdcPrntScrn("data_type : %hd\n",nsh->data_type); MdcPrntScrn("num_dimensions : %hd\n",nsh->num_dimensions); MdcPrntScrn("num_r_elements : %hd\n",nsh->num_r_elements); MdcPrntScrn("num_angles : %hd\n",nsh->num_angles); MdcPrntScrn("num_z_elements : %hd\n",nsh->num_z_elements); MdcPrntScrn("ring_difference : %hd\n",nsh->ring_difference); MdcPrntScrn("scale_factor : %e\n",nsh->scale_factor); MdcPrntScrn("norm_min : %g\n",nsh->norm_min); MdcPrntScrn("norm_max : %g\n",nsh->norm_max); MdcPrntScrn("fov_source_width : %g\n",nsh->fov_source_width); MdcPrntScrn("norm_quality_factor : %g\n",nsh->norm_quality_factor); MdcPrntScrn("norm_quality_factor_code : %hd\n",nsh->norm_quality_factor_code); MdcPrntScrn("storage_order : %hd\n",nsh->storage_order); MdcPrntScrn("span : %hd\n",nsh->span); MdcPrntScrn("z_elements[64] : \n"); MdcPrntScrn("cti_fill[123] : \n"); MdcPrntScrn("user_fill[50] : \n"); } const char *MdcReadECAT7(FILEINFO *fi) { FILE *fp = fi->ifp; int i, error, UNSUPPORTED; const char *err; char *str; struct tm time, *ptime; Mdc_Main_header7 mh; Mdc_Image_subheader7 ish; Mdc_Attn_subheader7 ash; /* Mdc_Scan_subheader7 ssh; Mdc_Norm_subheader7 nsh; */ struct Mdc_MatDir entry, matrix_list[MDC_ECAT7_MAX_MATRICES]; struct Mdc_Matval matval; Uint32 number, slice, img=0, vol=0, bytes; Uint32 group=0, group_slice, skip_bytes=0, row, rbytes; int bed,gate,frame,plane,nb,ng,nf,np,nd; int matnum, startblk, endblk, num_matrices; IMG_DATA *id; DYNAMIC_DATA *dd=NULL; Int16 bits, type; Uint8 *mbufr, *pmbufr, *pbuf; float slice_position; if (MDC_PROGRESS) MdcProgress(MDC_PROGRESS_BEGIN,0.,"Reading ECAT7:"); if (MDC_VERBOSE) MdcPrntMesg("ECAT7 Reading <%s> ...",fi->ifname); /* put some defaults we use */ fi->endian=MDC_FILE_ENDIAN=MDC_BIG_ENDIAN; fi->modality = M_PT; error = mdc_mat_read_main_header7(fp, &mh); if (error) return("ECAT7 Bad read main header"); if (MDC_INFO || MDC_INFO_DB) MdcEcatPrintMainHdr(&mh); if (MDC_INFO_DB) return(NULL); /* just needed db info */ /* check for supported file types */ switch (mh.file_type) { case MDC_ECAT7_FILE_TYPE_IMAGE16 : case MDC_ECAT7_FILE_TYPE_VOLUME8 : case MDC_ECAT7_FILE_TYPE_VOLUME16: case MDC_ECAT7_FILE_TYPE_IMAGE8 : UNSUPPORTED = MDC_NO; break; default: UNSUPPORTED = MDC_YES; } /* if (UNSUPPORTED == MDC_YES) return("ECAT7 Unsupported file type"); */ if (mh.num_frames <= 0 ) mh.num_frames = 1; if (mh.num_gates <= 0 ) mh.num_gates = 1; if (mh.num_bed_pos < 0 ) mh.num_bed_pos = 0; /* fill in global FILEINFO data */ fi->dim[0]= 6; fi->dim[3]= mh.num_planes; fi->dim[4]= mh.num_frames; fi->dim[5]= mh.num_gates; fi->dim[6]= mh.num_bed_pos + 1; /* must be 1-based */ /* check for unsupported bed overlap */ if (fi->dim[6] > 1) { float axial_width, bed_offset=mh.bed_position[0]; if (bed_offset < 0) bed_offset = -bed_offset; axial_width = mh.plane_separation * (float)fi->dim[3]; if ((axial_width - bed_offset) >= 1.0) { MdcPrntWarn("ECAT7 Bed overlaps unsupported"); } } for (i=3, number=1; i<=6; i++) number*=fi->dim[i]; if (number == 0) return("ECAT7 No valid images specified"); /* fill in orientation information */ switch (mh.patient_orientation) { case MDC_ECAT7_FEETFIRST_PRONE: fi->pat_slice_orient = MDC_PRONE_FEETFIRST_TRANSAXIAL; break; case MDC_ECAT7_HEADFIRST_PRONE: fi->pat_slice_orient = MDC_PRONE_HEADFIRST_TRANSAXIAL; break; case MDC_ECAT7_FEETFIRST_SUPINE: fi->pat_slice_orient = MDC_SUPINE_FEETFIRST_TRANSAXIAL; break; case MDC_ECAT7_HEADFIRST_SUPINE: fi->pat_slice_orient = MDC_SUPINE_HEADFIRST_TRANSAXIAL; break; case MDC_ECAT7_FEETFIRST_RIGHT: fi->pat_slice_orient = MDC_DECUBITUS_RIGHT_FEETFIRST_TRANSAXIAL; break; case MDC_ECAT7_HEADFIRST_RIGHT: fi->pat_slice_orient = MDC_DECUBITUS_RIGHT_HEADFIRST_TRANSAXIAL; break; case MDC_ECAT7_FEETFIRST_LEFT: fi->pat_slice_orient = MDC_DECUBITUS_LEFT_FEETFIRST_TRANSAXIAL; break; case MDC_ECAT7_HEADFIRST_LEFT: fi->pat_slice_orient = MDC_DECUBITUS_LEFT_HEADFIRST_TRANSAXIAL; break; default: fi->pat_slice_orient = MDC_SUPINE_HEADFIRST_TRANSAXIAL; MdcPrntWarn("ECAT7 unknown patient orientation"); } str = MdcGetStrPatPos(fi->pat_slice_orient); MdcStringCopy(fi->pat_pos,str,strlen(str)); str = MdcGetStrPatOrient(fi->pat_slice_orient); MdcStringCopy(fi->pat_orient,str,strlen(str)); /* fill in patient study related information */ switch (mh.patient_sex[0]) { case 0: fi->patient_sex[0] = 'M'; break; case 1: fi->patient_sex[0] = 'F'; break; default: fi->patient_sex[0] = 'U'; } fi->patient_sex[1]='\0'; MdcStringCopy(fi->patient_name,mh.patient_name,32); MdcStringCopy(fi->patient_id,mh.patient_id,16); fi->patient_height = mh.patient_height; fi->patient_weight = mh.patient_weight; ptime = &time; #ifdef HAVE_LOCALTIME_R localtime_r((time_t *)&(mh.scan_start_time), ptime); #else ptime = localtime((time_t *)&(mh.scan_start_time)); #endif if (ptime == NULL) { MdcPrntWarn("ECAT7: Couldn't resolve scan start time"); fi->study_date_day = 0; fi->study_date_month = 1; fi->study_date_year = 1900; fi->study_time_hour = 0; fi->study_time_minute= 0; fi->study_time_second= 0; }else{ fi->study_date_day = ptime->tm_mday; fi->study_date_month = ptime->tm_mon + 1; fi->study_date_year = ptime->tm_year + 1900; fi->study_time_hour = ptime->tm_hour; fi->study_time_minute= ptime->tm_min; fi->study_time_second= ptime->tm_sec; } switch (mh.acquisition_type) { case MDC_ECAT7_SCAN_TRANSMISSION: case MDC_ECAT7_SCAN_STATIC_EMISSION: fi->acquisition_type = MDC_ACQUISITION_TOMO; break; case MDC_ECAT7_SCAN_DYNAMIC_EMISSION: fi->acquisition_type = MDC_ACQUISITION_DYNAMIC; break; case MDC_ECAT7_SCAN_GATED_EMISSION: fi->acquisition_type = MDC_ACQUISITION_GSPECT; break; case MDC_ECAT7_SCAN_BLANK: case MDC_ECAT7_SCAN_TRANS_RECTILINEAR: case MDC_ECAT7_SCAN_EMISSION_RECTILINEAR: default: fi->acquisition_type = MDC_ACQUISITION_UNKNOWN; break; } sprintf(mdcbufr,"ECAT%hd",mh.system_type); MdcStringCopy(fi->manufacturer,mdcbufr,strlen(mdcbufr)); MdcStringCopy(fi->operator_name,mh.operator_name,32); MdcStringCopy(fi->study_descr,mh.study_description,32); MdcStringCopy(fi->study_id,mh.study_type,12); MdcStringCopy(fi->institution,mh.facility_name,20); MdcStringCopy(fi->radiopharma,mh.radiopharmaceutical,32); MdcStringCopy(fi->isotope_code,mh.isotope_name,8); fi->isotope_halflife = mh.isotope_halflife; fi->injected_dose = MdcmCi2MBq(mh.dosage); fi->gantry_tilt = mh.gantry_tilt; if (MDC_ECHO_ALIAS == MDC_YES) { MdcEchoAliasName(fi); return(NULL); } if (!MdcGetStructID(fi,number)) return("ECAT7 Bad malloc IMG_DATA structs"); /* always malloc dyndata structs */ if (!MdcGetStructDD(fi,(Uint32)fi->dim[4]*fi->dim[5]*fi->dim[6])) return("ECAT7 Couldn't malloc DYNAMIC_DATA structs"); /* ECAT7: matrices for each volume */ num_matrices = mdc_mat_list7(fp, matrix_list, MDC_ECAT7_MAX_MATRICES); if (num_matrices == 0) return("ECAT7 No matrices found"); if ((Uint32)num_matrices > (fi->number / fi->dim[3])) return("ECAT7 Too many matrices found"); if (MDC_MY_DEBUG) { int t; MdcDebugPrint("%d.%d.%d.%d",fi->dim[3] ,fi->dim[4] ,fi->dim[5] ,fi->dim[6]); for (t=0; tdim[6]; bed++) for (gate=1; gate<=fi->dim[5]; gate++) for (frame=1; frame<=fi->dim[4]; frame++, vol++) for (plane=1; plane<=fi->dim[3]; ) { if (vol == num_matrices) break; if (fi->dynnr > 0) dd = &fi->dyndata[(fi->dim[4]*bed) + (frame-1)]; mdc_mat_numdoc(matrix_list[vol].matnum,&matval); nf = matval.frame; np = matval.plane; ng = matval.gate; nb = matval.bed; nd = matval.data; matnum = mdc_mat_numcod(nf,np,ng,nd,nb); MdcDebugPrint("matnum = %d",matnum); if (!mdc_mat_lookup7(fp, matnum, &entry)) continue; startblk = entry.strtblk + 1; endblk = entry.endblk - entry.strtblk; MdcDebugPrint("entry.endblk = %d",entry.endblk); MdcDebugPrint("entry.strtblk= %d",entry.strtblk); MdcDebugPrint("startblk = %d",startblk); MdcDebugPrint("endblk = %d",endblk); switch (mh.file_type) { case MDC_ECAT7_FILE_TYPE_IMAGE8 : case MDC_ECAT7_FILE_TYPE_IMAGE16 : case MDC_ECAT7_FILE_TYPE_VOLUME8 : case MDC_ECAT7_FILE_TYPE_VOLUME16: error = mdc_mat_read_image_subheader7(fp, startblk-1, &ish); if (error) return("ECAT7 Bad read image subheader"); if (MDC_INFO) MdcEcatPrintImgSubHdr(&ish, (int)(vol + 1)); fi->dim[1] = ish.x_dimension; fi->dim[2] = ish.y_dimension; #if MDC_NUM_PLANES_FIX if ((mh.num_planes != ish.z_dimension) && (vol == 0)) { MdcPrntWarn("ECAT7 Fix wrong num_planes value"); mh.num_planes = ish.z_dimension; fi->dim[3] = ish.z_dimension; for (i=3, number=1; i<=6; i++) number*=fi->dim[i]; if (!MdcGetStructID(fi,number)) return("ECAT7 Bad realloc IMG_DATA structs"); } #endif switch (ish.data_type) { case BYTE_TYPE: bits = 8; type = BIT8_U; break; case VAX_I2: case SUN_I2: bits = 16; type = BIT16_S; break; case VAX_I4: case SUN_I4: bits = 32; type = BIT32_S; break; case VAX_R4: case IEEE_R4: bits = 32; type = FLT32; break; default: return("ECAT7: Unsupported data type"); } /* fill in DYNAMIC_DATA structs */ if ((dd != NULL) && (plane == 1)) { /* just one subheader */ dd->nr_of_slices = fi->dim[3]; dd->time_frame_start = (float)ish.frame_start_time; dd->time_frame_duration = (float)ish.frame_duration; } /* bytes entire volume (matrix blocks) */ bytes = fi->dim[1] * fi->dim[2] * fi->dim[3] * MdcType2Bytes(type); MdcDebugPrint("volume: %d bytes",bytes); bytes = MdcMatrixBlocks(bytes); MdcDebugPrint("matrix: %d bytes",bytes); mbufr = malloc(bytes); if (mbufr == NULL) return("ECAT7 Bad malloc image matrix data buffer"); error = mdc_mat_read_mat_data(fp,startblk,endblk,mbufr,ish.data_type); if (error) { MdcPrntWarn("ECAT7 Bad read image matrix data"); err=MdcHandleTruncated(fi,img+1,MDC_YES); if(err != NULL) { MdcFree(mbufr); return(err); } } if (fi->truncated) break; /* bytes each image */ bytes = fi->dim[1] * fi->dim[2] * MdcType2Bytes(type); for (slice=0; slice < fi->dim[3]; slice++, img++, plane++) { if (MDC_PROGRESS) MdcProgress(MDC_PROGRESS_INCR,1./(float)fi->number,NULL); /* fill in IMG_DATA struct */ id = &fi->image[img]; id->width = fi->dim[1]; id->height= fi->dim[2]; id->bits = bits; id->type = type; id->quant_units = 1; id->quant_scale = ish.scale_factor; id->calibr_units = mh.calibration_units; id->calibr_fctr = mh.ecat_calibration_factor; id->pixel_xsize = ish.x_pixel_size * 10.0; /* mm */ id->pixel_ysize = ish.y_pixel_size * 10.0; /* mm */ id->slice_width = ish.z_pixel_size * 10.0; /* mm */ id->slice_spacing = id->slice_width; /* slice position with bed offset (mm) */ if (bed == 0) { slice_position = mh.init_bed_position; }else{ slice_position = mh.init_bed_position + mh.bed_position[bed-1]; } slice_position *= 10.; /* mm */ MdcFillImgPos(fi,img,slice,slice_position); MdcFillImgOrient(fi,img); id->buf = MdcGetImgBuffer(bytes); if (id->buf == NULL) { MdcFree(mbufr); return("ECAT7 Bad malloc image buffer"); } memcpy(id->buf, mbufr + (bytes*slice), bytes); } MdcFree(mbufr); break; case MDC_ECAT7_FILE_TYPE_ATTNCORR: error = mdc_mat_read_attn_subheader7(fp, startblk-1, &ash); if (error) return("ECAT7 Bad read attenuation subheader"); if (MDC_INFO) MdcEcatPrintAttnSubHdr(&ash, (int)(vol + 1)); fi->dim[1] = ash.num_r_elements; fi->dim[2] = ash.num_angles; /* MARK: just retrieve group0 */ /* fi->dim[3] = ash.num_z_elements; */ /* MARK: or retrieve all */ fi->dim[3] = 0; for (i=0; ash.z_elements[i]; i++) fi->dim[3] += ash.z_elements[i]; for (i=3, number=1; i<=6; i++) number*=fi->dim[i]; if (!MdcGetStructID(fi,number)) return("ECAT7 Bad realloc IMG_DATA structs"); switch (ash.data_type) { case BYTE_TYPE: bits = 8; type = BIT8_U; break; case VAX_I2: case SUN_I2: bits = 16; type = BIT16_S; break; case VAX_I4: case SUN_I4: bits = 32; type = BIT32_S; break; case VAX_R4: case IEEE_R4: bits = 32; type = FLT32; break; default: return("ECAT7: Unsupported data type"); } /* bytes entire volume (matrix blocks) */ bytes = fi->dim[1] * fi->dim[2] * fi->dim[3] * MdcType2Bytes(type); MdcDebugPrint("volume: %d bytes",bytes); bytes = MdcMatrixBlocks(bytes); MdcDebugPrint("matrix: %d bytes",bytes); mbufr = malloc(bytes); if (mbufr == NULL) return("ECAT7 Bad malloc attenuation matrix data buffer"); endblk = startblk + (bytes / MdcMatBLKSIZE) - 1; error = mdc_mat_read_mat_data(fp,startblk,endblk,mbufr,ash.data_type); if (error) { MdcPrntWarn("ECAT7 Bad read attenuation matrix data"); err=MdcHandleTruncated(fi,img+1,MDC_YES); if(err != NULL) { MdcFree(mbufr); return(err); } } if (fi->truncated) break; /* bytes each image */ bytes = fi->dim[1] * fi->dim[2] * MdcType2Bytes(type); group_slice=0; for (slice=0; slice < fi->dim[3]; slice++, img++, plane++) { if (MDC_PROGRESS) MdcProgress(MDC_PROGRESS_INCR,1./(float)fi->number,NULL); /* fill in IMG_DATA struct */ id = &fi->image[img]; id->width = fi->dim[1]; id->height= fi->dim[2]; id->bits = bits; id->type = type; id->quant_units = 1; id->quant_scale = ash.scale_factor; id->calibr_units = mh.calibration_units; id->calibr_fctr = mh.ecat_calibration_factor; id->pixel_xsize = ash.x_resolution * 10.0; /* mm */ id->pixel_ysize = ash.y_resolution * 10.0; /* mm */ id->slice_width = ash.z_resolution * 10.0; /* mm */ id->slice_spacing = id->slice_width; /* slice position with bed offset (mm) */ if (bed == 0) { slice_position = mh.init_bed_position; }else{ slice_position = mh.init_bed_position + mh.bed_position[bed-1]; } slice_position *= 10.; /* mm */ MdcFillImgPos(fi,img,slice,slice_position); MdcFillImgOrient(fi,img); id->buf = MdcGetImgBuffer(bytes); if (id->buf == NULL) { MdcFree(mbufr); return("ECAT7 Bad malloc image buffer"); } /* copy date */ if (ash.storage_order == 0) { /* view mode: for the first group of z_elements we have */ /* all 1st rows, all 2nd rows, etc. Then follows */ /* same storage for next group of z_elements, */ /* at least we think */ /* MARK: still not proper for all groups, actually only 1st ok*/ rbytes = fi->dim[1] * MdcType2Bytes(type); if (group_slice == ash.z_elements[group] ) { skip_bytes += ash.z_elements[group] * bytes; group += 1; group_slice = 0; } pmbufr = mbufr + skip_bytes + group_slice * rbytes; /* MARK */ /* MARK printf("DEBUG: skip_bytes(%u) + group_slice(%u) * rbytes (%u) = %u\n",skip_bytes,group_slice,rbytes,skip_bytes+group_slice*rbytes); */ for (row=0; row < fi->dim[2]; row++) { pbuf = id->buf+(rbytes * row); memcpy(pbuf, pmbufr, rbytes); pmbufr += ash.z_elements[group] * rbytes; } }else{ /* sinogram mode: fine, just copy */ memcpy(id->buf, mbufr + (bytes*slice), bytes); } group_slice++; } MdcFree(mbufr); break; default: return("ECAT7 Unsupported file type"); } } /* set remaing FILEINFO data */ id = &fi->image[0]; fi->bits = id->bits; fi->type = id->type; fi->pixdim[0] = 3; fi->pixdim[1] = id->pixel_xsize; fi->pixdim[2] = id->pixel_ysize; fi->pixdim[3] = id->slice_width; switch (mh.file_type) { case MDC_ECAT7_FILE_TYPE_IMAGE8 : case MDC_ECAT7_FILE_TYPE_IMAGE16 : case MDC_ECAT7_FILE_TYPE_VOLUME8 : case MDC_ECAT7_FILE_TYPE_VOLUME16: fi->reconstructed = MDC_YES; if (ish.decay_corr_fctr > 1.0) fi->decay_corrected = MDC_YES; break; default: fi->reconstructed = MDC_NO; } MdcCloseFile(fi->ifp); if (fi->truncated) return("ECAT7 Truncated image file"); return(NULL); } #if MDC_INCLUDE_TPC /*! * Converts FILEINFO structure and MDC mainheader to TPC ecat7 mainheader * * @param mh pointer to MDC mainheader * @param h pointer to TPC imageheader * @param image_i image index number [0..fi->number-1] * @param frame_i frame index number [0..fi->dim[4]-1] */ int MdcConvertToTPCEcat7image(FILEINFO* fi, ECAT7_imageheader* h, int image_i, int frame_i) { int i = 0; /* short int <- ECAT7_SUNI2 (must be for matrix writing) */ h->data_type = ECAT7_SUNI2; h->num_dimensions = fi->dim[0]; switch (fi->pat_slice_orient) { #if MDC_TPC_SITE case MDC_SAGITTAL: /* short int <- Int16 */ h->x_dimension = fi->dim[3]; h->y_dimension = fi->dim[2]; h->z_dimension = fi->dim[1]; /* float <- ??? */ h->x_offset = 0; h->y_offset = 0; h->z_offset = 0; h->x_pixel_size = fi->pixdim[3]/10; h->y_pixel_size = fi->pixdim[2]/10; h->z_pixel_size = fi->pixdim[1]/10; /* float <- ??? */ h->x_resolution = 0.0f; h->y_resolution = 0.0f; h->z_resolution = 0.0f; break; case MDC_CORONAL: /* short int <- Int16 */ h->x_dimension = fi->dim[1]; h->y_dimension = fi->dim[3]; h->z_dimension = fi->dim[2]; /* float <- ??? */ h->x_offset = 0; h->y_offset = 0; h->z_offset = 0; h->x_pixel_size = fi->pixdim[1]/10; h->y_pixel_size = fi->pixdim[3]/10; h->z_pixel_size = fi->pixdim[2]/10; /* float <- ??? */ h->x_resolution = 0.0f; h->y_resolution = 0.0f; h->z_resolution = 0.0f; break; #endif default: /* short int <- Int16 */ h->x_dimension = fi->dim[1]; h->y_dimension = fi->dim[2]; h->z_dimension = fi->dim[3]; /* float <- ??? */ h->x_offset = 0; h->y_offset = 0; h->z_offset = 0; h->x_pixel_size = fi->pixdim[1]/10; h->y_pixel_size = fi->pixdim[2]/10; h->z_pixel_size = fi->pixdim[3]/10; /* float <- ??? */ h->x_resolution = 0.0f; h->y_resolution = 0.0f; h->z_resolution = 0.0f; break; } if (fi->image) { /* eNlf: MARK - leave out for now, currently no slice_location in IMG_DATA switch(fi->pat_slice_orient) { #if MDC_TPC_SITE case MDC_SAGITTAL: if(fi->dim[3] > 1 && fabs(fi->image[fi->number-1].slice_location - fi->image[0].slice_location) != 0) h->x_pixel_size = fabs(fi->image[fi->number-1].slice_location - fi->image[0].slice_location)/((fi->dim[3]-1)*10.0f); else h->x_pixel_size = fi->image[0].slice_width/10; break; case MDC_CORONAL: if(fi->dim[3] > 1 && fabs(fi->image[fi->number-1].slice_location - fi->image[0].slice_location) != 0) h->y_pixel_size = fabs(fi->image[fi->number-1].slice_location - fi->image[0].slice_location)/((fi->dim[3]-1)*10.0f); else h->y_pixel_size = fi->image[0].slice_width/10; break; #endif default: if(fi->dim[3] > 1 && fabs(fi->image[fi->number-1].slice_location - fi->image[0].slice_location) != 0) h->z_pixel_size = fabs(fi->image[fi->number-1].slice_location - fi->image[0].slice_location)/((fi->dim[3]-1)*10.0f); else h->z_pixel_size = fi->image[0].slice_width/10; } */ h->recon_zoom = fi->image[image_i].recon_scale; if (fi->image[image_i].rescaled) { h->scale_factor = fi->image[image_i].rescaled_fctr; }else{ h->scale_factor = 1.; } /* short int <- double */ h->image_min = fi->image[image_i].min; h->image_max = fi->image[image_i].max; } if (fi->dyndata && frame_i < fi->dynnr) { /* int <- float (ms) */ h->frame_duration = fi->dyndata[frame_i].time_frame_duration; /* int <- float (ms) */ h->frame_start_time = fi->dyndata[frame_i].time_frame_start; } /* short int <- ??? */ h->filter_code = 0; /* float <- ??? */ h->num_r_elements = 0; /* float <- ??? */ h->num_angles = 0.0f; /* float <- ??? */ h->z_rotation_angle = 0.0f; /* float <- ??? */ h->decay_corr_fctr = 0.0f; /* int <- ??? */ h->processing_code = 0; if (fi->gdata) { /* int <- float (ms) */ h->gate_duration = fi->gdata->image_duration; /* int <- float (ms) */ h->r_wave_offset = fi->gdata->window_low; h->num_accepted_beats = fi->gdata->cycles_acquired; } /* float <- ??? */ h->filter_cutoff_frequency = 0.0f; /* float <- ??? */ h->filter_resolution = 0.0f; /* float <- ??? */ h->filter_ramp_slope = 0.0f; /* short int <- ??? */ h->filter_order = 0; /* float <- ??? */ h->filter_scatter_fraction = 0.0f; /* float <- ??? */ h->filter_scatter_slope = 0.0f; /* char annotation[40]; */ /* float <- ??? */ h->mt_1_1 = 0.0f; /* float <- ??? */ h->mt_1_2 = 0.0f; /* float <- ??? */ h->mt_1_3 = 0.0f; /* float <- ??? */ h->mt_2_1 = 0.0f; /* float <- ??? */ h->mt_2_2 = 0.0f; /* float <- ??? */ h->mt_2_3 = 0.0f; /* float <- ??? */ h->mt_3_1 = 0.0f; /* float <- ??? */ h->mt_3_2 = 0.0f; /* float <- ??? */ h->mt_2_3 = 0.0f; /* float <- ??? */ h->rfilter_cutoff = 0.0f; /* float <- ??? */ h->rfilter_resolution = 0.0f; /* short int <- ??? */ h->rfilter_code = 0.0f; /* short int <- ??? */ h->rfilter_order = 0.0f; /* float <- ??? */ h->zfilter_cutoff = 0.0f; /* float <- ??? */ h->zfilter_resolution = 0.0f; /* short int <- ??? */ h->zfilter_code = 0; /* short int <- ??? */ h->zfilter_order = 0; /* float <- ??? */ h->mt_1_4 = 0.0f; /* float <- ??? */ h->mt_2_4 = 0.0f; /* float <- ??? */ h->mt_3_4 = 0.0f; /* short int <- ??? */ h->scatter_type = 0; /* short int <- ??? */ h->recon_type = 0; /* short int <- ??? */ h->recon_views = 0; /* short int <- ??? */ for(i = 0; i < 87; i++) h->fill_cti[i] = 0; /* short int <- ??? */ for(i = 0; i < 49; i++) h->fill_user[i] = 0; return 0; } /*! * Converts FILEINFO structure and MDC mainheader to TPC ecat7 mainheader * * @param fi file structure * @param mh pointer to MDC mainheader * @param h pointer to TPC mainheader */ int MdcConvertToTPCEcat7(FILEINFO* fi, Mdc_Main_header* mh, ECAT7_mainheader* h) { struct tm timeinfo = {0}; int i = 0; /* use default ecat7 magic number */ strncpy(h->magic_number, ECAT7V_MAGICNR,14); strncpy(h->original_file_name,mh->original_file_name,20); h->sw_version = 72; /* short int <- Int16 */ h->system_type = mh->system_type; /* short int <- ECAT7_VOLUME16 */ h->file_type = ECAT7_VOLUME16; strncpy(h->serial_number,"unknown",10); /* int <- Int16 Int16 Int16 Int16 */ timeinfo.tm_year = mh->scan_start_year-1900; timeinfo.tm_mon = mh->scan_start_month-1; timeinfo.tm_mday = mh->scan_start_day; timeinfo.tm_hour = mh->scan_start_hour; timeinfo.tm_min = mh->scan_start_minute; timeinfo.tm_sec = mh->scan_start_second; h->scan_start_time = (unsigned int)mktime(&timeinfo); strncpy(h->isotope_name,fi->isotope_code,(8isotope_halflife = mh->isotope_halflife; strncpy(h->radiopharmaceutical, fi->radiopharma,(32gantry_tilt = mh->gantry_tilt; h->gantry_rotation = mh->gantry_rotation; h->bed_elevation = mh->bed_elevation; /* float <- ??? */ h->intrinsic_tilt = 0.0f; /* short int <- Int16 */ h->wobble_speed = mh->wobble_speed; /* short int <- Int16 */ h->transm_source_type = mh->transm_source_type; /* float <- ??? */ h->distance_scanned = 0.0f; h->transaxial_fov = mh->transaxial_fov; /* short int <- Int16 */ h->angular_compression = mh->compression_code; /* short int <- Int16 */ h->coin_samp_mode = mh->coin_samp_mode; /* short int <- Int16 */ h->axial_samp_mode = mh->axial_samp_mode; h->ecat_calibration_factor = 1.; /* eNlf: global, prefer scale per plane*/ /* short int <- Int16 */ h->calibration_units = mh->calibration_units; /* short int <- ??? */ h->calibration_units_label = 0; /* short int <- Int16 */ h->compression_code = mh->compression_code; strncpy(h->study_type,mh->study_name,12); strncpy(h->patient_id,mh->patient_id,16); strncpy(h->patient_name,mh->patient_name,32); switch (fi->patient_sex[0]) { case 'M': h->patient_sex = 0; break; case 'F': h->patient_sex = 1; break; default : h->patient_sex = 3; } h->patient_dexterity = mh->patient_dexterity; sscanf(mh->patient_age,"%f",&h->patient_age); h->patient_height = fi->patient_height; h->patient_weight = fi->patient_weight; /* int <- char[MDC_MAXSTR] */ sscanf(fi->patient_dob,"%d",&h->patient_birth_date); strncpy(h->physician_name,mh->physician_name,32); strncpy(h->operator_name,mh->operator_name,32); strncpy(h->study_description,mh->study_description,32); /* short int <- Int16 */ h->acquisition_type = mh->acquisition_type; /* short int <- char[MDC_MAXSTR] */ h->patient_orientation = 0; if(strncmp(fi->pat_pos,"FFP",3) == 0) h->patient_orientation = 0; else if(strncmp(fi->pat_pos,"HFP",3) == 0) h->patient_orientation = 1; else if(strncmp(fi->pat_pos,"FFS",3) == 0) h->patient_orientation = 2; else if(strncmp(fi->pat_pos,"HFS",3) == 0) h->patient_orientation = 3; else if(strncmp(fi->pat_pos,"FFDR",4) == 0) h->patient_orientation = 4; else if(strncmp(fi->pat_pos,"HFDR",4) == 0) h->patient_orientation = 5; else if(strncmp(fi->pat_pos,"FFDL",4) == 0) h->patient_orientation = 6; else if(strncmp(fi->pat_pos,"HFDL",4) == 0) h->patient_orientation = 7; else MdcPrntWarn("Unrecognized patient position: %s\n",fi->pat_pos); #if MDC_TPC_SITE strncpy(h->facility_name,mh->original_file_name,20); #else strncpy(h->facility_name,fi->institution,20); #endif /* short int <- Int16 */ switch (fi->pat_slice_orient) { #if MDC_TPC_SITE case MDC_SAGITTAL: h->num_planes = fi->dim[1]; break; case MDC_CORONAL: h->num_planes = fi->dim[2]; break; #endif default: h->num_planes = fi->dim[3]; break; } /* short int <- Int16 */ h->num_frames = fi->dim[4]; /* short int <- Int16 */ h->num_gates = fi->dim[5]; /* short int (zero-based value) <- Int16 (one-based value) */ h->num_bed_pos = (fi->dim[6]>=1 ? fi->dim[6]-1 : 0); h->init_bed_position = mh->init_bed_position; for (i = 0; i < 15; i++) h->bed_position[i] = mh->bed_offset[i]; h->plane_separation = mh->plane_separation; /* short int <- Int16 */ h->lwr_sctr_thres = mh->lwr_sctr_thres; /* short int <- Int16 */ h->lwr_true_thres = mh->lwr_true_thres; /* short int <- Int16 */ h->upr_true_thres = mh->upr_true_thres; strncpy(h->user_process_code,mh->original_file_name,10); /* short int <- Int16 */ h->acquisition_mode = mh->acquisition_mode; /* float <- ?? */ h->bin_size = 0.0f; /* float <- ?? */ h->branching_fraction = 0.0f; /* int <- Int16 Int16 Int16 Int16 */ timeinfo.tm_year = fi->study_date_year-1900; timeinfo.tm_mon = fi->study_date_month-1; timeinfo.tm_mday = fi->study_date_day; timeinfo.tm_hour = fi->dose_time_hour; timeinfo.tm_min = fi->dose_time_minute; timeinfo.tm_sec = fi->dose_time_second; h->dose_start_time = (unsigned int)mktime(&timeinfo); h->dosage = MdcMBq2mCi(fi->injected_dose); /* float <- ?? */ h->well_counter_corr_factor = 0.0f; /* char[32] <- char[MDC_MAXSTR] */ strncpy(h->data_units,"unknown",32); /* eNlf: MARK - doesn't belong in modality XA if (fi->mod) { if ( strcmp(fi->mod->xa_info.Photo_Interp,"BQML") == 0 ) strncpy(h->data_units,"kBq/ml",32); } */ /* int <- ??? */ h->septa_state = 0; /* int[6] <- ??? */ for(i = 0; i < 6; i++) h->fill_cti[i] = 0; return 0; } /*! * Modified to execute TPC ecat7 writing * * @param fi file structure * @return Error message, or NULL if successfull */ const char *MdcWriteECAT7(FILEINFO *fi) { int ret = 0; int bytes = 0; ECAT7_mainheader h; ECAT7_imageheader ih; float* TPC_frame = 0; float* TPC_frame_start = 0; int frame_size = 0; int plane_dir = 0; Uint32 uwidth, uheight; IMG_DATA *id; Mdc_Main_header mh; Uint8 *buf, *maxbuf; Int16 type; Int32 matnum, bed, gate, frame, plane, img=0; #if MDC_TPC_SITE Int32 column, row; float flt32=0; #else Uint32 size; #endif if (MDC_FILE_STDOUT == MDC_YES) return("ECAT7 Writing to stdout unsupported for this format"); MDC_WRITE_ENDIAN = MDC_LITTLE_ENDIAN; /* always (VAX) */ if (XMDC_GUI == MDC_NO) { MdcDefaultName(fi,MDC_FRMT_ECAT7,fi->ofname,fi->ifname); } if (MDC_PROGRESS) MdcProgress(MDC_PROGRESS_BEGIN,0.,"Writing ECAT7:"); if (MDC_VERBOSE) MdcPrntMesg("ECAT7 Writing <%s> ...",fi->ofname); /* check for colored files */ if (fi->map == MDC_MAP_PRESENT) return("ECAT7 Colored files unsupported"); if (MdcKeepFile(fi->ofname)) { return("ECAT7 File exists!!"); } if (MDC_FORCE_INT != MDC_NO) { if (MDC_FORCE_INT != BIT16_S) { MdcPrntWarn("ECAT7 Only Int16 pixels supported"); } } /* check some integrities */ /* check integrity of planes, frames, gates, beds */ if (fi->dim[3] > MDC_ECAT7_MAX_PLANES) return("ECAT7 number of planes too big (1024)"); if (fi->dim[4] > MDC_ECAT7_MAX_FRAMES) return("ECAT7 number of frames too big (512)"); if (fi->dim[5] > MDC_ECAT7_MAX_GATES) return("ECAT7 number of gates too big (32)"); if ((fi->dim[6]*fi->dim[7]) > MDC_ECAT7_MAX_BEDS) return("ECAT7 number of beds too big (32)"); /* use TPC library to open file */ MdcFillMainHeader(fi,&mh); MdcConvertToTPCEcat7(fi,&mh,&h); fi->ofp=ecat7Create(fi->ofname, &h); if (fi->ofp == NULL) { return("ECAT7 Failed to open file for writing"); } /* write all planes */ frame_size = mh.num_planes*fi->mwidth*fi->mheight; TPC_frame_start = (float*)malloc(frame_size*sizeof(float)); if (TPC_frame_start == NULL) { MdcCloseFile(fi->ofp); return("ECAT7 Failed to allocate frame buffer"); } if ( ! ( fi->pat_slice_orient == MDC_TRANSAXIAL || fi->pat_slice_orient == MDC_CORONAL || fi->pat_slice_orient == MDC_SAGITTAL )) { MdcPrntWarn("ECAT7 Couldn't resolve slice orientation, using transaxial\n"); } /* head feet direction L\P,L\FP,P\F,L\F,P\FR,R\F */ plane_dir = MDC_HEADFIRST; if (strcmp(fi->pat_orient,"L\\P") == 0) plane_dir = MDC_FEETFIRST; else if (strcmp(fi->pat_orient,"R\\P") == 0) plane_dir = MDC_FEETFIRST; else if (strcmp(fi->pat_orient,"L\\FP") == 0) plane_dir = MDC_HEADFIRST; else if (strcmp(fi->pat_orient,"P\\F") == 0) plane_dir = MDC_HEADFIRST; else if (strcmp(fi->pat_orient,"L\\F") == 0) plane_dir = MDC_HEADFIRST; else if (strcmp(fi->pat_orient,"P\\FR") == 0) plane_dir = MDC_HEADFIRST; else if (strcmp(fi->pat_orient,"R\\F") == 0) plane_dir = MDC_HEADFIRST; else { MdcPrntWarn("ECAT7 Unrecognized patient orientation: %s\n",fi->pat_orient); } for (bed=0; bed <= mh.num_bed_pos; bed++) for (gate=1; gate <= mh.num_gates; gate++) for (frame=1; frame <= h.num_frames; frame++) { TPC_frame = TPC_frame_start; #if MDC_TPC_SITE for (plane = 0; plane < fi->dim[3]; plane++) { #else for (plane = 0; plane < fi->dim[3]; plane++, img++) { #endif if (MDC_PROGRESS) MdcProgress(MDC_PROGRESS_INCR,1./(float)fi->number,NULL); if (img < 0) { img = fi->number-1; MdcPrntWarn("ECAT7 underflow %d %d %d %d\n", mh.num_bed_pos,mh.num_gates,h.num_frames,fi->dim[3]); } if (img >= fi->number) { img = fi->number-1; MdcPrntWarn("ECAT7 overflow %d %d %d %d\n", mh.num_bed_pos,mh.num_gates,h.num_frames,fi->dim[3]); } #if MDC_TPC_SITE img = (h.num_frames - frame)*fi->dim[3]+plane; id = &fi->image[img]; #else id = &fi->image[img]; #endif /* TPC requires float buffer */ buf = MdcGetImgFLT32(fi, (Uint32)img); if (buf == NULL) { MdcFree(TPC_frame_start); return("ECAT7 Bad malloc float buf"); } type= FLT32; if (fi->diff_size) { uwidth = fi->mwidth; uheight = fi->mheight; maxbuf = MdcGetResizedImage(fi, buf, type, (Uint32)img); if (maxbuf == NULL) { MdcFree(buf); MdcFree(TPC_frame_start); return("ECAT7 Bad malloc maxbuf"); } MdcFree(buf); }else{ uwidth = id->width; uheight = id->height; maxbuf = buf; } bytes = MdcType2Bytes(type); #if MDC_TPC_SITE /* copy plane to row-column-plane orientation as scaled float data */ for (column=0; column < uwidth; column++) for (row=0; row < uheight*bytes; row+=bytes) { flt32 = *((float*)&maxbuf[column*uheight*bytes+row]); *(TPC_frame + ((plane)*uheight*uwidth + column*uheight + (row/bytes))) = flt32; } #else /* copy plane at once */ size = uwidth * uheight; TPC_frame = TPC_frame_start + (size*plane); memcpy(TPC_frame,maxbuf,size*bytes); #endif MdcFree(maxbuf); } TPC_frame = TPC_frame_start; matnum = mdc_mat_numcod(frame,1,1,0,0); MdcConvertToTPCEcat7image(fi,&ih,img-1,frame-1); ret = ecat7WriteImageMatrix(fi->ofp, matnum, &ih, TPC_frame); if (ret) { MdcFree(maxbuf); MdcFree(TPC_frame); MdcPrntWarn("ECAT7: Matrix write error code=%d\n",ret); return("ECAT7 Bad write image matrix"); } } MdcFree(TPC_frame); MdcCloseFile(fi->ofp); MdcCheckQuantitation(fi); return(NULL); } #else const char *MdcWriteECAT7(FILEINFO *fi) { return("ECAT7 Writing not yet supported"); } #endif