Mercurial > hg > orthanc-wsi
annotate Applications/Dicomizer.cpp @ 221:dbcf9ad44a70
upgrade to libtiff 4.2.0
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 12 Jan 2021 18:42:04 +0100 |
parents | 20bc074ec19a |
children | 443f219a68fd |
rev | line source |
---|---|
0 | 1 /** |
2 * Orthanc - A Lightweight, RESTful DICOM Store | |
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | |
4 * Department, University Hospital of Liege, Belgium | |
214
1e864138f0da
upgrade to year 2021
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
213
diff
changeset
|
5 * Copyright (C) 2017-2021 Osimis S.A., Belgium |
0 | 6 * |
7 * This program is free software: you can redistribute it and/or | |
8 * modify it under the terms of the GNU Affero General Public License | |
9 * as published by the Free Software Foundation, either version 3 of | |
10 * the License, or (at your option) any later version. | |
11 * | |
12 * This program is distributed in the hope that it will be useful, but | |
13 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 * Affero General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU Affero General Public License | |
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
19 **/ | |
20 | |
21 | |
22 #include "../Framework/Algorithms/ReconstructPyramidCommand.h" | |
23 #include "../Framework/Algorithms/TranscodeTileCommand.h" | |
24 #include "../Framework/DicomToolbox.h" | |
25 #include "../Framework/DicomizerParameters.h" | |
217
20bc074ec19a
Viewer can display DICOM pyramids whose tile sizes vary across levels
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
214
diff
changeset
|
26 #include "../Framework/ImageToolbox.h" |
0 | 27 #include "../Framework/ImagedVolumeParameters.h" |
28 #include "../Framework/Inputs/HierarchicalTiff.h" | |
29 #include "../Framework/Inputs/OpenSlidePyramid.h" | |
30 #include "../Framework/Inputs/TiledJpegImage.h" | |
31 #include "../Framework/Inputs/TiledPngImage.h" | |
32 #include "../Framework/Inputs/TiledPyramidStatistics.h" | |
151 | 33 #include "../Framework/MultiThreading/BagOfTasksProcessor.h" |
0 | 34 #include "../Framework/Outputs/DicomPyramidWriter.h" |
35 #include "../Framework/Outputs/TruncatedPyramidWriter.h" | |
36 | |
199
a1c265cb2174
replacing deprecated std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
192
diff
changeset
|
37 #include <Compatibility.h> // For std::unique_ptr |
192 | 38 #include <DicomParsing/FromDcmtkBridge.h> |
39 #include <Logging.h> | |
40 #include <OrthancException.h> | |
213
2a4e1f7de5ab
remove calls to deprecated classes of JsonCpp
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
199
diff
changeset
|
41 #include <Toolbox.h> |
192 | 42 #include <SystemToolbox.h> |
59
7a3853d51c45
Move "Framework/Orthanc/" as "Resources/Orthanc/"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
57
diff
changeset
|
43 |
0 | 44 #include "ApplicationToolbox.h" |
45 | |
46 #include <EmbeddedResources.h> | |
47 | |
48 #include <dcmtk/dcmdata/dcdeftag.h> | |
49 #include <dcmtk/dcmdata/dcuid.h> | |
50 #include <dcmtk/dcmdata/dcvrobow.h> | |
51 #include <dcmtk/dcmdata/dcvrat.h> | |
52 | |
53 | |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
54 static const char* OPTION_COLOR = "color"; |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
55 static const char* OPTION_COMPRESSION = "compression"; |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
56 static const char* OPTION_DATASET = "dataset"; |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
57 static const char* OPTION_FOLDER = "folder"; |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
58 static const char* OPTION_FOLDER_PATTERN = "folder-pattern"; |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
59 static const char* OPTION_HELP = "help"; |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
60 static const char* OPTION_ICC_PROFILE = "icc-profile"; |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
61 static const char* OPTION_IMAGED_DEPTH = "imaged-depth"; |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
62 static const char* OPTION_IMAGED_HEIGHT = "imaged-height"; |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
63 static const char* OPTION_IMAGED_WIDTH = "imaged-width"; |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
64 static const char* OPTION_INPUT = "input"; |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
65 static const char* OPTION_JPEG_QUALITY = "jpeg-quality"; |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
66 static const char* OPTION_LEVELS = "levels"; |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
67 static const char* OPTION_LOWER_LEVELS = "lower-levels"; |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
68 static const char* OPTION_MAX_SIZE = "max-size"; |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
69 static const char* OPTION_OFFSET_X = "offset-x"; |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
70 static const char* OPTION_OFFSET_Y = "offset-y"; |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
71 static const char* OPTION_OPENSLIDE = "openslide"; |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
72 static const char* OPTION_OPTICAL_PATH = "optical-path"; |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
73 static const char* OPTION_PYRAMID = "pyramid"; |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
74 static const char* OPTION_REENCODE = "reencode"; |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
75 static const char* OPTION_REPAINT = "repaint"; |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
76 static const char* OPTION_SAFETY = "safety"; |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
77 static const char* OPTION_SAMPLE_DATASET = "sample-dataset"; |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
78 static const char* OPTION_SMOOTH = "smooth"; |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
79 static const char* OPTION_THREADS = "threads"; |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
80 static const char* OPTION_TILE_HEIGHT = "tile-height"; |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
81 static const char* OPTION_TILE_WIDTH = "tile-width"; |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
82 static const char* OPTION_VERBOSE = "verbose"; |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
83 static const char* OPTION_VERSION = "version"; |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
84 |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
85 |
0 | 86 static void TranscodePyramid(OrthancWSI::PyramidWriterBase& target, |
87 OrthancWSI::ITiledPyramid& source, | |
88 const OrthancWSI::DicomizerParameters& parameters) | |
89 { | |
167
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
90 LOG(WARNING) << "Transcoding the source pyramid (not re-encoding)"; |
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
91 |
0 | 92 Orthanc::BagOfTasks tasks; |
93 | |
94 for (unsigned int i = 0; i < source.GetLevelCount(); i++) | |
95 { | |
96 LOG(WARNING) << "Creating level " << i << " of size " | |
97 << source.GetLevelWidth(i) << "x" << source.GetLevelHeight(i); | |
98 target.AddLevel(source.GetLevelWidth(i), source.GetLevelHeight(i)); | |
99 } | |
100 | |
101 OrthancWSI::TranscodeTileCommand::PrepareBagOfTasks(tasks, target, source, parameters); | |
102 OrthancWSI::ApplicationToolbox::Execute(tasks, parameters.GetThreadsCount()); | |
103 } | |
104 | |
105 | |
106 static void ReconstructPyramid(OrthancWSI::PyramidWriterBase& target, | |
107 OrthancWSI::ITiledPyramid& source, | |
108 const OrthancWSI::DicomizerParameters& parameters) | |
109 { | |
167
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
110 LOG(WARNING) << "Re-encoding the source pyramid (not transcoding, slower process)"; |
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
111 |
0 | 112 Orthanc::BagOfTasks tasks; |
113 | |
114 unsigned int levelsCount = parameters.GetPyramidLevelsCount(target, source); | |
115 LOG(WARNING) << "The target pyramid will have " << levelsCount << " levels"; | |
116 assert(levelsCount >= 1); | |
117 | |
118 for (unsigned int i = 0; i < levelsCount; i++) | |
119 { | |
120 unsigned int width = OrthancWSI::CeilingDivision(source.GetLevelWidth(0), 1 << i); | |
121 unsigned int height = OrthancWSI::CeilingDivision(source.GetLevelHeight(0), 1 << i); | |
122 | |
123 LOG(WARNING) << "Creating level " << i << " of size " << width << "x" << height; | |
124 target.AddLevel(width, height); | |
125 } | |
126 | |
127 unsigned int lowerLevelsCount = parameters.GetPyramidLowerLevelsCount(target, source); | |
128 if (lowerLevelsCount > levelsCount) | |
129 { | |
130 LOG(WARNING) << "The number of lower levels (" << lowerLevelsCount | |
131 << ") exceeds the number of levels (" << levelsCount | |
132 << "), cropping it"; | |
133 lowerLevelsCount = levelsCount; | |
134 } | |
135 | |
136 assert(lowerLevelsCount <= levelsCount); | |
137 if (lowerLevelsCount != levelsCount) | |
138 { | |
139 LOG(WARNING) << "Constructing the " << lowerLevelsCount << " lower levels of the pyramid"; | |
166
f0dac1e8f736
access to photometric interpretation of source pyramids
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
157
diff
changeset
|
140 OrthancWSI::TruncatedPyramidWriter truncated(target, lowerLevelsCount, source.GetPhotometricInterpretation()); |
0 | 141 OrthancWSI::ReconstructPyramidCommand::PrepareBagOfTasks |
142 (tasks, truncated, source, lowerLevelsCount + 1, 0, parameters); | |
143 OrthancWSI::ApplicationToolbox::Execute(tasks, parameters.GetThreadsCount()); | |
144 | |
145 assert(tasks.GetSize() == 0); | |
146 | |
147 const unsigned int upperLevelsCount = levelsCount - lowerLevelsCount; | |
148 LOG(WARNING) << "Constructing the " << upperLevelsCount << " upper levels of the pyramid"; | |
149 OrthancWSI::ReconstructPyramidCommand::PrepareBagOfTasks | |
150 (tasks, target, truncated.GetUpperLevel(), | |
151 upperLevelsCount, lowerLevelsCount, parameters); | |
152 OrthancWSI::ApplicationToolbox::Execute(tasks, parameters.GetThreadsCount()); | |
153 } | |
154 else | |
155 { | |
156 LOG(WARNING) << "Constructing the pyramid"; | |
157 OrthancWSI::ReconstructPyramidCommand::PrepareBagOfTasks | |
158 (tasks, target, source, levelsCount, 0, parameters); | |
159 OrthancWSI::ApplicationToolbox::Execute(tasks, parameters.GetThreadsCount()); | |
160 } | |
161 } | |
162 | |
163 | |
164 static void Recompress(OrthancWSI::IFileTarget& output, | |
165 OrthancWSI::ITiledPyramid& source, | |
166 const DcmDataset& dataset, | |
167 const OrthancWSI::DicomizerParameters& parameters, | |
167
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
168 const OrthancWSI::ImagedVolumeParameters& volume, |
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
169 OrthancWSI::ImageCompression sourceCompression) |
0 | 170 { |
171 OrthancWSI::TiledPyramidStatistics stats(source); | |
172 | |
217
20bc074ec19a
Viewer can display DICOM pyramids whose tile sizes vary across levels
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
214
diff
changeset
|
173 OrthancWSI::ImageToolbox::CheckConstantTileSize(stats); // Sanity check |
20bc074ec19a
Viewer can display DICOM pyramids whose tile sizes vary across levels
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
214
diff
changeset
|
174 LOG(WARNING) << "Size of source tiles: " << stats.GetTileWidth(0) << "x" << stats.GetTileHeight(0); |
167
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
175 LOG(WARNING) << "Pixel format: " << Orthanc::EnumerationToString(source.GetPixelFormat()); |
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
176 LOG(WARNING) << "Source photometric interpretation: " << Orthanc::EnumerationToString(source.GetPhotometricInterpretation()); |
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
177 LOG(WARNING) << "Source compression: " << EnumerationToString(sourceCompression); |
0 | 178 LOG(WARNING) << "Smoothing is " << (parameters.IsSmoothEnabled() ? "enabled" : "disabled"); |
179 | |
180 if (parameters.IsRepaintBackground()) | |
181 { | |
182 LOG(WARNING) << "Repainting the background with color: (" | |
183 << static_cast<int>(parameters.GetBackgroundColorRed()) << "," | |
184 << static_cast<int>(parameters.GetBackgroundColorGreen()) << "," | |
185 << static_cast<int>(parameters.GetBackgroundColorBlue()) << ")"; | |
186 } | |
187 else | |
188 { | |
189 LOG(WARNING) << "No repainting of the background"; | |
190 } | |
191 | |
167
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
192 Orthanc::PhotometricInterpretation targetPhotometric; |
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
193 bool transcoding; |
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
194 |
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
195 if (parameters.IsForceReencode() || |
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
196 parameters.IsReconstructPyramid() || |
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
197 sourceCompression != parameters.GetTargetCompression()) |
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
198 { |
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
199 // The tiles of the source image will be re-encoded |
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
200 transcoding = false; |
171 | 201 |
202 if (source.GetPixelFormat() == Orthanc::PixelFormat_Grayscale8) | |
203 { | |
204 targetPhotometric = source.GetPhotometricInterpretation(); | |
205 } | |
206 else | |
167
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
207 { |
171 | 208 switch (parameters.GetTargetCompression()) |
209 { | |
210 case OrthancWSI::ImageCompression_Jpeg: | |
211 case OrthancWSI::ImageCompression_Jpeg2000: | |
212 targetPhotometric = Orthanc::PhotometricInterpretation_YBRFull422; | |
213 break; | |
167
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
214 |
171 | 215 case OrthancWSI::ImageCompression_None: |
216 targetPhotometric = Orthanc::PhotometricInterpretation_RGB; | |
217 break; | |
167
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
218 |
171 | 219 default: |
220 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
221 } | |
167
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
222 } |
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
223 } |
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
224 else |
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
225 { |
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
226 // Transcoding: The tiles are copied (no re-encoding) |
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
227 transcoding = true; |
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
228 targetPhotometric = source.GetPhotometricInterpretation(); |
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
229 } |
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
230 |
0 | 231 OrthancWSI::DicomPyramidWriter target(output, dataset, |
232 source.GetPixelFormat(), | |
233 parameters.GetTargetCompression(), | |
234 parameters.GetTargetTileWidth(source), | |
235 parameters.GetTargetTileHeight(source), | |
236 parameters.GetDicomMaxFileSize(), | |
167
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
237 volume, targetPhotometric); |
29 | 238 target.SetJpegQuality(parameters.GetJpegQuality()); |
0 | 239 |
240 LOG(WARNING) << "Size of target tiles: " << target.GetTileWidth() << "x" << target.GetTileHeight(); | |
167
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
241 LOG(WARNING) << "Target photometric interpretation: " << Orthanc::EnumerationToString(targetPhotometric); |
0 | 242 |
167
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
243 if (!transcoding && |
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
244 target.GetImageCompression() == OrthancWSI::ImageCompression_Jpeg) |
0 | 245 { |
167
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
246 LOG(WARNING) << "Target compression: Jpeg with quality " |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
247 << static_cast<int>(target.GetJpegQuality()); |
0 | 248 target.SetJpegQuality(target.GetJpegQuality()); |
249 } | |
250 else | |
251 { | |
167
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
252 LOG(WARNING) << "Target compression: " |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
253 << OrthancWSI::EnumerationToString(target.GetImageCompression()); |
0 | 254 } |
255 | |
217
20bc074ec19a
Viewer can display DICOM pyramids whose tile sizes vary across levels
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
214
diff
changeset
|
256 OrthancWSI::ImageToolbox::CheckConstantTileSize(stats); |
20bc074ec19a
Viewer can display DICOM pyramids whose tile sizes vary across levels
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
214
diff
changeset
|
257 if (stats.GetTileWidth(0) % target.GetTileWidth() != 0 || |
20bc074ec19a
Viewer can display DICOM pyramids whose tile sizes vary across levels
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
214
diff
changeset
|
258 stats.GetTileHeight(0) % target.GetTileHeight() != 0) |
0 | 259 { |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
260 LOG(ERROR) << "When resampling the tile size, " |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
261 << "it must be a integer divisor of the original tile size"; |
0 | 262 throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageSize); |
263 } | |
264 | |
265 if (target.GetTileWidth() <= 16 || | |
266 target.GetTileHeight() <= 16) | |
267 { | |
268 LOG(ERROR) << "Tiles are too small (16 pixels minimum): " | |
269 << target.GetTileWidth() << "x" << target.GetTileHeight(); | |
270 throw Orthanc::OrthancException(Orthanc::ErrorCode_IncompatibleImageSize); | |
271 } | |
272 | |
167
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
273 if (transcoding) |
0 | 274 { |
167
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
275 TranscodePyramid(target, stats, parameters); |
0 | 276 } |
277 else | |
278 { | |
167
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
279 ReconstructPyramid(target, stats, parameters); |
0 | 280 } |
281 | |
282 target.Flush(); | |
283 } | |
284 | |
285 | |
286 | |
287 static DcmDataset* ParseDataset(const std::string& path) | |
288 { | |
289 Json::Value json; | |
290 | |
291 if (path.empty()) | |
292 { | |
293 json = Json::objectValue; // Empty dataset => TODO EMBED | |
294 } | |
295 else | |
296 { | |
297 std::string content; | |
43 | 298 Orthanc::SystemToolbox::ReadFile(content, path); |
0 | 299 |
213
2a4e1f7de5ab
remove calls to deprecated classes of JsonCpp
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
199
diff
changeset
|
300 if (!Orthanc::Toolbox::ReadJsonWithoutComments(json, content)) |
0 | 301 { |
302 LOG(ERROR) << "Cannot parse the JSON file in: " << path; | |
303 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); | |
304 } | |
305 } | |
306 | |
199
a1c265cb2174
replacing deprecated std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
192
diff
changeset
|
307 std::unique_ptr<DcmDataset> dataset(Orthanc::FromDcmtkBridge::FromJson(json, true, true, Orthanc::Encoding_Latin1, |
177
ea62c89b264b
fix due to change in the orthanc framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
175
diff
changeset
|
308 "" /* no private tag, thus no private creator */)); |
0 | 309 if (dataset.get() == NULL) |
310 { | |
311 LOG(ERROR) << "Cannot convert to JSON file to a DICOM dataset: " << path; | |
312 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); | |
313 } | |
314 | |
315 // VL Whole Slide Microscopy Image IOD | |
316 OrthancWSI::DicomToolbox::SetStringTag(*dataset, DCM_SOPClassUID, "1.2.840.10008.5.1.4.1.1.77.1.6"); | |
317 | |
318 // Slide Microscopy | |
319 OrthancWSI::DicomToolbox::SetStringTag(*dataset, DCM_Modality, "SM"); | |
320 | |
321 // Patient orientation makes no sense in whole-slide images | |
322 OrthancWSI::DicomToolbox::SetStringTag(*dataset, DCM_PatientOrientation, ""); | |
323 | |
324 // Some basic coordinate information | |
325 OrthancWSI::DicomToolbox::SetStringTag(*dataset, DCM_VolumetricProperties, "VOLUME"); | |
326 OrthancWSI::DicomToolbox::SetStringTag(*dataset, DCM_ImageOrientationSlide, "0\\-1\\0\\-1\\0\\0"); | |
327 | |
328 std::string date, time; | |
130 | 329 Orthanc::SystemToolbox::GetNowDicom(date, time, true /* use UTC time (not local time) */); |
0 | 330 OrthancWSI::DicomToolbox::SetStringTag(*dataset, DCM_StudyDate, date); |
331 OrthancWSI::DicomToolbox::SetStringTag(*dataset, DCM_StudyTime, time); | |
332 OrthancWSI::DicomToolbox::SetStringTag(*dataset, DCM_SeriesDate, date); | |
333 OrthancWSI::DicomToolbox::SetStringTag(*dataset, DCM_SeriesTime, time); | |
334 OrthancWSI::DicomToolbox::SetStringTag(*dataset, DCM_ContentDate, date); | |
335 OrthancWSI::DicomToolbox::SetStringTag(*dataset, DCM_ContentTime, time); | |
336 OrthancWSI::DicomToolbox::SetStringTag(*dataset, DCM_AcquisitionDateTime, date + time); | |
337 | |
338 return dataset.release(); | |
339 } | |
340 | |
341 | |
342 | |
343 static void SetupDimension(DcmDataset& dataset, | |
344 const std::string& opticalPathId, | |
345 const OrthancWSI::ITiledPyramid& source, | |
346 const OrthancWSI::ImagedVolumeParameters& volume) | |
347 { | |
83 | 348 // Extract the identifier of the Dimension Organization, if provided |
349 std::string organization; | |
0 | 350 DcmItem* previous = OrthancWSI::DicomToolbox::ExtractSingleSequenceItem(dataset, DCM_DimensionOrganizationSequence); |
351 | |
83 | 352 if (previous != NULL && |
353 previous->tagExists(DCM_DimensionOrganizationUID)) | |
354 { | |
355 organization = OrthancWSI::DicomToolbox::GetStringTag(*previous, DCM_DimensionOrganizationUID); | |
356 } | |
357 else | |
0 | 358 { |
83 | 359 // No Dimension Organization provided: Generate an unique identifier |
360 organization = Orthanc::FromDcmtkBridge::GenerateUniqueIdentifier(Orthanc::ResourceType_Instance); | |
361 } | |
362 | |
363 | |
364 { | |
365 // Construct tag "Dimension Organization Sequence" (0020,9221) | |
199
a1c265cb2174
replacing deprecated std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
192
diff
changeset
|
366 std::unique_ptr<DcmItem> item(new DcmItem); |
83 | 367 OrthancWSI::DicomToolbox::SetStringTag(*item, DCM_DimensionOrganizationUID, organization); |
368 | |
199
a1c265cb2174
replacing deprecated std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
192
diff
changeset
|
369 std::unique_ptr<DcmSequenceOfItems> sequence(new DcmSequenceOfItems(DCM_DimensionOrganizationSequence)); |
83 | 370 |
371 if (!sequence->insert(item.release(), false, false).good() || | |
372 !dataset.insert(sequence.release(), true /* replace */, false).good()) | |
0 | 373 { |
83 | 374 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); |
0 | 375 } |
376 } | |
377 | |
83 | 378 |
0 | 379 { |
83 | 380 // Construct tag "Dimension Index Sequence" (0020,9222) |
199
a1c265cb2174
replacing deprecated std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
192
diff
changeset
|
381 std::unique_ptr<DcmItem> item(new DcmItem); |
83 | 382 OrthancWSI::DicomToolbox::SetStringTag(*item, DCM_DimensionOrganizationUID, organization); |
84
727670c5c125
fix generation of "Dimension Index Sequence" and "Dimension Index Values"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
83
diff
changeset
|
383 OrthancWSI::DicomToolbox::SetAttributeTag(*item, DCM_FunctionalGroupPointer, DCM_PlanePositionSlideSequence); |
727670c5c125
fix generation of "Dimension Index Sequence" and "Dimension Index Values"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
83
diff
changeset
|
384 OrthancWSI::DicomToolbox::SetAttributeTag(*item, DCM_DimensionIndexPointer, DCM_ColumnPositionInTotalImagePixelMatrix); |
727670c5c125
fix generation of "Dimension Index Sequence" and "Dimension Index Values"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
83
diff
changeset
|
385 |
199
a1c265cb2174
replacing deprecated std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
192
diff
changeset
|
386 std::unique_ptr<DcmItem> item2(new DcmItem); |
84
727670c5c125
fix generation of "Dimension Index Sequence" and "Dimension Index Values"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
83
diff
changeset
|
387 OrthancWSI::DicomToolbox::SetStringTag(*item2, DCM_DimensionOrganizationUID, organization); |
727670c5c125
fix generation of "Dimension Index Sequence" and "Dimension Index Values"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
83
diff
changeset
|
388 OrthancWSI::DicomToolbox::SetAttributeTag(*item2, DCM_FunctionalGroupPointer, DCM_PlanePositionSlideSequence); |
727670c5c125
fix generation of "Dimension Index Sequence" and "Dimension Index Values"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
83
diff
changeset
|
389 OrthancWSI::DicomToolbox::SetAttributeTag(*item2, DCM_DimensionIndexPointer, DCM_RowPositionInTotalImagePixelMatrix); |
0 | 390 |
199
a1c265cb2174
replacing deprecated std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
192
diff
changeset
|
391 std::unique_ptr<DcmSequenceOfItems> sequence(new DcmSequenceOfItems(DCM_DimensionIndexSequence)); |
0 | 392 |
83 | 393 if (!sequence->insert(item.release(), false, false).good() || |
84
727670c5c125
fix generation of "Dimension Index Sequence" and "Dimension Index Values"
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
83
diff
changeset
|
394 !sequence->insert(item2.release(), false, false).good() || |
83 | 395 !dataset.insert(sequence.release(), true /* replace */, false).good()) |
396 { | |
397 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
398 } | |
0 | 399 } |
400 | |
401 | |
83 | 402 { |
403 // Construct tag "Shared Functional Groups Sequence" (5200,9229) | |
199
a1c265cb2174
replacing deprecated std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
192
diff
changeset
|
404 std::unique_ptr<DcmItem> item(new DcmItem); |
168
d3aea0af03e1
attempt to fix issue 139
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
167
diff
changeset
|
405 |
199
a1c265cb2174
replacing deprecated std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
192
diff
changeset
|
406 std::unique_ptr<DcmItem> item3(new DcmItem); |
168
d3aea0af03e1
attempt to fix issue 139
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
167
diff
changeset
|
407 OrthancWSI::DicomToolbox::SetStringTag(*item3, DCM_OpticalPathIdentifier, opticalPathId); |
d3aea0af03e1
attempt to fix issue 139
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
167
diff
changeset
|
408 |
199
a1c265cb2174
replacing deprecated std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
192
diff
changeset
|
409 std::unique_ptr<DcmSequenceOfItems> sequence(new DcmSequenceOfItems(DCM_SharedFunctionalGroupsSequence)); |
a1c265cb2174
replacing deprecated std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
192
diff
changeset
|
410 std::unique_ptr<DcmSequenceOfItems> sequence3(new DcmSequenceOfItems(DCM_OpticalPathIdentificationSequence)); |
168
d3aea0af03e1
attempt to fix issue 139
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
167
diff
changeset
|
411 |
d3aea0af03e1
attempt to fix issue 139
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
167
diff
changeset
|
412 if (!sequence3->insert(item3.release(), false, false).good() || |
d3aea0af03e1
attempt to fix issue 139
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
167
diff
changeset
|
413 !item->insert(sequence3.release(), false, false).good() || |
d3aea0af03e1
attempt to fix issue 139
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
167
diff
changeset
|
414 !sequence->insert(item.release(), false, false).good() || |
d3aea0af03e1
attempt to fix issue 139
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
167
diff
changeset
|
415 !dataset.insert(sequence.release(), true /* replace */, false).good()) |
d3aea0af03e1
attempt to fix issue 139
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
167
diff
changeset
|
416 { |
d3aea0af03e1
attempt to fix issue 139
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
167
diff
changeset
|
417 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); |
d3aea0af03e1
attempt to fix issue 139
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
167
diff
changeset
|
418 } |
0 | 419 } |
420 } | |
421 | |
422 | |
423 static void EnrichDataset(DcmDataset& dataset, | |
424 const OrthancWSI::ITiledPyramid& source, | |
57
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
43
diff
changeset
|
425 OrthancWSI::ImageCompression sourceCompression, |
0 | 426 const OrthancWSI::DicomizerParameters& parameters, |
427 const OrthancWSI::ImagedVolumeParameters& volume) | |
428 { | |
429 Orthanc::Encoding encoding = Orthanc::FromDcmtkBridge::DetectEncoding(dataset, Orthanc::Encoding_Latin1); | |
430 | |
57
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
43
diff
changeset
|
431 if (sourceCompression == OrthancWSI::ImageCompression_Jpeg || |
0 | 432 parameters.GetTargetCompression() == OrthancWSI::ImageCompression_Jpeg) |
433 { | |
434 // Takes as estimation a 1:10 compression ratio | |
435 OrthancWSI::DicomToolbox::SetStringTag(dataset, DCM_LossyImageCompression, "01"); | |
436 OrthancWSI::DicomToolbox::SetStringTag(dataset, DCM_LossyImageCompressionRatio, "10"); | |
437 OrthancWSI::DicomToolbox::SetStringTag(dataset, DCM_LossyImageCompressionMethod, "ISO_10918_1"); // JPEG Lossy Compression | |
438 } | |
439 else | |
440 { | |
441 OrthancWSI::DicomToolbox::SetStringTag(dataset, DCM_LossyImageCompression, "00"); | |
442 } | |
443 | |
444 OrthancWSI::DicomToolbox::SetStringTag(dataset, DCM_ImagedVolumeWidth, boost::lexical_cast<std::string>(volume.GetWidth())); | |
445 OrthancWSI::DicomToolbox::SetStringTag(dataset, DCM_ImagedVolumeHeight, boost::lexical_cast<std::string>(volume.GetHeight())); | |
446 OrthancWSI::DicomToolbox::SetStringTag(dataset, DCM_ImagedVolumeDepth, boost::lexical_cast<std::string>(volume.GetDepth())); | |
447 | |
199
a1c265cb2174
replacing deprecated std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
192
diff
changeset
|
448 std::unique_ptr<DcmItem> origin(new DcmItem); |
0 | 449 OrthancWSI::DicomToolbox::SetStringTag(*origin, DCM_XOffsetInSlideCoordinateSystem, |
450 boost::lexical_cast<std::string>(volume.GetOffsetX())); | |
451 OrthancWSI::DicomToolbox::SetStringTag(*origin, DCM_YOffsetInSlideCoordinateSystem, | |
452 boost::lexical_cast<std::string>(volume.GetOffsetY())); | |
453 | |
199
a1c265cb2174
replacing deprecated std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
192
diff
changeset
|
454 std::unique_ptr<DcmSequenceOfItems> sequenceOrigin(new DcmSequenceOfItems(DCM_TotalPixelMatrixOriginSequence)); |
0 | 455 if (!sequenceOrigin->insert(origin.release(), false, false).good() || |
456 !dataset.insert(sequenceOrigin.release(), false, false).good()) | |
457 { | |
458 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
459 } | |
460 | |
461 | |
462 if (parameters.GetOpticalPath() == OrthancWSI::OpticalPath_Brightfield) | |
463 { | |
464 if (dataset.tagExists(DCM_OpticalPathSequence)) | |
465 { | |
466 LOG(ERROR) << "The user DICOM dataset already contains an optical path sequence, giving up"; | |
467 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); | |
468 } | |
469 | |
470 std::string brightfield; | |
471 Orthanc::EmbeddedResources::GetFileResource(brightfield, Orthanc::EmbeddedResources::BRIGHTFIELD_OPTICAL_PATH); | |
472 | |
473 Json::Value json; | |
213
2a4e1f7de5ab
remove calls to deprecated classes of JsonCpp
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
199
diff
changeset
|
474 if (!Orthanc::Toolbox::ReadJsonWithoutComments(json, brightfield)) |
0 | 475 { |
476 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
477 } | |
478 | |
199
a1c265cb2174
replacing deprecated std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
192
diff
changeset
|
479 std::unique_ptr<DcmElement> element(Orthanc::FromDcmtkBridge::FromJson( |
0 | 480 Orthanc::DicomTag(DCM_OpticalPathSequence.getGroup(), |
481 DCM_OpticalPathSequence.getElement()), | |
177
ea62c89b264b
fix due to change in the orthanc framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
175
diff
changeset
|
482 json, false, encoding, |
ea62c89b264b
fix due to change in the orthanc framework
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
175
diff
changeset
|
483 "" /* no private tag, thus no private creator */)); |
0 | 484 if (!dataset.insert(element.release()).good()) |
485 { | |
486 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
487 } | |
488 } | |
489 | |
490 | |
491 std::string profile; | |
492 if (parameters.GetIccProfilePath().empty()) | |
493 { | |
494 Orthanc::EmbeddedResources::GetFileResource(profile, Orthanc::EmbeddedResources::SRGB_ICC_PROFILE); | |
495 } | |
496 else | |
497 { | |
43 | 498 Orthanc::SystemToolbox::ReadFile(profile, parameters.GetIccProfilePath()); |
0 | 499 } |
500 | |
501 | |
502 DcmItem* opticalPath = OrthancWSI::DicomToolbox::ExtractSingleSequenceItem(dataset, DCM_OpticalPathSequence); | |
503 if (opticalPath == NULL) | |
504 { | |
505 LOG(ERROR) << "No optical path specified"; | |
506 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); | |
507 } | |
508 | |
509 if (!opticalPath->tagExists(DCM_ICCProfile)) | |
510 { | |
199
a1c265cb2174
replacing deprecated std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
192
diff
changeset
|
511 std::unique_ptr<DcmOtherByteOtherWord> icc(new DcmOtherByteOtherWord(DCM_ICCProfile)); |
0 | 512 |
513 if (!icc->putUint8Array(reinterpret_cast<const Uint8*>(profile.c_str()), profile.size()).good() || | |
514 !opticalPath->insert(icc.release()).good()) | |
515 { | |
516 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
517 } | |
518 } | |
519 | |
520 const char* opticalPathId = NULL; | |
521 if (!opticalPath->findAndGetString(DCM_OpticalPathIdentifier, opticalPathId).good() || | |
522 opticalPathId == NULL) | |
523 { | |
524 LOG(ERROR) << "No identifier in the optical path"; | |
525 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); | |
526 } | |
527 | |
528 SetupDimension(dataset, opticalPathId, source, volume); | |
529 } | |
530 | |
531 | |
532 static bool ParseParameters(int& exitStatus, | |
533 OrthancWSI::DicomizerParameters& parameters, | |
534 OrthancWSI::ImagedVolumeParameters& volume, | |
535 int argc, | |
536 char* argv[]) | |
537 { | |
538 // Declare the supported parameters | |
539 boost::program_options::options_description generic("Generic options"); | |
540 generic.add_options() | |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
541 (OPTION_HELP, "Display this help and exit") |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
542 (OPTION_VERSION, "Output version information and exit") |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
543 (OPTION_VERBOSE, "Be verbose in logs") |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
544 (OPTION_THREADS, |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
545 boost::program_options::value<int>()->default_value(parameters.GetThreadsCount()), |
0 | 546 "Number of processing threads to be used") |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
547 (OPTION_OPENSLIDE, boost::program_options::value<std::string>(), |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
548 "Path to the shared library of OpenSlide " |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
549 "(not necessary if converting from standard hierarchical TIFF)") |
0 | 550 ; |
551 | |
552 boost::program_options::options_description source("Options for the source image"); | |
553 source.add_options() | |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
554 (OPTION_DATASET, boost::program_options::value<std::string>(), |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
555 "Path to a JSON file containing the DICOM dataset") |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
556 (OPTION_SAMPLE_DATASET, |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
557 "Display a minimalistic sample DICOM dataset in JSON format, then exit") |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
558 (OPTION_REENCODE, boost::program_options::value<bool>(), |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
559 "Whether to re-encode each tile (no transcoding, much slower) (Boolean)") |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
560 (OPTION_REPAINT, boost::program_options::value<bool>(), |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
561 "Whether to repaint the background of the image (Boolean)") |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
562 (OPTION_COLOR, boost::program_options::value<std::string>(), |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
563 "Color of the background (e.g. \"255,0,0\")") |
0 | 564 ; |
565 | |
566 boost::program_options::options_description pyramid("Options to construct the pyramid"); | |
567 pyramid.add_options() | |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
568 (OPTION_PYRAMID, boost::program_options::value<bool>()->default_value(false), |
0 | 569 "Reconstruct the full pyramid (slow) (Boolean)") |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
570 (OPTION_SMOOTH, boost::program_options::value<bool>()->default_value(false), |
0 | 571 "Apply smoothing when reconstructing the pyramid " |
572 "(slower, but higher quality) (Boolean)") | |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
573 (OPTION_LEVELS, boost::program_options::value<int>(), |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
574 "Number of levels in the target pyramid") |
0 | 575 ; |
576 | |
577 boost::program_options::options_description target("Options for the target image"); | |
578 target.add_options() | |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
579 (OPTION_TILE_WIDTH, boost::program_options::value<int>(), |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
580 "Width of the tiles in the target image") |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
581 (OPTION_TILE_HEIGHT, boost::program_options::value<int>(), |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
582 "Height of the tiles in the target image") |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
583 (OPTION_COMPRESSION, boost::program_options::value<std::string>(), |
0 | 584 "Compression of the target image (\"none\", \"jpeg\" or \"jpeg2000\")") |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
585 (OPTION_JPEG_QUALITY, boost::program_options::value<int>(), |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
586 "Set quality level for JPEG (0..100)") |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
587 (OPTION_MAX_SIZE, boost::program_options::value<int>()->default_value(10), |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
588 "Maximum size per DICOM instance (in MB), 0 means no limit on the file size") |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
589 (OPTION_FOLDER, boost::program_options::value<std::string>(), |
0 | 590 "Folder where to store the output DICOM instances") |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
591 (OPTION_FOLDER_PATTERN, |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
592 boost::program_options::value<std::string>()->default_value("wsi-%06d.dcm"), |
0 | 593 "Pattern for the files in the output folder") |
594 ("orthanc", boost::program_options::value<std::string>()->default_value("http://localhost:8042/"), | |
595 "URL to the REST API of the target Orthanc server") | |
596 ; | |
597 | |
598 boost::program_options::options_description volumeOptions("Description of the imaged volume"); | |
599 volumeOptions.add_options() | |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
600 (OPTION_IMAGED_WIDTH, boost::program_options::value<float>()->default_value(15), |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
601 "Width of the specimen (in mm)") |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
602 (OPTION_IMAGED_HEIGHT, boost::program_options::value<float>()->default_value(15), |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
603 "Height of the specimen (in mm)") |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
604 (OPTION_IMAGED_DEPTH, boost::program_options::value<float>()->default_value(1), |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
605 "Depth of the specimen (in mm)") |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
606 (OPTION_OFFSET_X, boost::program_options::value<float>()->default_value(20), |
0 | 607 "X offset the specimen, wrt. slide coordinates origin (in mm)") |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
608 (OPTION_OFFSET_Y, boost::program_options::value<float>()->default_value(40), |
0 | 609 "Y offset the specimen, wrt. slide coordinates origin (in mm)") |
610 ; | |
611 | |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
612 boost::program_options::options_description restOptions |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
613 ("HTTP/HTTPS client configuration to access the Orthanc REST API"); |
125
7a3f4d580625
SSL is enabled by default for HTTPS transfers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
123
diff
changeset
|
614 OrthancWSI::ApplicationToolbox::AddRestApiOptions(restOptions); |
7a3f4d580625
SSL is enabled by default for HTTPS transfers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
123
diff
changeset
|
615 |
0 | 616 boost::program_options::options_description advancedOptions("Advanced options"); |
617 advancedOptions.add_options() | |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
618 (OPTION_OPTICAL_PATH, boost::program_options::value<std::string>()->default_value("brightfield"), |
0 | 619 "Optical path to be automatically added to the DICOM dataset (\"none\" or \"brightfield\")") |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
620 (OPTION_ICC_PROFILE, boost::program_options::value<std::string>(), |
0 | 621 "Path to the ICC profile to be included. If empty, a default sRGB profile will be added.") |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
622 (OPTION_SAFETY, boost::program_options::value<bool>()->default_value(true), |
0 | 623 "Whether to do additional checks to verify the source image is supported (might slow down) (Boolean)") |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
624 (OPTION_LOWER_LEVELS, boost::program_options::value<int>(), |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
625 "Number of pyramid levels up to which multithreading " |
0 | 626 "should be applied (only for performance/memory tuning)") |
627 ; | |
628 | |
629 boost::program_options::options_description hidden; | |
630 hidden.add_options() | |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
631 (OPTION_INPUT, boost::program_options::value<std::string>(), |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
632 "Input file"); |
0 | 633 ; |
634 | |
635 boost::program_options::options_description allWithoutHidden; | |
125
7a3f4d580625
SSL is enabled by default for HTTPS transfers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
123
diff
changeset
|
636 allWithoutHidden |
7a3f4d580625
SSL is enabled by default for HTTPS transfers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
123
diff
changeset
|
637 .add(generic) |
7a3f4d580625
SSL is enabled by default for HTTPS transfers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
123
diff
changeset
|
638 .add(source) |
7a3f4d580625
SSL is enabled by default for HTTPS transfers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
123
diff
changeset
|
639 .add(pyramid) |
7a3f4d580625
SSL is enabled by default for HTTPS transfers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
123
diff
changeset
|
640 .add(target) |
7a3f4d580625
SSL is enabled by default for HTTPS transfers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
123
diff
changeset
|
641 .add(volumeOptions) |
7a3f4d580625
SSL is enabled by default for HTTPS transfers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
123
diff
changeset
|
642 .add(restOptions) |
7a3f4d580625
SSL is enabled by default for HTTPS transfers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
123
diff
changeset
|
643 .add(advancedOptions); |
0 | 644 |
645 boost::program_options::options_description all = allWithoutHidden; | |
646 all.add(hidden); | |
647 | |
648 boost::program_options::positional_options_description positional; | |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
649 positional.add(OPTION_INPUT, 1); |
0 | 650 |
651 boost::program_options::variables_map options; | |
652 bool error = false; | |
653 | |
654 try | |
655 { | |
656 boost::program_options::store(boost::program_options::command_line_parser(argc, argv). | |
657 options(all).positional(positional).run(), options); | |
658 boost::program_options::notify(options); | |
659 } | |
660 catch (boost::program_options::error& e) | |
661 { | |
662 LOG(ERROR) << "Error while parsing the command-line arguments: " << e.what(); | |
663 error = true; | |
664 } | |
665 | |
666 if (!error && | |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
667 options.count(OPTION_SAMPLE_DATASET)) |
0 | 668 { |
669 std::string sample; | |
670 Orthanc::EmbeddedResources::GetFileResource(sample, Orthanc::EmbeddedResources::SAMPLE_DATASET); | |
671 | |
672 std::cout << std::endl << sample << std::endl; | |
673 | |
674 return false; | |
675 } | |
676 | |
677 if (!error && | |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
678 options.count(OPTION_HELP) == 0 && |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
679 options.count(OPTION_VERSION) == 0 && |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
680 options.count(OPTION_INPUT) != 1) |
0 | 681 { |
682 LOG(ERROR) << "No input file was specified"; | |
683 error = true; | |
684 } | |
685 | |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
686 if (error || options.count(OPTION_HELP)) |
0 | 687 { |
688 std::cout << std::endl | |
689 << "Usage: " << argv[0] << " [OPTION]... [INPUT]" | |
690 << std::endl | |
691 << "Orthanc, lightweight, RESTful DICOM server for healthcare and medical research." | |
692 << std::endl << std::endl | |
693 << "Create a DICOM file from a digital pathology image." | |
694 << std::endl; | |
695 | |
696 std::cout << allWithoutHidden << "\n"; | |
697 | |
698 if (error) | |
699 { | |
700 exitStatus = -1; | |
701 } | |
702 | |
703 return false; | |
704 } | |
705 | |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
706 if (options.count(OPTION_VERSION)) |
8
62adabb8c122
Provide "--version" in command-line tools
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
707 { |
62adabb8c122
Provide "--version" in command-line tools
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
708 OrthancWSI::ApplicationToolbox::PrintVersion(argv[0]); |
62adabb8c122
Provide "--version" in command-line tools
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
709 return false; |
62adabb8c122
Provide "--version" in command-line tools
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
710 } |
62adabb8c122
Provide "--version" in command-line tools
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
0
diff
changeset
|
711 |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
712 if (options.count(OPTION_VERBOSE)) |
0 | 713 { |
714 Orthanc::Logging::EnableInfoLevel(true); | |
715 } | |
716 | |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
717 if (options.count(OPTION_OPENSLIDE)) |
0 | 718 { |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
719 OrthancWSI::OpenSlideLibrary::Initialize(options[OPTION_OPENSLIDE].as<std::string>()); |
0 | 720 } |
721 | |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
722 if (options.count(OPTION_PYRAMID) && |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
723 options[OPTION_PYRAMID].as<bool>()) |
0 | 724 { |
725 parameters.SetReconstructPyramid(true); | |
726 } | |
727 | |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
728 if (options.count(OPTION_SMOOTH) && |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
729 options[OPTION_SMOOTH].as<bool>()) |
0 | 730 { |
731 parameters.SetSmoothEnabled(true); | |
732 } | |
733 | |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
734 if (options.count(OPTION_SAFETY) && |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
735 options[OPTION_SAFETY].as<bool>()) |
0 | 736 { |
737 parameters.SetSafetyCheck(true); | |
738 } | |
739 | |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
740 if (options.count(OPTION_REENCODE) && |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
741 options[OPTION_REENCODE].as<bool>()) |
0 | 742 { |
743 parameters.SetForceReencode(true); | |
744 } | |
745 | |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
746 if (options.count(OPTION_REPAINT) && |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
747 options[OPTION_REPAINT].as<bool>()) |
0 | 748 { |
749 parameters.SetRepaintBackground(true); | |
750 } | |
751 | |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
752 if (options.count(OPTION_TILE_WIDTH) || |
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
753 options.count(OPTION_TILE_HEIGHT)) |
0 | 754 { |
755 int w = 0; | |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
756 if (options.count(OPTION_TILE_WIDTH)) |
0 | 757 { |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
758 w = options[OPTION_TILE_WIDTH].as<int>(); |
0 | 759 } |
760 | |
145 | 761 int h = 0; |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
762 if (options.count(OPTION_TILE_HEIGHT)) |
0 | 763 { |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
764 h = options[OPTION_TILE_HEIGHT].as<int>(); |
0 | 765 } |
766 | |
767 if (w < 0 || h < 0) | |
768 { | |
769 LOG(ERROR) << "Negative target tile size specified: " << w << "x" << h; | |
770 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
771 } | |
772 | |
773 parameters.SetTargetTileSize(w, h); | |
774 } | |
775 | |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
776 parameters.SetInputFile(options[OPTION_INPUT].as<std::string>()); |
0 | 777 |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
778 if (options.count(OPTION_COLOR)) |
0 | 779 { |
780 uint8_t r, g, b; | |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
781 OrthancWSI::ApplicationToolbox::ParseColor(r, g, b, options[OPTION_COLOR].as<std::string>()); |
0 | 782 parameters.SetBackgroundColor(r, g, b); |
783 } | |
784 | |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
785 if (options.count(OPTION_COMPRESSION)) |
0 | 786 { |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
787 std::string s = options[OPTION_COMPRESSION].as<std::string>(); |
0 | 788 if (s == "none") |
789 { | |
790 parameters.SetTargetCompression(OrthancWSI::ImageCompression_None); | |
791 } | |
792 else if (s == "jpeg") | |
793 { | |
794 parameters.SetTargetCompression(OrthancWSI::ImageCompression_Jpeg); | |
795 } | |
796 else if (s == "jpeg2000") | |
797 { | |
798 parameters.SetTargetCompression(OrthancWSI::ImageCompression_Jpeg2000); | |
799 } | |
800 else | |
801 { | |
802 LOG(ERROR) << "Unknown image compression for the target image: " << s; | |
803 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
804 } | |
805 } | |
806 | |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
807 if (options.count(OPTION_JPEG_QUALITY)) |
0 | 808 { |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
809 parameters.SetJpegQuality(options[OPTION_JPEG_QUALITY].as<int>()); |
0 | 810 } |
811 | |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
812 if (options.count(OPTION_LEVELS)) |
0 | 813 { |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
814 parameters.SetPyramidLevelsCount(options[OPTION_LEVELS].as<int>()); |
0 | 815 } |
816 | |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
817 if (options.count(OPTION_LOWER_LEVELS)) |
0 | 818 { |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
819 parameters.SetPyramidLowerLevelsCount(options[OPTION_LOWER_LEVELS].as<int>()); |
0 | 820 } |
821 | |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
822 if (options.count(OPTION_THREADS)) |
0 | 823 { |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
824 parameters.SetThreadsCount(options[OPTION_THREADS].as<int>()); |
0 | 825 } |
826 | |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
827 if (options.count(OPTION_MAX_SIZE)) |
0 | 828 { |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
829 parameters.SetDicomMaxFileSize(options[OPTION_MAX_SIZE].as<int>() * 1024 * 1024); |
0 | 830 } |
831 | |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
832 if (options.count(OPTION_FOLDER)) |
0 | 833 { |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
834 parameters.SetTargetFolder(options[OPTION_FOLDER].as<std::string>()); |
0 | 835 } |
836 | |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
837 if (options.count(OPTION_FOLDER_PATTERN)) |
0 | 838 { |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
839 parameters.SetTargetFolderPattern(options[OPTION_FOLDER_PATTERN].as<std::string>()); |
0 | 840 } |
841 | |
125
7a3f4d580625
SSL is enabled by default for HTTPS transfers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
123
diff
changeset
|
842 OrthancWSI::ApplicationToolbox::SetupRestApi(parameters.GetOrthancParameters(), options); |
0 | 843 |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
844 if (options.count(OPTION_DATASET)) |
0 | 845 { |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
846 parameters.SetDatasetPath(options[OPTION_DATASET].as<std::string>()); |
0 | 847 } |
848 | |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
849 if (options.count(OPTION_IMAGED_WIDTH)) |
0 | 850 { |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
851 volume.SetWidth(options[OPTION_IMAGED_WIDTH].as<float>()); |
0 | 852 } |
853 | |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
854 if (options.count(OPTION_IMAGED_HEIGHT)) |
0 | 855 { |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
856 volume.SetHeight(options[OPTION_IMAGED_HEIGHT].as<float>()); |
0 | 857 } |
858 | |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
859 if (options.count(OPTION_IMAGED_DEPTH)) |
0 | 860 { |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
861 volume.SetDepth(options[OPTION_IMAGED_DEPTH].as<float>()); |
0 | 862 } |
863 | |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
864 if (options.count(OPTION_OFFSET_X)) |
0 | 865 { |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
866 volume.SetOffsetX(options[OPTION_OFFSET_X].as<float>()); |
0 | 867 } |
868 | |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
869 if (options.count(OPTION_OFFSET_Y)) |
0 | 870 { |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
871 volume.SetOffsetY(options[OPTION_OFFSET_Y].as<float>()); |
0 | 872 } |
873 | |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
874 if (options.count(OPTION_OPTICAL_PATH)) |
0 | 875 { |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
876 std::string s = options[OPTION_OPTICAL_PATH].as<std::string>(); |
0 | 877 if (s == "none") |
878 { | |
879 parameters.SetOpticalPath(OrthancWSI::OpticalPath_None); | |
880 } | |
881 else if (s == "brightfield") | |
882 { | |
883 parameters.SetOpticalPath(OrthancWSI::OpticalPath_Brightfield); | |
884 } | |
885 else | |
886 { | |
887 LOG(ERROR) << "Unknown optical path definition: " << s; | |
888 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
889 } | |
890 } | |
891 | |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
892 if (options.count(OPTION_ICC_PROFILE)) |
0 | 893 { |
129
806d1bb56918
cleaning up options in Dicomizer
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
125
diff
changeset
|
894 parameters.SetIccProfilePath(options[OPTION_ICC_PROFILE].as<std::string>()); |
0 | 895 } |
896 | |
897 return true; | |
898 } | |
899 | |
900 | |
167
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
901 |
57
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
43
diff
changeset
|
902 OrthancWSI::ITiledPyramid* OpenInputPyramid(OrthancWSI::ImageCompression& sourceCompression, |
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
43
diff
changeset
|
903 const std::string& path, |
0 | 904 const OrthancWSI::DicomizerParameters& parameters) |
905 { | |
906 LOG(WARNING) << "The input image is: " << path; | |
907 | |
908 OrthancWSI::ImageCompression format = OrthancWSI::DetectFormatFromFile(path); | |
909 LOG(WARNING) << "File format of the input image: " << EnumerationToString(format); | |
910 | |
911 switch (format) | |
912 { | |
913 case OrthancWSI::ImageCompression_Png: | |
57
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
43
diff
changeset
|
914 { |
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
43
diff
changeset
|
915 sourceCompression = OrthancWSI::ImageCompression_Unknown; |
0 | 916 return new OrthancWSI::TiledPngImage(path, |
917 parameters.GetTargetTileWidth(512), | |
918 parameters.GetTargetTileHeight(512)); | |
57
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
43
diff
changeset
|
919 } |
0 | 920 |
921 case OrthancWSI::ImageCompression_Jpeg: | |
57
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
43
diff
changeset
|
922 { |
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
43
diff
changeset
|
923 sourceCompression = OrthancWSI::ImageCompression_Unknown; |
0 | 924 return new OrthancWSI::TiledJpegImage(path, |
925 parameters.GetTargetTileWidth(512), | |
926 parameters.GetTargetTileHeight(512)); | |
57
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
43
diff
changeset
|
927 } |
0 | 928 |
929 case OrthancWSI::ImageCompression_Tiff: | |
930 { | |
931 try | |
932 { | |
199
a1c265cb2174
replacing deprecated std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
192
diff
changeset
|
933 std::unique_ptr<OrthancWSI::HierarchicalTiff> tiff(new OrthancWSI::HierarchicalTiff(path)); |
57
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
43
diff
changeset
|
934 sourceCompression = tiff->GetImageCompression(); |
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
43
diff
changeset
|
935 return tiff.release(); |
0 | 936 } |
937 catch (Orthanc::OrthancException&) | |
938 { | |
939 LOG(WARNING) << "This is not a standard hierarchical TIFF file"; | |
940 } | |
941 } | |
942 | |
943 default: | |
944 break; | |
945 } | |
946 | |
947 try | |
948 { | |
949 LOG(WARNING) << "Trying to open the input pyramid with OpenSlide"; | |
57
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
43
diff
changeset
|
950 sourceCompression = OrthancWSI::ImageCompression_Unknown; |
0 | 951 return new OrthancWSI::OpenSlidePyramid(path, |
952 parameters.GetTargetTileWidth(512), | |
953 parameters.GetTargetTileHeight(512)); | |
954 } | |
955 catch (Orthanc::OrthancException&) | |
956 { | |
957 LOG(ERROR) << "This file is not supported by OpenSlide"; | |
958 return NULL; | |
959 } | |
960 } | |
961 | |
962 | |
963 int main(int argc, char* argv[]) | |
964 { | |
965 OrthancWSI::ApplicationToolbox::GlobalInitialize(); | |
93
14146ecd1688
Display version of the framework in the logs
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
84
diff
changeset
|
966 OrthancWSI::ApplicationToolbox::ShowVersionInLog(argv[0]); |
0 | 967 |
968 int exitStatus = 0; | |
969 | |
970 try | |
971 { | |
972 OrthancWSI::DicomizerParameters parameters; | |
973 OrthancWSI::ImagedVolumeParameters volume; | |
974 | |
975 if (ParseParameters(exitStatus, parameters, volume, argc, argv)) | |
976 { | |
57
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
43
diff
changeset
|
977 OrthancWSI::ImageCompression sourceCompression; |
199
a1c265cb2174
replacing deprecated std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
192
diff
changeset
|
978 std::unique_ptr<OrthancWSI::ITiledPyramid> source; |
57
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
43
diff
changeset
|
979 |
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
43
diff
changeset
|
980 source.reset(OpenInputPyramid(sourceCompression, parameters.GetInputFile(), parameters)); |
0 | 981 if (source.get() == NULL) |
982 { | |
983 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); | |
984 } | |
57
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
43
diff
changeset
|
985 |
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
43
diff
changeset
|
986 LOG(WARNING) << "Compression of the individual source tiles: " << OrthancWSI::EnumerationToString(sourceCompression); |
0 | 987 |
988 // Create the shared DICOM tags | |
199
a1c265cb2174
replacing deprecated std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
192
diff
changeset
|
989 std::unique_ptr<DcmDataset> dataset(ParseDataset(parameters.GetDatasetPath())); |
57
91fc9583b2de
big refactoring to support sparse tiling
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
43
diff
changeset
|
990 EnrichDataset(*dataset, *source, sourceCompression, parameters, volume); |
0 | 991 |
199
a1c265cb2174
replacing deprecated std::auto_ptr by std::unique_ptr
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
192
diff
changeset
|
992 std::unique_ptr<OrthancWSI::IFileTarget> output(parameters.CreateTarget()); |
167
605247fc8758
Fix issue #144 (OrthancWSIDicomizer PhotometricInterpretation)
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
166
diff
changeset
|
993 Recompress(*output, *source, *dataset, parameters, volume, sourceCompression); |
0 | 994 } |
995 } | |
996 catch (Orthanc::OrthancException& e) | |
997 { | |
998 LOG(ERROR) << "Terminating on exception: " << e.What(); | |
999 exitStatus = -1; | |
1000 } | |
1001 | |
1002 OrthancWSI::ApplicationToolbox::GlobalFinalize(); | |
1003 | |
1004 return exitStatus; | |
1005 } |