From 2c9740fd011a7fb139c154a24369ddff400f95c6 Mon Sep 17 00:00:00 2001 From: Andrey Fedorov Date: Thu, 2 May 2019 13:50:35 -0400 Subject: [PATCH] ENH: improve error handling - catch exceptions in SEG and PM converters - add error messages --- apps/paramaps/itkimage2paramap.cxx | 24 +++++---- apps/paramaps/paramap2itkimage.cxx | 51 ++++++++++--------- apps/seg/itkimage2segimage.cxx | 39 +++++++------- apps/seg/segimage2itkimage.cxx | 1 + ...SONParametricMapMetaInformationHandler.cpp | 5 +- ...JSONSegmentationMetaInformationHandler.cpp | 6 ++- libsrc/ParaMapConverter.cpp | 14 ++--- 7 files changed, 81 insertions(+), 59 deletions(-) diff --git a/apps/paramaps/itkimage2paramap.cxx b/apps/paramaps/itkimage2paramap.cxx index 583b86d9..911a6399 100644 --- a/apps/paramaps/itkimage2paramap.cxx +++ b/apps/paramaps/itkimage2paramap.cxx @@ -36,7 +36,7 @@ int main(int argc, char *argv[]) vector dcmDatasets = helper::loadDatasets(dicomImageFileList); if(dcmDatasets.empty()){ - cerr << "Error: no DICOM could be loaded from the specified list/directory" << endl; + cerr << "ERROR: no DICOM could be loaded from the specified list/directory" << endl; return EXIT_FAILURE; } @@ -44,15 +44,21 @@ int main(int argc, char *argv[]) std::string metadata( (std::istreambuf_iterator(metainfoStream) ), (std::istreambuf_iterator())); - DcmDataset* result = dcmqi::ParaMapConverter::itkimage2paramap(parametricMapImage, dcmDatasets, metadata); + try { + DcmDataset* result = dcmqi::ParaMapConverter::itkimage2paramap(parametricMapImage, dcmDatasets, metadata); - if (result == NULL) { - return EXIT_FAILURE; - } else { - DcmFileFormat segdocFF(result); - CHECK_COND(segdocFF.saveFile(outputParaMapFileName.c_str(), EXS_LittleEndianExplicit)); + if (result == NULL) { + std::cerr << "ERROR: Conversion failed." << std::endl; + return EXIT_FAILURE; + } else { + DcmFileFormat segdocFF(result); + CHECK_COND(segdocFF.saveFile(outputParaMapFileName.c_str(), EXS_LittleEndianExplicit)); - COUT << "Saved parametric map as " << outputParaMapFileName << endl; - return EXIT_SUCCESS; + COUT << "Saved parametric map as " << outputParaMapFileName << endl; + return EXIT_SUCCESS; + } + } catch (int e) { + std::cerr << "Fatal error encountered." << std::endl; + return EXIT_FAILURE; } } diff --git a/apps/paramaps/paramap2itkimage.cxx b/apps/paramaps/paramap2itkimage.cxx index aa1def1d..c0d82cd8 100644 --- a/apps/paramaps/paramap2itkimage.cxx +++ b/apps/paramaps/paramap2itkimage.cxx @@ -25,27 +25,32 @@ int main(int argc, char *argv[]) CHECK_COND(sliceFF.loadFile(inputFileName.c_str())); DcmDataset* dataset = sliceFF.getDataset(); - pair result = dcmqi::ParaMapConverter::paramap2itkimage(dataset); - - string fileExtension = helper::getFileExtensionFromType(outputType); - - typedef itk::ImageFileWriter WriterType; - string outputPrefix = prefix.empty() ? "" : prefix + "-"; - WriterType::Pointer writer = WriterType::New(); - stringstream imageFileNameSStream; - imageFileNameSStream << outputDirName << "/" << outputPrefix << "pmap" << fileExtension; - writer->SetFileName(imageFileNameSStream.str().c_str()); - writer->SetInput(result.first); - writer->SetUseCompression(1); - writer->Update(); - - stringstream jsonOutput; - jsonOutput << outputDirName << "/" << outputPrefix << "meta.json"; - - ofstream outputFile; - outputFile.open(jsonOutput.str().c_str()); - outputFile << result.second; - outputFile.close(); - - return EXIT_SUCCESS; + try { + pair result = dcmqi::ParaMapConverter::paramap2itkimage(dataset); + + string fileExtension = helper::getFileExtensionFromType(outputType); + + typedef itk::ImageFileWriter WriterType; + string outputPrefix = prefix.empty() ? "" : prefix + "-"; + WriterType::Pointer writer = WriterType::New(); + stringstream imageFileNameSStream; + imageFileNameSStream << outputDirName << "/" << outputPrefix << "pmap" << fileExtension; + writer->SetFileName(imageFileNameSStream.str().c_str()); + writer->SetInput(result.first); + writer->SetUseCompression(1); + writer->Update(); + + stringstream jsonOutput; + jsonOutput << outputDirName << "/" << outputPrefix << "meta.json"; + + ofstream outputFile; + outputFile.open(jsonOutput.str().c_str()); + outputFile << result.second; + outputFile.close(); + + return EXIT_SUCCESS; + } catch (int e) { + std::cerr << "Fatal error encountered." << std::endl; + return EXIT_FAILURE; + } } diff --git a/apps/seg/itkimage2segimage.cxx b/apps/seg/itkimage2segimage.cxx index 862eddc2..50213164 100644 --- a/apps/seg/itkimage2segimage.cxx +++ b/apps/seg/itkimage2segimage.cxx @@ -91,26 +91,31 @@ int main(int argc, char *argv[]) segmentations = segmentationsReordered; } - DcmDataset* result = dcmqi::ImageSEGConverter::itkimage2dcmSegmentation(dcmDatasets, segmentations, metadata, skipEmptySlices); + try { + DcmDataset* result = dcmqi::ImageSEGConverter::itkimage2dcmSegmentation(dcmDatasets, segmentations, metadata, skipEmptySlices); - if (result == NULL){ - return EXIT_FAILURE; - } else { - DcmFileFormat segdocFF(result); - bool compress = false; - if(compress){ - CHECK_COND(segdocFF.saveFile(outputSEGFileName.c_str(), EXS_DeflatedLittleEndianExplicit)); + if (result == NULL){ + std::cerr << "ERROR: Conversion failed." << std::endl; + return EXIT_FAILURE; } else { - CHECK_COND(segdocFF.saveFile(outputSEGFileName.c_str(), EXS_LittleEndianExplicit)); - } + DcmFileFormat segdocFF(result); + bool compress = false; + if(compress){ + CHECK_COND(segdocFF.saveFile(outputSEGFileName.c_str(), EXS_DeflatedLittleEndianExplicit)); + } else { + CHECK_COND(segdocFF.saveFile(outputSEGFileName.c_str(), EXS_LittleEndianExplicit)); + } - COUT << "Saved segmentation as " << outputSEGFileName << endl; - } + COUT << "Saved segmentation as " << outputSEGFileName << endl; + } - for(size_t i=0;ijsonInput); metainfoStream >> this->metaInfoRoot; + //std::cout << this->metaInfoRoot.asString() << std::endl; this->seriesDescription = this->metaInfoRoot.get("SeriesDescription", "Segmentation").asString(); this->seriesNumber = this->metaInfoRoot.get("SeriesNumber", "300").asString(); this->instanceNumber = this->metaInfoRoot.get("InstanceNumber", "1").asString(); @@ -158,7 +159,9 @@ namespace dcmqi { } } catch (exception& e) { - cout << e.what() << endl; + cerr << "ERROR: JSON parameter file could not be parsed!" << std::endl; + cerr << "You can validate the JSON file here: http://qiicr.org/dcmqi/#/validators" << std::endl; + cerr << "Exception details (probably not very useful): " << e.what() << endl; throw JSONReadErrorException(); } } diff --git a/libsrc/JSONSegmentationMetaInformationHandler.cpp b/libsrc/JSONSegmentationMetaInformationHandler.cpp index d6e01cb0..19208a05 100644 --- a/libsrc/JSONSegmentationMetaInformationHandler.cpp +++ b/libsrc/JSONSegmentationMetaInformationHandler.cpp @@ -52,8 +52,10 @@ namespace dcmqi { this->bodyPartExamined = this->metaInfoRoot.get("BodyPartExamined", "").asString(); this->readSegmentAttributes(); - } catch (exception &e) { - cout << e.what() << '\n'; + } catch (exception& e) { + cerr << "ERROR: JSON parameter file could not be parsed!" << std::endl; + cerr << "You can validate the JSON file here: http://qiicr.org/dcmqi/#/validators" << std::endl; + cerr << "Exception details (probably not very useful): " << e.what() << endl; throw JSONReadErrorException(); } } diff --git a/libsrc/ParaMapConverter.cpp b/libsrc/ParaMapConverter.cpp index 8ace2fbe..c8f9d4b8 100644 --- a/libsrc/ParaMapConverter.cpp +++ b/libsrc/ParaMapConverter.cpp @@ -220,7 +220,7 @@ namespace dcmqi { bval->getEntireConceptNameCodeSequence().push_back(qCodeName); bval->getEntireMeasurementUnitsCodeSequence().push_back(bvalUnits); if(bval->setNumericValue(metaInfo.metaInfoRoot["SourceImageDiffusionBValues"][static_cast(bvalId)].asCString()).bad()) - cout << "Failed to insert the value!" << endl;; + cout << "ERROR: Failed to insert the value!" << endl;; realWorldValueMappingItem->getEntireQuantityDefinitionSequence().push_back(bval); cout << bval->toString() << endl; } @@ -301,8 +301,8 @@ namespace dcmqi { metaInfo.getDerivationDescription().c_str(), derimgItem)); } else { - cerr << "DerivationCode must be specified in the input metadata!" << endl; - return NULL; + cerr << "ERROR: DerivationCode must be specified in the input metadata!" << endl; + throw -1; } //cout << "Total of " << siVector.size() << " source image items will be added" << endl; @@ -453,7 +453,7 @@ namespace dcmqi { FGInterface &fgInterface = pMapDoc->getFunctionalGroups(); FloatImageType::DirectionType direction; if(getImageDirections(fgInterface, direction)){ - cerr << "Failed to get image directions" << endl; + cerr << "ERROR: Failed to get image directions" << endl; throw -1; } @@ -466,14 +466,14 @@ namespace dcmqi { FloatImageType::PointType imageOrigin; if(computeVolumeExtent(fgInterface, sliceDirection, imageOrigin, computedSliceSpacing, computedVolumeExtent)){ - cerr << "Failed to compute origin and/or slice spacing!" << endl; + cerr << "ERROR: Failed to compute origin and/or slice spacing!" << endl; throw -1; } FloatImageType::SpacingType imageSpacing; imageSpacing.Fill(0); if(getDeclaredImageSpacing(fgInterface, imageSpacing)){ - cerr << "Failed to get image spacing from DICOM!" << endl; + cerr << "ERROR: Failed to get image spacing from DICOM!" << endl; throw -1; } @@ -616,7 +616,7 @@ namespace dcmqi { OFvariant result = DPMParametricMapIOD::loadDataset(*pmapDataset); if (OFCondition* pCondition = OFget(&result)) { - cerr << "Failed to load parametric map! " << pCondition->text() << endl; + cerr << "ERROR: Failed to load parametric map! " << pCondition->text() << endl; throw -1; } DPMParametricMapIOD* pMapDoc = *OFget(&result);