Added support for recording the RescaleIntecept and RescaleSlope from the dicome files and passing these values onto osgVolume::ImageLayer

This commit is contained in:
Robert Osfield 2009-09-01 10:48:32 +00:00
parent ea43bc7d52
commit 43e3089417
4 changed files with 460 additions and 318 deletions

View File

@ -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));

View File

@ -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;
};

View File

@ -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;

View File

@ -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));
}