/* OpenSceneGraph example, osggeometry. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "TransferFunctionWidget.h" class Histogram { public: Histogram() {} void analyse(const osg::Image* image, double interval=0.0); void insertZeroBoundaryValues(float xMin=FLT_MAX, float xMax=-FLT_MAX); osg::Node* createGraphicalRepresentation(); typedef std::map ValueMap; ValueMap& getValueMap() { return _valueMap; } protected: ValueMap _valueMap; }; struct PopulateHistogram { PopulateHistogram(Histogram::ValueMap& valueMap): _histogram(valueMap) {} float cast(char v) { return v; } float cast(unsigned char v) { return v; } float cast(short v) { return v; } float cast(unsigned short v) { return v; } float cast(int v) { return v; } float cast(unsigned int v) { return v; } float cast(float v) { return v; } float cast(double v) { return v; } Histogram::ValueMap& _histogram; void update(int v) { _histogram[v]+=1.0; } void normalize() { double maxValue = 0; for(Histogram::ValueMap::iterator itr = _histogram.begin(); itr != _histogram.end(); ++itr) { if (itr->second>maxValue) maxValue = itr->second; } for(Histogram::ValueMap::iterator itr = _histogram.begin(); itr != _histogram.end(); ++itr) { itr->second /= maxValue; } } void luminance(float l) { update(l); } void alpha(float a) { update(a); } void luminance_alpha(float l, float a) { update(l); } void rgb(float r, float g, float b) { update(r); } void rgba(float r, float g, float b, float a) { update(a); } }; void Histogram::analyse(const osg::Image* image, double interval) { PopulateHistogram populateHistogram(_valueMap); readImage(image, populateHistogram); populateHistogram.normalize(); for(Histogram::ValueMap::iterator itr = populateHistogram._histogram.begin(); itr != populateHistogram._histogram.end(); ++itr) { OSG_NOTICE<<" "<first<<", "<second<first) { _valueMap[xMin] = 0.0; } if (xMax>_valueMap.rbegin()->first) { _valueMap[xMax] = 0.0; } ValueMap::iterator itr = _valueMap.begin(); float previous_x = itr->first; for(; itr != _valueMap.end(); ++itr) { float current_x = itr->first; float gap = current_x-previous_x; if (gap>min_gap_for_double_insertion) { _valueMap[previous_x+interval] = 0.0f; _valueMap[current_x-interval] = 0.0f; } else if (gap>min_gap_for_single_insertion) { _valueMap[(previous_x+current_x)*0.5]=0.0f; } previous_x = current_x; } } osg::Node* Histogram::createGraphicalRepresentation() { if (_valueMap.empty()) return 0; osg::ref_ptr transform = new osg::MatrixTransform; float xMin = _valueMap.begin()->first; float xMax = _valueMap.rbegin()->first; float depth = 0.0f; float yMax = 0.0f; // find yMax for(ValueMap::iterator itr = _valueMap.begin(); itr != _valueMap.end(); ++itr) { float y = itr->second; if (y>yMax) yMax = y; } float xScale = 1.0f/(xMax-xMin); float yScale = 1.0f/yMax; { osg::ref_ptr geode = new osg::Geode; transform->addChild(geode.get()); osg::ref_ptr geometry = new osg::Geometry; geode->addDrawable(geometry.get()); geode->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); geode->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON); osg::ref_ptr vertices = new osg::Vec3Array; geometry->setVertexArray(vertices.get()); osg::ref_ptr colours = new osg::Vec4Array; geometry->setColorArray(colours.get(), osg::Array::BIND_PER_PRIMITIVE_SET); colours->push_back(osg::Vec4(1.0,1.0,1.0,1.0)); colours->push_back(osg::Vec4(1.0,1.0,1.0,1.0)); colours->push_back(osg::Vec4(1.0,1.0,1.0,0.1)); unsigned numColumnsRequired = _valueMap.size(); vertices->reserve(numColumnsRequired*3); for(ValueMap::iterator itr = _valueMap.begin(); itr != _valueMap.end(); ++itr) { float x = itr->first; float y = itr->second; vertices->push_back(osg::Vec3(x*xScale, 0.0f, depth)); vertices->push_back(osg::Vec3(x*xScale, y*yScale, depth)); vertices->push_back(osg::Vec3(x*xScale, yMax*yScale, depth)); } osg::ref_ptr background_primitives = new osg::DrawElementsUShort(GL_TRIANGLE_STRIP); osg::ref_ptr historgram_primitives = new osg::DrawElementsUShort(GL_TRIANGLE_STRIP); osg::ref_ptr outline_primitives = new osg::DrawElementsUShort(GL_LINE_STRIP); for(unsigned int i=0; ipush_back(iv+2); background_primitives->push_back(iv+1); historgram_primitives->push_back(iv+1); historgram_primitives->push_back(iv+0); outline_primitives->push_back(iv+1); } geometry->addPrimitiveSet(outline_primitives.get()); geometry->addPrimitiveSet(historgram_primitives.get()); geometry->addPrimitiveSet(background_primitives.get()); } //transform->setMatrix(osg::Matrix::scale(xScale/(maxX-minY), yScale/(yMax), 1.0f)); transform->setMatrix(osg::Matrix::scale(2.0,1.0,1.0)*osg::Matrix::rotate(osg::DegreesToRadians(90.0), osg::Vec3d(1.0,0.0,0.0))); return transform.release(); } osg::TransferFunction1D* readTransferFunctionFile(const std::string& filename, float colorScale=1.0f) { std::string foundFile = osgDB::findDataFile(filename); if (foundFile.empty()) { std::cout<<"Error: could not find transfer function file : "<> value >> red >> green >> blue >> alpha; if (fin) { std::cout<<"value = "<assign(colorMap); return tf; } class FindTransferFunctionPropertyVisitor : public osgVolume::PropertyVisitor { public: osg::ref_ptr _tfp; #if 0 virtual void apply(osgVolume::SwitchProperty& sp) { OSG_NOTICE<<"Found SwitchProperty"<(sp)); } virtual void apply(osgVolume::CompositeProperty& cp) { OSG_NOTICE<<"Found CompositeProperty"<accept(*this); } } #endif virtual void apply(osgVolume::TransferFunctionProperty& tfp) { OSG_NOTICE<<"Found TransferFunctionProperty "<<&tfp< _tfp; virtual void apply(osgVolume::SwitchProperty& sp) { OSG_NOTICE<<"Found SwitchProperty"<accept(*this); } } virtual void apply(osgVolume::CompositeProperty& cp) { OSG_NOTICE<<"Found CompositeProperty, inserting transfer function"< > Tiles; Tiles _tiles; void apply(osg::Group& group) { osgVolume::VolumeTile* tile = dynamic_cast(&group); if (tile) _tiles.push_back(tile); else traverse(group); } }; class MyScriptCallback : public osg::CallbackObject { public: MyScriptCallback(osg::ScriptEngine* se, osg::Script* script, const std::string& entryPoint) : _scriptEngine(se), _script(script) { setName(entryPoint); } virtual bool run(osg::Object* object, osg::Parameters& inputParameters, osg::Parameters& outputParameters) const { inputParameters.insert(inputParameters.begin(), object); return _scriptEngine->run(_script.get(), getName(), inputParameters, outputParameters); } osg::ref_ptr _scriptEngine; osg::ref_ptr _script; }; class MyClass : public osg::Object { public: MyClass() {} MyClass(const MyClass& rhs, const osg::CopyOp copyop=osg::CopyOp::SHALLOW_COPY):osg::Object(rhs,copyop) {} META_Object(local,MyClass) void myMethod() { osg::CallbackObject* co = osg::getCallbackObject(this, "myMethod"); if (co) co->run(this); else myMethodImplementation(); } virtual void myMethodImplementation() { OSG_NOTICE<<"MyClass::myMethodImplementation()"< myobject = new MyClass; myobject->getOrCreateUserDataContainer()->addUserObject(new osg::CallbackObject("myMethod")); myobject->myMethod(); osg::ref_ptr se = osgDB::readFile("ScriptEngine.lua"); osg::ref_ptr script = osgDB::readFile("script.lua"); osg::ref_ptr copyobject = new MyClass; copyobject->getOrCreateUserDataContainer()->addUserObject(new MyScriptCallback(se.get(), script.get(), "myMethod")); copyobject->myMethod(); #endif #if 0 osg::ref_ptr object = osgDB::readNodeFile("load.lua"); if (object.valid()) { osg::CallbackObject* co = osg::getCallbackObject(object.get(), "method"); OSG_NOTICE<<"Have object = "<className()<run(object.get(), inputParameters, outputParameters); OSG_NOTICE<<"outputParameters.size()="<className()< tf; std::string filename; if (arguments.read("--tf",filename)) { tf = readTransferFunctionFile(filename, 1.0f); } if (arguments.read("--tf-255",filename)) { tf = readTransferFunctionFile(filename,1.0f/255.0f); } bool createHistorgram = arguments.read("--histogram"); #if 0 for(int i=1; i image; osg::ref_ptr volume; osg::ref_ptr volumeTile; std::string filename = arguments[i]; osgDB::FileType fileType = osgDB::fileType(foundFile); if (fileType == osgDB::DIRECTORY) { osg::ref_ptr image = osgDB::readImageFile(foundFile+".dicom", options.get()); } else if (fileType == osgDB::REGULAR_FILE) { std::string ext = osgDB::getFileExtension(foundFile); if (ext=="osg" || ext=="ive" || ext=="osgx" || ext=="osgb" || ext=="osgt") { osg::ref_ptr obj = osgDB::readObjectFile(foundFile); image = dynamic_cast(obj.get()); volume = dynamic_cast(obj.get()); volumeTile = dynamic_cast(obj.get()); } else { image = osgDB::readImageFile( foundFile ); } } else { // not found image, so fallback to plugins/callbacks to find the model. image = osgDB::readImageFile( filename); } if (image.valid()) { volumeTile = new osgVolume::VolumeTile; } } OSG_NOTICE<<"Argument "< model = osgDB::readNodeFiles(arguments); #endif typedef std::vector< osg::ref_ptr > Nodes; Nodes nodes; if (!model && !tf) { OSG_NOTICE<<"Please specify dataset on command line."< volumeTile = dynamic_cast(model.get()); if (volumeTile.valid()) { OSG_NOTICE<<"Inserting Volume above VolumeTile."< volume = new osgVolume::Volume; volume->addChild(model.get()); model = volume.get(); // volumeTile->setVolumeTechnique(new osgVolume::RayTracedTechnique); // volumeTile->setVolumeTechnique(new osgVolume::FixedFunctionTechnique); } nodes.push_back(model.get()); FindVolumeTiles fvt; model->accept(fvt); if (!fvt._tiles.empty()) { osgVolume::VolumeTile* tile = fvt._tiles[0].get(); imageLayer = dynamic_cast(tile->getLayer()); tile->addEventCallback(new osgVolume::PropertyAdjustmentCallback()); } } if (createHistorgram && imageLayer) { Histogram histogram; histogram.analyse(imageLayer->getImage()); nodes.push_back(histogram.createGraphicalRepresentation()); } if (imageLayer) { osgVolume::Property* property = imageLayer->getProperty(); if (property) { FindTransferFunctionPropertyVisitor ftfpv; property->accept(ftfpv); if (ftfpv._tfp.valid()) { if (tf.valid()) { OSG_NOTICE<<"Need to replace volumes transfer function"<setTransferFunction(tf.get()); } else { OSG_NOTICE<<"Using volumes transfer function"<(ftfpv._tfp->getTransferFunction()); } } else if (tf.valid()) { // No existing transfer function but need to assign one OSG_NOTICE<<"Need to assign transfer function to CompositeProperty"<accept(itfpv); } } else if (tf.valid()) { OSG_NOTICE<<"Assign transfer function directly"<setProperty(new osgVolume::TransferFunctionProperty(tf.get())); } } if (tf.valid()) { osg::ref_ptr transform = new osg::MatrixTransform; transform->setMatrix(osg::Matrix::scale(2.0,1.0,1.0)*osg::Matrix::rotate(osg::DegreesToRadians(90.0), osg::Vec3d(1.0,0.0,0.0))); transform->addChild(new osgUI::TransferFunctionWidget(tf.get())); nodes.push_back(transform.get()); } if (nodes.empty()) { OSG_NOTICE<<"Please specify dataset on command line."< group = new osg::Group; for(Nodes::iterator itr = nodes.begin(); itr != nodes.end(); ++itr) { osg::ref_ptr child = *itr; if (!child) continue; #if 0 osg::ComputeBoundsVisitor cbv; child->accept(cbv); osg::BoundingBox bb = cbv.getBoundingBox(); double scale = 1.0/(bb.xMax()-bb.xMin()); #endif osg::BoundingSphere bb = child->getBound(); double scale = 0.7/bb.radius(); osg::ref_ptr pat = new osg::PositionAttitudeTransform; pat->addChild(child.get()); pat->setPosition(position); pat->setPivotPoint(bb.center()); pat->setScale(osg::Vec3d(scale, scale, scale)); position.x() += 1.1; group->addChild(pat.get()); } viewer.setSceneData(group.get()); } OSG_NOTICE<<"Reading to run viewer"<