File: fileio_interfile.cpp

package info (click to toggle)
odin 2.0.5-8
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 9,196 kB
  • sloc: cpp: 62,638; sh: 4,541; makefile: 779
file content (246 lines) | stat: -rw-r--r-- 9,006 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
#include "fileio.h"

/////////////////////////////////////////////////////////////

struct InterfileFormat : public FileFormat {

  STD_string description() const {return "Interfile";}

  svector suffix() const{
    svector result; result.resize(2);
    result[0]="hdr";
    result[1]="interfile"; // for disambiguation
    return result;
  }

  svector dialects() const {
    svector result; result.resize(1);
    result[0]="neurostat";
    return result;
  }


  static STD_string parse_header_entry(const STD_string& header, const STD_string& key) {
    Log<FileIO> odinlog("InterfileFormat","parse_header_entry");
    STD_string result;

    STD_string afterkey=extract(header, key, "\n");
    ODINLOG(odinlog,normalDebug) << "afterkey="<< afterkey << STD_endl;

    result=replaceStr(afterkey, ":=", "", firstOccurence);
    ODINLOG(odinlog,normalDebug) << "result="<< result << STD_endl;

    if(result=="") {
      ODINLOG(odinlog,warningLog) << "Cannot find key >" << key << "<" << STD_endl;
    }

    return result;
  }


  static STD_string get_imgfilename(const STD_string& filename) {
    Log<FileIO> odinlog("InterfileFormat","get_imgfilename");
    LDRfileName fname(filename);
    STD_string imgfilename=fname.get_dirname()+SEPARATOR_STR+fname.get_basename_nosuffix()+".img";
    ODINLOG(odinlog,normalDebug) << "imgfilename="<< imgfilename << STD_endl;
    return imgfilename;
  }


  int read(Data<float,4>& data, const STD_string& filename, const FileReadOpts& opts, Protocol& prot) {
    Log<FileIO> odinlog("InterfileFormat","read");

    STD_string header;
    if(load(header, filename)) {
      ODINLOG(odinlog,errorLog) << "Cannot read header file" << STD_endl;
      return -1;
    }
    header=dos2unix(header);

    int nx=atoi(parse_header_entry(header, "matrix size [1]").c_str());
    int ny=atoi(parse_header_entry(header, "matrix size [2]").c_str());
    int nz=atoi(parse_header_entry(header, "number of slices").c_str());

    TinyVector<int, 4> shape(1,nz,ny,nx);
    ODINLOG(odinlog,normalDebug) << "shape="<< shape << STD_endl;

    LONGEST_INT nvals=product(shape);
    if(nvals<=0) {
      ODINLOG(odinlog,errorLog) << "Cannot get shape of data" << STD_endl;
      return -1;
    }


    int wordsize=atoi(parse_header_entry(header, "number of bytes per pixel").c_str());
    ODINLOG(odinlog,normalDebug) << "wordsize="<< wordsize << STD_endl;

    LONGEST_INT offset=atoi(parse_header_entry(header, "data offset in bytes").c_str());
    ODINLOG(odinlog,normalDebug) << "offset="<< offset << STD_endl;

    STD_string endianness=shrink(parse_header_entry(header, "imagedata byte order"));
    ODINLOG(odinlog,normalDebug) << "endianness="<< endianness << STD_endl;

    STD_string format=parse_header_entry(header, "number format");
    ODINLOG(odinlog,normalDebug) << "format="<< format << STD_endl;


    LONGEST_INT nbytes=wordsize*nvals;
    ODINLOG(odinlog,normalDebug) << "nbytes="<< nbytes << STD_endl;

    int fd;
    void* ptr=filemap(get_imgfilename(filename), nbytes, offset, true, fd);
    if(!ptr) return -1;


    char* ptr_byteorder=(char*)ptr; // default
    bool swapped=false;

    bool little_endian_file=(endianness=="LITTLEENDIAN");
    if(little_endian_file != little_endian_byte_order()) {

      ptr_byteorder=new char[nbytes];

      ODINLOG(odinlog,normalDebug) << "swabbing data" << STD_endl;
//      swab(ptr, ptr_byteorder, wordsize);
      char* from=(char*)ptr;
      for(int ival=0; ival<nvals; ival++) {
        for(int iw=0; iw<wordsize; iw++) {
          LONGEST_INT base=ival*wordsize;
          ptr_byteorder[base+iw]=from[base+wordsize-1-iw];
        }
      }
      swapped=true;
    }

    STD_string type;
    if(format.find("integer")!=STD_string::npos) {
      if(format.find("unsigned")!=STD_string::npos) {
        if(wordsize==1) {convert_from_ptr(data,(u8bit*)ptr_byteorder,shape);  type=TypeTraits::type2label((u8bit)0);}
        if(wordsize==2) {convert_from_ptr(data,(u16bit*)ptr_byteorder,shape); type=TypeTraits::type2label((u16bit)0);}
        if(wordsize==4) {convert_from_ptr(data,(u32bit*)ptr_byteorder,shape); type=TypeTraits::type2label((u32bit)0);}
      } else {
        if(wordsize==1) {convert_from_ptr(data,(s8bit*)ptr_byteorder,shape);  type=TypeTraits::type2label((s8bit)0);}
        if(wordsize==2) {convert_from_ptr(data,(s16bit*)ptr_byteorder,shape); type=TypeTraits::type2label((s16bit)0);}
        if(wordsize==4) {convert_from_ptr(data,(s32bit*)ptr_byteorder,shape); type=TypeTraits::type2label((s32bit)0);}
      }
    }
    if(format.find("float")!=STD_string::npos) {
      if(format.find("long")!=STD_string::npos) {convert_from_ptr(data,(double*)ptr_byteorder,shape);  type=TypeTraits::type2label((double)0);}
      else                                      {convert_from_ptr(data,(float*) ptr_byteorder,shape);  type=TypeTraits::type2label((float)0);}
    }
    prot.system.set_data_type(type);

    fileunmap(fd, ptr, nbytes, offset);

    if(swapped) delete[] ptr_byteorder;

    // ignore pixel scaling value
//    float scale=atof(parse_header_entry(header, "pixel scaling value").c_str());

    float dx=atof(parse_header_entry(header, "scaling factor (mm/pixel) [1]").c_str());
    float dy=atof(parse_header_entry(header, "scaling factor (mm/pixel) [2]").c_str());
    if(dx>0.0) prot.geometry.set_FOV(readDirection, nx*dx);
    if(dy>0.0) prot.geometry.set_FOV(phaseDirection, ny*dy);

    float slicethick=atof(parse_header_entry(header, "slice thickness (mm/pixel)").c_str());
    if(slicethick>0.0) {
      prot.geometry.set_sliceThickness(slicethick);
      prot.geometry.set_sliceDistance(slicethick);
    }

    return nz;
  }



