// Released under the OSGPL license, as part of the OpenSceneGraph distribution. // // ReaderWriter for sgi's .rgb format. // specification can be found at http://local.wasp.uwa.edu.au/~pbourke/dataformats/sgirgb/sgiversion.html #include #include #include #include #include #include #include #include #include #include #include #ifdef USE_DCMTK #define HAVE_CONFIG_H #include #include #include #include #endif #ifdef USE_ITK #include #include #include #include #include #include #include #endif #include #include #include #include class ReaderWriterDICOM : public osgDB::ReaderWriter { public: ReaderWriterDICOM() { supportsExtension("mag","dicom image format"); supportsExtension("ph","dicom image format"); supportsExtension("ima","dicom image format"); supportsExtension("dic","dicom image format"); supportsExtension("dcm","dicom image format"); supportsExtension("dicom","dicom image format"); // supportsExtension("*","dicom image format"); } std::ostream& warning() const { return osg::notify(osg::WARN); } std::ostream& notice() const { return osg::notify(osg::NOTICE); } std::ostream& info() const { return osg::notify(osg::NOTICE); } template T* readData(std::istream& fin, unsigned int length, unsigned int& numComponents) const { numComponents = length/sizeof(T); T* data = new T[numComponents]; fin.read((char*)data, numComponents*sizeof(T)); // read over any padding length -= numComponents*sizeof(T); while(fin && length>0) { fin.get(); --length; } return data; } template void printData(std::ostream& out, T* data, unsigned int numComponents) const { if (sizeof(T)==1) { for(unsigned int i=0; i32) out< volume = new osgVolume::Volume; osg::ref_ptr tile = new osgVolume::VolumeTile; tile->setVolume(volume.get()); osg::ref_ptr layer= new osgVolume::ImageLayer(result.getImage()); tile->addLayer(layer.get()); // get matrix providing size of texels (in mm) osg::RefMatrix* matrix = dynamic_cast(result.getImage()->getUserData()); if (matrix) { // scale up to provide scale of complete tile osg::Vec3d scale(osg::Vec3(result.getImage()->s(),result.getImage()->t(), result.getImage()->r())); matrix->postMultScale(scale); tile->setLocator(new osgVolume::Locator(*matrix)); result.getImage()->setUserData(0); notice()<<"Locator "<<*matrix<addChild(tile.get()); return volume.release(); } virtual ReadResult readImage(std::istream& fin,const osgDB::ReaderWriter::Options*) const { return 0; } #ifdef USE_ITK virtual ReadResult readImage(const std::string& file, const osgDB::ReaderWriter::Options* options) const { std::string ext = osgDB::getLowerCaseFileExtension(file); if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED; std::string fileName = osgDB::findDataFile( file, options ); if (fileName.empty()) return ReadResult::FILE_NOT_FOUND; notice()<<"Reading DICOM file "< ImageType; typedef itk::ImageFileReader< ImageType > ReaderType; ReaderType::Pointer reader = ReaderType::New(); reader->SetFileName( fileName.c_str() ); typedef itk::GDCMImageIO ImageIOType; ImageIOType::Pointer gdcmImageIO = ImageIOType::New(); reader->SetImageIO( gdcmImageIO ); try { reader->Update(); } catch (itk::ExceptionObject & e) { std::cerr << "exception in file reader " << std::endl; std::cerr << e.GetDescription() << std::endl; std::cerr << e.GetLocation() << std::endl; return ReadResult::ERROR_IN_READING_FILE; } ImageType::Pointer inputImage = reader->GetOutput(); ImageType::RegionType region = inputImage->GetBufferedRegion(); ImageType::SizeType size = region.GetSize(); ImageType::IndexType start = region.GetIndex(); //inputImage->GetSpacing(); //inputImage->GetOrigin(); unsigned int width = size[0]; unsigned int height = size[1]; unsigned int depth = size[2]; osg::RefMatrix* matrix = new osg::RefMatrix; notice()<<"width = "< matrix = new osg::RefMatrix; osg::ref_ptr image; unsigned int imageNum = 0; EP_Representation pixelRep; int numPlanes = 0; GLenum pixelFormat = 0; GLenum dataType = 0; unsigned int pixelSize = 0; typedef std::list FileInfoList; FileInfoList fileInfoList; typedef std::map DistanceFileInfoMap; typedef std::map OrientationFileInfoMap; OrientationFileInfoMap orientationFileInfoMap; unsigned int totalNumSlices = 0; for(Files::iterator itr = files.begin(); itr != files.end(); ++itr) { DcmFileFormat fileformat; OFCondition status = fileformat.loadFile((*itr).c_str()); if(!status.good()) return ReadResult::ERROR_IN_READING_FILE; FileInfo fileInfo; fileInfo.filename = *itr; double pixelSize_y = 1.0; double pixelSize_x = 1.0; double sliceThickness = 1.0; double imagePositionPatient[3] = {0, 0, 0}; double imageOrientationPatient[6] = {1.0, 0.0, 0.0, 0.0, 1.0, 0.0 }; Uint16 numOfSlices = 1; double value = 0.0; if (fileformat.getDataset()->findAndGetFloat64(DCM_PixelSpacing, value,0).good()) { pixelSize_y = value; fileInfo.matrix(1,1) = pixelSize_y; } if (fileformat.getDataset()->findAndGetFloat64(DCM_PixelSpacing, value,1).good()) { pixelSize_x = value; fileInfo.matrix(0,0) = pixelSize_x; } // Get slice thickness if (fileformat.getDataset()->findAndGetFloat64(DCM_SliceThickness, value).good()) { sliceThickness = value; notice()<<"sliceThickness = "<second; if (dfim.empty()) return 0; double totalDistance = 0.0; if (dfim.size()>1) { totalDistance = fabs(dfim.rbegin()->first - dfim.begin()->first); } else { totalDistance = dfim.begin()->second.sliceThickness * double(dfim.begin()->second.numSlices); } notice()<<"Total Distance including ends "<second; std::auto_ptr dcmImage(new DicomImage(fileInfo.filename.c_str())); if (dcmImage.get()) { if (dcmImage->getStatus()==EIS_Normal) { // get the pixel data const DiPixel* pixelData = dcmImage->getInterData(); if(!pixelData) { warning()<<"Error: no data in DicomImage object."< imageAdapter = new osg::Image; EP_Representation curr_pixelRep; int curr_numPlanes; GLenum curr_pixelFormat; GLenum curr_dataType; unsigned int curr_pixelSize; // create the new image convertPixelTypes(pixelData, curr_pixelRep, curr_numPlanes, curr_dataType, curr_pixelFormat, curr_pixelSize); imageAdapter->setImage(dcmImage->getWidth(), dcmImage->getHeight(), dcmImage->getFrameCount(), curr_pixelFormat, curr_pixelFormat, curr_dataType, (unsigned char*)(pixelData->getData()), osg::Image::NO_DELETE); if (!image) { pixelRep = curr_pixelRep; numPlanes = curr_numPlanes; dataType = curr_dataType; pixelFormat = curr_pixelFormat; pixelSize = curr_pixelSize; (*matrix)(0,0) = fileInfo.matrix(0,0); (*matrix)(1,0) = fileInfo.matrix(1,0); (*matrix)(2,0) = fileInfo.matrix(2,0); (*matrix)(0,1) = fileInfo.matrix(0,1); (*matrix)(1,1) = fileInfo.matrix(1,1); (*matrix)(2,1) = fileInfo.matrix(2,1); (*matrix)(0,2) = fileInfo.matrix(0,2) * averageThickness; (*matrix)(1,2) = fileInfo.matrix(1,2) * averageThickness; (*matrix)(2,2) = fileInfo.matrix(2,2) * averageThickness; image = new osg::Image; image->setUserData(matrix.get()); image->setFileName(fileName.c_str()); image->allocateImage(dcmImage->getWidth(), dcmImage->getHeight(), totalNumSlices, pixelFormat, dataType); notice()<<"Image dimensions = "<s()<<", "<t()<<", "<r()<<" pixelFormat=0x"<getPlanes()>numPlanes || pixelData->getRepresentation()>pixelRep) { notice()<<"Need to reallocated "<s()<<", "<t()<<", "<r()< previous_image = image; // create the new image convertPixelTypes(pixelData, pixelRep, numPlanes, dataType, pixelFormat, pixelSize); image = new osg::Image; image->setUserData(previous_image->getUserData()); image->setFileName(fileName.c_str()); image->allocateImage(dcmImage->getWidth(), dcmImage->getHeight(), totalNumSlices, pixelFormat, dataType); osg::copyImage(previous_image.get(), 0,0,0, previous_image->s(), previous_image->t(), imageNum, image.get(), 0, 0, 0, false); } osg::copyImage(imageAdapter.get(), 0,0,0, imageAdapter->s(), imageAdapter->t(), imageAdapter->r(), image.get(), 0, 0, imageNum, false); imageNum += dcmImage->getFrameCount(); } else { warning()<<"Error in reading dicom file "<