1 /*
2  * The GNU Octave dicom package is Copyright Andy Buckle 2010
3  * Contact: blondandy using the sf.net system,
4  * <https://sourceforge.net/sendmessage.php?touser=1760416>
5  *
6  * Changes Copyright Kris Thielemans 2011:
7  * - support usage dicomread(struct-returned-by-dicominfo)
8  * - return image in same order as matlab
9  *
10  * The GNU Octave dicom package is free software: you can redistribute
11  * it and/or modify it under the terms of the GNU General Public
12  * License as published by the Free Software Foundation, either
13  * version 3 of the License, or (at your option) any later version.
14  *
15  * The GNU Octave dicom package is distributed in the hope that it
16  * will be useful, but WITHOUT ANY WARRANTY; without even the
17  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
18  * PURPOSE.  See the GNU General Public License for more details.
19  *
20  * Please see the file, "COPYING" for further details of GNU General
21  * Public License version 3.
22  *
23  */
24 
25 #include "octave/oct.h"
26 #include <octave/ov-struct.h>
27 
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31 
32 #include "gdcmImageReader.h"
33 using namespace gdcm;
34 
35 #define DICOM_ERR -1
36 #define DICOM_OK 0
37 
38 #define OCT_FN_NAME dicomread
39 #define QUOTED_(x) #x
40 #define QUOTED(x) QUOTED_(x)
41 
42 DEFUN_DLD (dicomread, args, nargout,
43   "-*- texinfo -*- \n\
44 @deftypefn {Loadable Function} @var{image} = dicomread (@var{filename}) \n\
45 @deftypefnx {Loadable Function} @var{image} = dicomread (@var{structure}) \n\
46 \n\
47 Load the image from a DICOM file. \n\
48 @var{filename} is a string (giving the filename).\n\
49 @var{structure} is a structure with a field @code{Filename} (such as returned by @code{dicominfo}).\n\
50 @var{image} may be two or three dimensional, depending on the content of the file. \n\
51 An integer or float matrix will be returned, the number of bits will depend on the file. \n\
52 \n\
53 @seealso{dicominfo} \n\
54 @end deftypefn \n\
55 ")
56 {
57   octave_value_list retval;  // create object to store return values
58   if ( 0 == args.length())
59     {
60       error (QUOTED(OCT_FN_NAME)": one arg required: dicom filename");
61       return retval;
62     }
63 
64   std::string filename;
65   // argument processing
66   // check if 1st argument is a string or a struct with field Filename
67   // If so, assign to filename variable, otherwise exit.
68   if (args(0).is_string ())
69     {
70       filename = args(0).string_value();
71     }
72   else
73     {
74       if (! args(0).OV_ISMAP ())
75         {
76           error(QUOTED(OCT_FN_NAME)": arg should be a filename, 1 row of chars, or a struct returned by dicominfo");
77           return retval;
78         }
79       octave_scalar_map arg0 = args(0).scalar_map_value ();
80       if (!arg0.contains("Filename"))
81         {
82           error (QUOTED(OCT_FN_NAME)": if arg is a struct, it should have the Filename field");
83           return retval;
84         }
85       octave_value tmp = arg0.getfield ("Filename");
86       filename = tmp.string_value();
87     }
88 
89 #if 0 /* TODO support 'frames' stuff, see Matlab docs for dicomread */
90   int i; // parse any additional args
91   for (i=1; i<args.length(); i++)
92     {
93       charMatrix chex = args(i).char_matrix_value();
94       if (chex.rows() != 1)
95         {
96           error (QUOTED(OCT_FN_NAME)": arg should be a string, 1 row of chars");
97           return retval;
98         }
99     }
100 #endif
101 
102   gdcm::ImageReader reader;
103   reader.SetFileName (filename.c_str());
104   if (!reader.Read())
105     {
106       error (QUOTED(OCT_FN_NAME)": Could not read DICOM file with image: %s",filename.c_str());
107       return retval;
108     }
109 
110   const gdcm::Image &image = reader.GetImage();
111 
112   const octave_idx_type ndim = image.GetNumberOfDimensions();
113   const unsigned int * const dims = image.GetDimensions();
114   // dim 0: cols (width)
115   // dim 1: rows (height)
116   // dim 2: number of frames
117 
118   dim_vector dv;
119   Array<octave_idx_type> perm_vect(dim_vector(ndim,1));
120   perm_vect(0) = 1;
121   perm_vect(1) = 0;
122 
123   // TODO check with non-square images if this needs to be dims[1],dims[0] etc
124   if( 2 == ndim )
125     {
126       //this transposes first two dimensions
127       dv = dim_vector(octave_idx_type(dims[0]), octave_idx_type(dims[1]));
128     }
129   else if (3 == ndim)
130     {
131       // should be (rows, cols, pages) in octave idiom
132       dv = dim_vector(octave_idx_type(dims[0]), octave_idx_type(dims[1]), octave_idx_type(dims[2]));
133       perm_vect(2) = 2;
134     }
135   else
136     {
137       error(QUOTED(OCT_FN_NAME)": %i dimensions. not supported: %s",(int)ndim, filename.c_str());
138       return retval;
139     }
140 
141   if (gdcm::PixelFormat::UINT32 == image.GetPixelFormat())
142     {
143       //tested
144       uint32NDArray arr(dv);
145       image.GetBuffer ((char *)arr.fortran_vec());
146       return octave_value (arr.permute(perm_vect));
147     }
148   else if ( gdcm::PixelFormat::UINT16 == image.GetPixelFormat() )
149     {
150       //tested
151       uint16NDArray arr(dv);
152       image.GetBuffer ((char *)arr.fortran_vec());
153       return octave_value (arr.permute(perm_vect));
154     }
155   else if ( gdcm::PixelFormat::UINT8 == image.GetPixelFormat() )
156     {
157       //tested
158       uint8NDArray arr(dv);
159       image.GetBuffer ((char *)arr.fortran_vec());
160       return octave_value (arr.permute(perm_vect));
161     }
162   else if ( gdcm::PixelFormat::INT8 == image.GetPixelFormat() )
163     {
164       // no example found to test
165       int8NDArray arr(dv);
166       image.GetBuffer((char *)arr.fortran_vec());
167       return octave_value(arr.permute(perm_vect));
168     }
169   else if ( gdcm::PixelFormat::INT16 == image.GetPixelFormat() )
170     {
171       // no example found to test
172       int16NDArray arr(dv);
173       image.GetBuffer((char *)arr.fortran_vec());
174       return octave_value(arr.permute(perm_vect));
175     }
176   else if ( gdcm::PixelFormat::INT32 == image.GetPixelFormat() )
177     {
178       // no example found to test
179       int32NDArray arr(dv);
180       image.GetBuffer((char *)arr.fortran_vec());
181       return octave_value(arr.permute(perm_vect));
182     }
183   else
184     {
185       octave_stdout << image.GetPixelFormat() << '\n' ;
186       error(QUOTED(OCT_FN_NAME)": pixel format not supported yet: %s", filename.c_str());
187       return retval;
188     }
189 }
190 
191 /*
192 %!shared testfile
193 %! testfile = urlwrite ( ...
194 %!   'http://sourceforge.net/p/octave/code/11601/tree/trunk/octave-forge/extra/dicom/dcm_examples/RD.15MV.DCM?format=raw', ...
195 %!   tempname() );
196 
197 %!fail ("dicomread");
198 %!fail ("dicomread (1)");
199 %!fail ("dicomread ('hopefully_a_non_existant_file')");
200 
201 %!test
202 %! rd=dicomread(testfile);
203 %! assert(rd(100,101,30),uint16(2021));
204 
205 %!test
206 %! data={};
207 %! data.Filename = testfile;
208 %! rd=dicomread(data);
209 %! assert(rd(100,101,30),uint16(2021));
210 
211 %! if exist (testfile, 'file')
212 %!   delete (testfile);
213 %! endif
214 */
215