in src/main.cpp [29:315]
int main(int argc, char *argv[]) {
std::string inputFile;
std::string jsonFile;
std::string outputFolder;
std::string compression;
std::string seriesDescription;
std::string seriesId;
std::string studyId;
std::string downsamplingAlgorithm;
std::string firstlevelCompression;
std::string jpegSubsampling;
int tileHeight;
int tileWidth;
int levels;
int start;
int stop;
int batch;
int threads;
bool debug;
bool dropFirstRowAndColumn;
bool stopDownsamplingAtSingleFrame;
bool floorCorrectDownsampling;
bool preferProgressiveDownsampling;
bool SVSImportPreferScannerTileingForLargestLevel;
bool SVSImportPreferScannerTileingForAllLevels;
int compressionQuality;
bool readUntiledImage;
double untiledImageHeightMM;
std::vector<int> downsamples;
bool sparse;
bool includeSingleFrameDownsample;
try {
namespace programOptions = boost::program_options;
programOptions::options_description desc("Options", 90, 20);
desc.add_options()("help", "Print help messages")(
"input", programOptions::value<std::string>(&inputFile)->required(),
"input file")("outFolder",
programOptions::value<std::string>(&outputFolder)
->required()
->default_value("./"),
"folder to store dcm files")(
"tileHeight",
programOptions::value<int>(&tileHeight)->required()->default_value(500),
"tile height px")(
"tileWidth",
programOptions::value<int>(&tileWidth)->required()->default_value(500),
"tile width px")("levels",
programOptions::value<int>(&levels)->default_value(0),
"number of levels, levels == 0 means number of levels "
"will be readed from wsi file")(
"downsamples",
programOptions::value<std::vector<int> >(&downsamples)->multitoken(),
"downsample for each level, downsample is size factor for each level."
" If used with progressiveDownsample, downsamples must be ordered from "
"low downsampling to high downsampling (e.g., 1 2 4)")(
"startOn", programOptions::value<int>(&start)->default_value(0),
"level to start")("stopOn",
programOptions::value<int>(&stop)->default_value(-1),
"level to stop")(
"sparse", programOptions::bool_switch(&sparse)->default_value(false),
"use TILED_SPARSE frame organization, by default it's TILED_FULL")(
"compression",
programOptions::value<std::string>(&compression)->default_value("jpeg"),
"compression, supported compressions: jpeg, jpeg2000, raw")(
"firstLevelCompression",
programOptions::value<std::string>(&firstlevelCompression)
->default_value("default"),
"compression, supported compressions: jpeg, jpeg2000, raw")
(
"seriesDescription",
programOptions::value<std::string>(&seriesDescription)->
default_value(""),
"series description in SeriesDescription tag")(
"studyId",
programOptions::value<std::string>(&studyId)->required()->default_value(
""),
"StudyID")("seriesId",
programOptions::value<std::string>(&seriesId)
->required()
->default_value(""),
"SeriesID")("jsonFile",
programOptions::value<std::string>(&jsonFile),
"dicom json file with additional tags "
"\nhttps://www.dicomstandard.org/dicomweb/dicom-json-format/")(
"batch", programOptions::value<int>(&batch)->default_value(0),
"maximum frames in one file")(
"threads",
programOptions::value<int>(&threads)->required()->default_value(-1),
"number of threads")(
"debug", programOptions::bool_switch(&debug)->default_value(false),
"debug messages")(
"dropFirstRowAndColumn",
programOptions::bool_switch(
&dropFirstRowAndColumn)->default_value(false),
"drop first row and column of the source image in order to "
"workaround bug\nhttps://github.com/openslide/openslide/issues/268")
("stopDownsamplingAtSingleFrame",
programOptions::bool_switch(
&stopDownsamplingAtSingleFrame)->default_value(false),
"Stop image downsampling if image dimensions < "
"frame dimensions.")
("floorCorrectOpenslideLevelDownsamples",
programOptions::bool_switch(
&floorCorrectDownsampling)->default_value(false),
"Floor openslide level downsampling to improve pixel-to-pixel "
"correspondance for level images which are dimensionally not perfect "
"multiples. Example (40x 45,771x35,037) downsampled (16x) -> "
"(2.5x 2,860 x 2,189) openslide reported downsampling: 16.004892."
" Floor correction = 16")
("progressiveDownsample",
programOptions::bool_switch(
&preferProgressiveDownsampling)->default_value(false),
"Preferentially generate downsampled images progressively from "
"prior downsampled images. Faster, increased memory requirment, and "
"avoids rounding bug in openslide api which can cause pixel level "
"alignemnt issues when generating output from images captured at "
"multiple downsampling levels. To use images must be generated from "
"highest to lowest magnification.")
("jpegCompressionQuality",
programOptions::value<int>(
&compressionQuality)->default_value(80),
"Compression quality range(0 - 100")
("opencvDownsampling",
programOptions::value<std::string>(
&downsamplingAlgorithm)->default_value("NONE"),
"OpenCV downsampling algorithm, supported: LANCZOS4, CUBIC, AREA, "
"LINEAR, LINEAR_EXACT, NEAREST, NEAREST_EXACT. Default value "
"'NONE' uses non-opencv boost::gli nearestneighbor downsampling.")
("SVSImportPreferScannerTileingForLargestLevel",
programOptions::bool_switch(
&SVSImportPreferScannerTileingForLargestLevel)->default_value(false),
"Optimization for DICOM generation from jpeg encoded SVS, generates "
" highest magification DICOM using svs encoded jpeg images "
"directly without decompression to avoid recompression artifacts."
" First slice compression and tile dimensions command line parameters "
" apply only DICOM generation from non-jpeg "
" encoded svs imaging and non-svs imaging. Does not support "
"re-tiling of jpeg encoded svs. Not compatiable with "
"row/column-dropping or cropping commandline settings options.")
("SVSImportPreferScannerTileingForAllLevels",
programOptions::bool_switch(
&SVSImportPreferScannerTileingForAllLevels)->default_value(false),
"Optimization for jpeg encoded SVS. Use jpeg images encoded in SVS at "
"all levels preferentially. Same limitations as "
"SVSImportPreferScannerTileingForLargestLevel. Compression settings "
"apply to generated levels only.")
("readImage",
programOptions::bool_switch(&readUntiledImage)->default_value(false),
"Generate DICOM Pyramid from untiled image.")
("untiledImageHeightMM",
programOptions::value<double>(&untiledImageHeightMM)->default_value(
0.0), "Height in mm of untiled image (assumed square pixel"
" aspect ratio).")
("singleFrameDownsample",
programOptions::bool_switch(&includeSingleFrameDownsample)->
default_value(false), "Force downsampling to include at least one "
"single frame downsample.")
("jpegSubsampling",
programOptions::value<std::string>(&jpegSubsampling)->
default_value("420"), "JPEG subsampling for Y component, supported: "
"444(best-quality), 440, 442, 420(most-compressed).");
programOptions::positional_options_description positionalOptions;
positionalOptions.add("input", 1);
positionalOptions.add("outFolder", 1);
programOptions::variables_map vm;
try {
programOptions::store(programOptions::command_line_parser(argc, argv)
.options(desc)
.positional(positionalOptions)
.run(),
vm);
if (vm.count("help")) {
std::cout << "Wsi2dcm" << std::endl << desc << std::endl;
return SUCCESS;
}
programOptions::notify(vm);
} catch (programOptions::error &e) {
std::cerr << "ERROR: " << e.what() << std::endl << std::endl;
std::cerr << desc << std::endl;
return ERROR_IN_COMMAND_LINE;
}
} catch (std::exception &exception) {
std::cerr << "Unhandled Exception reached the top of main: "
<< exception.what() << ", application will now exit" << std::endl;
return ERROR_UNHANDLED_EXCEPTION;
}
if (dropFirstRowAndColumn &&
(SVSImportPreferScannerTileingForLargestLevel ||
SVSImportPreferScannerTileingForAllLevels)) {
std::cerr << "Options: dropFirstRowAndColumn is"
<< " not compatible with Options: " <<
"SVSImportPreferScannerTileingForLargestLevel and " <<
"SVSImportPreferScannerTileingForAllLevels." << std::endl;
return ERROR_IN_COMMAND_LINE;
}
if (readUntiledImage & !preferProgressiveDownsampling) {
std::cerr << "Generating WSI Pyramids from un-tiled images requires "
"enabling progressive downsampling." << std::endl;
return ERROR_IN_COMMAND_LINE;
}
if (downsamples.size() > 0 && levels != 0) {
std::cerr << "Invalid configuration cannot use the combination of "
"downsamples and levels." << std::endl;
return ERROR_IN_COMMAND_LINE;
}
wsiToDicomConverter::WsiRequest request;
request.genPyramidFromUntiledImage = readUntiledImage;
request.untiledImageHeightMM = untiledImageHeightMM;
request.inputFile = inputFile;
request.outputFileMask = outputFolder;
request.frameSizeX = std::max(tileWidth, 1);
request.frameSizeY = std::max(tileHeight, 1);
request.firstlevelCompression = (firstlevelCompression == "default") ?
dcmCompressionFromString(compression) :
dcmCompressionFromString(firstlevelCompression);
request.compression = dcmCompressionFromString(compression);
request.quality = std::max(std::min(100, compressionQuality), 0);
request.startOnLevel = std::max(start, 0);
request.stopOnLevel = std::max(stop, -1);
request.imageName = seriesDescription;
request.studyId = studyId;
request.seriesId = seriesId;
request.jsonFile = jsonFile;
request.retileLevels = std::max(levels, 0);
request.includeSingleFrameDownsample = includeSingleFrameDownsample;
for (int downsample : downsamples) {
if (downsample > 0) {
request.downsamples.push_back(downsample);
}
}
request.tiled = !sparse;
request.batchLimit = std::max(batch, 0);
request.threads = std::max(threads, -1);
request.dropFirstRowAndColumn = dropFirstRowAndColumn;
request.stopDownsamplingAtSingleFrame = stopDownsamplingAtSingleFrame;
request.floorCorrectDownsampling = floorCorrectDownsampling;
if (request.genPyramidFromUntiledImage) {
request.preferProgressiveDownsampling = true;
} else {
request.preferProgressiveDownsampling = preferProgressiveDownsampling;
}
request.SVSImportPreferScannerTileingForLargestLevel =
SVSImportPreferScannerTileingForLargestLevel;
request.SVSImportPreferScannerTileingForAllLevels =
SVSImportPreferScannerTileingForAllLevels;
request.useOpenCVDownsampling = true;
if (downsamplingAlgorithm == "LANCZOS4") {
request.openCVInterpolationMethod = cv::INTER_LANCZOS4;
} else if (downsamplingAlgorithm == "CUBIC") {
request.openCVInterpolationMethod = cv::INTER_CUBIC;
} else if (downsamplingAlgorithm == "AREA") {
request.openCVInterpolationMethod = cv::INTER_AREA;
} else if (downsamplingAlgorithm == "LINEAR") {
request.openCVInterpolationMethod = cv::INTER_LINEAR;
} else if (downsamplingAlgorithm == "LINEAR_EXACT") {
request.openCVInterpolationMethod = cv::INTER_LINEAR_EXACT;
} else if (downsamplingAlgorithm == "NEAREST") {
request.openCVInterpolationMethod = cv::INTER_NEAREST;
} else if (downsamplingAlgorithm == "NEAREST_EXACT") {
request.openCVInterpolationMethod = cv::INTER_NEAREST_EXACT;
} else if (downsamplingAlgorithm == "NONE") {
request.openCVInterpolationMethod = cv::INTER_AREA;
request.useOpenCVDownsampling = false;
} else {
std::cerr << "Unrecognized OpenCVDownsamplingAlgorithm: " <<
downsamplingAlgorithm;
return 1;
}
request.debug = debug;
if (jpegSubsampling == "444") {
request.jpegSubsampling = subsample_444;
} else if (jpegSubsampling == "440") {
request.jpegSubsampling = subsample_440;
} else if (jpegSubsampling == "422") {
request.jpegSubsampling = subsample_422;
} else if (jpegSubsampling == "420") {
request.jpegSubsampling = subsample_420;
} else {
std::cerr << "Unrecognized jpegSubsampling: " <<
jpegSubsampling;
return 1;
}
wsiToDicomConverter::WsiToDcm converter(&request);
return converter.wsi2dcm();
}