36 #include <QDomDocument>
38 #include <vtkImageAccumulate.h>
39 #include <vtkImageReslice.h>
40 #include <vtkImageData.h>
41 #include <vtkMatrix4x4.h>
43 #include <vtkPlanes.h>
44 #include <vtkImageResample.h>
45 #include <vtkImageChangeInformation.h>
46 #include <vtkImageClip.h>
47 #include <vtkImageIterator.h>
48 #include <vtkPiecewiseFunction.h>
49 #include <vtkColorTransferFunction.h>
80 double Image::ShadingStruct::loadAttribute(QDomNode dataNode, QString name,
double defVal)
82 QString text = dataNode.toElement().attribute(name);
84 double val = text.toDouble(&ok);
92 QDomElement elem = dataNode.toElement();
93 elem.setAttribute(
"on", on);
94 elem.setAttribute(
"ambient", ambient);
95 elem.setAttribute(
"diffuse", diffuse);
96 elem.setAttribute(
"specular", specular);
97 elem.setAttribute(
"specularPower", specularPower);
102 if (dataNode.isNull())
105 on = dataNode.toElement().attribute(
"on").toInt();
107 ambient = loadAttribute(dataNode,
"ambient", ambient);
108 diffuse = loadAttribute(dataNode,
"diffuse", diffuse);
109 specular = loadAttribute(dataNode,
"specular", specular);
110 specularPower = loadAttribute(dataNode,
"specularPower", specularPower);
129 mInitialWindowWidth = -1;
130 mInitialWindowLevel = -1;
137 mImageLookupTable2D.reset();
138 mImageTransferFunctions3D.reset();
148 baseImageDataCopy = vtkImageDataPtr::New();
159 retval->mImageLookupTable2D = mImageLookupTable2D;
160 retval->mImageTransferFunctions3D = mImageTransferFunctions3D;
161 retval->mInitialWindowWidth = mInitialWindowWidth;
162 retval->mInitialWindowLevel = mInitialWindowLevel;
175 ImageTF3DPtr transferFunctions = parentImage->getUnmodifiedTransferFunctions3D()->createCopy();
176 ImageLUT2DPtr LUT2D = parentImage->getUnmodifiedLookupTable2D()->createCopy();
182 mInitialWindowWidth = parentImage->getInitialWindowWidth();
183 mInitialWindowLevel = parentImage->getInitialWindowLevel();
232 this->blockSignals(
true);
234 this->resetTransferFunction(imageTransferFunctions3D);
235 this->resetTransferFunction(imageLookupTable2D);
237 this->blockSignals(
false);
241 void Image::resetTransferFunction(
ImageLUT2DPtr imageLookupTable2D)
243 if (mImageLookupTable2D)
248 mImageLookupTable2D = imageLookupTable2D;
250 if (mImageLookupTable2D)
258 void Image::resetTransferFunction(
ImageTF3DPtr imageTransferFunctions3D)
260 if (mImageTransferFunctions3D)
265 mImageTransferFunctions3D = imageTransferFunctions3D;
267 if (mImageTransferFunctions3D)
282 this->moveToThread(thread);
283 this->getUnmodifiedTransferFunctions3D()->moveToThread(thread);
284 this->getUnmodifiedLookupTable2D()->moveToThread(thread);
294 if (resetTransferFunctions)
301 double windowWidth = mImageLookupTable2D->getWindow();
302 double windowLevel = mImageLookupTable2D->getLevel();
319 if(mThresholdPreview)
320 return mTresholdPreviewTransferfunctions3D;
321 return getUnmodifiedTransferFunctions3D();
326 if(!this->mImageTransferFunctions3D)
328 return mImageTransferFunctions3D;
333 this->resetTransferFunction(transferFuntion);
338 if(mThresholdPreview)
339 return mTresholdPreviewLookupTable2D;
340 return getUnmodifiedLookupTable2D();
345 if(!mImageLookupTable2D)
347 return mImageLookupTable2D;
352 this->resetTransferFunction(imageLookupTable2D);
388 template<
typename scalartype>
static int getRGBMax(
vtkImageDataPtr image)
391 vtkImageIterator<scalartype> iter(image, image->GetExtent());
392 while (!iter.IsAtEnd())
394 typename vtkImageIterator<scalartype>::SpanIterator siter = iter.BeginSpan();
395 while (siter != iter.EndSpan())
426 QDateTime before = QDateTime::currentDateTime();
430 case VTK_UNSIGNED_CHAR:
433 case VTK_UNSIGNED_SHORT:
473 if (vtkScalarType==VTK_CHAR)
475 else if (vtkScalarType==VTK_UNSIGNED_CHAR)
476 return VTK_UNSIGNED_CHAR_MIN;
477 else if (vtkScalarType==VTK_SIGNED_CHAR)
478 return VTK_SIGNED_CHAR_MIN;
479 else if (vtkScalarType==VTK_UNSIGNED_SHORT)
480 return VTK_UNSIGNED_SHORT_MIN;
481 else if (vtkScalarType==VTK_SHORT)
482 return VTK_SHORT_MIN;
483 else if (vtkScalarType==VTK_UNSIGNED_INT)
484 return VTK_UNSIGNED_INT_MIN;
485 else if (vtkScalarType==VTK_INT)
488 reportError(QString(
"Unknown VTK ScalarType: %1").arg(vtkScalarType));
496 if (vtkScalarType==VTK_CHAR)
498 else if (vtkScalarType==VTK_UNSIGNED_CHAR)
499 return VTK_UNSIGNED_CHAR_MAX;
500 else if (vtkScalarType==VTK_SIGNED_CHAR)
501 return VTK_SIGNED_CHAR_MAX;
502 else if (vtkScalarType==VTK_UNSIGNED_SHORT)
503 return VTK_UNSIGNED_SHORT_MAX;
504 else if (vtkScalarType==VTK_SHORT)
505 return VTK_SHORT_MAX;
506 else if (vtkScalarType==VTK_UNSIGNED_INT)
507 return VTK_UNSIGNED_INT_MAX;
508 else if (vtkScalarType==VTK_INT)
511 reportError(QString(
"Unknown VTK ScalarType: %1").arg(vtkScalarType));
518 QDomNode imageNode = dataNode;
519 QDomDocument doc = dataNode.ownerDocument();
521 QDomElement tf3DNode = doc.createElement(
"transferfunctions");
522 this->getUnmodifiedTransferFunctions3D()->addXml(tf3DNode);
523 imageNode.appendChild(tf3DNode);
525 QDomElement lut2DNode = doc.createElement(
"lookuptable2D");
526 this->getUnmodifiedLookupTable2D()->addXml(lut2DNode);
527 imageNode.appendChild(lut2DNode);
529 QDomElement shadingNode = doc.createElement(
"shading");
531 imageNode.appendChild(shadingNode);
537 QDomElement cropNode = doc.createElement(
"crop");
540 imageNode.appendChild(cropNode);
542 QDomElement clipNode = doc.createElement(
"clip");
545 QDomElement planeNode = doc.createElement(
"plane");
550 clipNode.appendChild(planeNode);
552 imageNode.appendChild(clipNode);
554 QDomElement modalityNode = doc.createElement(
"modality");
555 modalityNode.appendChild(doc.createTextNode(
mModality));
556 imageNode.appendChild(modalityNode);
558 QDomElement imageTypeNode = doc.createElement(
"imageType");
559 imageTypeNode.appendChild(doc.createTextNode(
mImageType));
560 imageNode.appendChild(imageTypeNode);
562 QDomElement interpolationNode = doc.createElement(
"vtk_interpolation");
564 imageNode.appendChild(interpolationNode);
566 QDomElement initialWindowNode = doc.createElement(
"initialWindow");
567 initialWindowNode.setAttribute(
"width", mInitialWindowWidth);
568 initialWindowNode.setAttribute(
"level", mInitialWindowLevel);
571 double Image::loadAttribute(QDomNode dataNode, QString name,
double defVal)
573 QString text = dataNode.toElement().attribute(name);
575 double val = text.toDouble(&ok);
595 if (dataNode.isNull())
599 QDomNode transferfunctionsNode = dataNode.namedItem(
"transferfunctions");
600 if (!transferfunctionsNode.isNull())
601 this->getUnmodifiedTransferFunctions3D()->parseXml(transferfunctionsNode);
604 std::cout <<
"Warning: Image::parseXml() found no transferfunctions";
605 std::cout << std::endl;
608 mInitialWindowWidth = this->loadAttribute(dataNode.namedItem(
"initialWindow"),
"width", -1);
609 mInitialWindowLevel = this->loadAttribute(dataNode.namedItem(
"initialWindow"),
"level", -1);
611 this->getUnmodifiedLookupTable2D()->parseXml(dataNode.namedItem(
"lookuptable2D"));
614 mShading.
on = dataNode.namedItem(
"shading").toElement().text().toInt();
616 if (!dataNode.namedItem(
"shadingAmbient").isNull())
617 mShading.
ambient = dataNode.namedItem(
"shadingAmbient").toElement().text().toDouble();
618 if (!dataNode.namedItem(
"shadingDiffuse").isNull())
619 mShading.
diffuse = dataNode.namedItem(
"shadingDiffuse").toElement().text().toDouble();
620 if (!dataNode.namedItem(
"shadingSpecular").isNull())
621 mShading.
specular = dataNode.namedItem(
"shadingSpecular").toElement().text().toDouble();
622 if (!dataNode.namedItem(
"shadingSpecularPower").isNull())
630 QDomElement cropNode = dataNode.namedItem(
"crop").toElement();
631 if (!cropNode.isNull())
637 QDomElement clipNode = dataNode.namedItem(
"clip").toElement();
638 QDomElement clipPlaneNode = clipNode.firstChildElement(
"plane");
639 for (; !clipPlaneNode.isNull(); clipPlaneNode = clipPlaneNode.nextSiblingElement(
"plane"))
641 Vector3D normal = Vector3D::fromString(clipPlaneNode.attribute(
"normal"));
642 Vector3D origin = Vector3D::fromString(clipPlaneNode.attribute(
"origin"));
644 plane->SetNormal(normal.begin());
645 plane->SetOrigin(origin.begin());
649 mModality = dataNode.namedItem(
"modality").toElement().text();
650 mImageType = dataNode.namedItem(
"imageType").toElement().text();
652 QDomElement interpoationNode = dataNode.namedItem(
"vtk_interpolation").toElement();
653 if (!interpoationNode.isNull())
662 mInitialWindowWidth = width;
663 mInitialWindowLevel = level;
674 if (mThresholdPreview)
818 info->SetOutputExtentStart(0, 0, 0);
819 info->SetOutputOrigin(0, 0, 0);
821 info->UpdateInformation();
859 int size = axisSize - 1;
861 dummyImageData->SetExtent(0, size, 0, size, 0, size);
862 dummyImageData->SetSpacing(1, 1, 1);
867 dummyImageData->AllocateScalars(VTK_UNSIGNED_CHAR, 1);
868 unsigned char* dataPtr =
static_cast<unsigned char*
> (dummyImageData->GetScalarPointer());
871 int minVoxelValue = 0;
872 int numVoxels = axisSize*axisSize*axisSize;
873 for (
int i = 0; i < numVoxels; ++i)
875 int voxelValue = minVoxelValue + i;
877 dataPtr[i] = maxVoxelValue;
878 else if (voxelValue < maxVoxelValue)
879 dataPtr[i] = voxelValue;
881 dataPtr[i] = maxVoxelValue;
884 return dummyImageData;
897 if (mThresholdPreview)
904 if (mThresholdPreview)
905 return VTK_NEAREST_INTERPOLATION;
914 double factor = computeResampleFactor(maxVoxels);
916 if (fabs(1.0-factor)>0.01)
919 resampler->SetInterpolationModeToLinear();
920 resampler->SetAxisMagnificationFactor(0, factor);
921 resampler->SetAxisMagnificationFactor(1, factor);
922 resampler->SetAxisMagnificationFactor(2, factor);
923 resampler->SetInputData(retval);
926 resampler->GetOutput()->GetScalarRange();
927 retval = resampler->GetOutput();
929 long voxelsDown = retval->GetNumberOfPoints();
940 double Image::computeResampleFactor(
long maxVoxels)
946 double factor = (double)maxVoxels/(
double)voxels;
947 factor = pow(factor, 1.0/3.0);
959 QString filename = basePath +
"/Images/" + this->
getUid() +
".mhd";
960 this->
setFilename(QDir(basePath).relativeFilePath(filename));
968 mThresholdPreview =
true;
970 this->createThresholdPreviewTransferFunctions3D(threshold);
971 this->createThresholdPreviewLookupTable2D(threshold);
976 void Image::createThresholdPreviewTransferFunctions3D(
const Eigen::Vector2d &threshold)
980 ColorMap colors = this->createPreviewColorMap(threshold);
981 IntIntMap opacity = this->createPreviewOpacityMap(threshold);
983 mTresholdPreviewTransferfunctions3D = tfGenerator.generate3DTFPreset();
984 mTresholdPreviewTransferfunctions3D->resetColor(colors);
985 mTresholdPreviewTransferfunctions3D->resetAlpha(opacity);
988 void Image::createThresholdPreviewLookupTable2D(
const Eigen::Vector2d &threshold)
990 ImageDefaultTFGenerator tfGenerator(
ImagePtr(
this, null_deleter()));
992 ColorMap colors = this->createPreviewColorMap(threshold);
994 mTresholdPreviewLookupTable2D = tfGenerator.generate2DTFPreset();
995 mTresholdPreviewLookupTable2D->resetColor(colors);
996 mTresholdPreviewLookupTable2D->setLLR(threshold[0]);
999 ColorMap Image::createPreviewColorMap(
const Eigen::Vector2d &threshold)
1001 double lower = threshold[0];
1003 colors[lower] = Qt::green;
1004 colors[this->
getMax()] = Qt::green;
1008 IntIntMap Image::createPreviewOpacityMap(
const Eigen::Vector2d &threshold)
1010 double lower = threshold[0];
1011 double upper = threshold[1];
1013 opacity[lower - 1] = 0;
1016 opacity[upper + 1] = 0;
1022 mThresholdPreview =
false;
1023 mTresholdPreviewTransferfunctions3D.reset();
1024 mTresholdPreviewLookupTable2D.reset();
virtual void parseXml(QDomNode &dataNode)
Use a XML node to load data.
QString qstring_cast(const T &val)
void transferFunctionsChanged()
static vtkImageDataPtr createDummyImageData(int axisSize, int maxVoxelValue)
Create a moc object of vtkImageData.
Image(const QString &uid, const vtkImageDataPtr &data, const QString &name="")
virtual bool getCropping() const
void reportError(QString msg)
virtual void setModality(const QString &val)
virtual Transform3D get_rMd() const
bool mUseCropping
image should be cropped using mCroppingBox
virtual vtkImageDataPtr getGrayScaleVtkImageData()
as getBaseVtkImageData(), but constrained to 1 component if multicolor.
int getInterpolationType() const
virtual Eigen::Array3d getSpacing() const
QString mImageType
type of the image, defined as DICOM tag (0008,0008) (mainly value 3, but might be a merge of value 4)...
void parseXml(QDomNode dataNode)
virtual void setTransferFunctions3D(ImageTF3DPtr transferFuntion)
PlainObject normal() const
virtual double getShadingDiffuse()
Get shading diffuse parmeter.
virtual vtkImageAccumulatePtr getHistogram()
void mergevtkSettingsIntosscTransform()
static ImagePtr create(const QString &uid, const QString &name)
void addXml(QDomNode dataNode)
#define CX_ASSERT(statement)
virtual void setShadingDiffuse(double diffuse)
Set shading diffuse parmeter.
virtual QString getModality() const
virtual std::vector< vtkPlanePtr > getAllClipPlanes()
virtual void addPersistentClipPlane(vtkPlanePtr plane)
virtual void setVtkImageData(const vtkImageDataPtr &data, bool resetTransferFunctions=true)
vtkSmartPointer< class vtkImageAccumulate > vtkImageAccumulatePtr
void propertiesChanged()
emitted when one of the metadata properties (uid, name etc) changes
virtual void setLookupTable2D(ImageLUT2DPtr imageLookupTable2D)
boost::shared_ptr< class Image > ImagePtr
virtual void setInitialWindowLevel(double width, double level)
vtkSmartPointer< vtkImageChangeInformation > vtkImageChangeInformationPtr
static DoubleBoundingBox3D fromString(const QString &text)
construct a bb from a string containing 6 whitespace-separated numbers
virtual void setCropping(bool on)
virtual Image::ShadingStruct getShading()
virtual void setShadingOn(bool on)
DoubleBoundingBox3D mCroppingBox_d
box defining the cropping size.
virtual void setShadingAmbient(double ambient)
Set shading ambient parmeter.
virtual vtkImageDataPtr getBaseVtkImageData()
static ImagePtr create(ImagePtr base)
virtual void addXml(QDomNode &dataNode)
adds xml information about the data and its variabels
virtual double getShadingSpecular()
Get shading specular parmeter.
virtual void setShadingSpecular(double specular)
Set shading specular parmeter.
virtual void setImageType(const QString &val)
ImagePtr mUnsigned
version of this containing unsigned data.
virtual ImagePtr getUnsigned(ImagePtr self)
virtual void intitializeFromParentImage(ImagePtr parentImage)
virtual QString getUid() const
bool similar(const DoubleBoundingBox3D &a, const DoubleBoundingBox3D &b, double tol)
virtual ImageTF3DPtr getTransferFunctions3D()
void addXml(QDomNode &dataNode)
adds xml information about the image and its variabels
virtual RegistrationHistoryPtr get_rMd_History()
std::map< int, QColor > ColorMap
boost::shared_ptr< class ImageLUT2D > ImageLUT2DPtr
ImageLUT2DPtr generate2DTFPreset()
void startThresholdPreview(const Eigen::Vector2d &threshold)
vtkPlanePtr mInteractiveClipPlane
QString mModality
modality of the image, defined as DICOM tag (0008,0060), Section 3, C.7.3.1.1.1
void reportWarning(QString msg)
virtual int getMaxAlphaValue()
Max alpha value (probably 255)
vtkImageDataPtr convertImageDataTo8Bit(vtkImageDataPtr image, double windowWidth, double windowLevel)
Have never been used or tested. Create a test for it.
virtual void parseXml(QDomNode &dataNode)
Use a XML node to load data.
virtual void setShadingSpecularPower(double specularPower)
Set shading specular power parmeter.
void moveThisAndChildrenToThread(QThread *thread)
Move this and all children to thread. Use the thread is generated in a worker thread and the result i...
virtual int getRange()
For convenience: getMax() - getMin()
virtual void save(const QString &basePath)
void setAcquisitionTime(QDateTime time)
void transferFunctionsChanged()
emitted when image transfer functions in 2D or 3D are changed.
Transform3D createTransformTranslate(const Vector3D &translation)
Representation of an integer bounding box in 3D. The data are stored as {xmin,xmax,ymin,ymax,zmin,zmax}, in order to simplify communication with vtk.
Representation of a floating-point bounding box in 3D. The data are stored as {xmin,xmax,ymin,ymax,zmin,zmax}, in order to simplify communication with vtk.
vtkSmartPointer< class vtkImageResample > vtkImageResamplePtr
vtkImageAccumulatePtr mHistogramPtr
Histogram.
vtkImageDataPtr resample(long maxVoxels)
Eigen::Vector3d Vector3D
Vector3D is a representation of a point or vector in 3D.
Vector3D multiply_elems(const Vector3D &a, const Vector3D &b)
perform element-wise multiplication of a and b.
virtual void setInteractiveClipPlane(vtkPlanePtr plane)
set a plane that is not saved
virtual void setShading(Image::ShadingStruct shading)
vtkImageDataPtr convertImageDataToGrayScale(vtkImageDataPtr image)
RegistrationHistoryPtr m_rMd_History
Superclass for all data objects.
std::map< int, int > IntIntMap
void setDeepModified(vtkImageDataPtr image)
void readInto(DataPtr data, QString path)
virtual DoubleBoundingBox3D getCroppingBox() const
std::vector< vtkPlanePtr > mPersistentClipPlanes
virtual void setCroppingBox(const DoubleBoundingBox3D &bb_d)
ImageTF3DPtr generate3DTFPreset()
void vtkImageDataChanged()
emitted when the vktimagedata are invalidated and must be retrieved anew.
virtual vtkImageDataPtr get8bitGrayScaleVtkImageData()
Have never been used or tested. Create a test for it.
REGISTRATION_STATUS mRegistrationStatus
virtual double getShadingAmbient()
Get shading ambient parmeter.
virtual bool load(QString path)
void stopThresholdPreview()
void setInterpolationType(int val)
virtual QString getImageType() const
void setInterpolationTypeToNearest()
virtual double getShadingSpecularPower()
Get shading specular power parmeter.
vtkImageDataPtr mBaseImageData
image data in data space
int mInterpolationType
mirror the interpolationType in vtkVolumeProperty
vtkSmartPointer< class vtkPlane > vtkPlanePtr
void setInterpolationTypeToLinear()
virtual void clearPersistentClipPlanes()
boost::shared_ptr< class ImageTF3D > ImageTF3DPtr
virtual void setFilename(QString val)
virtual void transformChangedSlot()
virtual ImageLUT2DPtr getLookupTable2D()
virtual bool getShadingOn() const
void resetTransferFunctions(bool _2D=true, bool _3D=true)
Resets the transfer functions and creates new default values.
virtual DoubleBoundingBox3D boundingBox() const
bounding box in image space
vtkImageDataPtr mBaseGrayScaleImageData
image data in data space