Mercurial > hg > minc-tools
changeset 2190:3039df28a422
Latest changes ported from 1.0 branch
author | bert <bert> |
---|---|
date | Fri, 26 Aug 2005 21:25:54 +0000 |
parents | b6517dede232 |
children | 5118db14bd54 |
files | conversion/dcm2mnc/acr_element_defs.h conversion/dcm2mnc/dcm2mnc.c conversion/dcm2mnc/dcm2mnc.h conversion/dcm2mnc/dcm2mnc.man1 conversion/dcm2mnc/dicom_read.c conversion/dcm2mnc/dicom_to_minc.c conversion/dcm2mnc/minc_file.c |
diffstat | 7 files changed, 205 insertions(+), 52 deletions(-) [+] |
line wrap: on
line diff
--- a/conversion/dcm2mnc/acr_element_defs.h +++ b/conversion/dcm2mnc/acr_element_defs.h @@ -118,6 +118,8 @@ 0x0020, 0x0035, DS); GLOBAL_ELEMENT(ACR_Image_orientation_patient, 0x0020, 0x0037, DS); +GLOBAL_ELEMENT(ACR_Number_of_temporal_positions, + 0x0020, 0x0105, IS); GLOBAL_ELEMENT(ACR_Acquisitions_in_series, 0x0020, 0x1001, IS); GLOBAL_ELEMENT(ACR_Images_in_acquisition, 0x0020, 0x1002, IS); GLOBAL_ELEMENT(ACR_Slice_location, 0x0020, 0x1041, DS);
--- a/conversion/dcm2mnc/dcm2mnc.c +++ b/conversion/dcm2mnc/dcm2mnc.c @@ -5,8 +5,14 @@ @CREATED : June 2001 (Rick Hoge) @MODIFIED : * $Log: dcm2mnc.c,v $ - * Revision 1.16 2005-07-14 19:00:30 bert - * Changes ported from 1.X branch + * Revision 1.17 2005-08-26 21:25:54 bert + * Latest changes ported from 1.0 branch + * + * Revision 1.14.2.10 2005/08/18 18:17:36 bert + * Add -usecoordinates option + * + * Revision 1.14.2.9 2005/07/22 20:03:16 bert + * Minor change to consider sequence name when finding series boundaries * * Revision 1.14.2.8 2005/07/12 16:01:14 bert * Sort on filename if all else fails @@ -113,7 +119,7 @@ * ---------------------------------------------------------------------------- */ -static const char rcsid[]="$Header: /private-cvsroot/minc/conversion/dcm2mnc/dcm2mnc.c,v 1.16 2005-07-14 19:00:30 bert Exp $"; +static const char rcsid[]="$Header: /private-cvsroot/minc/conversion/dcm2mnc/dcm2mnc.c,v 1.17 2005-08-26 21:25:54 bert Exp $"; #define GLOBAL_ELEMENT_DEFINITION /* To define elements */ #include "dcm2mnc.h" @@ -207,6 +213,11 @@ (char *)&G.dirname_format, "Set format for output directory name."}, + {"-usecoordinates", + ARGV_CONSTANT, + (char *) TRUE, + (char *) &G.prefer_coords, + "Derive step value from coordinates rather than slice spacing."}, {NULL, ARGV_END, NULL, NULL, NULL} }; @@ -234,6 +245,7 @@ G.dirname_format = NULL; G.minc_history = time_stamp(argc, argv); /* Create minc history string */ + G.prefer_coords = FALSE; G.pname = argv[0]; /* get program name */ @@ -643,6 +655,7 @@ int cur_dyn_scan_number; string_t cur_patient_name; string_t cur_patient_id; + string_t cur_sequence_name; int exit_status; char *output_file_name; string_t file_prefix; @@ -723,6 +736,7 @@ strcpy(cur_patient_name, di_ptr[ifile]->patient_name); strcpy(cur_patient_id, di_ptr[ifile]->patient_id); + strcpy(cur_sequence_name, di_ptr[ifile]->sequence_name); used_file[ifile] = TRUE; } @@ -738,7 +752,8 @@ (di_ptr[ifile]->dyn_scan_number == cur_dyn_scan_number || !G.splitDynScan) && !strcmp(cur_patient_name, di_ptr[ifile]->patient_name) && - !strcmp(cur_patient_id, di_ptr[ifile]->patient_id)) { + !strcmp(cur_patient_id, di_ptr[ifile]->patient_id) && + !strcmp(cur_sequence_name, di_ptr[ifile]->sequence_name)) { used_file[ifile] = TRUE; }
--- a/conversion/dcm2mnc/dcm2mnc.h +++ b/conversion/dcm2mnc/dcm2mnc.h @@ -7,8 +7,11 @@ @MODIFIED : * $Log: dcm2mnc.h,v $ - * Revision 1.12 2005-07-14 19:00:30 bert - * Changes ported from 1.X branch + * Revision 1.13 2005-08-26 21:25:54 bert + * Latest changes ported from 1.0 branch + * + * Revision 1.10.2.4 2005/08/18 18:17:36 bert + * Add -usecoordinates option * * Revision 1.10.2.3 2005/06/09 20:46:11 bert * Fairly major fixes to use integers for all arguments, add filename_format and dirname_format to global options, always include math.h, and defined OPTS_NO_RESCALE for testing converter without ICV @@ -249,6 +252,9 @@ int use_stdin; char * filename_format; char * dirname_format; + int prefer_coords; /* In event of slice thickness conflict, + use the coordinate information rather + than the slice thickness or spacing. */ }; /* Values for options flags */
--- a/conversion/dcm2mnc/dcm2mnc.man1 +++ b/conversion/dcm2mnc/dcm2mnc.man1 @@ -1,4 +1,4 @@ -.TH dcm2mnc 1 "May 03 2005" "$Revision: 1.3 $" "" +.TH dcm2mnc 1 "May 03 2005" "$Revision: 1.4 $" "" .SH NAME .B dcm2mnc @@ -152,6 +152,13 @@ interpreted by someone familiar with both this program and the DICOM standard. .TP +.BI -usecoordinates +This option requests that the conversion rely on the slice coordinates +rather than the standard DICOM fields for slice thickness and spacing. +It is useful if for some reason the standard DICOM fields for +slice thickness and spacing are incorrect. + +.TP .BI -opts " <value>" This is a private option intended only for debugging purposes. Please avoid using it. @@ -230,8 +237,7 @@ .SH AUTHORS -Peter Neelin -Richard D. Hoge +Peter Neelin and Richard D. Hoge Please direct all complaints and inquiries to Robert Vincent (bert@bic.mni.mcgill.ca)
--- a/conversion/dcm2mnc/dicom_read.c +++ b/conversion/dcm2mnc/dicom_read.c @@ -7,8 +7,14 @@ @CREATED : January 28, 1997 (Peter Neelin) @MODIFIED : * $Log: dicom_read.c,v $ - * Revision 1.17 2005-07-14 19:00:30 bert - * Changes ported from 1.X branch + * Revision 1.18 2005-08-26 21:25:54 bert + * Latest changes ported from 1.0 branch + * + * Revision 1.16.2.5 2005/08/26 03:50:16 bert + * Use ACR_Number_of_temporal_positions for number of time slices + * + * Revision 1.16.2.4 2005/08/18 16:38:43 bert + * Minor updates for dealing w/older numaris data * * Revision 1.16.2.3 2005/06/20 22:03:01 bert * Add functions for traversing DICOM sequences and recursively hunting for needed fields. @@ -198,6 +204,14 @@ return (int) floor(x); } +int +is_numaris3(Acr_Group group_list) +{ + return (strstr(acr_find_string(group_list, ACR_Manufacturer, ""), + "SIEMENS") != NULL && + strstr(acr_find_string(group_list, ACR_Software_versions, ""), + "VB33") != NULL); +} /* ----------------------------- MNI Header ----------------------------------- @NAME : init_general_info @@ -300,8 +314,13 @@ /* Look for the official time slice count field first. */ def_val = acr_find_int(group_list, + ACR_Number_of_temporal_positions, + 0); + + def_val = acr_find_int(group_list, ACR_Number_of_time_slices, - 0); + def_val); + } gi_ptr->max_size[imri] = acr_find_int(group_list, mri_total_list[imri], @@ -1150,6 +1169,7 @@ } found_coordinate = FALSE; +#if 0 /* TODO: For now this appears to be necessary. In cases I don't fully * understand, the Siemens Numaris 3 DICOM image orientation does not * give the correct direction cosines, so we use the nonstandard Siemens @@ -1161,8 +1181,7 @@ * files, with a version string that looks like VB33 (VB33D, VB33G, etc.) * Later versions do not seem to use these fields. */ - if (strstr(acr_find_string(group_list, ACR_Manufacturer, ""), "SIEMENS") && - strstr(acr_find_string(group_list, ACR_Software_versions, ""), "VB33")) { + if (is_numaris3(group_list)) { Acr_Element_Id dircos_elid[VOL_NDIMS]; /* Set direction cosine element ids. Note that the reversal of @@ -1192,6 +1211,7 @@ found_dircos[ivolume] = TRUE; } } +#endif /* If we did not find the Siemens proprietary image vectors, try * the DICOM standard image position.
--- a/conversion/dcm2mnc/dicom_to_minc.c +++ b/conversion/dcm2mnc/dicom_to_minc.c @@ -8,8 +8,14 @@ @CREATED : January 28, 1997 (Peter Neelin) @MODIFIED : * $Log: dicom_to_minc.c,v $ - * Revision 1.14 2005-07-14 19:00:30 bert - * Changes ported from 1.X branch + * Revision 1.15 2005-08-26 21:25:54 bert + * Latest changes ported from 1.0 branch + * + * Revision 1.13.2.5 2005/08/18 18:18:35 bert + * Implement the -usecoordinates option, also some minor cleanup and fixes for some warning messages. + * + * Revision 1.13.2.4 2005/08/18 16:38:44 bert + * Minor updates for dealing w/older numaris data * * Revision 1.13.2.3 2005/07/14 16:47:55 bert * Handle additional classes of Numa3 mosaics by using the Siemens 'base raw matrix size' element @@ -162,7 +168,7 @@ provided "as is" without express or implied warranty. ---------------------------------------------------------------------------- */ -static const char rcsid[] = "$Header: /private-cvsroot/minc/conversion/dcm2mnc/dicom_to_minc.c,v 1.14 2005-07-14 19:00:30 bert Exp $"; +static const char rcsid[] = "$Header: /private-cvsroot/minc/conversion/dcm2mnc/dicom_to_minc.c,v 1.15 2005-08-26 21:25:54 bert Exp $"; #include "dcm2mnc.h" const char *World_Names[WORLD_NDIMS] = { "X", "Y", "Z" }; @@ -1040,6 +1046,64 @@ /* TODO: should also correct the image position here? */ } + + /* Hacks for specific numaris3 sequences. + */ + if (is_numaris3(group_list)) { + int tmp; + + str_ptr = acr_find_string(group_list, ACR_Sequence_name, ""); + + /* This first hack is for Sebastian's Numaris-3 DTI scans. + */ + if (!strcmp(str_ptr, "ep_d33a ")) { + /* Numaris-3 DTI scan. Individual scans are identified by + * echo number. We need to change echos to time. + */ + tmp = acr_find_int(group_list, SPI_Number_of_echoes, 1); + acr_insert_numeric(&group_list, SPI_Number_of_echoes, 1); + + element = acr_find_group_element(group_list, + ACR_Acquisitions_in_series); + if (element != NULL) { + int grp_id = acr_get_element_group(element); + int elm_id = acr_get_element_element(element); + acr_group_remove_element(acr_find_group(group_list, grp_id), + elm_id); + } + acr_insert_short(&group_list, ACR_Number_of_time_slices, tmp); + + tmp = acr_find_int(group_list, ACR_Echo_number, 0); + acr_insert_numeric(&group_list, ACR_Echo_number, 1); + acr_insert_numeric(&group_list, ACR_Frame_reference_time, + tmp * 1000); + + /* Just use defaults for these values. */ + acr_insert_numeric(&group_list, ACR_Actual_frame_duration, 1000); + } + + /* An additional hack required for Sebastian's Numaris-3 FMRI scans. + */ + if (!strcmp(str_ptr, "ep_fid")) { + /* Numaris-3 FMRI scan. Each time slice uses a different + * series number!! + */ + tmp = acr_find_int(group_list, ACR_Series_time, 0); + acr_insert_numeric(&group_list, ACR_Series, tmp); + + tmp = acr_find_int(group_list, ACR_Acquisitions_in_series, 0); + acr_insert_short(&group_list, ACR_Number_of_time_slices, tmp); + + element = acr_find_group_element(group_list, + ACR_Acquisitions_in_series); + if (element != NULL) { + int grp_id = acr_get_element_group(element); + int elm_id = acr_get_element_element(element); + acr_group_remove_element(acr_find_group(group_list, grp_id), + elm_id); + } + } + } return (group_list); } @@ -1484,17 +1548,22 @@ * many PET scanners produce irregular timings. */ if (nvalues >= 2 && imri == SLICE) { + /* Calculate the spacing between the first and second slice. + */ double delta = (gi_ptr->coordinates[imri][1] - gi_ptr->coordinates[imri][0]); for (i = 1; i < nvalues; i++) { + /* Check that each successive slice has roughly the same + * spacing, to within 2 percent of the initial delta. + */ if (!fcmp(delta, (gi_ptr->coordinates[imri][i] - gi_ptr->coordinates[imri][i - 1]), - 1.0e-3)) { - printf("WARNING: Missing data for %s dimension\n", - Mri_Names[imri]); - printf(" slice # %d %.12f %.12f\n", + 2.0 * (delta / 100.0))) { + /* TODO: Perhaps this message could be improved?? */ + printf("WARNING: Missing %s data at index %d, %g %g\n", + Mri_Names[imri], i, delta, (gi_ptr->coordinates[imri][i] - @@ -1523,11 +1592,16 @@ * assumed value is the default (1.0), we adopt the * calculated value. */ - if (!fcmp(dbl_tmp1, dbl_tmp2, 2.0e-5)) { - printf("WARNING: calculated slice width (%.10f) disagrees with file's slice width (%.10f)\n", dbl_tmp2, dbl_tmp1); - if (dbl_tmp1 == 1.0) { + if (!fcmp(dbl_tmp1, dbl_tmp2, (dbl_tmp1 / 1000.0))) { + printf("WARNING: Coordinate spacing (%g) differs from DICOM slice spacing (%g)\n", dbl_tmp2, dbl_tmp1); + if (!G.prefer_coords) { + printf(" (perhaps you should consider the -usecoordinates option)\n"); + } + if (dbl_tmp1 == 1.0 || G.prefer_coords) { gi_ptr->step[gi_ptr->slice_world] = dbl_tmp2; } + printf(" Using %g for the slice spacing value.\n", + gi_ptr->step[gi_ptr->slice_world]); } } @@ -1781,9 +1855,6 @@ memcpy(dircos[VCOLUMN], RowColVec, sizeof(*RowColVec) * WORLD_NDIMS); memcpy(dircos[VROW], &RowColVec[3], sizeof(*RowColVec) * WORLD_NDIMS); - convert_dicom_coordinate(dircos[VROW]); - convert_dicom_coordinate(dircos[VCOLUMN]); - /* compute slice normal as cross product of row/column unit vectors * (should check for unit length?) */ @@ -1815,7 +1886,6 @@ mi_ptr->position[XCOORD] = mi_ptr->position[YCOORD] = mi_ptr->position[ZCOORD] = 0.0; } - convert_dicom_coordinate(mi_ptr->position); if (G.Debug >= HI_LOGGING) { printf(" step %.3f %.3f %.3f pos %.3f %.3f %.3f normal %.3f,%.3f,%.3f\n", @@ -1832,25 +1902,33 @@ } if (mi_ptr->mosaic_seq != MOSAIC_SEQ_INTERLEAVED) { - /* Numaris 4 mosaic correction: - * - position given is edge of huge slice constructed as if - * real slice was at center of mosaic - * - mi_ptr->big[0,1] are number of columns and rows of mosaic - * - mi_ptr->size[0,1] are number of columns and rows of sub-image - */ - - for (i = 0; i < WORLD_NDIMS; i++) { - /* Correct offset from mosaic Center + if (is_numaris3(group_list)) { + for (i = 0; i < WORLD_NDIMS; i++) { + mi_ptr->position[i] -= + (double) (mi_ptr->sub_images-1) * mi_ptr->step[i]; + } + } + else { + /* Numaris 4 mosaic correction: + * - position given is edge of huge slice constructed as if + * real slice was at center of mosaic + * - mi_ptr->big[0,1] are number of columns and rows of mosaic + * - mi_ptr->size[0,1] are number of columns and rows of sub-image */ - mi_ptr->position[i] += (double) - ((dircos[VCOLUMN][i] * mi_ptr->big[0] * pixel_spacing[0]/2.0) + - (dircos[VROW][i] * mi_ptr->big[1] * pixel_spacing[1]/2)); - - /* Move from center to corner of slice - */ - mi_ptr->position[i] -= - ((dircos[VCOLUMN][i] * mi_ptr->size[0] * pixel_spacing[0]/2.0) + - (dircos[VROW][i] * mi_ptr->size[1] * pixel_spacing[1]/2.0)); + + for (i = 0; i < WORLD_NDIMS; i++) { + /* Correct offset from mosaic Center + */ + mi_ptr->position[i] += (double) + ((dircos[VCOLUMN][i] * mi_ptr->big[0] * pixel_spacing[0]/2.0) + + (dircos[VROW][i] * mi_ptr->big[1] * pixel_spacing[1]/2)); + + /* Move from center to corner of slice + */ + mi_ptr->position[i] -= + ((dircos[VCOLUMN][i] * mi_ptr->size[0] * pixel_spacing[0]/2.0) + + (dircos[VROW][i] * mi_ptr->size[1] * pixel_spacing[1]/2.0)); + } } } @@ -1995,6 +2073,12 @@ break; } +#if 0 + if (is_numaris3(group_list)) { + islice = mi_ptr->slice_count - islice - 1; + } +#endif + /* Check the image number */ if ((iimage < 0) || (iimage > mi_ptr->sub_images)) { @@ -2027,6 +2111,12 @@ position[XCOORD], position[YCOORD], position[ZCOORD]); acr_insert_string(&group_list, ACR_Image_position_patient, string); + acr_insert_string(&group_list, SPI_Image_position, string); + + /* HMM - is this necessary?? */ + if (is_numaris3(group_list)) { + update_coordinate_info(group_list); + } if (G.Debug >= HI_LOGGING) { printf(" position %s\n", string);
--- a/conversion/dcm2mnc/minc_file.c +++ b/conversion/dcm2mnc/minc_file.c @@ -7,8 +7,14 @@ @CREATED : January 28, 1997 (Peter Neelin) @MODIFIED : * $Log: minc_file.c,v $ - * Revision 1.9 2005-07-14 19:00:30 bert - * Changes ported from 1.X branch + * Revision 1.10 2005-08-26 21:25:54 bert + * Latest changes ported from 1.0 branch + * + * Revision 1.6.2.7 2005/08/18 18:17:55 bert + * Fix up one warning message + * + * Revision 1.6.2.6 2005/07/22 20:02:45 bert + * 1) Save start value for time coordinate. 2) Don't append fractional seconds to time in filename * * Revision 1.6.2.5 2005/06/20 21:59:33 bert * Add strfminc() to allow arbitrary output file naming, implement OPTS_NO_RESCALE debug option, fix rounding @@ -119,7 +125,7 @@ software for any purpose. It is provided "as is" without express or implied warranty. ---------------------------------------------------------------------------- */ -static const char rcsid[] = "$Header: /private-cvsroot/minc/conversion/dcm2mnc/minc_file.c,v 1.9 2005-07-14 19:00:30 bert Exp $"; +static const char rcsid[] = "$Header: /private-cvsroot/minc/conversion/dcm2mnc/minc_file.c,v 1.10 2005-08-26 21:25:54 bert Exp $"; #include "dcm2mnc.h" @@ -180,8 +186,15 @@ tmp_ptr = tmp_str; break; case 'T': - string_to_filename(gi_ptr->patient.reg_time, - tmp_str, sizeof(tmp_str)); + strcpy(tmp_str, gi_ptr->patient.reg_time); + tmp_ptr = tmp_str; + while (*tmp_ptr != '\0') { + if (!isdigit(*tmp_ptr)) { + *tmp_ptr = '\0'; + break; + } + tmp_ptr++; + } tmp_ptr = tmp_str; break; case 'A': @@ -454,7 +467,7 @@ avg = sum / length; /* compute mean */ if (step != 0.0 && avg != step) { - printf("WARNING: Sample width %f not equal to average delta %f\n", + printf("WARNING: Sample width (%g) not equal to average delta (%g)\n", step, avg); } @@ -499,6 +512,7 @@ * The step should always equal the average spacing of the dimension. */ miattputdbl(mincid, varid, MIstep, step); + miattputdbl(mincid, varid, MIstart, gi_ptr->coordinates[imri][0]); if (regular) { miattputstr(mincid, varid, MIspacing, MI_REGULAR);