Discussion:
[osg-users] Volume rendering issues...
Tom Williamson
2018-07-25 12:20:25 UTC
Permalink
Hi gang,

Thanks for all the work on OSG, is rad. I'm currently having a problem with the rendering of a volume, here's what I'm trying to do:
- I'm using ITK to read a NIFTI file, (segmentation of a bone). The file contains zeros (background) and ones (object), format is unsigned short.
- I am then normalizing/scaling this and converting it to an osg::Image.
- I am then attempting to convert this to an osgVolume and display an iso-surface, or at this stage any kind of volume rendering.
- All the reading, conversion etc. seems to work okay, but I'm getting a read access violation on line 408 of Texture3d.cpp (specifically:Exception thrown at 0x00007FFE64D576B0 (ig9icd64.dll) in RobotSimulation.exe: 0xC0000005: Access violation reading location 0x000002F5732EE070.)

I'm pretty sure I'm just forgetting something very obvious, but if anyone could point out what it is that I'm doing wrong that would be much appreciated. I've put a cut down example of the code below (pretty rough).
I know that the data is definitely in the osg::image object (wrote it to file, calculated min and max), so I don't necessarily think the conversion is the problem (though could very well be wrong). I'm on a Windows 10 laptop, with a built in Intel graphics card (Intel HD Graphics 620, drivers are up to date), opengl is version 4.5.
Thanks very much for the help, let me know if you need any other info. Cheers,
Tom

PS: I'm happy to provide some example data if needed, but I guess this would be more or less the same for any data loaded through ITK and converted to OSG.
PPS: I've left the code as normal text, it looked somewhat unreadable in the preview, so sorry about that.

