mhdimagereader.cpp 8.35 KB
Newer Older
1
2
// ================================================================================================
// 
schultezub's avatar
schultezub committed
3
// This file is part of the CAMPVis Software Framework.
4
// 
5
// If not explicitly stated otherwise: Copyright (C) 2012-2013, all rights reserved,
schultezub's avatar
schultezub committed
6
//      Christian Schulte zu Berge <christian.szb@in.tum.de>
7
//      Chair for Computer Aided Medical Procedures
8
9
//      Technische Universität München
//      Boltzmannstr. 3, 85748 Garching b. München, Germany
10
// 
schultezub's avatar
schultezub committed
11
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
12
// 
13
14
15
16
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 
// except in compliance with the License. You may obtain a copy of the License at
// 
// http://www.apache.org/licenses/LICENSE-2.0
17
// 
18
19
20
21
// Unless required by applicable law or agreed to in writing, software distributed under the 
// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
// either express or implied. See the License for the specific language governing permissions 
// and limitations under the License.
22
23
24
// 
// ================================================================================================

schultezub's avatar
schultezub committed
25
26
27
28
29
#include "mhdimagereader.h"

#include <fstream>

#include "tgt/filesystem.h"
30
31
32
#include "core/datastructures/imagedata.h"
#include "core/datastructures/imagerepresentationdisk.h"
#include "core/datastructures/genericimagerepresentationlocal.h"
schultezub's avatar
schultezub committed
33
34
35
36
37
38
#include "core/tools/textfileparser.h"

/*
 * Full format specification at http://www.itk.org/Wiki/MetaIO/Documentation
 */

schultezub's avatar
schultezub committed
39
40
namespace campvis {
    const std::string MhdImageReader::loggerCat_ = "CAMPVis.modules.io.MhdImageReader";
schultezub's avatar
schultezub committed
41
42

    MhdImageReader::MhdImageReader() 
43
        : AbstractImageReader()
44
45
        , p_imageOffset("ImageOffset", "Image Offset in mm", tgt::vec3(0.f), tgt::vec3(-10000.f), tgt::vec3(10000.f), tgt::vec3(0.1f))
        , p_voxelSize("VoxelSize", "Voxel Size in mm", tgt::vec3(1.f), tgt::vec3(-100.f), tgt::vec3(100.f), tgt::vec3(0.1f))
schultezub's avatar
schultezub committed
46
    {
47
        this->_ext.push_back(".mhd");
48
        this->p_targetImageID.setValue("MhdImageReader.output");
49
50
51
52
        addProperty(p_url);
        addProperty(p_targetImageID);
        addProperty(p_imageOffset);
        addProperty(p_voxelSize);
schultezub's avatar
schultezub committed
53
54
55
56
57
58
    }

