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);