mhdimagereader.cpp 8.79 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, all rights reserved,
schultezub's avatar
schultezub committed
6
//      Christian Schulte zu Berge <christian.szb@in.tum.de>
7
8
9
//      Chair for Computer Aided Medical Procedures
//      Technische Universitt Mnchen
//      Boltzmannstr. 3, 85748 Garching b. Mnchen, Germany
schultezub's avatar
schultezub committed
10
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 
// The licensing of this softare is not yet resolved. Until then, redistribution in source or
// binary forms outside the CAMP chair is not permitted, unless explicitly stated in legal form.
// However, the names of the original authors and the above copyright notice must retain in its
// original state in any case.
// 
// Legal disclaimer provided by the BSD license:
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 
// AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
// 
// ================================================================================================

schultezub's avatar
schultezub committed
30
31
32
33
34
#include "mhdimagereader.h"

#include <fstream>

#include "tgt/filesystem.h"
35
36
37
#include "core/datastructures/imagedata.h"
#include "core/datastructures/imagerepresentationdisk.h"
#include "core/datastructures/genericimagerepresentationlocal.h"
schultezub's avatar
schultezub committed
38
39
40
41
42
43
#include "core/tools/textfileparser.h"

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

schultezub's avatar
schultezub committed
44
45
namespace campvis {
    const std::string MhdImageReader::loggerCat_ = "CAMPVis.modules.io.MhdImageReader";
schultezub's avatar
schultezub committed
46
47
48

    MhdImageReader::MhdImageReader() 
        : AbstractProcessor()
49
50
        , p_url("url", "Image URL", "")
        , p_targetImageID("targetImageName", "Target Image ID", "MhdImageReader.output", DataNameProperty::WRITE)
51
52
        , 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
53
    {
54
55
        addProperty(&p_url);
        addProperty(&p_targetImageID);
56
57
        addProperty(&p_imageOffset);
        addProperty(&p_voxelSize);
schultezub's avatar
schultezub committed
58
59
60
61
62
63
    }

    MhdImageReader::~MhdImageReader() {

    }

64
    void MhdImageReader::process(DataContainer& data) {
schultezub's avatar
schultezub committed
65
        try {
schultezub's avatar
schultezub committed
66
            // start parsing
67
            TextFileParser tfp(p_url.getValue(), true, "=");
schultezub's avatar
schultezub committed
68
69
70
71
72
73
74
            tfp.parse<TextFileParser::ItemSeparatorLines>();

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

79
80
81
            tgt::vec3 voxelSize(1.f);
            tgt::vec3 imageOffset(0.f);

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

            // dimensionality and size
            dimensionality = tfp.getSizeT("NDims");
            if (dimensionality == 2)
96
                size = tgt::svec3(tfp.getSvec2("DimSize"), 1);
schultezub's avatar
schultezub committed
97
98
99
100
101
102
103
104
105
106
            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
107
                pt = WeaklyTypedPointer::UINT8;
schultezub's avatar
schultezub committed
108
            else if (et == "MET_CHAR")
schultezub's avatar
schultezub committed
109
                pt = WeaklyTypedPointer::INT8;
schultezub's avatar
schultezub committed
110
            else if (et == "MET_USHORT")
schultezub's avatar
schultezub committed
111
                pt = WeaklyTypedPointer::UINT16;
schultezub's avatar
schultezub committed
112
            else if (et == "MET_SHORT")
schultezub's avatar
schultezub committed
113
                pt = WeaklyTypedPointer::INT16;
schultezub's avatar
schultezub committed
114
            else if (et == "MET_UINT")
schultezub's avatar
schultezub committed
115
                pt = WeaklyTypedPointer::UINT32;
schultezub's avatar
schultezub committed
116
            else if (et == "MET_INT")
schultezub's avatar
schultezub committed
117
                pt = WeaklyTypedPointer::INT32;
schultezub's avatar
schultezub committed
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
            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
133
                e = (tfp.getBool("ElementByteOrderMSB") ? EndianHelper::IS_BIG_ENDIAN : EndianHelper::IS_LITTLE_ENDIAN);
schultezub's avatar
schultezub committed
134
135
            
            // TODO: spacing, element size, etc.
136
            if (tfp.hasKey("ElementSpacing")) {
137
138
139
140
                if (dimensionality == 3)
                    voxelSize = tfp.getVec3("ElementSpacing");
                else if (dimensionality == 2)
                    voxelSize = tgt::vec3(tfp.getVec2("ElementSpacing"), 1.f);
141
142
            }
            if (tfp.hasKey("Position")) {
143
144
145
146
                if (dimensionality == 3)
                    imageOffset = tfp.getVec3("Position");
                else if (dimensionality == 2)
                    imageOffset = tgt::vec3(tfp.getVec2("Position"), 0.f);
147
            }
schultezub's avatar
schultezub committed
148
149
150
151
152
153
            if (tfp.hasKey("VolumePosition")) {
                if (dimensionality == 3)
                    imageOffset = tfp.getVec3("VolumePosition");
                else if (dimensionality == 2)
                    imageOffset = tgt::vec3(tfp.getVec2("VolumePosition"), 0.f);
            }
154
155
156
            if (tfp.hasKey("ElementNumberOfChannels")) {
                numChannels = tfp.getSizeT("ElementNumberOfChannels");
            }
schultezub's avatar
schultezub committed
157
158

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

                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
180
            else {
181
                url = tgt::FileSystem::cleanupPath(tgt::FileSystem::dirName(p_url.getValue()) + "/" + url);
schultezub's avatar
schultezub committed
182
183
            } 

schultezub's avatar
schultezub committed
184
185
186


            // all parsing done - lets create the image:
187
            ImageData* image = new ImageData(dimensionality, size, numChannels);
188
            ImageRepresentationDisk::create(image, url, pt, offset, e);
schultezub's avatar
schultezub committed
189
            image->setMappingInformation(ImageMappingInformation(size, imageOffset + p_imageOffset.getValue(), voxelSize * p_voxelSize.getValue()));
190
191
            data.addData(p_targetImageID.getValue(), image);
            p_targetImageID.issueWrite();
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
    }
}