comparison Framework/Inputs/DicomPyramidInstance.cpp @ 0:4a7a53257c7d

initial commit
author Sebastien Jodogne <s.jodogne@gmail.com>
date Sat, 22 Oct 2016 21:48:33 +0200
parents
children 7a88c614be04
comparison
equal deleted inserted replaced
-1:000000000000 0:4a7a53257c7d
1 /**
2 * Orthanc - A Lightweight, RESTful DICOM Store
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
4 * Department, University Hospital of Liege, Belgium
5 *
6 * This program is free software: you can redistribute it and/or
7 * modify it under the terms of the GNU Affero General Public License
8 * as published by the Free Software Foundation, either version 3 of
9 * the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 **/
19
20
21 #include "DicomPyramidInstance.h"
22
23 #include "../Orthanc/Core/Logging.h"
24 #include "../Orthanc/Core/OrthancException.h"
25 #include "../Orthanc/Core/Toolbox.h"
26 #include "../DicomToolbox.h"
27
28 #include <cassert>
29
30 namespace OrthancWSI
31 {
32 static ImageCompression DetectImageCompression(const Json::Value& header)
33 {
34 std::string s = Orthanc::Toolbox::StripSpaces
35 (DicomToolbox::GetMandatoryStringTag(header, "TransferSyntaxUID"));
36
37 if (s == "1.2.840.10008.1.2" ||
38 s == "1.2.840.10008.1.2.1")
39 {
40 return ImageCompression_None;
41 }
42 else if (s == "1.2.840.10008.1.2.4.50")
43 {
44 return ImageCompression_Jpeg;
45 }
46 else if (s == "1.2.840.10008.1.2.4.90" ||
47 s == "1.2.840.10008.1.2.4.91")
48 {
49 return ImageCompression_Jpeg2000;
50 }
51 else
52 {
53 LOG(ERROR) << "Unsupported transfer syntax: " << s;
54 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
55 }
56 }
57
58
59 static Orthanc::PixelFormat DetectPixelFormat(const Json::Value& dicom)
60 {
61 std::string photometric = Orthanc::Toolbox::StripSpaces
62 (DicomToolbox::GetMandatoryStringTag(dicom, "PhotometricInterpretation"));
63
64 if (photometric == "PALETTE")
65 {
66 LOG(ERROR) << "Unsupported photometric interpretation: " << photometric;
67 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
68 }
69
70 unsigned int bitsStored = DicomToolbox::GetUnsignedIntegerTag(dicom, "BitsStored");
71 unsigned int samplesPerPixel = DicomToolbox::GetUnsignedIntegerTag(dicom, "SamplesPerPixel");
72 bool isSigned = (DicomToolbox::GetUnsignedIntegerTag(dicom, "PixelRepresentation") != 0);
73
74 if (bitsStored == 8 &&
75 samplesPerPixel == 1 &&
76 !isSigned)
77 {
78 return Orthanc::PixelFormat_Grayscale8;
79 }
80 else if (bitsStored == 8 &&
81 samplesPerPixel == 3 &&
82 !isSigned)
83 {
84 return Orthanc::PixelFormat_RGB24;
85 }
86 else
87 {
88 LOG(ERROR) << "Unsupported pixel format";
89 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
90 }
91 }
92
93
94 DicomPyramidInstance::DicomPyramidInstance(IOrthancConnection& orthanc,
95 const std::string& instanceId) :
96 instanceId_(instanceId)
97 {
98 Json::Value dicom, header;
99 IOrthancConnection::RestApiGet(dicom, orthanc, "/instances/" + instanceId + "/tags?simplify");
100 IOrthancConnection::RestApiGet(header, orthanc, "/instances/" + instanceId + "/header?simplify");
101
102 if (DicomToolbox::GetMandatoryStringTag(dicom, "SOPClassUID") != "1.2.840.10008.5.1.4.1.1.77.1.6" ||
103 DicomToolbox::GetMandatoryStringTag(dicom, "Modality") != "SM")
104 {
105 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
106 }
107
108 compression_ = DetectImageCompression(header);
109 format_ = DetectPixelFormat(dicom);
110 tileWidth_ = DicomToolbox::GetUnsignedIntegerTag(dicom, "Columns");
111 tileHeight_ = DicomToolbox::GetUnsignedIntegerTag(dicom, "Rows");
112 totalWidth_ = DicomToolbox::GetUnsignedIntegerTag(dicom, "TotalPixelMatrixColumns");
113 totalHeight_ = DicomToolbox::GetUnsignedIntegerTag(dicom, "TotalPixelMatrixRows");
114
115 const Json::Value& frames = DicomToolbox::GetSequenceTag(dicom, "PerFrameFunctionalGroupsSequence");
116
117 if (frames.size() != DicomToolbox::GetUnsignedIntegerTag(dicom, "NumberOfFrames"))
118 {
119 LOG(ERROR) << "Mismatch between the number of frames in instance: " << instanceId;
120 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
121 }
122
123 frames_.resize(frames.size());
124
125 for (Json::Value::ArrayIndex i = 0; i < frames.size(); i++)
126 {
127 const Json::Value& frame = DicomToolbox::GetSequenceTag(frames[i], "PlanePositionSlideSequence");
128 if (frame.size() != 1)
129 {
130 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
131 }
132
133 // "-1", because coordinates are shifted by 1 in DICOM
134 int xx = DicomToolbox::GetIntegerTag(frame[0], "ColumnPositionInTotalImagePixelMatrix") - 1;
135 int yy = DicomToolbox::GetIntegerTag(frame[0], "RowPositionInTotalImagePixelMatrix") - 1;
136
137 unsigned int x = static_cast<unsigned int>(xx);
138 unsigned int y = static_cast<unsigned int>(yy);
139
140 if (xx < 0 ||
141 yy < 0 ||
142 x % tileWidth_ != 0 ||
143 y % tileHeight_ != 0 ||
144 x >= totalWidth_ ||
145 y >= totalHeight_)
146 {
147 LOG(ERROR) << "Frame " << i << " with unexpected tile location ("
148 << x << "," << y << ") in instance: " << instanceId;
149 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
150 }
151
152 frames_[i].first = x / tileWidth_;
153 frames_[i].second = y / tileHeight_;
154 }
155 }
156
157
158 unsigned int DicomPyramidInstance::GetFrameLocationX(size_t frame) const
159 {
160 assert(frame < frames_.size());
161 return frames_[frame].first;
162 }
163
164
165 unsigned int DicomPyramidInstance::GetFrameLocationY(size_t frame) const
166 {
167 assert(frame < frames_.size());
168 return frames_[frame].second;
169 }
170 }