[code]
osg::ref_ptr<osgVolume::Volume> getOsgVolume(std::string filename)
{
osg::ref_ptr<osg::Image> osgImage = new osg::Image();
itk::NiftiImageIOFactory::RegisterOneFactory();
itk::ImageIOBase::Pointer imageIO = itk::ImageIOFactory::CreateImageIO(filename.c_str(), itk::ImageIOFactory::ReadMode);
imageIO->SetFileName(filename);
imageIO->ReadImageInformation();
osg::ref_ptr<osgVolume::Volume> volume = new osgVolume::Volume;

std::cout << "numDimensions: " << imageIO->GetNumberOfDimensions() << std::endl;
std::cout << "component type: " << imageIO->GetComponentTypeAsString(imageIO->GetComponentType()) << std::endl;
std::cout << "pixel type: " << imageIO->GetPixelTypeAsString(imageIO->GetPixelType()) << std::endl;

if (imageIO->GetNumberOfDimensions() == 3) {
typedef itk::Image<unsigned short, 3> imType;
typedef itk::ImageFileReader<imType> imTypeReader;

imTypeReader::Pointer imageReader = imTypeReader::New();
imageReader->SetFileName(imageIO->GetFileName());
imageReader->Update();

imType::RegionType region;
imType::IndexType start;
imType::SizeType size;

for (int i = 0; i < imageIO->GetNumberOfDimensions(); ++i) {
start[i] = 0;
size[i] = imageIO->GetDimensions(i);
}

region.SetSize(size);
region.SetIndex(start);
typedef itk::MultiplyImageFilter< imType> miType;
miType::Pointer mif = miType::New();
mif->SetInput(imageReader->GetOutput());
mif->SetConstant(pow(2, 16) - 1);
mif->Update();
imType::Pointer itkImage = mif->GetOutput();
region = itkImage->GetBufferedRegion();
size = region.GetSize();
start = region.GetIndex();

unsigned int width = size[0];
unsigned int height = size[1];
unsigned int depth = size[2];

osg::RefMatrix* matrix = new osg::RefMatrix;

std::cout << "width = " << width << " height = " << height << " depth = " << depth << std::endl;
for (unsigned int i = 0; i<3; ++i)
{
(*matrix)(i, i) = itkImage->GetSpacing()[i];
}

osgImage->setImage(width, height, depth, GL_LUMINANCE16, GL_LUMINANCE, GL_UNSIGNED_SHORT, (BYTE*)itkImage->GetBufferPointer(), osg::Image::NO_DELETE, 1, width);

// Setup the transfer function
osg::ref_ptr<osg::TransferFunction1D> transferFunction = new osg::TransferFunction1D;
transferFunction->setColor(0.0, osg::Vec4(1.0, 0.0, 0.0, 0.0));
transferFunction->setColor(0.5, osg::Vec4(1.0, 1.0, 0.0, 0.5));
transferFunction->setColor(1.0, osg::Vec4(0.0, 0.0, 1.0, 1.0));

// Setup the volume
osgVolume::ImageDetails* details = new osgVolume::ImageDetails;
details->setMatrix(matrix);
osgImage->setUserData(details);
matrix->preMult(osg::Matrix::scale(double(osgImage->s()), double(osgImage->t()), double(osgImage->r())));
osg::ref_ptr<osgVolume::VolumeTile> tile = new osgVolume::VolumeTile;
volume->addChild(tile.get());
osg::ref_ptr<osgVolume::ImageLayer> layer = new osgVolume::ImageLayer(osgImage.get());
layer->setLocator(new osgVolume::Locator(*matrix));
tile->setLocator(new osgVolume::Locator(*matrix));
tile->setLayer(layer.get());

// Rest of this is setting up the volume rendering...
float alphaFunc = 0.02f;

osgVolume::AlphaFuncProperty* ap = new osgVolume::AlphaFuncProperty(alphaFunc);
osgVolume::IsoSurfaceProperty* isop = new osgVolume::IsoSurfaceProperty(alphaFunc);
osgVolume::SampleDensityProperty* sd = new osgVolume::SampleDensityProperty(0.5f);
osgVolume::SampleDensityWhenMovingProperty* sdwm = new osgVolume::SampleDensityWhenMovingProperty(0.1);
osgVolume::SampleRatioProperty* sr = new osgVolume::SampleRatioProperty(1.0f);
osgVolume::SampleRatioWhenMovingProperty* srwm = new osgVolume::SampleRatioWhenMovingProperty(0.1);
osgVolume::TransparencyProperty* tp = new osgVolume::TransparencyProperty(1.0);
osgVolume::TransferFunctionProperty* tfp = new osgVolume::TransferFunctionProperty(transferFunction.get());
osgVolume::CompositeProperty* cp = new osgVolume::CompositeProperty;
cp->addProperty(sr);
cp->addProperty(tp);
cp->addProperty(isop);
cp->addProperty(sdwm);
cp->addProperty(tfp);

layer->addProperty(cp);
tile->setVolumeTechnique(new osgVolume::MultipassTechnique);

}
std::cout << "Valid: " << volume.valid() << std::endl;
return volume;

}
[/code]

------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=74384#74384
Robert Osfield
2018-07-26 13:29:46 UTC
Permalink
Hi Tom.

My best guess would be that the ITK image data is being deleted prior
to the graphics thread gets a chance copy the data into OpenGL. Try
either copying the data into the osg::Image and let osg::Image then
manage the lifetime of it's own data, or prevent the ITK image data
from getting deleted prior to the osg::Texture3D being used in the
graphics thread - for instance keeping the ITK image object around for
the lifetime of the app, or perhaps more elegantly assigning the ITK
image data via a adapter class that you write to assign it to the
osg:Image as user data.

