Skip to content

Commit

Permalink
ENH: adding functionality - temp commit
Browse files Browse the repository at this point in the history
  • Loading branch information
fedorov committed May 5, 2017
1 parent 925b282 commit ff52820
Show file tree
Hide file tree
Showing 7 changed files with 218 additions and 33 deletions.
28 changes: 0 additions & 28 deletions docker/dcmqi/imagefiles/docker_entry.sh

This file was deleted.

5 changes: 5 additions & 0 deletions include/dcmqi/Helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
// DCMQI includes
#include "dcmqi/Exceptions.h"

#include <json/json.h>

using namespace std;

namespace dcmqi {
Expand Down Expand Up @@ -45,6 +47,9 @@ namespace dcmqi {

static CodeSequenceMacro stringToCodeSequenceMacro(string str);
static DSRCodedEntryValue stringToDSRCodedEntryValue(string str);
static string codeSequenceMacroToString(CodeSequenceMacro);

static CodeSequenceMacro jsonToCodeSequenceMacro(Json::Value);

static void checkValidityOfFirstSrcImage(DcmSegmentation *segdoc);

Expand Down
6 changes: 5 additions & 1 deletion include/dcmqi/MultiframeObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,12 @@ class MultiframeObject {
virtual int initializeCompositeContext();
virtual bool metaDataIsComplete();



// List of tags, and FGs they belong to, for initializing dimensions module
int initializeDimensions(IODMultiframeDimensionModule&, std::vector<std::pair<DcmTag, DcmTag> >);
int initializeDimensions(std::vector<std::pair<DcmTag, DcmTag> >);
int initializePixelMeasuresFG();
int initializePlaneOrientationFG();

// constants to describe original representation of the data being converted
enum {
Expand Down
4 changes: 3 additions & 1 deletion include/dcmqi/ParametricMapObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,13 @@ class ParametricMapObject : public MultiframeObject {
protected:
typedef itk::CastImageFilter<Float32ITKImageType,DummyImageType>
Float32ToDummyCasterType;
typedef itk::MinimumMaximumImageCalculator<Float32ITKImageType> MinMaxCalculatorType;

int initializeVolumeGeometry();
int createParametricMap();
int initializeDimensionsModule();
int initializeCompositeContext();
int initializeFrameAnatomyFG();
int initializeRWVMFG();

// Functional groups initialization

Expand Down
12 changes: 12 additions & 0 deletions libsrc/Helper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -352,4 +352,16 @@ namespace dcmqi {
CHECK_COND(dcm->findAndGetOFString(tag, value));
return value;
}

CodeSequenceMacro Helper::jsonToCodeSequenceMacro(Json::Value jv){
return CodeSequenceMacro(jv["CodeValue"].asCString(),
jv["CodingSchemeDesignator"].asCString(),
jv["CodeMeaning"].asCString());
}

string Helper::codeSequenceMacroToString(CodeSequenceMacro c){
OFString codeValue, codingSchemeDesignator, codeMeaning;
string s = string()+codeValue.c_str()+","+codingSchemeDesignator.c_str()+","+codeMeaning.c_str();
return s;
}
}
33 changes: 30 additions & 3 deletions libsrc/MultiframeObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,42 @@ bool MultiframeObject::metaDataIsComplete() {
}

// List of tags, and FGs they belong to, for initializing dimensions module
int MultiframeObject::initializeDimensions(IODMultiframeDimensionModule& dimModule,
std::vector<std::pair<DcmTag,DcmTag> > dimTagList){
int MultiframeObject::initializeDimensions(std::vector<std::pair<DcmTag,DcmTag> > dimTagList){
OFString dimUID;

dimensionsModule.clearData();

dimUID = dcmqi::Helper::generateUID();
for(int i=0;i<dimTagList.size();i++){
std::pair<DcmTag,DcmTag> dimTagPair = dimTagList[i];
CHECK_COND(dimModule.addDimensionIndex(dimTagPair.first, dimUID, dimTagPair.second,
CHECK_COND(dimensionsModule.addDimensionIndex(dimTagPair.first, dimUID, dimTagPair.second,
dimTagPair.first.getTagName()));
}
return EXIT_SUCCESS;
}

int MultiframeObject::initializePixelMeasuresFG(){
string pixelSpacingStr, sliceSpacingStr;

pixelSpacingStr = dcmqi::Helper::floatToStrScientific(volumeGeometry.spacing[0])+
"\\"+dcmqi::Helper::floatToStrScientific(volumeGeometry.spacing[1]);
sliceSpacingStr = dcmqi::Helper::floatToStrScientific(volumeGeometry.spacing[2]);

CHECK_COND(pixelMeasuresFG.setPixelSpacing(pixelSpacingStr.c_str()));
CHECK_COND(pixelMeasuresFG.setSpacingBetweenSlices(sliceSpacingStr.c_str()));
CHECK_COND(pixelMeasuresFG.setSliceThickness(sliceSpacingStr.c_str()));

return EXIT_SUCCESS;
}

int MultiframeObject::initializePlaneOrientationFG() {
planeOrientationPatientFG.setImageOrientationPatient(
dcmqi::Helper::floatToStrScientific(volumeGeometry.rowDirection[0]).c_str(),
dcmqi::Helper::floatToStrScientific(volumeGeometry.rowDirection[1]).c_str(),
dcmqi::Helper::floatToStrScientific(volumeGeometry.rowDirection[2]).c_str(),
dcmqi::Helper::floatToStrScientific(volumeGeometry.columnDirection[0]).c_str(),
dcmqi::Helper::floatToStrScientific(volumeGeometry.columnDirection[1]).c_str(),
dcmqi::Helper::floatToStrScientific(volumeGeometry.columnDirection[2]).c_str()
);
return EXIT_SUCCESS;
}
163 changes: 163 additions & 0 deletions libsrc/ParametricMapObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
//

#include <dcmqi/Helper.h>
#include <itkMinimumMaximumImageCalculator.h>
#include "dcmqi/ParametricMapObject.h"

int ParametricMapObject::initializeFromITK(Float32ITKImageType::Pointer inputImage,
Expand All @@ -20,10 +21,25 @@ int ParametricMapObject::initializeFromITK(Float32ITKImageType::Pointer inputIma

initializeVolumeGeometry();

// TODO: consider creating parametric map object after all FGs are initialized instead
createParametricMap();

// populate metadata about patient/study, from derivation
// datasets or from metadata
initializeCompositeContext();

// populate functional groups
std::vector<std::pair<DcmTag,DcmTag> > dimensionTags;
dimensionTags.push_back(std::pair<DcmTag,DcmTag>(DCM_ImagePositionPatient, DCM_PlanePositionSequence));
initializeDimensions(dimensionTags);

initializePixelMeasuresFG();
initializePlaneOrientationFG();

// PM-specific FGs
initializeFrameAnatomyFG();
initializeRWVMFG();

return EXIT_SUCCESS;
}

Expand Down Expand Up @@ -74,10 +90,20 @@ int ParametricMapObject::createParametricMap() {

parametricMap = OFget<DPMParametricMapIOD>(&obj);

// These FG are constant
FGIdentityPixelValueTransformation idTransFG;
CHECK_COND(parametricMap->addForAllFrames(idTransFG));

FGParametricMapFrameType frameTypeFG;
std::string frameTypeStr = "DERIVED\\PRIMARY\\VOLUME\\QUANTITY";
frameTypeFG.setFrameType(frameTypeStr.c_str());
CHECK_COND(parametricMap->addForAllFrames(frameTypeFG));

return EXIT_SUCCESS;
}

int ParametricMapObject::initializeCompositeContext() {
// TODO: should this be done in the parent?
if(derivationDcmDatasets.size()){
CHECK_COND(parametricMap->import(*derivationDcmDatasets[0], OFTrue, OFTrue, OFFalse, OFTrue));

Expand All @@ -87,4 +113,141 @@ int ParametricMapObject::initializeCompositeContext() {
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

int ParametricMapObject::initializeFrameAnatomyFG() {
if(metaDataJson.isMember("FrameLaterality"))
frameAnatomyFG.setLaterality(FGFrameAnatomy::str2Laterality(metaDataJson["FrameLaterality"].asCString()));
else
frameAnatomyFG.setLaterality(FGFrameAnatomy::str2Laterality("U"));

// TODO: simplify code initialization from metadata
if(metaDataJson.isMember("AnatomicRegionSequence")){
frameAnatomyFG.getAnatomy().getAnatomicRegion().set(
metaDataJson["AnatomicRegionSequence"]["CodeValue"].asCString(),
metaDataJson["AnatomicRegionSequence"]["CodingSchemeDesignator"].asCString(),
metaDataJson["AnatomicRegionSequence"]["CodeMeaning"].asCString());
} else {
frameAnatomyFG.getAnatomy().getAnatomicRegion().set("T-D0050", "SRT", "Tissue");
}

return EXIT_SUCCESS;
}

int ParametricMapObject::initializeRWVMFG() {
FGRealWorldValueMapping::RWVMItem* realWorldValueMappingItem =
new FGRealWorldValueMapping::RWVMItem();

if (!realWorldValueMappingItem )
return EXIT_FAILURE;

realWorldValueMappingItem->setRealWorldValueSlope(metaDataJson["RealWorldValueSlope"].asFloat());
realWorldValueMappingItem->setRealWorldValueIntercept(0);

// Calculate intensity range - required
MinMaxCalculatorType::Pointer calculator = MinMaxCalculatorType::New();
calculator->SetImage(itkImage);
calculator->Compute();

realWorldValueMappingItem->setRealWorldValueFirstValueMappeSigned(calculator->GetMinimum());
realWorldValueMappingItem->setRealWorldValueLastValueMappedSigned(calculator->GetMaximum());

if(metaDataJson.isMember("MeasurementsUnitsCode")){
CodeSequenceMacro& unitsCodeDcmtk = realWorldValueMappingItem->getMeasurementUnitsCode();
unitsCodeDcmtk = dcmqi::Helper::jsonToCodeSequenceMacro(metaDataJson["MeasurementsUnitsCode"]);
cout << "Measurements units initialized to " <<
dcmqi::Helper::codeSequenceMacroToString(unitsCodeDcmtk);
realWorldValueMappingItem->setLUTExplanation(metaDataJson["MeasurementUnitsCode"]["CodeMeaning"].asCString());
realWorldValueMappingItem->setLUTLabel(metaDataJson["MeasurementUnitsCode"]["CodeValue"].asCString());
}

if(metaDataJson.isMember("QuantityValueCode")){
CodeSequenceMacro& unitsCodeDcmtk = realWorldValueMappingItem->getMeasurementUnitsCode();
unitsCodeDcmtk = dcmqi::Helper::jsonToCodeSequenceMacro(metaDataJson["QuantityValueCode"]);

ContentItemMacro* quantity = new ContentItemMacro;
CodeSequenceMacro* qCodeName = new CodeSequenceMacro("G-C1C6", "SRT", "Quantity");
CodeSequenceMacro* qSpec = new CodeSequenceMacro(
metaDataJson["QuantityValueCode"]["CodeValue"].asCString(),
metaDataJson["QuantityValueCode"]["CodingSchemeDesignator"].asCString(),
metaDataJson["QuantityValueCode"]["CodeMeaning"].asCString());

if (!quantity || !qSpec || !qCodeName)
{
return NULL;
}

quantity->getEntireConceptNameCodeSequence().push_back(qCodeName);
quantity->getEntireConceptCodeSequence().push_back(qSpec);
realWorldValueMappingItem->getEntireQuantityDefinitionSequence().push_back(quantity);
quantity->setValueType(ContentItemMacro::VT_CODE);

}


#if 0

// initialize optional RWVM items, if available
if(metaInfo.metaInfoRoot.isMember("MeasurementMethodCode")){
ContentItemMacro* measureMethod = new ContentItemMacro;
CodeSequenceMacro* qCodeName = new CodeSequenceMacro("G-C306", "SRT", "Measurement Method");
CodeSequenceMacro* qSpec = new CodeSequenceMacro(
metaInfo.metaInfoRoot["MeasurementMethodCode"]["CodeValue"].asCString(),
metaInfo.metaInfoRoot["MeasurementMethodCode"]["CodingSchemeDesignator"].asCString(),
metaInfo.metaInfoRoot["MeasurementMethodCode"]["CodeMeaning"].asCString());

if (!measureMethod || !qSpec || !qCodeName)
{
return NULL;
}

measureMethod->getEntireConceptNameCodeSequence().push_back(qCodeName);
measureMethod->getEntireConceptCodeSequence().push_back(qSpec);
realWorldValueMappingItem->getEntireQuantityDefinitionSequence().push_back(measureMethod);
measureMethod->setValueType(ContentItemMacro::VT_CODE);
}

if(metaInfo.metaInfoRoot.isMember("ModelFittingMethodCode")){
ContentItemMacro* fittingMethod = new ContentItemMacro;
CodeSequenceMacro* qCodeName = new CodeSequenceMacro("DWMPxxxxx2", "99QIICR", "Model fitting method");
CodeSequenceMacro* qSpec = new CodeSequenceMacro(
metaInfo.metaInfoRoot["ModelFittingMethodCode"]["CodeValue"].asCString(),
metaInfo.metaInfoRoot["ModelFittingMethodCode"]["CodingSchemeDesignator"].asCString(),
metaInfo.metaInfoRoot["ModelFittingMethodCode"]["CodeMeaning"].asCString());

if (!fittingMethod || !qSpec || !qCodeName)
{
return NULL;
}

fittingMethod->getEntireConceptNameCodeSequence().push_back(qCodeName);
fittingMethod->getEntireConceptCodeSequence().push_back(qSpec);
realWorldValueMappingItem->getEntireQuantityDefinitionSequence().push_back(fittingMethod);
fittingMethod->setValueType(ContentItemMacro::VT_CODE);
}

if(metaInfo.metaInfoRoot.isMember("SourceImageDiffusionBValues")){
for(int bvalId=0;bvalId<metaInfo.metaInfoRoot["SourceImageDiffusionBValues"].size();bvalId++){
ContentItemMacro* bval = new ContentItemMacro;
CodeSequenceMacro* bvalUnits = new CodeSequenceMacro("s/mm2", "UCUM", "seconds per square millimeter");
CodeSequenceMacro* qCodeName = new CodeSequenceMacro("DWMPxxxxx1", "99QIICR", "Source image diffusion b-value");

if (!bval || !bvalUnits || !qCodeName)
{
return NULL;
}

bval->setValueType(ContentItemMacro::VT_NUMERIC);
bval->getEntireConceptNameCodeSequence().push_back(qCodeName);
bval->getEntireMeasurementUnitsCodeSequence().push_back(bvalUnits);
if(bval->setNumericValue(metaInfo.metaInfoRoot["SourceImageDiffusionBValues"][bvalId].asCString()).bad())
cout << "Failed to insert the value!" << endl;;
realWorldValueMappingItem->getEntireQuantityDefinitionSequence().push_back(bval);
cout << bval->toString() << endl;
}
}

rwvmFG.getRealWorldValueMapping().push_back(realWorldValueMappingItem);
#endif
return EXIT_SUCCESS;
}

0 comments on commit ff52820

Please sign in to comment.