Added support for recording the RescaleIntecept and RescaleSlope from the dicome files and passing these values onto osgVolume::ImageLayer
This commit is contained in:
parent
ea43bc7d52
commit
43e3089417
@ -1206,7 +1206,8 @@ int main( int argc, char **argv )
|
||||
}
|
||||
|
||||
|
||||
osg::ref_ptr<osg::RefMatrix> matrix = dynamic_cast<osg::RefMatrix*>(images.front()->getUserData());
|
||||
osg::ref_ptr<osgVolume::ImageDetails> details = dynamic_cast<osgVolume::ImageDetails*>(images.front()->getUserData());
|
||||
osg::ref_ptr<osg::RefMatrix> matrix = details ? details->getMatrix() : dynamic_cast<osg::RefMatrix*>(images.front()->getUserData());
|
||||
|
||||
if (!matrix)
|
||||
{
|
||||
@ -1261,7 +1262,7 @@ int main( int argc, char **argv )
|
||||
maxComponent = osg::maximum(maxComponent,maxValue[2]);
|
||||
maxComponent = osg::maximum(maxComponent,maxValue[3]);
|
||||
|
||||
|
||||
#if 0
|
||||
switch(rescaleOperation)
|
||||
{
|
||||
case(NO_RESCALE):
|
||||
@ -1297,7 +1298,7 @@ int main( int argc, char **argv )
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -1348,7 +1349,30 @@ int main( int argc, char **argv )
|
||||
osg::ref_ptr<osgVolume::VolumeTile> tile = new osgVolume::VolumeTile;
|
||||
volume->addChild(tile.get());
|
||||
|
||||
osg::ref_ptr<osgVolume::Layer> layer = new osgVolume::ImageLayer(image_3d.get());
|
||||
osg::ref_ptr<osgVolume::ImageLayer> layer = new osgVolume::ImageLayer(image_3d.get());
|
||||
|
||||
if (details)
|
||||
{
|
||||
layer->setRescaleIntercept(details->getRescaleIntercept());
|
||||
layer->setRescaleSlope(details->getRescaleSlope());
|
||||
}
|
||||
|
||||
switch(rescaleOperation)
|
||||
{
|
||||
case(NO_RESCALE):
|
||||
break;
|
||||
|
||||
case(RESCALE_TO_ZERO_TO_ONE_RANGE):
|
||||
{
|
||||
layer->rescaleToZeroToOneRange();
|
||||
break;
|
||||
}
|
||||
case(SHIFT_MIN_TO_ZERO):
|
||||
{
|
||||
layer->translateMinToZero();
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
layer->setLocator(new osgVolume::Locator(*matrix));
|
||||
tile->setLocator(new osgVolume::Locator(*matrix));
|
||||
|
@ -22,6 +22,37 @@
|
||||
|
||||
namespace osgVolume {
|
||||
|
||||
/** Data strucutre for passing details about the loading imagery on to osgVolume for use when setting up dimensions etc.*/
|
||||
class OSGVOLUME_EXPORT ImageDetails : public osg::Object
|
||||
{
|
||||
public:
|
||||
|
||||
ImageDetails();
|
||||
|
||||
/** Copy constructor using CopyOp to manage deep vs shallow copy.*/
|
||||
ImageDetails(const ImageDetails&,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY);
|
||||
|
||||
META_Object(osgVolume, ImageDetails);
|
||||
|
||||
void setRescaleIntercept(double intercept) { _rescaleIntercept = intercept; }
|
||||
double getRescaleIntercept() const { return _rescaleIntercept; }
|
||||
|
||||
void setRescaleSlope(double slope) { _rescaleSlope = slope; }
|
||||
double getRescaleSlope() const { return _rescaleSlope; }
|
||||
|
||||
void setMatrix(osg::RefMatrix* matrix) { _matrix = matrix; }
|
||||
osg::RefMatrix* getMatrix() { return _matrix.get(); }
|
||||
const osg::RefMatrix* getMatrix() const { return _matrix.get(); }
|
||||
|
||||
protected:
|
||||
|
||||
double _rescaleIntercept;
|
||||
double _rescaleSlope;
|
||||
osg::ref_ptr<osg::RefMatrix> _matrix;
|
||||
|
||||
};
|
||||
|
||||
/** Base class for representing a single layer of volume data.*/
|
||||
class OSGVOLUME_EXPORT Layer : public osg::Object
|
||||
{
|
||||
public:
|
||||
@ -131,6 +162,14 @@ class OSGVOLUME_EXPORT ImageLayer : public Layer
|
||||
/** Return const image associated with layer. */
|
||||
virtual const osg::Image* getImage() const { return _image.get(); }
|
||||
|
||||
|
||||
void setRescaleIntercept(double intercept) { _rescaleIntercept = intercept; }
|
||||
double getRescaleIntercept() const { return _rescaleIntercept; }
|
||||
|
||||
void setRescaleSlope(double slope) { _rescaleSlope = slope; }
|
||||
double setRescaleSlope() const { return _rescaleSlope; }
|
||||
|
||||
|
||||
/** Compute the min and max pixel colors.*/
|
||||
bool computeMinMax(osg::Vec4& min, osg::Vec4& max);
|
||||
|
||||
@ -155,6 +194,8 @@ class OSGVOLUME_EXPORT ImageLayer : public Layer
|
||||
|
||||
virtual ~ImageLayer() {}
|
||||
|
||||
double _rescaleIntercept;
|
||||
double _rescaleSlope;
|
||||
osg::ref_ptr<osg::Image> _image;
|
||||
|
||||
};
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <dcmtk/config/osconfig.h>
|
||||
#include <dcmtk/dcmdata/dcfilefo.h>
|
||||
#include <dcmtk/dcmdata/dcdeftag.h>
|
||||
#include <dcmtk/dcmdata/dcuid.h>
|
||||
#include <dcmtk/dcmimgle/dcmimage.h>
|
||||
#endif
|
||||
|
||||
@ -206,7 +207,14 @@ class ReaderWriterDICOM : public osgDB::ReaderWriter
|
||||
tile->setLayer(layer.get());
|
||||
|
||||
// get matrix providing size of texels (in mm)
|
||||
osg::RefMatrix* matrix = dynamic_cast<osg::RefMatrix*>(result.getImage()->getUserData());
|
||||
osgVolume::ImageDetails* details = dynamic_cast<osgVolume::ImageDetails*>(result.getImage()->getUserData());
|
||||
osg::RefMatrix* matrix = details ? details->getMatrix() : 0;
|
||||
|
||||
if (details)
|
||||
{
|
||||
layer->setRescaleIntercept(details->getRescaleIntercept());
|
||||
layer->setRescaleSlope(details->getRescaleSlope());
|
||||
}
|
||||
|
||||
if (matrix)
|
||||
{
|
||||
@ -298,7 +306,8 @@ class ReaderWriterDICOM : public osgDB::ReaderWriter
|
||||
++itr)
|
||||
{
|
||||
osg::Image* image = itr->get();
|
||||
osg::RefMatrix* matrix = dynamic_cast<osg::RefMatrix*>(image->getUserData());
|
||||
osgVolume::ImageDetails* details = dynamic_cast<osgVolume::ImageDetails*>(result.getImage()->getUserData());
|
||||
osg::RefMatrix* matrix = details ? details->getMatrix() : 0;
|
||||
if (matrix)
|
||||
{
|
||||
osg::Vec3 p0 = osg::Vec3(0.0, 0.0, 0.0) * (*matrix);
|
||||
@ -346,12 +355,13 @@ class ReaderWriterDICOM : public osgDB::ReaderWriter
|
||||
}
|
||||
|
||||
osg::Image* firstImage = dim.begin()->second.get();
|
||||
osg::RefMatrix* matrix = dynamic_cast<osg::RefMatrix*>(firstImage->getUserData());
|
||||
osgVolume::ImageDetails* details = dynamic_cast<osgVolume::ImageDetails*>(result.getImage()->getUserData());
|
||||
osg::RefMatrix* matrix = details ? details->getMatrix() : 0;
|
||||
if (matrix)
|
||||
{
|
||||
image3D->setUserData(
|
||||
new osg::RefMatrix(osg::Matrix::scale(1.0,1.0,totalThickness) * (*matrix))
|
||||
);
|
||||
osgVolume::ImageDetails* details3D = new osgVolume::ImageDetails(*details);
|
||||
details3D->getMatrix()->preMult(osg::Matrix::scale(1.0,1.0,totalThickness));
|
||||
image3D->setUserData(details3D);
|
||||
}
|
||||
|
||||
return image3D.get();
|
||||
@ -422,7 +432,10 @@ class ReaderWriterDICOM : public osgDB::ReaderWriter
|
||||
++it;
|
||||
}
|
||||
|
||||
image->setUserData(matrix);
|
||||
osgVolume::ImageDetails* details = new osgVolume::ImageDetails;
|
||||
details->setMatrix(matrix);
|
||||
|
||||
image->setUserData(details);
|
||||
|
||||
matrix->preMult(osg::Matrix::scale(double(image->s()), double(image->t()), double(image->r())));
|
||||
|
||||
@ -534,8 +547,11 @@ class ReaderWriterDICOM : public osgDB::ReaderWriter
|
||||
return ReadResult::FILE_NOT_FOUND;
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::RefMatrix> matrix = new osg::RefMatrix;
|
||||
osg::ref_ptr<osgVolume::ImageDetails> details = new osgVolume::ImageDetails;
|
||||
details->setMatrix(new osg::RefMatrix);
|
||||
|
||||
osg::ref_ptr<osg::Image> image;
|
||||
|
||||
unsigned int imageNum = 0;
|
||||
EP_Representation pixelRep = EPR_Uint8;
|
||||
int numPlanes = 0;
|
||||
@ -570,6 +586,32 @@ class ReaderWriterDICOM : public osgDB::ReaderWriter
|
||||
double imageOrientationPatient[6] = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0 };
|
||||
Uint16 numOfSlices = 1;
|
||||
|
||||
// code for reading the intercept and scale that is required to convert to Hounsfield units.
|
||||
bool rescaling = false;
|
||||
double rescaleIntercept = 0.0;
|
||||
double rescaleSlope = 1.0;
|
||||
const char *classUID = NULL;
|
||||
if (fileformat.getDataset()->findAndGetString(DCM_SOPClassUID, classUID).good())
|
||||
{
|
||||
osg::notify(osg::NOTICE)<<" classUID = "<<classUID<<std::endl;
|
||||
if (0 == strcmp(classUID, UID_CTImageStorage))
|
||||
{
|
||||
osg::notify(osg::NOTICE)<<" is a UID_CTImageStorage "<<std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
rescaling = fileformat.getDataset()->findAndGetFloat64(DCM_RescaleIntercept, rescaleIntercept).good();
|
||||
rescaling &= fileformat.getDataset()->findAndGetFloat64(DCM_RescaleSlope, rescaleSlope).good();
|
||||
if (rescaling)
|
||||
{
|
||||
fileInfo.rescaleIntercept = rescaleIntercept;
|
||||
fileInfo.rescaleSlope = rescaleSlope;
|
||||
osg::notify(osg::NOTICE)<<" rescaleIntercept = "<<rescaleIntercept<<std::endl;
|
||||
osg::notify(osg::NOTICE)<<" rescaleSlope = "<<rescaleSlope<<std::endl;
|
||||
}
|
||||
|
||||
|
||||
double value = 0.0;
|
||||
if (fileformat.getDataset()->findAndGetFloat64(DCM_PixelSpacing, value,0).good())
|
||||
{
|
||||
@ -775,6 +817,8 @@ class ReaderWriterDICOM : public osgDB::ReaderWriter
|
||||
pixelFormat = curr_pixelFormat;
|
||||
pixelSize = curr_pixelSize;
|
||||
|
||||
osg::RefMatrix* matrix = details->getMatrix();
|
||||
|
||||
(*matrix)(0,0) = fileInfo.matrix(0,0);
|
||||
(*matrix)(1,0) = fileInfo.matrix(1,0);
|
||||
(*matrix)(2,0) = fileInfo.matrix(2,0);
|
||||
@ -785,10 +829,11 @@ class ReaderWriterDICOM : public osgDB::ReaderWriter
|
||||
(*matrix)(1,2) = fileInfo.matrix(1,2) * averageThickness;
|
||||
(*matrix)(2,2) = fileInfo.matrix(2,2) * averageThickness;
|
||||
|
||||
|
||||
details->setRescaleIntercept(fileInfo.rescaleIntercept);
|
||||
details->setRescaleSlope(fileInfo.rescaleSlope);
|
||||
|
||||
image = new osg::Image;
|
||||
image->setUserData(matrix.get());
|
||||
image->setUserData(details.get());
|
||||
image->setFileName(fileName.c_str());
|
||||
image->allocateImage(dcmImage->getWidth(), dcmImage->getHeight(), totalNumSlices,
|
||||
pixelFormat, dataType);
|
||||
@ -841,7 +886,7 @@ class ReaderWriterDICOM : public osgDB::ReaderWriter
|
||||
return ReadResult::ERROR_IN_READING_FILE;
|
||||
}
|
||||
|
||||
info()<<"Spacing = "<<*matrix<<std::endl;
|
||||
info()<<"Spacing = "<<*(details->getMatrix())<<std::endl;
|
||||
|
||||
return image.get();
|
||||
}
|
||||
@ -850,6 +895,8 @@ class ReaderWriterDICOM : public osgDB::ReaderWriter
|
||||
struct FileInfo
|
||||
{
|
||||
FileInfo():
|
||||
rescaleIntercept(0.0),
|
||||
rescaleSlope(1.0),
|
||||
numX(0),
|
||||
numY(0),
|
||||
numSlices(1),
|
||||
@ -859,6 +906,8 @@ class ReaderWriterDICOM : public osgDB::ReaderWriter
|
||||
FileInfo(const FileInfo& rhs):
|
||||
filename(rhs.filename),
|
||||
matrix(rhs.matrix),
|
||||
rescaleIntercept(rhs.rescaleIntercept),
|
||||
rescaleSlope(rhs.rescaleSlope),
|
||||
numX(rhs.numX),
|
||||
numY(rhs.numY),
|
||||
numSlices(rhs.numSlices),
|
||||
@ -871,6 +920,8 @@ class ReaderWriterDICOM : public osgDB::ReaderWriter
|
||||
|
||||
filename = rhs.filename;
|
||||
matrix = rhs.matrix;
|
||||
rescaleIntercept = rhs.rescaleIntercept;
|
||||
rescaleSlope = rhs.rescaleSlope;
|
||||
numX = rhs.numX;
|
||||
numY = rhs.numY;
|
||||
sliceThickness = rhs.sliceThickness;
|
||||
@ -882,6 +933,8 @@ class ReaderWriterDICOM : public osgDB::ReaderWriter
|
||||
|
||||
std::string filename;
|
||||
osg::Matrixd matrix;
|
||||
double rescaleIntercept;
|
||||
double rescaleSlope;
|
||||
unsigned int numX;
|
||||
unsigned int numY;
|
||||
unsigned int numSlices;
|
||||
|
@ -21,6 +21,19 @@
|
||||
|
||||
using namespace osgVolume;
|
||||
|
||||
ImageDetails::ImageDetails():
|
||||
_rescaleIntercept(0.0),
|
||||
_rescaleSlope(1.0)
|
||||
{
|
||||
}
|
||||
|
||||
ImageDetails::ImageDetails(const ImageDetails& rhs,const osg::CopyOp& copyop):
|
||||
_rescaleIntercept(rhs._rescaleIntercept),
|
||||
_rescaleSlope(rhs._rescaleSlope),
|
||||
_matrix(rhs._matrix)
|
||||
{
|
||||
}
|
||||
|
||||
Layer::Layer():
|
||||
_minFilter(osg::Texture::LINEAR),
|
||||
_magFilter(osg::Texture::LINEAR)
|
||||
@ -82,12 +95,16 @@ void Layer::addProperty(Property* property)
|
||||
// ImageLayer
|
||||
//
|
||||
ImageLayer::ImageLayer(osg::Image* image):
|
||||
_rescaleIntercept(0.0),
|
||||
_rescaleSlope(1.0),
|
||||
_image(image)
|
||||
{
|
||||
}
|
||||
|
||||
ImageLayer::ImageLayer(const ImageLayer& imageLayer,const osg::CopyOp& copyop):
|
||||
Layer(imageLayer, copyop),
|
||||
_rescaleIntercept(imageLayer._rescaleIntercept),
|
||||
_rescaleSlope(imageLayer._rescaleSlope),
|
||||
_image(imageLayer._image)
|
||||
{
|
||||
}
|
||||
@ -129,6 +146,10 @@ void ImageLayer::offsetAndScaleImage(const osg::Vec4& offset, const osg::Vec4& s
|
||||
|
||||
void ImageLayer::rescaleToZeroToOneRange()
|
||||
{
|
||||
osg::notify(osg::NOTICE)<<"ImageLayer::rescaleToZeroToOneRange()"<<std::endl;
|
||||
osg::notify(osg::NOTICE)<<" _rescaleIntercept "<<_rescaleIntercept<<std::endl;
|
||||
osg::notify(osg::NOTICE)<<" _rescaleSlope "<<_rescaleSlope<<std::endl;
|
||||
|
||||
osg::Vec4 minValue, maxValue;
|
||||
if (computeMinMax(minValue, maxValue))
|
||||
{
|
||||
@ -145,6 +166,9 @@ void ImageLayer::rescaleToZeroToOneRange()
|
||||
float scale = 0.99f/(maxComponent-minComponent);
|
||||
float offset = -minComponent * scale;
|
||||
|
||||
osg::notify(osg::NOTICE)<<" scale "<<scale<<std::endl;
|
||||
osg::notify(osg::NOTICE)<<" offset "<<offset<<std::endl;
|
||||
|
||||
offsetAndScaleImage(osg::Vec4(offset, offset, offset, offset),
|
||||
osg::Vec4(scale, scale, scale, scale));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user