  int write(const Data<float,4>& data, const STD_string& filename, const FileWriteOpts& opts, const Protocol& prot) {
    Log<FileIO> odinlog("InterfileFormat","write");

    Range all=Range::all();

    TinyVector<int, 4> shape(data.shape());

    STD_string header;
    header+="!data offset in bytes :=0\n";

    STD_string endian="BIGENDIAN";
    if(little_endian_byte_order()) endian="LITTLEENDIAN";
    header+="!imagedata byte order :="+endian+"\n";

    header+="!matrix size [1] :="+itos(shape(readDim))+"\n";
    header+="!matrix size [2] :="+itos(shape(phaseDim))+"\n";

    STD_string type=select_write_datatype(prot,opts);
    ODINLOG(odinlog,normalDebug) << "type=" << type << STD_endl;
    char schar=' ';
    if(type.size()) schar=type[0];
    STD_string format;
    if(schar=='u') format+="unsigned ";
    if(schar=='s') format+="signed ";
    if(type.find("bit")!=STD_string::npos) format+="integer";
    if(type=="float") format="short float";
    if(type=="double") format="long float";
    header+="!number format :="+format+"\n";
    header+="!number of bytes per pixel :="+itos(TypeTraits::typesize(type))+"\n";

    const Geometry& geo=prot.geometry;
    header+="scaling factor (mm/pixel) [1] :="+ftos(voxel_extent(geo, readDirection,  data.extent(readDim )))+"\n";
    header+="scaling factor (mm/pixel) [2] :="+ftos(voxel_extent(geo, phaseDirection, data.extent(phaseDim)))+"\n";

    header+="!pixel scaling value :=32.767\n"; // for NEUROSTAT

    header+="!number of slices :="+itos(data.extent(sliceDim))+"\n";
    header+="!slice thickness (mm/pixel) :="+ftos(prot.geometry.get_sliceDistance())+"\n";

    STD_string rlstr="0";
    if(prot.geometry.get_readVector()[readDirection]<0.0) rlstr="1";
    header+="!the right brain on the left   :="+rlstr+"\n";

    STD_string apstr="0";
    if(prot.geometry.get_phaseVector()[phaseDirection]<0.0) apstr="1";
    header+="!the anterior to the posterior :="+apstr+"\n";

    STD_string sistr="0";
    if(prot.geometry.get_sliceVector()[sliceDirection]<0.0) sistr="1";
    header+="!the superior to the inferior  :="+sistr+"\n";

    header+="!END OF HEADER:=\n";

    LDRfileName fname(filename);

    int nrep=shape(timeDim);

    Data<float,4> onefiledata(1,shape(sliceDim), shape(phaseDim), shape(readDim));

    for(int irep=0; irep<nrep; irep++) {
      STD_string onefilename=fname.get_dirname()+SEPARATOR_STR+fname.get_basename_nosuffix();
      if(nrep>1) onefilename+="_time"+itos(irep,nrep-1);
      onefilename+="."+fname.get_suffix();
      ODINLOG(odinlog,normalDebug) << "Writing " << onefilename <<  STD_endl;

      if(::write(header, onefilename)) return -1;

      onefiledata(0,all,all,all)=data(irep,all,all,all);

      if(opts.dialect=="neurostat" && type=="s16bit") { // signed datatype, but only positive values
        Data<s16bit,4> posdata;
        onefiledata.convert_to(posdata);
        posdata=posdata/2;
        posdata=posdata-min(posdata);
        if(posdata.write(get_imgfilename(onefilename))) return -1;
      } else {
        if(onefiledata.write(type, get_imgfilename(onefilename))) return -1;
      }
    }

    return data.extent(sliceDim)*data.extent(timeDim);
  }

};

//////////////////////////////////////////////////////////////

void register_interfile_format() {
  static InterfileFormat iff;
  iff.register_format();
}