    MhdImageReader::~MhdImageReader() {

    }

59
    void MhdImageReader::updateResult(DataContainer& data) {
schultezub's avatar
schultezub committed
60
        try {
schultezub's avatar
schultezub committed
61
            // start parsing
62
            TextFileParser tfp(p_url.getValue(), true, "=");
schultezub's avatar
schultezub committed
63
64
65
66
67
68
69
            tfp.parse<TextFileParser::ItemSeparatorLines>();

            // init optional parameters with sane default values
            std::string url;
            size_t dimensionality;
            tgt::svec3 size;
            WeaklyTypedPointer::BaseType pt;
70
            size_t numChannels = 1;
schultezub's avatar
schultezub committed
71
            size_t offset = 0;
schultezub's avatar
schultezub committed
72
            EndianHelper::Endianness e = EndianHelper::IS_LITTLE_ENDIAN;
schultezub's avatar
schultezub committed
73

74
75
76
            tgt::vec3 voxelSize(1.f);
            tgt::vec3 imageOffset(0.f);

schultezub's avatar
schultezub committed
77
            // image type
78
            if (tfp.hasKey("ObjectType")) {
79
80
81
82
83
84
85
86
                if (tfp.getString("ObjectType") == "Image") {
                    numChannels = 1;
                }
                else if (tfp.getString("ObjectType") == "TensorImage") {
                    numChannels = 6;
                }
                else {
                    LERROR("Error while parsing MHD header: ObjectType = Image or ObjectType = TensorImage expected");
87
88
89
90
91
                    return;
                }
            }
            else {
                LWARNING("No Key 'ObjectType' found - assuming Image.");
schultezub's avatar
schultezub committed
92
93
94
95
96
            }

            // dimensionality and size
            dimensionality = tfp.getSizeT("NDims");
            if (dimensionality == 2)
97
                size = tgt::svec3(tfp.getSvec2("DimSize"), 1);
schultezub's avatar
schultezub committed
98
99
100
101
102
103
104
105
106
107
            else if (dimensionality == 3)
                size = tfp.getSvec3("DimSize");
            else {
                LERROR("Error while parsing MHD header: Unsupported dimensionality: " << dimensionality);
                return;
            }

            // element type
            std::string et = tfp.getString("ElementType");
            if (et == "MET_UCHAR")
schultezub's avatar
schultezub committed
108
                pt = WeaklyTypedPointer::UINT8;
schultezub's avatar
schultezub committed
109
            else if (et == "MET_CHAR")
schultezub's avatar
schultezub committed
110
                pt = WeaklyTypedPointer::INT8;
schultezub's avatar
schultezub committed
111
            else if (et == "MET_USHORT")
schultezub's avatar
schultezub committed
112
                pt = WeaklyTypedPointer::UINT16;
schultezub's avatar
schultezub committed
113
            else if (et == "MET_SHORT")
schultezub's avatar
schultezub committed
114
                pt = WeaklyTypedPointer::INT16;
schultezub's avatar
schultezub committed
115
            else if (et == "MET_UINT")
schultezub's avatar
schultezub committed
116
                pt = WeaklyTypedPointer::UINT32;
schultezub's avatar
schultezub committed
117
            else if (et == "MET_INT")
schultezub's avatar
schultezub committed
118
                pt = WeaklyTypedPointer::INT32;
schultezub's avatar
schultezub committed
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
            else if (et == "MET_FLOAT")
                pt = WeaklyTypedPointer::FLOAT;
            else {
                LERROR("Error while parsing MHD header: Unsupported element type: " << et);
                return;
            }

            // further optional parameters:
            if (tfp.hasKey("HeaderSize")) {
                // header size can be -1...
                int tmp = tfp.getInt("HeaderSize");
                if (tmp >= 0)
                    offset = static_cast<int>(tmp);
            }
            if (tfp.hasKey("ElementByteOrderMSB"))
schultezub's avatar
schultezub committed
134
                e = (tfp.getBool("ElementByteOrderMSB") ? EndianHelper::IS_BIG_ENDIAN : EndianHelper::IS_LITTLE_ENDIAN);
schultezub's avatar
schultezub committed
135
136
            
            // TODO: spacing, element size, etc.
137
            if (tfp.hasKey("ElementSpacing")) {
138
139
140
141
                if (dimensionality == 3)
                    voxelSize = tfp.getVec3("ElementSpacing");
                else if (dimensionality == 2)
                    voxelSize = tgt::vec3(tfp.getVec2("ElementSpacing"), 1.f);
142
143
            }
            if (tfp.hasKey("Position")) {
144
145
146
147
                if (dimensionality == 3)
                    imageOffset = tfp.getVec3("Position");
                else if (dimensionality == 2)
                    imageOffset = tgt::vec3(tfp.getVec2("Position"), 0.f);
148
            }
schultezub's avatar
schultezub committed
149
150
151
152
153
154
            if (tfp.hasKey("VolumePosition")) {
                if (dimensionality == 3)
                    imageOffset = tfp.getVec3("VolumePosition");
                else if (dimensionality == 2)
                    imageOffset = tgt::vec3(tfp.getVec2("VolumePosition"), 0.f);
            }
155
156
157
            if (tfp.hasKey("ElementNumberOfChannels")) {
                numChannels = tfp.getSizeT("ElementNumberOfChannels");
            }
schultezub's avatar
schultezub committed
158
159

            // get raw image location:
schultezub's avatar
schultezub committed
160
            url = StringUtils::trim(tfp.getString("ElementDataFile"));
schultezub's avatar
schultezub committed
161
            if (url == "LOCAL") {
162
                url = p_url.getValue();
schultezub's avatar
schultezub committed
163
                // find beginning of local data:
164
                tgt::File* file = FileSys.open(p_url.getValue());
schultezub's avatar
schultezub committed
165
                if (!file || !file->isOpen())
166
                    throw tgt::FileException("Could not open file " + p_url.getValue() + " for reading.", p_url.getValue());
schultezub's avatar
schultezub committed
167
168
169
170
171
172
173
174
175
176
177
178
179
180

                while (!file->eof()) {
                    std::string line = StringUtils::trim(file->getLine());
                    if (line.find("ElementDataFile") == 0) {
                        offset = file->tell();
                    }
                file->close();
                delete file;
                }
            }
            else if (url == "LIST") {
                LERROR("Error while loading MHD file: Image list currently not supported.");
                return;
            }
schultezub's avatar
schultezub committed
181
            else {
182
                url = tgt::FileSystem::cleanupPath(tgt::FileSystem::dirName(p_url.getValue()) + "/" + url);
schultezub's avatar
schultezub committed
183
184
            } 

schultezub's avatar
schultezub committed
185
186
187


            // all parsing done - lets create the image:
188
            ImageData* image = new ImageData(dimensionality, size, numChannels);
189
            ImageRepresentationDisk::create(image, url, pt, offset, e);
schultezub's avatar
schultezub committed
190
            image->setMappingInformation(ImageMappingInformation(size, imageOffset + p_imageOffset.getValue(), voxelSize * p_voxelSize.getValue()));
191
            data.addData(p_targetImageID.getValue(), image);
schultezub's avatar
schultezub committed
192
193
194
        }
        catch (tgt::Exception& e) {
            LERROR("Error while parsing MHD header: " << e.what());
195
            validate(INVALID_RESULT);
schultezub's avatar
schultezub committed
196
197
198
199
            return;
        }
        catch (std::exception& e) {
            LERROR("Error while parsing MHD header: " << e.what());
200
            validate(INVALID_RESULT);
schultezub's avatar
schultezub committed
201
202
203
            return;
        }

204
        validate(INVALID_RESULT);
schultezub's avatar
schultezub committed
205
    }
206

schultezub's avatar
schultezub committed
207
}