Robert.
Post by Tom Williamson
Hi gang,
- I'm using ITK to read a NIFTI file, (segmentation of a bone). The file contains zeros (background) and ones (object), format is unsigned short.
- I am then normalizing/scaling this and converting it to an osg::Image.
- I am then attempting to convert this to an osgVolume and display an iso-surface, or at this stage any kind of volume rendering.
- All the reading, conversion etc. seems to work okay, but I'm getting a read access violation on line 408 of Texture3d.cpp (specifically:Exception thrown at 0x00007FFE64D576B0 (ig9icd64.dll) in RobotSimulation.exe: 0xC0000005: Access violation reading location 0x000002F5732EE070.)
I'm pretty sure I'm just forgetting something very obvious, but if anyone could point out what it is that I'm doing wrong that would be much appreciated. I've put a cut down example of the code below (pretty rough).
I know that the data is definitely in the osg::image object (wrote it to file, calculated min and max), so I don't necessarily think the conversion is the problem (though could very well be wrong). I'm on a Windows 10 laptop, with a built in Intel graphics card (Intel HD Graphics 620, drivers are up to date), opengl is version 4.5.
Thanks very much for the help, let me know if you need any other info. Cheers,
Tom
PS: I'm happy to provide some example data if needed, but I guess this would be more or less the same for any data loaded through ITK and converted to OSG.
PPS: I've left the code as normal text, it looked somewhat unreadable in the preview, so sorry about that.
[code]
osg::ref_ptr<osgVolume::Volume> getOsgVolume(std::string filename)
{
osg::ref_ptr<osg::Image> osgImage = new osg::Image();
itk::NiftiImageIOFactory::RegisterOneFactory();
itk::ImageIOBase::Pointer imageIO = itk::ImageIOFactory::CreateImageIO(filename.c_str(), itk::ImageIOFactory::ReadMode);
imageIO->SetFileName(filename);
imageIO->ReadImageInformation();
osg::ref_ptr<osgVolume::Volume> volume = new osgVolume::Volume;
std::cout << "numDimensions: " << imageIO->GetNumberOfDimensions() << std::endl;
std::cout << "component type: " << imageIO->GetComponentTypeAsString(imageIO->GetComponentType()) << std::endl;
std::cout << "pixel type: " << imageIO->GetPixelTypeAsString(imageIO->GetPixelType()) << std::endl;
if (imageIO->GetNumberOfDimensions() == 3) {
typedef itk::Image<unsigned short, 3> imType;
typedef itk::ImageFileReader<imType> imTypeReader;
imTypeReader::Pointer imageReader = imTypeReader::New();
imageReader->SetFileName(imageIO->GetFileName());
imageReader->Update();
imType::RegionType region;
imType::IndexType start;
imType::SizeType size;
for (int i = 0; i < imageIO->GetNumberOfDimensions(); ++i) {
start[i] = 0;
size[i] = imageIO->GetDimensions(i);
}
region.SetSize(size);
region.SetIndex(start);
typedef itk::MultiplyImageFilter< imType> miType;
miType::Pointer mif = miType::New();
mif->SetInput(imageReader->GetOutput());
mif->SetConstant(pow(2, 16) - 1);
mif->Update();
imType::Pointer itkImage = mif->GetOutput();
region = itkImage->GetBufferedRegion();
size = region.GetSize();
start = region.GetIndex();
unsigned int width = size[0];
unsigned int height = size[1];
unsigned int depth = size[2];
osg::RefMatrix* matrix = new osg::RefMatrix;
std::cout << "width = " << width << " height = " << height << " depth = " << depth << std::endl;
for (unsigned int i = 0; i<3; ++i)
{
(*matrix)(i, i) = itkImage->GetSpacing()[i];
}
osgImage->setImage(width, height, depth, GL_LUMINANCE16, GL_LUMINANCE, GL_UNSIGNED_SHORT, (BYTE*)itkImage->GetBufferPointer(), osg::Image::NO_DELETE, 1, width);
// Setup the transfer function
osg::ref_ptr<osg::TransferFunction1D> transferFunction = new osg::TransferFunction1D;
transferFunction->setColor(0.0, osg::Vec4(1.0, 0.0, 0.0, 0.0));
transferFunction->setColor(0.5, osg::Vec4(1.0, 1.0, 0.0, 0.5));
transferFunction->setColor(1.0, osg::Vec4(0.0, 0.0, 1.0, 1.0));
// Setup the volume
osgVolume::ImageDetails* details = new osgVolume::ImageDetails;
details->setMatrix(matrix);
osgImage->setUserData(details);
matrix->preMult(osg::Matrix::scale(double(osgImage->s()), double(osgImage->t()), double(osgImage->r())));
osg::ref_ptr<osgVolume::VolumeTile> tile = new osgVolume::VolumeTile;
volume->addChild(tile.get());
osg::ref_ptr<osgVolume::ImageLayer> layer = new osgVolume::ImageLayer(osgImage.get());
layer->setLocator(new osgVolume::Locator(*matrix));
tile->setLocator(new osgVolume::Locator(*matrix));
tile->setLayer(layer.get());
// Rest of this is setting up the volume rendering...
float alphaFunc = 0.02f;
osgVolume::AlphaFuncProperty* ap = new osgVolume::AlphaFuncProperty(alphaFunc);
osgVolume::IsoSurfaceProperty* isop = new osgVolume::IsoSurfaceProperty(alphaFunc);
osgVolume::SampleDensityProperty* sd = new osgVolume::SampleDensityProperty(0.5f);
osgVolume::SampleDensityWhenMovingProperty* sdwm = new osgVolume::SampleDensityWhenMovingProperty(0.1);
osgVolume::SampleRatioProperty* sr = new osgVolume::SampleRatioProperty(1.0f);
osgVolume::SampleRatioWhenMovingProperty* srwm = new osgVolume::SampleRatioWhenMovingProperty(0.1);
osgVolume::TransparencyProperty* tp = new osgVolume::TransparencyProperty(1.0);
osgVolume::TransferFunctionProperty* tfp = new osgVolume::TransferFunctionProperty(transferFunction.get());
osgVolume::CompositeProperty* cp = new osgVolume::CompositeProperty;
cp->addProperty(sr);
cp->addProperty(tp);
cp->addProperty(isop);
cp->addProperty(sdwm);
cp->addProperty(tfp);
layer->addProperty(cp);
tile->setVolumeTechnique(new osgVolume::MultipassTechnique);
}
std::cout << "Valid: " << volume.valid() << std::endl;
return volume;
}
[/code]
------------------
http://forum.openscenegraph.org/viewtopic.php?p=74384#74384
_______________________________________________
osg-users mailing list
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org
Voerman, L.
2018-07-29 12:27:54 UTC
Permalink
Hi Tom,
I was wondering if your call to setimage should have the width in the
last argument.
laurens
Tom Williamson
2018-07-29 23:31:48 UTC
Permalink
Thanks guys,

Turns out it was a scoping issue (as suggested by Robert), is more or less working as expected now...
Unfortunately now have to deal with shader issues when using the multipass rendering, as my graphics card doesn't provide compatibility mode for the existing shaders. Does anyone have any advice here, or is it pretty much re-write the shaders or buy a new gfx card?
Thanks again for the help!

Tom

------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=74420#74420
Robert Osfield
2018-07-30 05:48:33 UTC
Permalink
Hi Tom,
Post by Tom Williamson
Turns out it was a scoping issue (as suggested by Robert), is more or less working as expected now...
Good to hear it's resolved.
Post by Tom Williamson
Unfortunately now have to deal with shader issues when using the multipass rendering, as my graphics card doesn't provide compatibility mode for the existing shaders.
Could you explain a bit more about what you mean here.
Post by Tom Williamson
Does anyone have any advice here, or is it pretty much re-write the shaders or buy a new gfx card?
For serious volume rendering you really need an NVidia or AMD
dedicated graphics card. This has more to do with raw performance for
doing 3D volume rendering than compatibility. Intel drivers can be a
separate issue, as can be support for 3D textures.

Robert.

Continue reading on narkive:
Loading...