comparison Framework/DicomizerParameters.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 "DicomizerParameters.h"
22
23 #include "Messaging/FolderTarget.h"
24 #include "Messaging/OrthancTarget.h"
25
26 #include "Orthanc/Core/OrthancException.h"
27
28 #include <boost/thread.hpp>
29 #include <boost/lexical_cast.hpp>
30
31 namespace OrthancWSI
32 {
33 static unsigned int ChooseNumberOfThreads()
34 {
35 unsigned int nthreads = boost::thread::hardware_concurrency();
36
37 if (nthreads % 2 == 0)
38 {
39 nthreads = nthreads / 2;
40 }
41 else
42 {
43 nthreads = nthreads / 2 + 1;
44 }
45
46 if (nthreads == 0)
47 {
48 nthreads = 1;
49 }
50
51 return nthreads;
52 }
53
54
55 DicomizerParameters::DicomizerParameters()
56 {
57 safetyCheck_ = false;
58 repaintBackground_ = false;
59 backgroundColor_[0] = 255;
60 backgroundColor_[1] = 255;
61 backgroundColor_[2] = 255;
62 targetCompression_ = ImageCompression_Jpeg;
63 hasTargetTileSize_ = false;
64 threadsCount_ = ChooseNumberOfThreads();
65 maxDicomFileSize_ = 10 * 1024 * 1024; // 10MB
66 reconstructPyramid_ = false;
67 pyramidLevelsCount_ = 0;
68 pyramidLowerLevelsCount_ = 0;
69 smooth_ = false;
70 jpegQuality_ = 90;
71 forceReencode_ = false;
72 opticalPath_ = OpticalPath_Brightfield;
73 }
74
75
76 void DicomizerParameters::SetBackgroundColor(uint8_t red,
77 uint8_t green,
78 uint8_t blue)
79 {
80 repaintBackground_ = true;
81 backgroundColor_[0] = red;
82 backgroundColor_[1] = green;
83 backgroundColor_[2] = blue;
84 }
85
86
87 void DicomizerParameters::SetTargetTileSize(unsigned int width,
88 unsigned int height)
89 {
90 hasTargetTileSize_ = true;
91 targetTileWidth_ = width;
92 targetTileHeight_ = height;
93 }
94
95
96 unsigned int DicomizerParameters::GetTargetTileWidth(unsigned int defaultWidth) const
97 {
98 if (hasTargetTileSize_ &&
99 targetTileWidth_ != 0)
100 {
101 return targetTileWidth_;
102 }
103 else
104 {
105 return defaultWidth;
106 }
107 }
108
109
110 unsigned int DicomizerParameters::GetTargetTileHeight(unsigned int defaultHeight) const
111 {
112 if (hasTargetTileSize_ &&
113 targetTileHeight_ != 0)
114 {
115 return targetTileHeight_;
116 }
117 else
118 {
119 return defaultHeight;
120 }
121 }
122
123
124 void DicomizerParameters::SetThreadsCount(unsigned int threads)
125 {
126 if (threads == 0)
127 {
128 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
129 }
130
131 threadsCount_ = threads;
132 }
133
134
135 void DicomizerParameters::SetDicomMaxFileSize(unsigned int size)
136 {
137 if (size <= 1024)
138 {
139 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
140 }
141
142 maxDicomFileSize_ = size;
143 }
144
145
146 void DicomizerParameters::SetPyramidLevelsCount(unsigned int count)
147 {
148 if (count <= 0)
149 {
150 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
151 }
152
153 pyramidLevelsCount_ = count;
154 }
155
156
157 unsigned int DicomizerParameters::GetPyramidLevelsCount(const IPyramidWriter& target,
158 const ITiledPyramid& source) const
159 {
160 if (!reconstructPyramid_)
161 {
162 // Only makes sense if reconstructing the pyramid
163 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
164 }
165
166 if (pyramidLevelsCount_ != 0)
167 {
168 return pyramidLevelsCount_;
169 }
170
171 // By default, the number of levels for the pyramid is taken so that
172 // the upper level is reduced either to 1 column of tiles, or to 1
173 // row of tiles.
174 unsigned int totalWidth = source.GetLevelWidth(0);
175 unsigned int totalHeight = source.GetLevelHeight(0);
176
177 unsigned int countLevels = 1;
178 for (;;)
179 {
180 unsigned int zoom = 1 << (countLevels - 1);
181
182 if (CeilingDivision(totalWidth, zoom) <= target.GetTileWidth() ||
183 CeilingDivision(totalHeight, zoom) <= target.GetTileHeight())
184 {
185 break;
186 }
187
188 countLevels += 1;
189 }
190
191 return countLevels;
192 }
193
194
195 void DicomizerParameters::SetPyramidLowerLevelsCount(unsigned int count)
196 {
197 if (count <= 0)
198 {
199 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
200 }
201
202 pyramidLowerLevelsCount_ = count;
203 }
204
205
206 unsigned int DicomizerParameters::GetPyramidLowerLevelsCount(const IPyramidWriter& target,
207 const ITiledPyramid& source) const
208 {
209 if (!reconstructPyramid_)
210 {
211 // Only makes sense if reconstructing the pyramid
212 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
213 }
214
215 if (pyramidLowerLevelsCount_ != 0)
216 {
217 return pyramidLowerLevelsCount_;
218 }
219
220 unsigned int fullNumberOfTiles = (
221 CeilingDivision(source.GetLevelWidth(0), source.GetTileWidth()) *
222 CeilingDivision(source.GetLevelHeight(0), source.GetTileHeight()));
223
224 // By default, the number of lower levels in the pyramid is chosen
225 // as a compromise between the number of tasks (there should not be
226 // too few tasks, otherwise multithreading would not be efficient)
227 // and memory consumption (maximum 64MB of RAM due to the decoding
228 // of the tiles of the source image per thread: cf. PyramidReader).
229 unsigned int result = 1;
230 for (;;)
231 {
232 unsigned int zoom = 1 << (result - 1);
233 unsigned int numberOfTiles = CeilingDivision(fullNumberOfTiles, zoom * zoom);
234
235 if (result + 1 > target.GetLevelCount() ||
236 numberOfTiles < 4 * GetThreadsCount() ||
237 zoom * target.GetTileWidth() > 4096 ||
238 zoom * target.GetTileHeight() > 4096)
239 {
240 break;
241 }
242
243 result += 1;
244 }
245
246 return result - 1;
247 }
248
249
250 void DicomizerParameters::SetJpegQuality(int quality)
251 {
252 if (quality <= 0 ||
253 quality > 100)
254 {
255 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
256 }
257
258 jpegQuality_ = quality;
259 }
260
261
262 IFileTarget* DicomizerParameters::CreateTarget() const
263 {
264 if (folder_.empty() ||
265 folderPattern_.empty())
266 {
267 return new OrthancTarget(orthanc_);
268 }
269 else
270 {
271 return new FolderTarget(folder_ + "/" + folderPattern_);
272 }
273 }
274 }