comparison Applications/DicomToTiff.cpp @ 128:788dd04b87f5

cleaning up options in DicomToTiff
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 02 Feb 2018 17:56:48 +0100
parents 7a3f4d580625
children a0f9a3df1110
comparison
equal deleted inserted replaced
127:2cb9fabb529e 128:788dd04b87f5
30 #include "../Resources/Orthanc/Plugins/Samples/Common/OrthancHttpConnection.h" 30 #include "../Resources/Orthanc/Plugins/Samples/Common/OrthancHttpConnection.h"
31 31
32 #include "ApplicationToolbox.h" 32 #include "ApplicationToolbox.h"
33 33
34 34
35 static const char* OPTION_COLOR = "color";
36 static const char* OPTION_HELP = "help";
37 static const char* OPTION_INPUT = "input";
38 static const char* OPTION_JPEG_QUALITY = "jpeg-quality";
39 static const char* OPTION_OUTPUT = "output";
40 static const char* OPTION_REENCODE = "reencode";
41 static const char* OPTION_VERBOSE = "verbose";
42 static const char* OPTION_VERSION = "version";
43
35 static bool ParseParameters(int& exitStatus, 44 static bool ParseParameters(int& exitStatus,
36 boost::program_options::variables_map& options, 45 boost::program_options::variables_map& options,
37 int argc, 46 int argc,
38 char* argv[]) 47 char* argv[])
39 { 48 {
40 // Declare the supported parameters 49 // Declare the supported parameters
41 boost::program_options::options_description generic("Generic options"); 50 boost::program_options::options_description generic("Generic options");
42 generic.add_options() 51 generic.add_options()
43 ("help", "Display this help and exit") 52 (OPTION_HELP, "Display this help and exit")
44 ("version", "Output version information and exit") 53 (OPTION_VERSION, "Output version information and exit")
45 ("verbose", "Be verbose in logs") 54 (OPTION_VERBOSE, "Be verbose in logs")
46 ; 55 ;
47 56
48 boost::program_options::options_description source("Options for the source DICOM image"); 57 boost::program_options::options_description source("Options for the source DICOM image");
49 source.add_options() 58 source.add_options()
50 ("orthanc", boost::program_options::value<std::string>()->default_value("http://localhost:8042/"), 59 ("orthanc", boost::program_options::value<std::string>()->default_value("http://localhost:8042/"),
52 ; 61 ;
53 OrthancWSI::ApplicationToolbox::AddRestApiOptions(source); 62 OrthancWSI::ApplicationToolbox::AddRestApiOptions(source);
54 63
55 boost::program_options::options_description target("Options for the target TIFF image"); 64 boost::program_options::options_description target("Options for the target TIFF image");
56 target.add_options() 65 target.add_options()
57 ("color", boost::program_options::value<std::string>(), "Color of the background for missing tiles (e.g. \"255,0,0\")") 66 (OPTION_COLOR, boost::program_options::value<std::string>(),
58 ("reencode", boost::program_options::value<bool>(), 67 "Color of the background for missing tiles (e.g. \"255,0,0\")")
68 (OPTION_REENCODE, boost::program_options::value<bool>(),
59 "Whether to re-encode each tile in JPEG (no transcoding, much slower) (Boolean)") 69 "Whether to re-encode each tile in JPEG (no transcoding, much slower) (Boolean)")
60 ("jpeg-quality", boost::program_options::value<int>(), "Set quality level for JPEG (0..100)") 70 (OPTION_JPEG_QUALITY, boost::program_options::value<int>(),
71 "Set quality level for JPEG (0..100)")
61 ; 72 ;
62 73
63 boost::program_options::options_description hidden; 74 boost::program_options::options_description hidden;
64 hidden.add_options() 75 hidden.add_options()
65 ("input", boost::program_options::value<std::string>(), "Orthanc identifier of the input series of interest") 76 (OPTION_INPUT, boost::program_options::value<std::string>(),
66 ("output", boost::program_options::value<std::string>(), "Output TIFF file"); 77 "Orthanc identifier of the input series of interest")
67 ; 78 (OPTION_OUTPUT, boost::program_options::value<std::string>(),
79 "Output TIFF file");
68 80
69 boost::program_options::options_description allWithoutHidden; 81 boost::program_options::options_description allWithoutHidden;
70 allWithoutHidden.add(generic).add(source).add(target); 82 allWithoutHidden.add(generic).add(source).add(target);
71 83
72 boost::program_options::options_description all = allWithoutHidden; 84 boost::program_options::options_description all = allWithoutHidden;
73 all.add(hidden); 85 all.add(hidden);
74 86
75 boost::program_options::positional_options_description positional; 87 boost::program_options::positional_options_description positional;
76 positional.add("input", 1); 88 positional.add(OPTION_INPUT, 1);
77 positional.add("output", 1); 89 positional.add(OPTION_OUTPUT, 1);
78 90
79 bool error = false; 91 bool error = false;
80 92
81 try 93 try
82 { 94 {
89 LOG(ERROR) << "Error while parsing the command-line arguments: " << e.what(); 101 LOG(ERROR) << "Error while parsing the command-line arguments: " << e.what();
90 error = true; 102 error = true;
91 } 103 }
92 104
93 if (!error && 105 if (!error &&
94 options.count("help") == 0 && 106 options.count(OPTION_HELP) == 0 &&
95 options.count("version") == 0) 107 options.count(OPTION_VERSION) == 0)
96 { 108 {
97 if (options.count("input") != 1) 109 if (options.count(OPTION_INPUT) != 1)
98 { 110 {
99 LOG(ERROR) << "No input series was specified"; 111 LOG(ERROR) << "No input series was specified";
100 error = true; 112 error = true;
101 } 113 }
102 114
103 if (options.count("output") != 1) 115 if (options.count(OPTION_OUTPUT) != 1)
104 { 116 {
105 LOG(ERROR) << "No output file was specified"; 117 LOG(ERROR) << "No output file was specified";
106 error = true; 118 error = true;
107 } 119 }
108 } 120 }
109 121
110 if (error || options.count("help")) 122 if (error || options.count(OPTION_HELP))
111 { 123 {
112 std::cout << std::endl 124 std::cout << std::endl
113 << "Usage: " << argv[0] << " [OPTION]... [INPUT] [OUTPUT]" 125 << "Usage: " << argv[0] << " [OPTION]... [INPUT] [OUTPUT]"
114 << std::endl 126 << std::endl
115 << "Orthanc, lightweight, RESTful DICOM server for healthcare and medical research." 127 << "Orthanc, lightweight, RESTful DICOM server for healthcare and medical research."
126 } 138 }
127 139
128 return false; 140 return false;
129 } 141 }
130 142
131 if (options.count("version")) 143 if (options.count(OPTION_VERSION))
132 { 144 {
133 OrthancWSI::ApplicationToolbox::PrintVersion(argv[0]); 145 OrthancWSI::ApplicationToolbox::PrintVersion(argv[0]);
134 return false; 146 return false;
135 } 147 }
136 148
137 if (options.count("verbose")) 149 if (options.count(OPTION_VERBOSE))
138 { 150 {
139 Orthanc::Logging::EnableInfoLevel(true); 151 Orthanc::Logging::EnableInfoLevel(true);
140 } 152 }
141 153
142 return true; 154 return true;
154 166
155 uint8_t red = 255; 167 uint8_t red = 255;
156 uint8_t green = 255; 168 uint8_t green = 255;
157 uint8_t blue = 255; 169 uint8_t blue = 255;
158 170
159 if (options.count("color")) 171 if (options.count(OPTION_COLOR))
160 { 172 {
161 OrthancWSI::ApplicationToolbox::ParseColor(red, green, blue, options["color"].as<std::string>()); 173 OrthancWSI::ApplicationToolbox::ParseColor(red, green, blue, options[OPTION_COLOR].as<std::string>());
162 } 174 }
163 175
164 OrthancWSI::ImageToolbox::Set(*tile, red, green, blue); 176 OrthancWSI::ImageToolbox::Set(*tile, red, green, blue);
165 177
166 return tile.release(); 178 return tile.release();
169 181
170 182
171 static void Run(OrthancWSI::ITiledPyramid& source, 183 static void Run(OrthancWSI::ITiledPyramid& source,
172 const boost::program_options::variables_map& options) 184 const boost::program_options::variables_map& options)
173 { 185 {
174 OrthancWSI::HierarchicalTiffWriter target(options["output"].as<std::string>(), 186 OrthancWSI::HierarchicalTiffWriter target(options[OPTION_OUTPUT].as<std::string>(),
175 source.GetPixelFormat(), 187 source.GetPixelFormat(),
176 OrthancWSI::ImageCompression_Jpeg, 188 OrthancWSI::ImageCompression_Jpeg,
177 source.GetTileWidth(), 189 source.GetTileWidth(),
178 source.GetTileHeight()); 190 source.GetTileHeight());
179 191
180 bool reencode = (options.count("reencode") && 192 bool reencode = (options.count(OPTION_REENCODE) &&
181 options["reencode"].as<bool>()); 193 options[OPTION_REENCODE].as<bool>());
182 194
183 if (options.count("jpeg-quality")) 195 if (options.count(OPTION_JPEG_QUALITY))
184 { 196 {
185 target.SetJpegQuality(options["jpeg-quality"].as<int>()); 197 target.SetJpegQuality(options[OPTION_JPEG_QUALITY].as<int>());
186 } 198 }
187 199
188 std::auto_ptr<Orthanc::ImageAccessor> empty(CreateEmptyTile(target, options)); 200 std::auto_ptr<Orthanc::ImageAccessor> empty(CreateEmptyTile(target, options));
189 201
190 for (unsigned int level = 0; level < source.GetLevelCount(); level++) 202 for (unsigned int level = 0; level < source.GetLevelCount(); level++)
194 target.AddLevel(source.GetLevelWidth(level), source.GetLevelHeight(level)); 206 target.AddLevel(source.GetLevelWidth(level), source.GetLevelHeight(level));
195 } 207 }
196 208
197 for (unsigned int level = 0; level < source.GetLevelCount(); level++) 209 for (unsigned int level = 0; level < source.GetLevelCount(); level++)
198 { 210 {
199 LOG(WARNING) << std::string(reencode ? "Reencoding" : "Transcoding") << " level " << level; 211 LOG(WARNING) << std::string(reencode ? "Reencoding" : "Transcoding")
200 212 << " level " << level;
201 unsigned int countX = OrthancWSI::CeilingDivision(source.GetLevelWidth(level), source.GetTileWidth()); 213
202 unsigned int countY = OrthancWSI::CeilingDivision(source.GetLevelHeight(level), source.GetTileHeight()); 214 unsigned int countX = OrthancWSI::CeilingDivision
215 (source.GetLevelWidth(level), source.GetTileWidth());
216
217 unsigned int countY = OrthancWSI::CeilingDivision
218 (source.GetLevelHeight(level), source.GetTileHeight());
203 219
204 for (unsigned int tileY = 0; tileY < countY; tileY++) 220 for (unsigned int tileY = 0; tileY < countY; tileY++)
205 { 221 {
206 for (unsigned int tileX = 0; tileX < countX; tileX++) 222 for (unsigned int tileX = 0; tileX < countX; tileX++)
207 { 223 {
248 264
249 if (!success) 265 if (!success)
250 { 266 {
251 LOG(WARNING) << "Cannot transcode a DICOM image that is not encoded using JPEG (it is " 267 LOG(WARNING) << "Cannot transcode a DICOM image that is not encoded using JPEG (it is "
252 << OrthancWSI::EnumerationToString(compression) 268 << OrthancWSI::EnumerationToString(compression)
253 << "), please use the --reencode=1 option"; 269 << "), please use the --" << OPTION_REENCODE << "=1 option";
254 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); 270 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
255 } 271 }
256 272
257 if (missing) 273 if (missing)
258 { 274 {
284 Orthanc::WebServiceParameters params; 300 Orthanc::WebServiceParameters params;
285 301
286 OrthancWSI::ApplicationToolbox::SetupRestApi(params, options); 302 OrthancWSI::ApplicationToolbox::SetupRestApi(params, options);
287 303
288 OrthancPlugins::OrthancHttpConnection orthanc(params); 304 OrthancPlugins::OrthancHttpConnection orthanc(params);
289 OrthancWSI::DicomPyramid source(orthanc, options["input"].as<std::string>(), 305 OrthancWSI::DicomPyramid source(orthanc, options[OPTION_INPUT].as<std::string>(),
290 false /* don't use cached metadata */); 306 false /* don't use cached metadata */);
291 307
292 OrthancWSI::TiledPyramidStatistics stats(source); 308 OrthancWSI::TiledPyramidStatistics stats(source);
293 Run(stats, options); 309 Run(stats, options);
294 } 310 }
295 } 311 }
296 catch (Orthanc::OrthancException& e) 312 catch (Orthanc::OrthancException& e)
297 { 313 {
298 LOG(ERROR) << "Terminating on exception: " << e.What(); 314 LOG(ERROR) << "Terminating on exception: " << e.What();
299 315
300 if (options.count("reencode") == 0) 316 if (options.count(OPTION_REENCODE) == 0)
301 { 317 {
302 LOG(ERROR) << "Consider using option \"--reencode\""; 318 LOG(ERROR) << "Consider using option \"--" << OPTION_REENCODE << "\"";
303 } 319 }
304 320
305 exitStatus = -1; 321 exitStatus = -1;
306 } 322 }
307 323